From 90b4ceaa71f70126b61fd8be77bce4d3abeaf7f5 Mon Sep 17 00:00:00 2001 From: bohdanbirdie Date: Mon, 14 Jan 2019 00:37:03 +0100 Subject: [PATCH] Remove deprecated react lifecycle method --- build/index.js | 92027 ++++++++++++++++++++++++--------------------- src/OBJViewer.js | 5 +- src/STLViewer.js | 2 +- 3 files changed, 49519 insertions(+), 42515 deletions(-) diff --git a/build/index.js b/build/index.js index 91b6292..563eefb 100644 --- a/build/index.js +++ b/build/index.js @@ -61,17 +61,207 @@ module.exports = /******/ __webpack_require__.p = ""; /******/ /******/ // Load entry module and return exports -/******/ return __webpack_require__(__webpack_require__.s = 23); +/******/ return __webpack_require__(__webpack_require__.s = 21); /******/ }) /************************************************************************/ /******/ ([ /* 0 */ /***/ (function(module, exports) { -module.exports = require("react"); +// shim for using process in browser +var process = module.exports = {}; + +// cached from whatever global is present so that test runners that stub it +// don't break things. But we need to wrap it in a try catch in case it is +// wrapped in strict mode code which doesn't define any globals. It's inside a +// function because try/catches deoptimize in certain engines. + +var cachedSetTimeout; +var cachedClearTimeout; + +function defaultSetTimout() { + throw new Error('setTimeout has not been defined'); +} +function defaultClearTimeout () { + throw new Error('clearTimeout has not been defined'); +} +(function () { + try { + if (typeof setTimeout === 'function') { + cachedSetTimeout = setTimeout; + } else { + cachedSetTimeout = defaultSetTimout; + } + } catch (e) { + cachedSetTimeout = defaultSetTimout; + } + try { + if (typeof clearTimeout === 'function') { + cachedClearTimeout = clearTimeout; + } else { + cachedClearTimeout = defaultClearTimeout; + } + } catch (e) { + cachedClearTimeout = defaultClearTimeout; + } +} ()) +function runTimeout(fun) { + if (cachedSetTimeout === setTimeout) { + //normal enviroments in sane situations + return setTimeout(fun, 0); + } + // if setTimeout wasn't available but was latter defined + if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) { + cachedSetTimeout = setTimeout; + return setTimeout(fun, 0); + } + try { + // when when somebody has screwed with setTimeout but no I.E. maddness + return cachedSetTimeout(fun, 0); + } catch(e){ + try { + // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally + return cachedSetTimeout.call(null, fun, 0); + } catch(e){ + // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error + return cachedSetTimeout.call(this, fun, 0); + } + } + + +} +function runClearTimeout(marker) { + if (cachedClearTimeout === clearTimeout) { + //normal enviroments in sane situations + return clearTimeout(marker); + } + // if clearTimeout wasn't available but was latter defined + if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) { + cachedClearTimeout = clearTimeout; + return clearTimeout(marker); + } + try { + // when when somebody has screwed with setTimeout but no I.E. maddness + return cachedClearTimeout(marker); + } catch (e){ + try { + // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally + return cachedClearTimeout.call(null, marker); + } catch (e){ + // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error. + // Some versions of I.E. have different rules for clearTimeout vs setTimeout + return cachedClearTimeout.call(this, marker); + } + } + + + +} +var queue = []; +var draining = false; +var currentQueue; +var queueIndex = -1; + +function cleanUpNextTick() { + if (!draining || !currentQueue) { + return; + } + draining = false; + if (currentQueue.length) { + queue = currentQueue.concat(queue); + } else { + queueIndex = -1; + } + if (queue.length) { + drainQueue(); + } +} + +function drainQueue() { + if (draining) { + return; + } + var timeout = runTimeout(cleanUpNextTick); + draining = true; + + var len = queue.length; + while(len) { + currentQueue = queue; + queue = []; + while (++queueIndex < len) { + if (currentQueue) { + currentQueue[queueIndex].run(); + } + } + queueIndex = -1; + len = queue.length; + } + currentQueue = null; + draining = false; + runClearTimeout(timeout); +} + +process.nextTick = function (fun) { + var args = new Array(arguments.length - 1); + if (arguments.length > 1) { + for (var i = 1; i < arguments.length; i++) { + args[i - 1] = arguments[i]; + } + } + queue.push(new Item(fun, args)); + if (queue.length === 1 && !draining) { + runTimeout(drainQueue); + } +}; + +// v8 likes predictible objects +function Item(fun, array) { + this.fun = fun; + this.array = array; +} +Item.prototype.run = function () { + this.fun.apply(null, this.array); +}; +process.title = 'browser'; +process.browser = true; +process.env = {}; +process.argv = []; +process.version = ''; // empty string to avoid regexp issues +process.versions = {}; + +function noop() {} + +process.on = noop; +process.addListener = noop; +process.once = noop; +process.off = noop; +process.removeListener = noop; +process.removeAllListeners = noop; +process.emit = noop; +process.prependListener = noop; +process.prependOnceListener = noop; + +process.listeners = function (name) { return [] } + +process.binding = function (name) { + throw new Error('process.binding is not supported'); +}; + +process.cwd = function () { return '/' }; +process.chdir = function (dir) { + throw new Error('process.chdir is not supported'); +}; +process.umask = function() { return 0; }; + /***/ }), /* 1 */ +/***/ (function(module, exports) { + +module.exports = require("react"); + +/***/ }), +/* 2 */ /***/ (function(module, exports, __webpack_require__) { /* WEBPACK VAR INJECTION */(function(process) {/** @@ -96,422 +286,319 @@ if (process.env.NODE_ENV !== 'production') { // By explicitly using `prop-types` you are opting into new development behavior. // http://fb.me/prop-types-in-prod var throwOnDirectAccess = true; - module.exports = __webpack_require__(25)(isValidElement, throwOnDirectAccess); + module.exports = __webpack_require__(23)(isValidElement, throwOnDirectAccess); } else { // By explicitly using `prop-types` you are opting into new production behavior. // http://fb.me/prop-types-in-prod - module.exports = __webpack_require__(26)(); + module.exports = __webpack_require__(24)(); } -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(4))) +/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0))) /***/ }), -/* 2 */ +/* 3 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; Object.defineProperty(__webpack_exports__, "__esModule", { value: true }); -/* WEBPACK VAR INJECTION */(function(process) {/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "sheet", function() { return sheet; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "useStylisPlugin", function() { return useStylisPlugin; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "registered", function() { return registered; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "inserted", function() { return inserted; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "css", function() { return css; }); +/* WEBPACK VAR INJECTION */(function(process) {/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "withEmotionCache", function() { return withEmotionCache; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CacheProvider", function() { return CacheProvider; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ThemeContext", function() { return ThemeContext; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "jsx", function() { return jsx; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Global", function() { return Global; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "keyframes", function() { return keyframes; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "injectGlobal", function() { return injectGlobal; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "fontFace", function() { return fontFace; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "getRegisteredStyles", function() { return getRegisteredStyles; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "merge", function() { return merge; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "cx", function() { return cx; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "hydrate", function() { return hydrate; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "flush", function() { return flush; }); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_emotion_utils__ = __webpack_require__(38); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1_stylis_rule_sheet__ = __webpack_require__(39); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1_stylis_rule_sheet___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_1_stylis_rule_sheet__); - +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ClassNames", function() { return ClassNames; }); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_react__ = __webpack_require__(1); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_react___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_0_react__); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__emotion_cache__ = __webpack_require__(34); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__emotion_utils__ = __webpack_require__(37); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__emotion_serialize__ = __webpack_require__(16); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_4__emotion_sheet__ = __webpack_require__(15); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_5__emotion_css__ = __webpack_require__(17); +/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "css", function() { return __WEBPACK_IMPORTED_MODULE_5__emotion_css__["a"]; }); -/* -high performance StyleSheet for css-in-js systems -- uses multiple style tags behind the scenes for millions of rules -- uses `insertRule` for appending in production for *much* faster performance -- 'polyfills' on server side -// usage -import StyleSheet from 'glamor/lib/sheet' -let styleSheet = new StyleSheet() -styleSheet.inject() -- 'injects' the stylesheet into the page (or into memory if on server) -styleSheet.insert('#box { border: 1px solid red; }') -- appends a css rule into the stylesheet +function _inheritsLoose(subClass, superClass) { + subClass.prototype = Object.create(superClass.prototype); + subClass.prototype.constructor = subClass; + subClass.__proto__ = superClass; +} -styleSheet.flush() -- empties the stylesheet of all its contents +var EmotionCacheContext = Object(__WEBPACK_IMPORTED_MODULE_0_react__["createContext"])(Object(__WEBPACK_IMPORTED_MODULE_1__emotion_cache__["a" /* default */])()); +var ThemeContext = Object(__WEBPACK_IMPORTED_MODULE_0_react__["createContext"])({}); +var CacheProvider = EmotionCacheContext.Provider; -*/ -function sheetForTag(tag) { - if (tag.sheet) { - return tag.sheet; - } // this weirdness brought to you by firefox +var withEmotionCache = function withEmotionCache(func) { + var render = function render(props, ref) { + return Object(__WEBPACK_IMPORTED_MODULE_0_react__["createElement"])(EmotionCacheContext.Consumer, null, function ( // $FlowFixMe we know it won't be null + cache) { + return func(props, cache, ref); + }); + }; // $FlowFixMe - for (var i = 0; i < document.styleSheets.length; i++) { - if (document.styleSheets[i].ownerNode === tag) { - return document.styleSheets[i]; - } - } -} + return Object(__WEBPACK_IMPORTED_MODULE_0_react__["forwardRef"])(render); +}; -function makeStyleTag() { - var tag = document.createElement('style'); - tag.type = 'text/css'; - tag.setAttribute('data-emotion', ''); - tag.appendChild(document.createTextNode('')); - document.head.appendChild(tag); - return tag; -} +var typePropName = '__EMOTION_TYPE_PLEASE_DO_NOT_USE__'; +var labelPropName = '__EMOTION_LABEL_PLEASE_DO_NOT_USE__'; +var hasOwnProperty = Object.prototype.hasOwnProperty; -var StyleSheet = -/*#__PURE__*/ -function () { - function StyleSheet() { - this.isBrowser = typeof window !== 'undefined'; - this.isSpeedy = process.env.NODE_ENV === 'production'; // the big drawback here is that the css won't be editable in devtools +var render = function render(cache, props, theme, ref) { + var type = props[typePropName]; + var registeredStyles = []; + var className = ''; + var cssProp = theme === null ? props.css : props.css(theme); // so that using `css` from `emotion` and passing the result to the css prop works + // not passing the registered cache to serializeStyles because it would + // make certain babel optimisations not possible - this.tags = []; - this.ctr = 0; + if (typeof cssProp === 'string' && cache.registered[cssProp] !== undefined) { + cssProp = cache.registered[cssProp]; } - var _proto = StyleSheet.prototype; + registeredStyles.push(cssProp); - _proto.inject = function inject() { - if (this.injected) { - throw new Error('already injected!'); - } + if (props.className !== undefined) { + className = Object(__WEBPACK_IMPORTED_MODULE_2__emotion_utils__["a" /* getRegisteredStyles */])(cache.registered, registeredStyles, props.className); + } - if (this.isBrowser) { - this.tags[0] = makeStyleTag(); - } else { - // server side 'polyfill'. just enough behavior to be useful. - this.sheet = []; - } + var serialized = Object(__WEBPACK_IMPORTED_MODULE_3__emotion_serialize__["a" /* serializeStyles */])(registeredStyles); - this.injected = true; - }; + if (process.env.NODE_ENV !== 'production' && serialized.name.indexOf('-') === -1) { + var labelFromStack = props[labelPropName]; - _proto.speedy = function speedy(bool) { - if (this.ctr !== 0) { - // cannot change speedy mode after inserting any rule to sheet. Either call speedy(${bool}) earlier in your app, or call flush() before speedy(${bool}) - throw new Error("cannot change speedy now"); + if (labelFromStack) { + serialized = Object(__WEBPACK_IMPORTED_MODULE_3__emotion_serialize__["a" /* serializeStyles */])([serialized, 'label:' + labelFromStack + ';']); } + } - this.isSpeedy = !!bool; - }; - - _proto.insert = function insert(rule, sourceMap) { - if (this.isBrowser) { - // this is the ultrafast version, works across browsers - if (this.isSpeedy) { - var tag = this.tags[this.tags.length - 1]; - var sheet = sheetForTag(tag); - - try { - sheet.insertRule(rule, sheet.cssRules.length); - } catch (e) { - if (process.env.NODE_ENV !== 'production') { - console.warn('illegal rule', rule); // eslint-disable-line no-console - } - } - } else { - var _tag = makeStyleTag(); - - this.tags.push(_tag); - - _tag.appendChild(document.createTextNode(rule + (sourceMap || ''))); - } - - this.ctr++; - - if (this.ctr % 65000 === 0) { - this.tags.push(makeStyleTag()); - } - } else { - // enough 'spec compliance' to be able to extract the rules later - // in other words, just the rule - this.sheet.push(rule); - } - }; + var rules = Object(__WEBPACK_IMPORTED_MODULE_2__emotion_utils__["b" /* insertStyles */])(cache, serialized, typeof type === 'string'); + className += cache.key + "-" + serialized.name; + var newProps = {}; - _proto.flush = function flush() { - if (this.isBrowser) { - this.tags.forEach(function (tag) { - return tag.parentNode.removeChild(tag); - }); - this.tags = []; - this.ctr = 0; // todo - look for remnants in document.styleSheets - } else { - // simpler on server - this.sheet = []; + for (var key in props) { + if (hasOwnProperty.call(props, key) && key !== 'css' && key !== typePropName && (process.env.NODE_ENV === 'production' || key !== labelPropName)) { + newProps[key] = props[key]; } + } - this.injected = false; - }; - - return StyleSheet; -}(); - -var sheet = new StyleSheet(); // 🚀 + newProps.ref = ref; + newProps.className = className; + var ele = Object(__WEBPACK_IMPORTED_MODULE_0_react__["createElement"])(type, newProps); -sheet.inject(); -var stylisOptions = { - keyframe: false + return ele; }; -if (process.env.NODE_ENV !== 'production') { - stylisOptions.compress = false; -} - -var stylis = new __WEBPACK_IMPORTED_MODULE_0_emotion_utils__["b" /* Stylis */](stylisOptions); -var externalStylisPlugins = []; -var use = stylis.use; +var Emotion = withEmotionCache(function (props, cache, ref) { + // use Context.read for the theme when it's stable + if (typeof props.css === 'function') { + return Object(__WEBPACK_IMPORTED_MODULE_0_react__["createElement"])(ThemeContext.Consumer, null, function (theme) { + return render(cache, props, theme, ref); + }); + } -function insertRule(rule) { - sheet.insert(rule, currentSourceMap); -} + return render(cache, props, null, ref); +}); // $FlowFixMe -var insertionPlugin = __WEBPACK_IMPORTED_MODULE_1_stylis_rule_sheet___default()(insertRule); -var useStylisPlugin = function useStylisPlugin(plugin) { - externalStylisPlugins.push(plugin); - use(null)(externalStylisPlugins)(insertionPlugin); -}; -var registered = {}; -var inserted = {}; -var currentSourceMap = ''; -stylis.use(insertionPlugin); +var jsx = function jsx(type, props) { + var args = arguments; -function handleInterpolation(interpolation, couldBeSelectorInterpolation) { - if (interpolation == null) { - return ''; + if (props == null || props.css == null) { + // $FlowFixMe + return __WEBPACK_IMPORTED_MODULE_0_react__["createElement"].apply(undefined, args); } - switch (typeof interpolation) { - case 'boolean': - return ''; - - case 'function': - if (interpolation[__WEBPACK_IMPORTED_MODULE_0_emotion_utils__["a" /* STYLES_KEY */]] !== undefined) { - if (process.env.NODE_ENV !== 'production' && interpolation[__WEBPACK_IMPORTED_MODULE_0_emotion_utils__["c" /* TARGET_KEY */]] === undefined) { - throw new Error('Component selectors can only be used in conjunction with babel-plugin-emotion.'); - } + if (process.env.NODE_ENV !== 'production' && typeof props.css === 'string' && // check if there is a css declaration + props.css.indexOf(':') !== -1) { + throw new Error("Strings are not allowed as css prop values, please wrap it in a css template literal from '@emotion/css' like this: css`" + props.css + "`"); + } - return "." + interpolation[__WEBPACK_IMPORTED_MODULE_0_emotion_utils__["c" /* TARGET_KEY */]]; - } + var argsLength = args.length; + var createElementArgArray = new Array(argsLength); + createElementArgArray[0] = Emotion; + var newProps = {}; - return handleInterpolation.call(this, this === undefined ? interpolation() : interpolation(this.mergedProps, this.context), couldBeSelectorInterpolation); + for (var key in props) { + if (hasOwnProperty.call(props, key)) { + newProps[key] = props[key]; + } + } - case 'object': - return createStringFromObject.call(this, interpolation); + newProps[typePropName] = type; - default: - var cached = registered[interpolation]; - return couldBeSelectorInterpolation === false && cached !== undefined ? cached : interpolation; - } -} + if (process.env.NODE_ENV !== 'production') { + var error = new Error(); -var hyphenateRegex = /[A-Z]|^ms/g; -var processStyleName = Object(__WEBPACK_IMPORTED_MODULE_0_emotion_utils__["e" /* memoize */])(function (styleName) { - return styleName.replace(hyphenateRegex, '-$&').toLowerCase(); -}); + if (error.stack) { + // chrome + var match = error.stack.match(/at jsx.*\n\s+at ([A-Z][A-Za-z]+) /); -var processStyleValue = function processStyleValue(key, value) { - if (value === undefined || value === null || typeof value === 'boolean') return ''; + if (!match) { + // safari and firefox + match = error.stack.match(/^.*\n([A-Z][A-Za-z]+)@/); + } - if (__WEBPACK_IMPORTED_MODULE_0_emotion_utils__["f" /* unitless */][key] !== 1 && key.charCodeAt(1) !== 45 && // custom properties - !isNaN(value) && value !== 0) { - return value + 'px'; + if (match) { + newProps[labelPropName] = match[1]; + } + } } - return value; -}; + createElementArgArray[1] = newProps; -var objectToStringCache = new WeakMap(); + for (var i = 2; i < argsLength; i++) { + createElementArgArray[i] = args[i]; + } // $FlowFixMe -function createStringFromObject(obj) { - if (objectToStringCache.has(obj)) { - return objectToStringCache.get(obj); - } - var string = ''; + return __WEBPACK_IMPORTED_MODULE_0_react__["createElement"].apply(null, createElementArgArray); +}; - if (Array.isArray(obj)) { - obj.forEach(function (interpolation) { - string += handleInterpolation.call(this, interpolation, false); - }, this); - } else { - Object.keys(obj).forEach(function (key) { - if (typeof obj[key] !== 'object') { - if (registered[obj[key]] !== undefined) { - string += key + "{" + registered[obj[key]] + "}"; - } else { - string += processStyleName(key) + ":" + processStyleValue(key, obj[key]) + ";"; - } - } else { - string += key + "{" + handleInterpolation.call(this, obj[key], false) + "}"; - } - }, this); +var warnedAboutCssPropForGlobal = false; +var Global = +/* #__PURE__ */ +withEmotionCache(function (props, cache) { + if (process.env.NODE_ENV !== 'production' && !warnedAboutCssPropForGlobal && ( // check for className as well since the user is + // probably using the custom createElement which + // means it will be turned into a className prop + // $FlowFixMe I don't really want to add it to the type since it shouldn't be used + props.className || props.css)) { + console.error("It looks like you're using the css prop on Global, did you mean to use the styles prop instead?"); + warnedAboutCssPropForGlobal = true; + } + + var styles = props.styles; + + if (typeof styles === 'function') { + return Object(__WEBPACK_IMPORTED_MODULE_0_react__["createElement"])(ThemeContext.Consumer, null, function (theme) { + var serialized = Object(__WEBPACK_IMPORTED_MODULE_3__emotion_serialize__["a" /* serializeStyles */])([styles(theme)]); + return Object(__WEBPACK_IMPORTED_MODULE_0_react__["createElement"])(InnerGlobal, { + serialized: serialized, + cache: cache + }); + }); } - objectToStringCache.set(obj, string); - return string; -} + var serialized = Object(__WEBPACK_IMPORTED_MODULE_3__emotion_serialize__["a" /* serializeStyles */])([styles]); + return Object(__WEBPACK_IMPORTED_MODULE_0_react__["createElement"])(InnerGlobal, { + serialized: serialized, + cache: cache + }); +}); -function isLastCharDot(string) { - return string.charCodeAt(string.length - 1) === 46; // . -} +// maintain place over rerenders. +// initial render from browser, insertBefore context.sheet.tags[0] or if a style hasn't been inserted there yet, appendChild +// initial client-side render from SSR, use place of hydrating tag +var InnerGlobal = +/*#__PURE__*/ +function (_React$Component) { + _inheritsLoose(InnerGlobal, _React$Component); -var hash; -var name; -var labelPattern = /label:\s*([^\s;\n]+)\s*[;\n]/g; + function InnerGlobal(props, context, updater) { + return _React$Component.call(this, props, context, updater) || this; + } -function createStyles(strings) { - var stringMode = true; - var styles = ''; - var identifierName = ''; + var _proto = InnerGlobal.prototype; - if (strings == null || strings.raw === undefined) { - stringMode = false; - styles = handleInterpolation.call(this, strings, false); - } else { - styles = strings[0]; - } + _proto.componentDidMount = function componentDidMount() { + this.sheet = new __WEBPACK_IMPORTED_MODULE_4__emotion_sheet__["a" /* StyleSheet */]({ + key: this.props.cache.key + "-global", + nonce: this.props.cache.sheet.nonce, + container: this.props.cache.sheet.container + }); // $FlowFixMe - for (var _len = arguments.length, interpolations = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { - interpolations[_key - 1] = arguments[_key]; - } + var node = document.querySelector("style[data-emotion-" + this.props.cache.key + "=\"" + this.props.serialized.name + "\"]"); - interpolations.forEach(function (interpolation, i) { - styles += handleInterpolation.call(this, interpolation, isLastCharDot(styles)); + if (node !== null) { + this.sheet.tags.push(node); + } - if (stringMode === true && strings[i + 1] !== undefined) { - styles += strings[i + 1]; + if (this.props.cache.sheet.tags.length) { + this.sheet.before = this.props.cache.sheet.tags[0]; } - }, this); - styles = styles.replace(labelPattern, function (match, p1) { - identifierName += "-" + p1; - return ''; - }); - hash = Object(__WEBPACK_IMPORTED_MODULE_0_emotion_utils__["d" /* hashString */])(styles + identifierName); - name = hash + identifierName; - return styles; -} -if (process.env.NODE_ENV !== 'production') { - var sourceMapRegEx = /\/\*#\ssourceMappingURL=data:application\/json;\S+\s+\*\//; - var oldStylis = stylis; - - stylis = function stylis(selector, styles) { - var result = sourceMapRegEx.exec(styles); - currentSourceMap = result ? result[0] : ''; - oldStylis(selector, styles); - currentSourceMap = ''; + this.insertStyles(); }; -} -function css() { - var styles = createStyles.apply(this, arguments); - var selector = "css-" + name; + _proto.componentDidUpdate = function componentDidUpdate(prevProps) { + if (prevProps.serialized.name !== this.props.serialized.name) { + this.insertStyles(); + } + }; - if (registered[selector] === undefined) { - registered[selector] = styles; - } + _proto.insertStyles = function insertStyles$$1() { + if (this.props.serialized.next !== undefined) { + // insert keyframes + Object(__WEBPACK_IMPORTED_MODULE_2__emotion_utils__["b" /* insertStyles */])(this.props.cache, this.props.serialized.next, true); + } - if (inserted[hash] === undefined) { - stylis("." + selector, styles); - inserted[hash] = true; - } + if (this.sheet.tags.length) { + // if this doesn't exist then it will be null so the style element will be appended + var element = this.sheet.tags[this.sheet.tags.length - 1].nextElementSibling; + this.sheet.before = element; + this.sheet.flush(); + } - return selector; -} -function keyframes() { - var styles = createStyles.apply(this, arguments); - var animation = "animation-" + name; + this.props.cache.insert("", this.props.serialized, this.sheet, false); + }; - if (inserted[hash] === undefined) { - stylis('', "@keyframes " + animation + "{" + styles + "}"); - inserted[hash] = true; - } + _proto.componentWillUnmount = function componentWillUnmount() { + this.sheet.flush(); + }; - return animation; -} -function injectGlobal() { - var styles = createStyles.apply(this, arguments); + _proto.render = function render() { - if (inserted[hash] === undefined) { - stylis('', styles); - inserted[hash] = true; - } -} -function fontFace() { - var styles = createStyles.apply(void 0, arguments); + return null; + }; - if (inserted[hash] === undefined) { - stylis('', "@font-face{" + styles + "}"); - inserted[hash] = true; - } -} -function getRegisteredStyles(registeredStyles, classNames) { - var rawClassName = ''; - classNames.split(' ').forEach(function (className) { - if (registered[className] !== undefined) { - registeredStyles.push(className); - } else { - rawClassName += className + " "; - } - }); - return rawClassName; -} -function merge(className, sourceMap) { - var registeredStyles = []; - var rawClassName = getRegisteredStyles(registeredStyles, className); + return InnerGlobal; +}(__WEBPACK_IMPORTED_MODULE_0_react__["Component"]); - if (registeredStyles.length < 2) { - return className; - } +var keyframes = function keyframes() { + var insertable = __WEBPACK_IMPORTED_MODULE_5__emotion_css__["a" /* default */].apply(void 0, arguments); + var name = "animation-" + insertable.name; // $FlowFixMe - return rawClassName + css(registeredStyles, sourceMap); -} + return { + name: name, + styles: "@keyframes " + name + "{" + insertable.styles + "}", + anim: 1, + toString: function toString() { + return "_EMO_" + this.name + "_" + this.styles + "_EMO_"; + } + }; +}; -function classnames() { - var len = arguments.length; +var classnames = function classnames(args) { + var len = args.length; var i = 0; var cls = ''; for (; i < len; i++) { - var arg = arguments[i]; + var arg = args[i]; if (arg == null) continue; - var next = cls && cls + ' ' || cls; + var toAdd = void 0; switch (typeof arg) { case 'boolean': break; - case 'function': - cls = next + classnames(arg()); - break; - case 'object': { if (Array.isArray(arg)) { - cls = next + classnames.apply(null, arg); + toAdd = classnames(arg); } else { + toAdd = ''; + for (var k in arg) { - if (arg[k]) { - cls && (cls += ' '); - cls += k; + if (arg[k] && k) { + toAdd && (toAdd += ' '); + toAdd += k; } } } @@ -521,3167 +608,1583 @@ function classnames() { default: { - cls = next + arg; + toAdd = arg; } } - } - - return cls; -} - -function cx() { - return merge(classnames.apply(void 0, arguments)); -} -function hydrate(ids) { - ids.forEach(function (id) { - inserted[id] = true; - }); -} -function flush() { - sheet.flush(); - inserted = {}; - registered = {}; - sheet.inject(); -} - - -//# sourceMappingURL=index.es.js.map - -/* WEBPACK VAR INJECTION */}.call(__webpack_exports__, __webpack_require__(4))) - -/***/ }), -/* 3 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -Object.defineProperty(__webpack_exports__, "__esModule", { value: true }); -/* WEBPACK VAR INJECTION */(function(process) {/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "mapProps", function() { return mapProps; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "withProps", function() { return withProps; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "withPropsOnChange", function() { return withPropsOnChange; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "withHandlers", function() { return withHandlers; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "defaultProps", function() { return defaultProps; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "renameProp", function() { return renameProp; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "renameProps", function() { return renameProps; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "flattenProp", function() { return flattenProp; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "withState", function() { return withState; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "withStateHandlers", function() { return withStateHandlers; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "withReducer", function() { return withReducer; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "branch", function() { return branch; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "renderComponent", function() { return renderComponent; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "renderNothing", function() { return renderNothing; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "shouldUpdate", function() { return shouldUpdate; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "pure", function() { return pure; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "onlyUpdateForKeys", function() { return onlyUpdateForKeys; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "onlyUpdateForPropTypes", function() { return onlyUpdateForPropTypes; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "withContext", function() { return withContext; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "getContext", function() { return getContext; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "lifecycle", function() { return lifecycle; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "toClass", function() { return toClass; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "setStatic", function() { return setStatic; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "setPropTypes", function() { return setPropTypes; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "setDisplayName", function() { return setDisplayName; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "compose", function() { return compose; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "getDisplayName", function() { return getDisplayName; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "wrapDisplayName", function() { return wrapDisplayName; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "isClassComponent", function() { return isClassComponent; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "createSink", function() { return createSink; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "componentFromProp", function() { return componentFromProp; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "nest", function() { return nest; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "hoistStatics", function() { return hoistStatics; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "componentFromStream", function() { return componentFromStream; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "componentFromStreamWithConfig", function() { return componentFromStreamWithConfig; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "mapPropsStream", function() { return mapPropsStream; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "mapPropsStreamWithConfig", function() { return mapPropsStreamWithConfig; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "createEventHandler", function() { return createEventHandler; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "createEventHandlerWithConfig", function() { return createEventHandlerWithConfig; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "setObservableConfig", function() { return configureObservable; }); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_react__ = __webpack_require__(0); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_react___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_0_react__); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1_fbjs_lib_shallowEqual__ = __webpack_require__(10); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1_fbjs_lib_shallowEqual___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_1_fbjs_lib_shallowEqual__); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2_hoist_non_react_statics__ = __webpack_require__(40); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2_hoist_non_react_statics___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_2_hoist_non_react_statics__); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3_change_emitter__ = __webpack_require__(41); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3_change_emitter___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_3_change_emitter__); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_4_symbol_observable__ = __webpack_require__(42); -/* harmony reexport (default from non-hamory) */ __webpack_require__.d(__webpack_exports__, "shallowEqual", function() { return __WEBPACK_IMPORTED_MODULE_1_fbjs_lib_shallowEqual___default.a; }); - - - - - - -var setStatic = function setStatic(key, value) { - return function (BaseComponent) { - /* eslint-disable no-param-reassign */ - BaseComponent[key] = value; - /* eslint-enable no-param-reassign */ - return BaseComponent; - }; -}; - -var setDisplayName = function setDisplayName(displayName) { - return setStatic('displayName', displayName); -}; -var getDisplayName = function getDisplayName(Component$$1) { - if (typeof Component$$1 === 'string') { - return Component$$1; - } - - if (!Component$$1) { - return undefined; + if (toAdd) { + cls && (cls += ' '); + cls += toAdd; + } } - return Component$$1.displayName || Component$$1.name || 'Component'; -}; - -var wrapDisplayName = function wrapDisplayName(BaseComponent, hocName) { - return hocName + '(' + getDisplayName(BaseComponent) + ')'; + return cls; }; -var mapProps = function mapProps(propsMapper) { - return function (BaseComponent) { - var factory = Object(__WEBPACK_IMPORTED_MODULE_0_react__["createFactory"])(BaseComponent); - var MapProps = function MapProps(props) { - return factory(propsMapper(props)); - }; - if (process.env.NODE_ENV !== 'production') { - return setDisplayName(wrapDisplayName(BaseComponent, 'mapProps'))(MapProps); - } - return MapProps; - }; -}; +function merge(registered, css$$1, className) { + var registeredStyles = []; + var rawClassName = Object(__WEBPACK_IMPORTED_MODULE_2__emotion_utils__["a" /* getRegisteredStyles */])(registered, registeredStyles, className); -var classCallCheck = function (instance, Constructor) { - if (!(instance instanceof Constructor)) { - throw new TypeError("Cannot call a class as a function"); + if (registeredStyles.length < 2) { + return className; } -}; - - + return rawClassName + css$$1(registeredStyles); +} +var ClassNames = withEmotionCache(function (props, context) { + return Object(__WEBPACK_IMPORTED_MODULE_0_react__["createElement"])(ThemeContext.Consumer, null, function (theme) { + var hasRendered = false; + var css$$1 = function css$$1() { + if (hasRendered && process.env.NODE_ENV !== 'production') { + throw new Error('css can only be used during render'); + } + for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { + args[_key] = arguments[_key]; + } + var serialized = Object(__WEBPACK_IMPORTED_MODULE_3__emotion_serialize__["a" /* serializeStyles */])(args, context.registered); + { + Object(__WEBPACK_IMPORTED_MODULE_2__emotion_utils__["b" /* insertStyles */])(context, serialized, false); + } -var _extends = Object.assign || function (target) { - for (var i = 1; i < arguments.length; i++) { - var source = arguments[i]; + return context.key + "-" + serialized.name; + }; - for (var key in source) { - if (Object.prototype.hasOwnProperty.call(source, key)) { - target[key] = source[key]; + var cx = function cx() { + if (hasRendered && process.env.NODE_ENV !== 'production') { + throw new Error('cx can only be used during render'); } - } - } - - return target; -}; + for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { + args[_key2] = arguments[_key2]; + } + return merge(context.registered, css$$1, classnames(args)); + }; -var inherits = function (subClass, superClass) { - if (typeof superClass !== "function" && superClass !== null) { - throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); - } + var content = { + css: css$$1, + cx: cx, + theme: theme + }; + var ele = props.children(content); + hasRendered = true; - subClass.prototype = Object.create(superClass && superClass.prototype, { - constructor: { - value: subClass, - enumerable: false, - writable: true, - configurable: true - } + return ele; }); - if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; -}; - +}); +/* WEBPACK VAR INJECTION */}.call(__webpack_exports__, __webpack_require__(0))) +/***/ }), +/* 4 */ +/***/ (function(module, exports, __webpack_require__) { +"use strict"; +/* WEBPACK VAR INJECTION */(function(process) { +var _interopRequireDefault = __webpack_require__(5); +exports.__esModule = true; +exports.default = void 0; -var objectWithoutProperties = function (obj, keys) { - var target = {}; +var _shouldUpdate = _interopRequireDefault(__webpack_require__(41)); - for (var i in obj) { - if (keys.indexOf(i) >= 0) continue; - if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; - target[i] = obj[i]; - } +var _shallowEqual = _interopRequireDefault(__webpack_require__(45)); - return target; -}; +var _setDisplayName = _interopRequireDefault(__webpack_require__(18)); -var possibleConstructorReturn = function (self, call) { - if (!self) { - throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); - } +var _wrapDisplayName = _interopRequireDefault(__webpack_require__(19)); - return call && (typeof call === "object" || typeof call === "function") ? call : self; -}; +var _pick = _interopRequireDefault(__webpack_require__(47)); -var withProps = function withProps(input) { - var hoc = mapProps(function (props) { - return _extends({}, props, typeof input === 'function' ? input(props) : input); +var onlyUpdateForKeys = function onlyUpdateForKeys(propKeys) { + var hoc = (0, _shouldUpdate.default)(function (props, nextProps) { + return !(0, _shallowEqual.default)((0, _pick.default)(nextProps, propKeys), (0, _pick.default)(props, propKeys)); }); + if (process.env.NODE_ENV !== 'production') { return function (BaseComponent) { - return setDisplayName(wrapDisplayName(BaseComponent, 'withProps'))(hoc(BaseComponent)); + return (0, _setDisplayName.default)((0, _wrapDisplayName.default)(BaseComponent, 'onlyUpdateForKeys'))(hoc(BaseComponent)); }; } + return hoc; }; -var pick = function pick(obj, keys) { - var result = {}; - for (var i = 0; i < keys.length; i++) { - var key = keys[i]; - if (obj.hasOwnProperty(key)) { - result[key] = obj[key]; - } - } - return result; -}; +var _default = onlyUpdateForKeys; +exports.default = _default; +/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0))) -var withPropsOnChange = function withPropsOnChange(shouldMapOrKeys, propsMapper) { - return function (BaseComponent) { - var factory = Object(__WEBPACK_IMPORTED_MODULE_0_react__["createFactory"])(BaseComponent); - var shouldMap = typeof shouldMapOrKeys === 'function' ? shouldMapOrKeys : function (props, nextProps) { - return !__WEBPACK_IMPORTED_MODULE_1_fbjs_lib_shallowEqual___default()(pick(props, shouldMapOrKeys), pick(nextProps, shouldMapOrKeys)); - }; +/***/ }), +/* 5 */ +/***/ (function(module, exports) { - var WithPropsOnChange = function (_Component) { - inherits(WithPropsOnChange, _Component); +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { + default: obj + }; +} - function WithPropsOnChange() { - var _temp, _this, _ret; +module.exports = _interopRequireDefault; - classCallCheck(this, WithPropsOnChange); +/***/ }), +/* 6 */ +/***/ (function(module, exports, __webpack_require__) { - for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { - args[_key] = arguments[_key]; - } +"use strict"; +/* +object-assign +(c) Sindre Sorhus +@license MIT +*/ - return _ret = (_temp = (_this = possibleConstructorReturn(this, _Component.call.apply(_Component, [this].concat(args))), _this), _this.computedProps = propsMapper(_this.props), _temp), possibleConstructorReturn(_this, _ret); - } - WithPropsOnChange.prototype.componentWillReceiveProps = function componentWillReceiveProps(nextProps) { - if (shouldMap(this.props, nextProps)) { - this.computedProps = propsMapper(nextProps); - } - }; +/* eslint-disable no-unused-vars */ +var getOwnPropertySymbols = Object.getOwnPropertySymbols; +var hasOwnProperty = Object.prototype.hasOwnProperty; +var propIsEnumerable = Object.prototype.propertyIsEnumerable; - WithPropsOnChange.prototype.render = function render() { - return factory(_extends({}, this.props, this.computedProps)); - }; +function toObject(val) { + if (val === null || val === undefined) { + throw new TypeError('Object.assign cannot be called with null or undefined'); + } - return WithPropsOnChange; - }(__WEBPACK_IMPORTED_MODULE_0_react__["Component"]); + return Object(val); +} - if (process.env.NODE_ENV !== 'production') { - return setDisplayName(wrapDisplayName(BaseComponent, 'withPropsOnChange'))(WithPropsOnChange); - } - return WithPropsOnChange; - }; -}; +function shouldUseNative() { + try { + if (!Object.assign) { + return false; + } -var mapValues = function mapValues(obj, func) { - var result = {}; - /* eslint-disable no-restricted-syntax */ - for (var key in obj) { - if (obj.hasOwnProperty(key)) { - result[key] = func(obj[key], key); - } - } - /* eslint-enable no-restricted-syntax */ - return result; -}; - -/* eslint-disable no-console */ -var withHandlers = function withHandlers(handlers) { - return function (BaseComponent) { - var factory = Object(__WEBPACK_IMPORTED_MODULE_0_react__["createFactory"])(BaseComponent); - - var WithHandlers = function (_Component) { - inherits(WithHandlers, _Component); - - function WithHandlers() { - var _temp, _this, _ret; - - classCallCheck(this, WithHandlers); - - for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { - args[_key] = arguments[_key]; - } - - return _ret = (_temp = (_this = possibleConstructorReturn(this, _Component.call.apply(_Component, [this].concat(args))), _this), _initialiseProps.call(_this), _temp), possibleConstructorReturn(_this, _ret); - } - - WithHandlers.prototype.componentWillReceiveProps = function componentWillReceiveProps() { - this.cachedHandlers = {}; - }; - - WithHandlers.prototype.render = function render() { - return factory(_extends({}, this.props, this.handlers)); - }; - - return WithHandlers; - }(__WEBPACK_IMPORTED_MODULE_0_react__["Component"]); - - var _initialiseProps = function _initialiseProps() { - var _this2 = this; - - this.cachedHandlers = {}; - this.handlers = mapValues(typeof handlers === 'function' ? handlers(this.props) : handlers, function (createHandler, handlerName) { - return function () { - var cachedHandler = _this2.cachedHandlers[handlerName]; - if (cachedHandler) { - return cachedHandler.apply(undefined, arguments); - } + // Detect buggy property enumeration order in older V8 versions. - var handler = createHandler(_this2.props); - _this2.cachedHandlers[handlerName] = handler; + // https://bugs.chromium.org/p/v8/issues/detail?id=4118 + var test1 = new String('abc'); // eslint-disable-line no-new-wrappers + test1[5] = 'de'; + if (Object.getOwnPropertyNames(test1)[0] === '5') { + return false; + } - if (process.env.NODE_ENV !== 'production' && typeof handler !== 'function') { - console.error( - // eslint-disable-line no-console - 'withHandlers(): Expected a map of higher-order functions. ' + 'Refer to the docs for more info.'); - } + // https://bugs.chromium.org/p/v8/issues/detail?id=3056 + var test2 = {}; + for (var i = 0; i < 10; i++) { + test2['_' + String.fromCharCode(i)] = i; + } + var order2 = Object.getOwnPropertyNames(test2).map(function (n) { + return test2[n]; + }); + if (order2.join('') !== '0123456789') { + return false; + } - return handler.apply(undefined, arguments); - }; - }); - }; + // https://bugs.chromium.org/p/v8/issues/detail?id=3056 + var test3 = {}; + 'abcdefghijklmnopqrst'.split('').forEach(function (letter) { + test3[letter] = letter; + }); + if (Object.keys(Object.assign({}, test3)).join('') !== + 'abcdefghijklmnopqrst') { + return false; + } - if (process.env.NODE_ENV !== 'production') { - return setDisplayName(wrapDisplayName(BaseComponent, 'withHandlers'))(WithHandlers); - } - return WithHandlers; - }; -}; + return true; + } catch (err) { + // We don't expect any of the above to throw, but better to be safe. + return false; + } +} -var defaultProps = function defaultProps(props) { - return function (BaseComponent) { - var factory = Object(__WEBPACK_IMPORTED_MODULE_0_react__["createFactory"])(BaseComponent); - var DefaultProps = function DefaultProps(ownerProps) { - return factory(ownerProps); - }; - DefaultProps.defaultProps = props; - if (process.env.NODE_ENV !== 'production') { - return setDisplayName(wrapDisplayName(BaseComponent, 'defaultProps'))(DefaultProps); - } - return DefaultProps; - }; -}; +module.exports = shouldUseNative() ? Object.assign : function (target, source) { + var from; + var to = toObject(target); + var symbols; -var omit = function omit(obj, keys) { - var rest = objectWithoutProperties(obj, []); + for (var s = 1; s < arguments.length; s++) { + from = Object(arguments[s]); - for (var i = 0; i < keys.length; i++) { - var key = keys[i]; - if (rest.hasOwnProperty(key)) { - delete rest[key]; - } - } - return rest; -}; + for (var key in from) { + if (hasOwnProperty.call(from, key)) { + to[key] = from[key]; + } + } -var renameProp = function renameProp(oldName, newName) { - var hoc = mapProps(function (props) { - var _babelHelpers$extends; + if (getOwnPropertySymbols) { + symbols = getOwnPropertySymbols(from); + for (var i = 0; i < symbols.length; i++) { + if (propIsEnumerable.call(from, symbols[i])) { + to[symbols[i]] = from[symbols[i]]; + } + } + } + } - return _extends({}, omit(props, [oldName]), (_babelHelpers$extends = {}, _babelHelpers$extends[newName] = props[oldName], _babelHelpers$extends)); - }); - if (process.env.NODE_ENV !== 'production') { - return function (BaseComponent) { - return setDisplayName(wrapDisplayName(BaseComponent, 'renameProp'))(hoc(BaseComponent)); - }; - } - return hoc; + return to; }; -var keys = Object.keys; - -var mapKeys = function mapKeys(obj, func) { - return keys(obj).reduce(function (result, key) { - var val = obj[key]; - /* eslint-disable no-param-reassign */ - result[func(val, key)] = val; - /* eslint-enable no-param-reassign */ - return result; - }, {}); -}; +/***/ }), +/* 7 */ +/***/ (function(module, exports, __webpack_require__) { -var renameProps = function renameProps(nameMap) { - var hoc = mapProps(function (props) { - return _extends({}, omit(props, keys(nameMap)), mapKeys(pick(props, keys(nameMap)), function (_, oldName) { - return nameMap[oldName]; - })); - }); - if (process.env.NODE_ENV !== 'production') { - return function (BaseComponent) { - return setDisplayName(wrapDisplayName(BaseComponent, 'renameProps'))(hoc(BaseComponent)); - }; - } - return hoc; -}; +"use strict"; +/** + * Copyright (c) 2013-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ -var flattenProp = function flattenProp(propName) { - return function (BaseComponent) { - var factory = Object(__WEBPACK_IMPORTED_MODULE_0_react__["createFactory"])(BaseComponent); - var FlattenProp = function FlattenProp(props) { - return factory(_extends({}, props, props[propName])); - }; - if (process.env.NODE_ENV !== 'production') { - return setDisplayName(wrapDisplayName(BaseComponent, 'flattenProp'))(FlattenProp); - } - return FlattenProp; - }; -}; -var withState = function withState(stateName, stateUpdaterName, initialState) { - return function (BaseComponent) { - var factory = Object(__WEBPACK_IMPORTED_MODULE_0_react__["createFactory"])(BaseComponent); +var ReactPropTypesSecret = 'SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED'; - var WithState = function (_Component) { - inherits(WithState, _Component); +module.exports = ReactPropTypesSecret; - function WithState() { - var _temp, _this, _ret; - classCallCheck(this, WithState); +/***/ }), +/* 8 */ +/***/ (function(module, exports, __webpack_require__) { - for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { - args[_key] = arguments[_key]; - } +"use strict"; +/* WEBPACK VAR INJECTION */(function(process) {/** + * Copyright (c) 2013-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ - return _ret = (_temp = (_this = possibleConstructorReturn(this, _Component.call.apply(_Component, [this].concat(args))), _this), _this.state = { - stateValue: typeof initialState === 'function' ? initialState(_this.props) : initialState - }, _this.updateStateValue = function (updateFn, callback) { - return _this.setState(function (_ref) { - var stateValue = _ref.stateValue; - return { - stateValue: typeof updateFn === 'function' ? updateFn(stateValue) : updateFn - }; - }, callback); - }, _temp), possibleConstructorReturn(_this, _ret); - } - WithState.prototype.render = function render() { - var _babelHelpers$extends; - return factory(_extends({}, this.props, (_babelHelpers$extends = {}, _babelHelpers$extends[stateName] = this.state.stateValue, _babelHelpers$extends[stateUpdaterName] = this.updateStateValue, _babelHelpers$extends))); - }; +var printWarning = function() {}; - return WithState; - }(__WEBPACK_IMPORTED_MODULE_0_react__["Component"]); +if (process.env.NODE_ENV !== 'production') { + var ReactPropTypesSecret = __webpack_require__(7); + var loggedTypeFailures = {}; - if (process.env.NODE_ENV !== 'production') { - return setDisplayName(wrapDisplayName(BaseComponent, 'withState'))(WithState); + printWarning = function(text) { + var message = 'Warning: ' + text; + if (typeof console !== 'undefined') { + console.error(message); } - return WithState; + try { + // --- Welcome to debugging React --- + // This error was thrown as a convenience so that you can use this stack + // to find the callsite that caused this warning to fire. + throw new Error(message); + } catch (x) {} }; -}; - -var withStateHandlers = function withStateHandlers(initialState, stateUpdaters) { - return function (BaseComponent) { - var factory = Object(__WEBPACK_IMPORTED_MODULE_0_react__["createFactory"])(BaseComponent); - - var WithStateHandlers = function (_Component) { - inherits(WithStateHandlers, _Component); - - function WithStateHandlers() { - var _temp, _this, _ret; - - classCallCheck(this, WithStateHandlers); - - for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { - args[_key] = arguments[_key]; - } - - return _ret = (_temp = (_this = possibleConstructorReturn(this, _Component.call.apply(_Component, [this].concat(args))), _this), _initialiseProps.call(_this), _temp), possibleConstructorReturn(_this, _ret); - } - - WithStateHandlers.prototype.shouldComponentUpdate = function shouldComponentUpdate(nextProps, nextState) { - var propsChanged = nextProps !== this.props; - // the idea is to skip render if stateUpdater handler return undefined - // this allows to create no state update handlers with access to state and props - var stateChanged = !__WEBPACK_IMPORTED_MODULE_1_fbjs_lib_shallowEqual___default()(nextState, this.state); - return propsChanged || stateChanged; - }; - - WithStateHandlers.prototype.render = function render() { - return factory(_extends({}, this.props, this.state, this.stateUpdaters)); - }; - - return WithStateHandlers; - }(__WEBPACK_IMPORTED_MODULE_0_react__["Component"]); - - var _initialiseProps = function _initialiseProps() { - var _this2 = this; - - this.state = typeof initialState === 'function' ? initialState(this.props) : initialState; - this.stateUpdaters = mapValues(stateUpdaters, function (handler) { - return function (mayBeEvent) { - for (var _len2 = arguments.length, args = Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) { - args[_key2 - 1] = arguments[_key2]; - } +} - // Having that functional form of setState can be called async - // we need to persist SyntheticEvent - if (mayBeEvent && typeof mayBeEvent.persist === 'function') { - mayBeEvent.persist(); +/** + * Assert that the values match with the type specs. + * Error messages are memorized and will only be shown once. + * + * @param {object} typeSpecs Map of name to a ReactPropType + * @param {object} values Runtime values that need to be type-checked + * @param {string} location e.g. "prop", "context", "child context" + * @param {string} componentName Name of the component for error messages. + * @param {?Function} getStack Returns the component stack. + * @private + */ +function checkPropTypes(typeSpecs, values, location, componentName, getStack) { + if (process.env.NODE_ENV !== 'production') { + for (var typeSpecName in typeSpecs) { + if (typeSpecs.hasOwnProperty(typeSpecName)) { + var error; + // Prop type validation may throw. In case they do, we don't want to + // fail the render phase where it didn't fail before. So we log it. + // After these have been cleaned up, we'll let them throw. + try { + // This is intentionally an invariant that gets caught. It's the same + // behavior as without this statement except with a better message. + if (typeof typeSpecs[typeSpecName] !== 'function') { + var err = Error( + (componentName || 'React class') + ': ' + location + ' type `' + typeSpecName + '` is invalid; ' + + 'it must be a function, usually from the `prop-types` package, but received `' + typeof typeSpecs[typeSpecName] + '`.' + ); + err.name = 'Invariant Violation'; + throw err; } - - _this2.setState(function (state, props) { - return handler(state, props).apply(undefined, [mayBeEvent].concat(args)); - }); - }; - }); - }; - - if (process.env.NODE_ENV !== 'production') { - return setDisplayName(wrapDisplayName(BaseComponent, 'withStateHandlers'))(WithStateHandlers); - } - return WithStateHandlers; - }; -}; - -var withReducer = function withReducer(stateName, dispatchName, reducer, initialState) { - return function (BaseComponent) { - var factory = Object(__WEBPACK_IMPORTED_MODULE_0_react__["createFactory"])(BaseComponent); - - var WithReducer = function (_Component) { - inherits(WithReducer, _Component); - - function WithReducer() { - var _temp, _this, _ret; - - classCallCheck(this, WithReducer); - - for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { - args[_key] = arguments[_key]; + error = typeSpecs[typeSpecName](values, typeSpecName, componentName, location, null, ReactPropTypesSecret); + } catch (ex) { + error = ex; } + if (error && !(error instanceof Error)) { + printWarning( + (componentName || 'React class') + ': type specification of ' + + location + ' `' + typeSpecName + '` is invalid; the type checker ' + + 'function must return `null` or an `Error` but returned a ' + typeof error + '. ' + + 'You may have forgotten to pass an argument to the type checker ' + + 'creator (arrayOf, instanceOf, objectOf, oneOf, oneOfType, and ' + + 'shape all require an argument).' + ) - return _ret = (_temp = (_this = possibleConstructorReturn(this, _Component.call.apply(_Component, [this].concat(args))), _this), _this.state = { - stateValue: _this.initializeStateValue() - }, _this.dispatch = function (action) { - return _this.setState(function (_ref) { - var stateValue = _ref.stateValue; - return { - stateValue: reducer(stateValue, action) - }; - }); - }, _temp), possibleConstructorReturn(_this, _ret); - } - - WithReducer.prototype.initializeStateValue = function initializeStateValue() { - if (initialState !== undefined) { - return typeof initialState === 'function' ? initialState(this.props) : initialState; } - return reducer(undefined, { type: '@@recompose/INIT' }); - }; - - WithReducer.prototype.render = function render() { - var _babelHelpers$extends; - - return factory(_extends({}, this.props, (_babelHelpers$extends = {}, _babelHelpers$extends[stateName] = this.state.stateValue, _babelHelpers$extends[dispatchName] = this.dispatch, _babelHelpers$extends))); - }; - - return WithReducer; - }(__WEBPACK_IMPORTED_MODULE_0_react__["Component"]); - - if (process.env.NODE_ENV !== 'production') { - return setDisplayName(wrapDisplayName(BaseComponent, 'withReducer'))(WithReducer); - } - return WithReducer; - }; -}; - -var identity = function identity(Component$$1) { - return Component$$1; -}; - -var branch = function branch(test, left) { - var right = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : identity; - return function (BaseComponent) { - var leftFactory = void 0; - var rightFactory = void 0; - var Branch = function Branch(props) { - if (test(props)) { - leftFactory = leftFactory || Object(__WEBPACK_IMPORTED_MODULE_0_react__["createFactory"])(left(BaseComponent)); - return leftFactory(props); - } - rightFactory = rightFactory || Object(__WEBPACK_IMPORTED_MODULE_0_react__["createFactory"])(right(BaseComponent)); - return rightFactory(props); - }; - - if (process.env.NODE_ENV !== 'production') { - return setDisplayName(wrapDisplayName(BaseComponent, 'branch'))(Branch); - } - return Branch; - }; -}; - -var renderComponent = function renderComponent(Component$$1) { - return function (_) { - var factory = Object(__WEBPACK_IMPORTED_MODULE_0_react__["createFactory"])(Component$$1); - var RenderComponent = function RenderComponent(props) { - return factory(props); - }; - if (process.env.NODE_ENV !== 'production') { - RenderComponent.displayName = wrapDisplayName(Component$$1, 'renderComponent'); - } - return RenderComponent; - }; -}; - -var Nothing = function (_Component) { - inherits(Nothing, _Component); - - function Nothing() { - classCallCheck(this, Nothing); - return possibleConstructorReturn(this, _Component.apply(this, arguments)); - } - - Nothing.prototype.render = function render() { - return null; - }; - - return Nothing; -}(__WEBPACK_IMPORTED_MODULE_0_react__["Component"]); - -var renderNothing = function renderNothing(_) { - return Nothing; -}; - -var shouldUpdate = function shouldUpdate(test) { - return function (BaseComponent) { - var factory = Object(__WEBPACK_IMPORTED_MODULE_0_react__["createFactory"])(BaseComponent); - - var ShouldUpdate = function (_Component) { - inherits(ShouldUpdate, _Component); - - function ShouldUpdate() { - classCallCheck(this, ShouldUpdate); - return possibleConstructorReturn(this, _Component.apply(this, arguments)); - } - - ShouldUpdate.prototype.shouldComponentUpdate = function shouldComponentUpdate(nextProps) { - return test(this.props, nextProps); - }; - - ShouldUpdate.prototype.render = function render() { - return factory(this.props); - }; - - return ShouldUpdate; - }(__WEBPACK_IMPORTED_MODULE_0_react__["Component"]); - - if (process.env.NODE_ENV !== 'production') { - return setDisplayName(wrapDisplayName(BaseComponent, 'shouldUpdate'))(ShouldUpdate); - } - return ShouldUpdate; - }; -}; - -var pure = function pure(BaseComponent) { - var hoc = shouldUpdate(function (props, nextProps) { - return !__WEBPACK_IMPORTED_MODULE_1_fbjs_lib_shallowEqual___default()(props, nextProps); - }); - - if (process.env.NODE_ENV !== 'production') { - return setDisplayName(wrapDisplayName(BaseComponent, 'pure'))(hoc(BaseComponent)); - } - - return hoc(BaseComponent); -}; - -var onlyUpdateForKeys = function onlyUpdateForKeys(propKeys) { - var hoc = shouldUpdate(function (props, nextProps) { - return !__WEBPACK_IMPORTED_MODULE_1_fbjs_lib_shallowEqual___default()(pick(nextProps, propKeys), pick(props, propKeys)); - }); - - if (process.env.NODE_ENV !== 'production') { - return function (BaseComponent) { - return setDisplayName(wrapDisplayName(BaseComponent, 'onlyUpdateForKeys'))(hoc(BaseComponent)); - }; - } - return hoc; -}; - -var onlyUpdateForPropTypes = function onlyUpdateForPropTypes(BaseComponent) { - var propTypes = BaseComponent.propTypes; - - if (process.env.NODE_ENV !== 'production') { - if (!propTypes) { - /* eslint-disable */ - console.error('A component without any `propTypes` was passed to ' + '`onlyUpdateForPropTypes()`. Check the implementation of the ' + ('component with display name "' + getDisplayName(BaseComponent) + '".')); - /* eslint-enable */ - } - } - - var propKeys = Object.keys(propTypes || {}); - var OnlyUpdateForPropTypes = onlyUpdateForKeys(propKeys)(BaseComponent); - - if (process.env.NODE_ENV !== 'production') { - return setDisplayName(wrapDisplayName(BaseComponent, 'onlyUpdateForPropTypes'))(OnlyUpdateForPropTypes); - } - return OnlyUpdateForPropTypes; -}; - -var withContext = function withContext(childContextTypes, getChildContext) { - return function (BaseComponent) { - var factory = Object(__WEBPACK_IMPORTED_MODULE_0_react__["createFactory"])(BaseComponent); - - var WithContext = function (_Component) { - inherits(WithContext, _Component); - - function WithContext() { - var _temp, _this, _ret; + if (error instanceof Error && !(error.message in loggedTypeFailures)) { + // Only monitor this failure once because there tends to be a lot of the + // same error. + loggedTypeFailures[error.message] = true; - classCallCheck(this, WithContext); + var stack = getStack ? getStack() : ''; - for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { - args[_key] = arguments[_key]; + printWarning( + 'Failed ' + location + ' type: ' + error.message + (stack != null ? stack : '') + ); } - - return _ret = (_temp = (_this = possibleConstructorReturn(this, _Component.call.apply(_Component, [this].concat(args))), _this), _this.getChildContext = function () { - return getChildContext(_this.props); - }, _temp), possibleConstructorReturn(_this, _ret); - } - - WithContext.prototype.render = function render() { - return factory(this.props); - }; - - return WithContext; - }(__WEBPACK_IMPORTED_MODULE_0_react__["Component"]); - - WithContext.childContextTypes = childContextTypes; - - if (process.env.NODE_ENV !== 'production') { - return setDisplayName(wrapDisplayName(BaseComponent, 'withContext'))(WithContext); - } - return WithContext; - }; -}; - -var getContext = function getContext(contextTypes) { - return function (BaseComponent) { - var factory = Object(__WEBPACK_IMPORTED_MODULE_0_react__["createFactory"])(BaseComponent); - var GetContext = function GetContext(ownerProps, context) { - return factory(_extends({}, ownerProps, context)); - }; - - GetContext.contextTypes = contextTypes; - - if (process.env.NODE_ENV !== 'production') { - return setDisplayName(wrapDisplayName(BaseComponent, 'getContext'))(GetContext); - } - return GetContext; - }; -}; - -/* eslint-disable no-console */ -var lifecycle = function lifecycle(spec) { - return function (BaseComponent) { - var factory = Object(__WEBPACK_IMPORTED_MODULE_0_react__["createFactory"])(BaseComponent); - - if (process.env.NODE_ENV !== 'production' && spec.hasOwnProperty('render')) { - console.error('lifecycle() does not support the render method; its behavior is to ' + 'pass all props and state to the base component.'); - } - - var Lifecycle = function (_Component) { - inherits(Lifecycle, _Component); - - function Lifecycle() { - classCallCheck(this, Lifecycle); - return possibleConstructorReturn(this, _Component.apply(this, arguments)); } - - Lifecycle.prototype.render = function render() { - return factory(_extends({}, this.props, this.state)); - }; - - return Lifecycle; - }(__WEBPACK_IMPORTED_MODULE_0_react__["Component"]); - - Object.keys(spec).forEach(function (hook) { - return Lifecycle.prototype[hook] = spec[hook]; - }); - - if (process.env.NODE_ENV !== 'production') { - return setDisplayName(wrapDisplayName(BaseComponent, 'lifecycle'))(Lifecycle); - } - return Lifecycle; - }; -}; - -var isClassComponent = function isClassComponent(Component$$1) { - return Boolean(Component$$1 && Component$$1.prototype && typeof Component$$1.prototype.render === 'function'); -}; - -var toClass = function toClass(baseComponent) { - if (isClassComponent(baseComponent)) { - return baseComponent; - } - - var ToClass = function (_Component) { - inherits(ToClass, _Component); - - function ToClass() { - classCallCheck(this, ToClass); - return possibleConstructorReturn(this, _Component.apply(this, arguments)); } - - ToClass.prototype.render = function render() { - if (typeof baseComponent === 'string') { - return __WEBPACK_IMPORTED_MODULE_0_react___default.a.createElement(baseComponent, this.props); - } - return baseComponent(this.props, this.context); - }; - - return ToClass; - }(__WEBPACK_IMPORTED_MODULE_0_react__["Component"]); - - ToClass.displayName = getDisplayName(baseComponent); - ToClass.propTypes = baseComponent.propTypes; - ToClass.contextTypes = baseComponent.contextTypes; - ToClass.defaultProps = baseComponent.defaultProps; - - return ToClass; -}; - -var setPropTypes = function setPropTypes(propTypes) { - return setStatic('propTypes', propTypes); -}; - -function compose() { - for (var _len = arguments.length, funcs = Array(_len), _key = 0; _key < _len; _key++) { - funcs[_key] = arguments[_key]; - } - - if (funcs.length === 0) { - return function (arg) { - return arg; - }; - } - - if (funcs.length === 1) { - return funcs[0]; } - - return funcs.reduce(function (a, b) { - return function () { - return a(b.apply(undefined, arguments)); - }; - }); } -var createSink = function createSink(callback) { - return function (_Component) { - inherits(Sink, _Component); - - function Sink() { - classCallCheck(this, Sink); - return possibleConstructorReturn(this, _Component.apply(this, arguments)); - } - - Sink.prototype.componentWillMount = function componentWillMount() { - callback(this.props); - }; - - Sink.prototype.componentWillReceiveProps = function componentWillReceiveProps(nextProps) { - callback(nextProps); - }; +module.exports = checkPropTypes; - Sink.prototype.render = function render() { - return null; - }; +/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0))) - return Sink; - }(__WEBPACK_IMPORTED_MODULE_0_react__["Component"]); -}; +/***/ }), +/* 9 */ +/***/ (function(module, exports, __webpack_require__) { -var componentFromProp = function componentFromProp(propName) { - var Component$$1 = function Component$$1(props) { - return Object(__WEBPACK_IMPORTED_MODULE_0_react__["createElement"])(props[propName], omit(props, [propName])); - }; - Component$$1.displayName = 'componentFromProp(' + propName + ')'; - return Component$$1; -}; +"use strict"; +/* WEBPACK VAR INJECTION */(function(process) { -var nest = function nest() { - for (var _len = arguments.length, Components = Array(_len), _key = 0; _key < _len; _key++) { - Components[_key] = arguments[_key]; +function checkDCE() { + /* global __REACT_DEVTOOLS_GLOBAL_HOOK__ */ + if ( + typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ === 'undefined' || + typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE !== 'function' + ) { + return; } - - var factories = Components.map(__WEBPACK_IMPORTED_MODULE_0_react__["createFactory"]); - var Nest = function Nest(_ref) { - var props = objectWithoutProperties(_ref, []), - children = _ref.children; - return factories.reduceRight(function (child, factory) { - return factory(props, child); - }, children); - }; - if (process.env.NODE_ENV !== 'production') { - var displayNames = Components.map(getDisplayName); - Nest.displayName = 'nest(' + displayNames.join(', ') + ')'; + // This branch is unreachable because this function is only called + // in production, but the condition is true only in development. + // Therefore if the branch is still here, dead code elimination wasn't + // properly applied. + // Don't change the message. React DevTools relies on it. Also make sure + // this message doesn't occur elsewhere in this function, or it will cause + // a false positive. + throw new Error('^_^'); } - - return Nest; -}; - -var hoistStatics = function hoistStatics(higherOrderComponent) { - return function (BaseComponent) { - var NewComponent = higherOrderComponent(BaseComponent); - __WEBPACK_IMPORTED_MODULE_2_hoist_non_react_statics___default()(NewComponent, BaseComponent); - return NewComponent; - }; -}; - -var _config = { - fromESObservable: null, - toESObservable: null -}; - -var configureObservable = function configureObservable(c) { - _config = c; -}; - -var config = { - fromESObservable: function fromESObservable(observable) { - return typeof _config.fromESObservable === 'function' ? _config.fromESObservable(observable) : observable; - }, - toESObservable: function toESObservable(stream) { - return typeof _config.toESObservable === 'function' ? _config.toESObservable(stream) : stream; + try { + // Verify that the code above has been dead code eliminated (DCE'd). + __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(checkDCE); + } catch (err) { + // DevTools shouldn't crash React, no matter what. + // We should still report in case we break this code. + console.error(err); } -}; - -var componentFromStreamWithConfig = function componentFromStreamWithConfig(config$$1) { - return function (propsToVdom) { - return function (_Component) { - inherits(ComponentFromStream, _Component); - - function ComponentFromStream() { - var _config$fromESObserva; - - var _temp, _this, _ret; - - classCallCheck(this, ComponentFromStream); - - for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { - args[_key] = arguments[_key]; - } - - return _ret = (_temp = (_this = possibleConstructorReturn(this, _Component.call.apply(_Component, [this].concat(args))), _this), _this.state = { vdom: null }, _this.propsEmitter = Object(__WEBPACK_IMPORTED_MODULE_3_change_emitter__["createChangeEmitter"])(), _this.props$ = config$$1.fromESObservable((_config$fromESObserva = { - subscribe: function subscribe(observer) { - var unsubscribe = _this.propsEmitter.listen(function (props) { - if (props) { - observer.next(props); - } else { - observer.complete(); - } - }); - return { unsubscribe: unsubscribe }; - } - }, _config$fromESObserva[__WEBPACK_IMPORTED_MODULE_4_symbol_observable__["a" /* default */]] = function () { - return this; - }, _config$fromESObserva)), _this.vdom$ = config$$1.toESObservable(propsToVdom(_this.props$)), _temp), possibleConstructorReturn(_this, _ret); - } - - // Stream of props - - - // Stream of vdom - +} - ComponentFromStream.prototype.componentWillMount = function componentWillMount() { - var _this2 = this; +if (process.env.NODE_ENV === 'production') { + // DCE check should happen before ReactDOM bundle executes so that + // DevTools can report bad minification during injection. + checkDCE(); + module.exports = __webpack_require__(25); +} else { + module.exports = __webpack_require__(28); +} - // Subscribe to child prop changes so we know when to re-render - this.subscription = this.vdom$.subscribe({ - next: function next(vdom) { - _this2.setState({ vdom: vdom }); - } - }); - this.propsEmitter.emit(this.props); - }; +/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0))) - ComponentFromStream.prototype.componentWillReceiveProps = function componentWillReceiveProps(nextProps) { - // Receive new props from the owner - this.propsEmitter.emit(nextProps); - }; +/***/ }), +/* 10 */ +/***/ (function(module, exports, __webpack_require__) { - ComponentFromStream.prototype.shouldComponentUpdate = function shouldComponentUpdate(nextProps, nextState) { - return nextState.vdom !== this.state.vdom; - }; +"use strict"; +/* WEBPACK VAR INJECTION */(function(process) { - ComponentFromStream.prototype.componentWillUnmount = function componentWillUnmount() { - // Call without arguments to complete stream - this.propsEmitter.emit(); +if (process.env.NODE_ENV === 'production') { + module.exports = __webpack_require__(26); +} else { + module.exports = __webpack_require__(27); +} - // Clean-up subscription before un-mounting - this.subscription.unsubscribe(); - }; +/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0))) - ComponentFromStream.prototype.render = function render() { - return this.state.vdom; - }; +/***/ }), +/* 11 */ +/***/ (function(module, exports) { - return ComponentFromStream; - }(__WEBPACK_IMPORTED_MODULE_0_react__["Component"]); - }; -}; +var g; + +// This works in non-strict mode +g = (function() { + return this; +})(); + +try { + // This works if eval is allowed (see CSP) + g = g || Function("return this")() || (1,eval)("this"); +} catch(e) { + // This works if the window reference is available + if(typeof window === "object") + g = window; +} + +// g can still be undefined, but nothing to do about it... +// We return undefined, instead of nothing here, so it's +// easier to handle this case. if(!global) { ...} + +module.exports = g; -var componentFromStream = function componentFromStream(propsToVdom) { - return componentFromStreamWithConfig(config)(propsToVdom); -}; -var identity$1 = function identity(t) { - return t; -}; +/***/ }), +/* 12 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { -var mapPropsStreamWithConfig = function mapPropsStreamWithConfig(config$$1) { - var componentFromStream = componentFromStreamWithConfig({ - fromESObservable: identity$1, - toESObservable: identity$1 - }); - return function (transform) { - return function (BaseComponent) { - var factory = Object(__WEBPACK_IMPORTED_MODULE_0_react__["createFactory"])(BaseComponent); - var fromESObservable = config$$1.fromESObservable, - toESObservable = config$$1.toESObservable; - - return componentFromStream(function (props$) { - var _ref; - - return _ref = { - subscribe: function subscribe(observer) { - var subscription = toESObservable(transform(fromESObservable(props$))).subscribe({ - next: function next(childProps) { - return observer.next(factory(childProps)); - } - }); - return { - unsubscribe: function unsubscribe() { - return subscription.unsubscribe(); - } - }; - } - }, _ref[__WEBPACK_IMPORTED_MODULE_4_symbol_observable__["a" /* default */]] = function () { - return this; - }, _ref; - }); - }; - }; -}; +"use strict"; +Object.defineProperty(__webpack_exports__, "__esModule", { value: true }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "WebGLRenderTargetCube", function() { return WebGLRenderTargetCube; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "WebGLRenderTarget", function() { return WebGLRenderTarget; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "WebGLRenderer", function() { return WebGLRenderer; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ShaderLib", function() { return ShaderLib; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "UniformsLib", function() { return UniformsLib; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "UniformsUtils", function() { return UniformsUtils; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ShaderChunk", function() { return ShaderChunk; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FogExp2", function() { return FogExp2; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Fog", function() { return Fog; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Scene", function() { return Scene; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Sprite", function() { return Sprite; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LOD", function() { return LOD; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SkinnedMesh", function() { return SkinnedMesh; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Skeleton", function() { return Skeleton; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Bone", function() { return Bone; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Mesh", function() { return Mesh; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LineSegments", function() { return LineSegments; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LineLoop", function() { return LineLoop; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Line", function() { return Line; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Points", function() { return Points; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Group", function() { return Group; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "VideoTexture", function() { return VideoTexture; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "DataTexture", function() { return DataTexture; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "DataTexture3D", function() { return DataTexture3D; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CompressedTexture", function() { return CompressedTexture; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CubeTexture", function() { return CubeTexture; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CanvasTexture", function() { return CanvasTexture; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "DepthTexture", function() { return DepthTexture; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Texture", function() { return Texture; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "AnimationLoader", function() { return AnimationLoader; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CompressedTextureLoader", function() { return CompressedTextureLoader; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "DataTextureLoader", function() { return DataTextureLoader; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CubeTextureLoader", function() { return CubeTextureLoader; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "TextureLoader", function() { return TextureLoader; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ObjectLoader", function() { return ObjectLoader; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MaterialLoader", function() { return MaterialLoader; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "BufferGeometryLoader", function() { return BufferGeometryLoader; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "DefaultLoadingManager", function() { return DefaultLoadingManager; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LoadingManager", function() { return LoadingManager; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ImageLoader", function() { return ImageLoader; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ImageBitmapLoader", function() { return ImageBitmapLoader; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FontLoader", function() { return FontLoader; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FileLoader", function() { return FileLoader; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Loader", function() { return Loader; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LoaderUtils", function() { return LoaderUtils; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Cache", function() { return Cache; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "AudioLoader", function() { return AudioLoader; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SpotLightShadow", function() { return SpotLightShadow; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SpotLight", function() { return SpotLight; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "PointLight", function() { return PointLight; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RectAreaLight", function() { return RectAreaLight; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "HemisphereLight", function() { return HemisphereLight; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "DirectionalLightShadow", function() { return DirectionalLightShadow; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "DirectionalLight", function() { return DirectionalLight; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "AmbientLight", function() { return AmbientLight; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LightShadow", function() { return LightShadow; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Light", function() { return Light; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "StereoCamera", function() { return StereoCamera; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "PerspectiveCamera", function() { return PerspectiveCamera; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "OrthographicCamera", function() { return OrthographicCamera; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CubeCamera", function() { return CubeCamera; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ArrayCamera", function() { return ArrayCamera; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Camera", function() { return Camera; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "AudioListener", function() { return AudioListener; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "PositionalAudio", function() { return PositionalAudio; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "AudioContext", function() { return AudioContext; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "AudioAnalyser", function() { return AudioAnalyser; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Audio", function() { return Audio; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "VectorKeyframeTrack", function() { return VectorKeyframeTrack; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "StringKeyframeTrack", function() { return StringKeyframeTrack; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "QuaternionKeyframeTrack", function() { return QuaternionKeyframeTrack; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "NumberKeyframeTrack", function() { return NumberKeyframeTrack; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ColorKeyframeTrack", function() { return ColorKeyframeTrack; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "BooleanKeyframeTrack", function() { return BooleanKeyframeTrack; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "PropertyMixer", function() { return PropertyMixer; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "PropertyBinding", function() { return PropertyBinding; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "KeyframeTrack", function() { return KeyframeTrack; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "AnimationUtils", function() { return AnimationUtils; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "AnimationObjectGroup", function() { return AnimationObjectGroup; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "AnimationMixer", function() { return AnimationMixer; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "AnimationClip", function() { return AnimationClip; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Uniform", function() { return Uniform; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "InstancedBufferGeometry", function() { return InstancedBufferGeometry; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "BufferGeometry", function() { return BufferGeometry; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Geometry", function() { return Geometry; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "InterleavedBufferAttribute", function() { return InterleavedBufferAttribute; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "InstancedInterleavedBuffer", function() { return InstancedInterleavedBuffer; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "InterleavedBuffer", function() { return InterleavedBuffer; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "InstancedBufferAttribute", function() { return InstancedBufferAttribute; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Face3", function() { return Face3; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Object3D", function() { return Object3D; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Raycaster", function() { return Raycaster; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Layers", function() { return Layers; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "EventDispatcher", function() { return EventDispatcher; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Clock", function() { return Clock; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "QuaternionLinearInterpolant", function() { return QuaternionLinearInterpolant; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LinearInterpolant", function() { return LinearInterpolant; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "DiscreteInterpolant", function() { return DiscreteInterpolant; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CubicInterpolant", function() { return CubicInterpolant; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Interpolant", function() { return Interpolant; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Triangle", function() { return Triangle; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Math", function() { return _Math; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Spherical", function() { return Spherical; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Cylindrical", function() { return Cylindrical; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Plane", function() { return Plane; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Frustum", function() { return Frustum; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Sphere", function() { return Sphere; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Ray", function() { return Ray; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Matrix4", function() { return Matrix4; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Matrix3", function() { return Matrix3; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Box3", function() { return Box3; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Box2", function() { return Box2; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Line3", function() { return Line3; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Euler", function() { return Euler; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Vector4", function() { return Vector4; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Vector3", function() { return Vector3; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Vector2", function() { return Vector2; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Quaternion", function() { return Quaternion; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Color", function() { return Color; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ImmediateRenderObject", function() { return ImmediateRenderObject; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "VertexNormalsHelper", function() { return VertexNormalsHelper; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SpotLightHelper", function() { return SpotLightHelper; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SkeletonHelper", function() { return SkeletonHelper; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "PointLightHelper", function() { return PointLightHelper; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RectAreaLightHelper", function() { return RectAreaLightHelper; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "HemisphereLightHelper", function() { return HemisphereLightHelper; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "GridHelper", function() { return GridHelper; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "PolarGridHelper", function() { return PolarGridHelper; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FaceNormalsHelper", function() { return FaceNormalsHelper; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "DirectionalLightHelper", function() { return DirectionalLightHelper; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CameraHelper", function() { return CameraHelper; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "BoxHelper", function() { return BoxHelper; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Box3Helper", function() { return Box3Helper; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "PlaneHelper", function() { return PlaneHelper; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ArrowHelper", function() { return ArrowHelper; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "AxesHelper", function() { return AxesHelper; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Shape", function() { return Shape; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Path", function() { return Path; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ShapePath", function() { return ShapePath; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Font", function() { return Font; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CurvePath", function() { return CurvePath; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Curve", function() { return Curve; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ImageUtils", function() { return ImageUtils; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ShapeUtils", function() { return ShapeUtils; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "WebGLUtils", function() { return WebGLUtils; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "WireframeGeometry", function() { return WireframeGeometry; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ParametricGeometry", function() { return ParametricGeometry; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ParametricBufferGeometry", function() { return ParametricBufferGeometry; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "TetrahedronGeometry", function() { return TetrahedronGeometry; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "TetrahedronBufferGeometry", function() { return TetrahedronBufferGeometry; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "OctahedronGeometry", function() { return OctahedronGeometry; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "OctahedronBufferGeometry", function() { return OctahedronBufferGeometry; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "IcosahedronGeometry", function() { return IcosahedronGeometry; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "IcosahedronBufferGeometry", function() { return IcosahedronBufferGeometry; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "DodecahedronGeometry", function() { return DodecahedronGeometry; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "DodecahedronBufferGeometry", function() { return DodecahedronBufferGeometry; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "PolyhedronGeometry", function() { return PolyhedronGeometry; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "PolyhedronBufferGeometry", function() { return PolyhedronBufferGeometry; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "TubeGeometry", function() { return TubeGeometry; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "TubeBufferGeometry", function() { return TubeBufferGeometry; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "TorusKnotGeometry", function() { return TorusKnotGeometry; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "TorusKnotBufferGeometry", function() { return TorusKnotBufferGeometry; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "TorusGeometry", function() { return TorusGeometry; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "TorusBufferGeometry", function() { return TorusBufferGeometry; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "TextGeometry", function() { return TextGeometry; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "TextBufferGeometry", function() { return TextBufferGeometry; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SphereGeometry", function() { return SphereGeometry; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SphereBufferGeometry", function() { return SphereBufferGeometry; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RingGeometry", function() { return RingGeometry; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RingBufferGeometry", function() { return RingBufferGeometry; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "PlaneGeometry", function() { return PlaneGeometry; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "PlaneBufferGeometry", function() { return PlaneBufferGeometry; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LatheGeometry", function() { return LatheGeometry; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LatheBufferGeometry", function() { return LatheBufferGeometry; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ShapeGeometry", function() { return ShapeGeometry; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ShapeBufferGeometry", function() { return ShapeBufferGeometry; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ExtrudeGeometry", function() { return ExtrudeGeometry; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ExtrudeBufferGeometry", function() { return ExtrudeBufferGeometry; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "EdgesGeometry", function() { return EdgesGeometry; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ConeGeometry", function() { return ConeGeometry; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ConeBufferGeometry", function() { return ConeBufferGeometry; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CylinderGeometry", function() { return CylinderGeometry; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CylinderBufferGeometry", function() { return CylinderBufferGeometry; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CircleGeometry", function() { return CircleGeometry; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CircleBufferGeometry", function() { return CircleBufferGeometry; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "BoxGeometry", function() { return BoxGeometry; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "BoxBufferGeometry", function() { return BoxBufferGeometry; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ShadowMaterial", function() { return ShadowMaterial; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SpriteMaterial", function() { return SpriteMaterial; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RawShaderMaterial", function() { return RawShaderMaterial; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ShaderMaterial", function() { return ShaderMaterial; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "PointsMaterial", function() { return PointsMaterial; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MeshPhysicalMaterial", function() { return MeshPhysicalMaterial; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MeshStandardMaterial", function() { return MeshStandardMaterial; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MeshPhongMaterial", function() { return MeshPhongMaterial; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MeshToonMaterial", function() { return MeshToonMaterial; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MeshNormalMaterial", function() { return MeshNormalMaterial; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MeshLambertMaterial", function() { return MeshLambertMaterial; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MeshDepthMaterial", function() { return MeshDepthMaterial; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MeshDistanceMaterial", function() { return MeshDistanceMaterial; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MeshBasicMaterial", function() { return MeshBasicMaterial; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MeshMatcapMaterial", function() { return MeshMatcapMaterial; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LineDashedMaterial", function() { return LineDashedMaterial; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LineBasicMaterial", function() { return LineBasicMaterial; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Material", function() { return Material; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Float64BufferAttribute", function() { return Float64BufferAttribute; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Float32BufferAttribute", function() { return Float32BufferAttribute; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Uint32BufferAttribute", function() { return Uint32BufferAttribute; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Int32BufferAttribute", function() { return Int32BufferAttribute; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Uint16BufferAttribute", function() { return Uint16BufferAttribute; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Int16BufferAttribute", function() { return Int16BufferAttribute; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Uint8ClampedBufferAttribute", function() { return Uint8ClampedBufferAttribute; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Uint8BufferAttribute", function() { return Uint8BufferAttribute; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Int8BufferAttribute", function() { return Int8BufferAttribute; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "BufferAttribute", function() { return BufferAttribute; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ArcCurve", function() { return ArcCurve; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CatmullRomCurve3", function() { return CatmullRomCurve3; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CubicBezierCurve", function() { return CubicBezierCurve; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CubicBezierCurve3", function() { return CubicBezierCurve3; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "EllipseCurve", function() { return EllipseCurve; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LineCurve", function() { return LineCurve; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LineCurve3", function() { return LineCurve3; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "QuadraticBezierCurve", function() { return QuadraticBezierCurve; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "QuadraticBezierCurve3", function() { return QuadraticBezierCurve3; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SplineCurve", function() { return SplineCurve; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "REVISION", function() { return REVISION; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MOUSE", function() { return MOUSE; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CullFaceNone", function() { return CullFaceNone; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CullFaceBack", function() { return CullFaceBack; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CullFaceFront", function() { return CullFaceFront; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CullFaceFrontBack", function() { return CullFaceFrontBack; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FrontFaceDirectionCW", function() { return FrontFaceDirectionCW; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FrontFaceDirectionCCW", function() { return FrontFaceDirectionCCW; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "BasicShadowMap", function() { return BasicShadowMap; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "PCFShadowMap", function() { return PCFShadowMap; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "PCFSoftShadowMap", function() { return PCFSoftShadowMap; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FrontSide", function() { return FrontSide; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "BackSide", function() { return BackSide; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "DoubleSide", function() { return DoubleSide; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FlatShading", function() { return FlatShading; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SmoothShading", function() { return SmoothShading; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "NoColors", function() { return NoColors; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FaceColors", function() { return FaceColors; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "VertexColors", function() { return VertexColors; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "NoBlending", function() { return NoBlending; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "NormalBlending", function() { return NormalBlending; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "AdditiveBlending", function() { return AdditiveBlending; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SubtractiveBlending", function() { return SubtractiveBlending; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MultiplyBlending", function() { return MultiplyBlending; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CustomBlending", function() { return CustomBlending; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "AddEquation", function() { return AddEquation; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SubtractEquation", function() { return SubtractEquation; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ReverseSubtractEquation", function() { return ReverseSubtractEquation; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MinEquation", function() { return MinEquation; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MaxEquation", function() { return MaxEquation; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ZeroFactor", function() { return ZeroFactor; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "OneFactor", function() { return OneFactor; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SrcColorFactor", function() { return SrcColorFactor; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "OneMinusSrcColorFactor", function() { return OneMinusSrcColorFactor; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SrcAlphaFactor", function() { return SrcAlphaFactor; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "OneMinusSrcAlphaFactor", function() { return OneMinusSrcAlphaFactor; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "DstAlphaFactor", function() { return DstAlphaFactor; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "OneMinusDstAlphaFactor", function() { return OneMinusDstAlphaFactor; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "DstColorFactor", function() { return DstColorFactor; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "OneMinusDstColorFactor", function() { return OneMinusDstColorFactor; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SrcAlphaSaturateFactor", function() { return SrcAlphaSaturateFactor; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "NeverDepth", function() { return NeverDepth; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "AlwaysDepth", function() { return AlwaysDepth; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LessDepth", function() { return LessDepth; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LessEqualDepth", function() { return LessEqualDepth; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "EqualDepth", function() { return EqualDepth; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "GreaterEqualDepth", function() { return GreaterEqualDepth; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "GreaterDepth", function() { return GreaterDepth; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "NotEqualDepth", function() { return NotEqualDepth; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MultiplyOperation", function() { return MultiplyOperation; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MixOperation", function() { return MixOperation; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "AddOperation", function() { return AddOperation; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "NoToneMapping", function() { return NoToneMapping; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LinearToneMapping", function() { return LinearToneMapping; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ReinhardToneMapping", function() { return ReinhardToneMapping; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Uncharted2ToneMapping", function() { return Uncharted2ToneMapping; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CineonToneMapping", function() { return CineonToneMapping; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ACESFilmicToneMapping", function() { return ACESFilmicToneMapping; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "UVMapping", function() { return UVMapping; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CubeReflectionMapping", function() { return CubeReflectionMapping; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CubeRefractionMapping", function() { return CubeRefractionMapping; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "EquirectangularReflectionMapping", function() { return EquirectangularReflectionMapping; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "EquirectangularRefractionMapping", function() { return EquirectangularRefractionMapping; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SphericalReflectionMapping", function() { return SphericalReflectionMapping; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CubeUVReflectionMapping", function() { return CubeUVReflectionMapping; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CubeUVRefractionMapping", function() { return CubeUVRefractionMapping; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RepeatWrapping", function() { return RepeatWrapping; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ClampToEdgeWrapping", function() { return ClampToEdgeWrapping; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MirroredRepeatWrapping", function() { return MirroredRepeatWrapping; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "NearestFilter", function() { return NearestFilter; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "NearestMipMapNearestFilter", function() { return NearestMipMapNearestFilter; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "NearestMipMapLinearFilter", function() { return NearestMipMapLinearFilter; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LinearFilter", function() { return LinearFilter; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LinearMipMapNearestFilter", function() { return LinearMipMapNearestFilter; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LinearMipMapLinearFilter", function() { return LinearMipMapLinearFilter; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "UnsignedByteType", function() { return UnsignedByteType; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ByteType", function() { return ByteType; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ShortType", function() { return ShortType; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "UnsignedShortType", function() { return UnsignedShortType; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "IntType", function() { return IntType; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "UnsignedIntType", function() { return UnsignedIntType; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FloatType", function() { return FloatType; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "HalfFloatType", function() { return HalfFloatType; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "UnsignedShort4444Type", function() { return UnsignedShort4444Type; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "UnsignedShort5551Type", function() { return UnsignedShort5551Type; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "UnsignedShort565Type", function() { return UnsignedShort565Type; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "UnsignedInt248Type", function() { return UnsignedInt248Type; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "AlphaFormat", function() { return AlphaFormat; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RGBFormat", function() { return RGBFormat; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RGBAFormat", function() { return RGBAFormat; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LuminanceFormat", function() { return LuminanceFormat; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LuminanceAlphaFormat", function() { return LuminanceAlphaFormat; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RGBEFormat", function() { return RGBEFormat; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "DepthFormat", function() { return DepthFormat; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "DepthStencilFormat", function() { return DepthStencilFormat; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RedFormat", function() { return RedFormat; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RGB_S3TC_DXT1_Format", function() { return RGB_S3TC_DXT1_Format; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RGBA_S3TC_DXT1_Format", function() { return RGBA_S3TC_DXT1_Format; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RGBA_S3TC_DXT3_Format", function() { return RGBA_S3TC_DXT3_Format; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RGBA_S3TC_DXT5_Format", function() { return RGBA_S3TC_DXT5_Format; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RGB_PVRTC_4BPPV1_Format", function() { return RGB_PVRTC_4BPPV1_Format; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RGB_PVRTC_2BPPV1_Format", function() { return RGB_PVRTC_2BPPV1_Format; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RGBA_PVRTC_4BPPV1_Format", function() { return RGBA_PVRTC_4BPPV1_Format; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RGBA_PVRTC_2BPPV1_Format", function() { return RGBA_PVRTC_2BPPV1_Format; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RGB_ETC1_Format", function() { return RGB_ETC1_Format; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RGBA_ASTC_4x4_Format", function() { return RGBA_ASTC_4x4_Format; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RGBA_ASTC_5x4_Format", function() { return RGBA_ASTC_5x4_Format; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RGBA_ASTC_5x5_Format", function() { return RGBA_ASTC_5x5_Format; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RGBA_ASTC_6x5_Format", function() { return RGBA_ASTC_6x5_Format; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RGBA_ASTC_6x6_Format", function() { return RGBA_ASTC_6x6_Format; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RGBA_ASTC_8x5_Format", function() { return RGBA_ASTC_8x5_Format; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RGBA_ASTC_8x6_Format", function() { return RGBA_ASTC_8x6_Format; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RGBA_ASTC_8x8_Format", function() { return RGBA_ASTC_8x8_Format; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RGBA_ASTC_10x5_Format", function() { return RGBA_ASTC_10x5_Format; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RGBA_ASTC_10x6_Format", function() { return RGBA_ASTC_10x6_Format; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RGBA_ASTC_10x8_Format", function() { return RGBA_ASTC_10x8_Format; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RGBA_ASTC_10x10_Format", function() { return RGBA_ASTC_10x10_Format; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RGBA_ASTC_12x10_Format", function() { return RGBA_ASTC_12x10_Format; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RGBA_ASTC_12x12_Format", function() { return RGBA_ASTC_12x12_Format; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LoopOnce", function() { return LoopOnce; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LoopRepeat", function() { return LoopRepeat; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LoopPingPong", function() { return LoopPingPong; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "InterpolateDiscrete", function() { return InterpolateDiscrete; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "InterpolateLinear", function() { return InterpolateLinear; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "InterpolateSmooth", function() { return InterpolateSmooth; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ZeroCurvatureEnding", function() { return ZeroCurvatureEnding; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ZeroSlopeEnding", function() { return ZeroSlopeEnding; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "WrapAroundEnding", function() { return WrapAroundEnding; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "TrianglesDrawMode", function() { return TrianglesDrawMode; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "TriangleStripDrawMode", function() { return TriangleStripDrawMode; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "TriangleFanDrawMode", function() { return TriangleFanDrawMode; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LinearEncoding", function() { return LinearEncoding; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "sRGBEncoding", function() { return sRGBEncoding; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "GammaEncoding", function() { return GammaEncoding; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RGBEEncoding", function() { return RGBEEncoding; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LogLuvEncoding", function() { return LogLuvEncoding; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RGBM7Encoding", function() { return RGBM7Encoding; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RGBM16Encoding", function() { return RGBM16Encoding; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RGBDEncoding", function() { return RGBDEncoding; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "BasicDepthPacking", function() { return BasicDepthPacking; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RGBADepthPacking", function() { return RGBADepthPacking; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "TangentSpaceNormalMap", function() { return TangentSpaceNormalMap; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ObjectSpaceNormalMap", function() { return ObjectSpaceNormalMap; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CubeGeometry", function() { return BoxGeometry; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Face4", function() { return Face4; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LineStrip", function() { return LineStrip; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LinePieces", function() { return LinePieces; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MeshFaceMaterial", function() { return MeshFaceMaterial; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MultiMaterial", function() { return MultiMaterial; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "PointCloud", function() { return PointCloud; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Particle", function() { return Particle; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ParticleSystem", function() { return ParticleSystem; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "PointCloudMaterial", function() { return PointCloudMaterial; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ParticleBasicMaterial", function() { return ParticleBasicMaterial; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ParticleSystemMaterial", function() { return ParticleSystemMaterial; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Vertex", function() { return Vertex; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "DynamicBufferAttribute", function() { return DynamicBufferAttribute; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Int8Attribute", function() { return Int8Attribute; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Uint8Attribute", function() { return Uint8Attribute; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Uint8ClampedAttribute", function() { return Uint8ClampedAttribute; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Int16Attribute", function() { return Int16Attribute; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Uint16Attribute", function() { return Uint16Attribute; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Int32Attribute", function() { return Int32Attribute; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Uint32Attribute", function() { return Uint32Attribute; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Float32Attribute", function() { return Float32Attribute; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Float64Attribute", function() { return Float64Attribute; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ClosedSplineCurve3", function() { return ClosedSplineCurve3; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SplineCurve3", function() { return SplineCurve3; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Spline", function() { return Spline; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "AxisHelper", function() { return AxisHelper; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "BoundingBoxHelper", function() { return BoundingBoxHelper; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "EdgesHelper", function() { return EdgesHelper; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "WireframeHelper", function() { return WireframeHelper; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "XHRLoader", function() { return XHRLoader; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "BinaryTextureLoader", function() { return BinaryTextureLoader; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "GeometryUtils", function() { return GeometryUtils; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Projector", function() { return Projector; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CanvasRenderer", function() { return CanvasRenderer; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "JSONLoader", function() { return JSONLoader; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SceneUtils", function() { return SceneUtils; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LensFlare", function() { return LensFlare; }); +// Polyfills -var mapPropsStream = function mapPropsStream(transform) { - var hoc = mapPropsStreamWithConfig(config)(transform); +if ( Number.EPSILON === undefined ) { - if (process.env.NODE_ENV !== 'production') { - return function (BaseComponent) { - return setDisplayName(wrapDisplayName(BaseComponent, 'mapPropsStream'))(hoc(BaseComponent)); - }; - } - return hoc; -}; + Number.EPSILON = Math.pow( 2, - 52 ); -var createEventHandlerWithConfig = function createEventHandlerWithConfig(config$$1) { - return function () { - var _config$fromESObserva; +} - var emitter = Object(__WEBPACK_IMPORTED_MODULE_3_change_emitter__["createChangeEmitter"])(); - var stream = config$$1.fromESObservable((_config$fromESObserva = { - subscribe: function subscribe(observer) { - var unsubscribe = emitter.listen(function (value) { - return observer.next(value); - }); - return { unsubscribe: unsubscribe }; - } - }, _config$fromESObserva[__WEBPACK_IMPORTED_MODULE_4_symbol_observable__["a" /* default */]] = function () { - return this; - }, _config$fromESObserva)); - return { - handler: emitter.emit, - stream: stream - }; - }; -}; +if ( Number.isInteger === undefined ) { -var createEventHandler = createEventHandlerWithConfig(config); + // Missing in IE + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isInteger -// Higher-order component helpers + Number.isInteger = function ( value ) { + return typeof value === 'number' && isFinite( value ) && Math.floor( value ) === value; + }; -/* WEBPACK VAR INJECTION */}.call(__webpack_exports__, __webpack_require__(4))) +} -/***/ }), -/* 4 */ -/***/ (function(module, exports) { +// -// shim for using process in browser -var process = module.exports = {}; +if ( Math.sign === undefined ) { -// cached from whatever global is present so that test runners that stub it -// don't break things. But we need to wrap it in a try catch in case it is -// wrapped in strict mode code which doesn't define any globals. It's inside a -// function because try/catches deoptimize in certain engines. + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/sign -var cachedSetTimeout; -var cachedClearTimeout; + Math.sign = function ( x ) { + + return ( x < 0 ) ? - 1 : ( x > 0 ) ? 1 : + x; + + }; -function defaultSetTimout() { - throw new Error('setTimeout has not been defined'); -} -function defaultClearTimeout () { - throw new Error('clearTimeout has not been defined'); } -(function () { - try { - if (typeof setTimeout === 'function') { - cachedSetTimeout = setTimeout; - } else { - cachedSetTimeout = defaultSetTimout; - } - } catch (e) { - cachedSetTimeout = defaultSetTimout; - } - try { - if (typeof clearTimeout === 'function') { - cachedClearTimeout = clearTimeout; - } else { - cachedClearTimeout = defaultClearTimeout; - } - } catch (e) { - cachedClearTimeout = defaultClearTimeout; - } -} ()) -function runTimeout(fun) { - if (cachedSetTimeout === setTimeout) { - //normal enviroments in sane situations - return setTimeout(fun, 0); - } - // if setTimeout wasn't available but was latter defined - if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) { - cachedSetTimeout = setTimeout; - return setTimeout(fun, 0); - } - try { - // when when somebody has screwed with setTimeout but no I.E. maddness - return cachedSetTimeout(fun, 0); - } catch(e){ - try { - // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally - return cachedSetTimeout.call(null, fun, 0); - } catch(e){ - // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error - return cachedSetTimeout.call(this, fun, 0); - } - } +if ( 'name' in Function.prototype === false ) { + + // Missing in IE + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/name + + Object.defineProperty( Function.prototype, 'name', { + + get: function () { + + return this.toString().match( /^\s*function\s*([^\(\s]*)/ )[ 1 ]; + + } + + } ); } -function runClearTimeout(marker) { - if (cachedClearTimeout === clearTimeout) { - //normal enviroments in sane situations - return clearTimeout(marker); - } - // if clearTimeout wasn't available but was latter defined - if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) { - cachedClearTimeout = clearTimeout; - return clearTimeout(marker); - } - try { - // when when somebody has screwed with setTimeout but no I.E. maddness - return cachedClearTimeout(marker); - } catch (e){ - try { - // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally - return cachedClearTimeout.call(null, marker); - } catch (e){ - // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error. - // Some versions of I.E. have different rules for clearTimeout vs setTimeout - return cachedClearTimeout.call(this, marker); - } - } - - - -} -var queue = []; -var draining = false; -var currentQueue; -var queueIndex = -1; - -function cleanUpNextTick() { - if (!draining || !currentQueue) { - return; - } - draining = false; - if (currentQueue.length) { - queue = currentQueue.concat(queue); - } else { - queueIndex = -1; - } - if (queue.length) { - drainQueue(); - } -} -function drainQueue() { - if (draining) { - return; - } - var timeout = runTimeout(cleanUpNextTick); - draining = true; +if ( Object.assign === undefined ) { - var len = queue.length; - while(len) { - currentQueue = queue; - queue = []; - while (++queueIndex < len) { - if (currentQueue) { - currentQueue[queueIndex].run(); - } - } - queueIndex = -1; - len = queue.length; - } - currentQueue = null; - draining = false; - runClearTimeout(timeout); -} + // Missing in IE + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign -process.nextTick = function (fun) { - var args = new Array(arguments.length - 1); - if (arguments.length > 1) { - for (var i = 1; i < arguments.length; i++) { - args[i - 1] = arguments[i]; - } - } - queue.push(new Item(fun, args)); - if (queue.length === 1 && !draining) { - runTimeout(drainQueue); - } -}; + ( function () { -// v8 likes predictible objects -function Item(fun, array) { - this.fun = fun; - this.array = array; -} -Item.prototype.run = function () { - this.fun.apply(null, this.array); -}; -process.title = 'browser'; -process.browser = true; -process.env = {}; -process.argv = []; -process.version = ''; // empty string to avoid regexp issues -process.versions = {}; + Object.assign = function ( target ) { -function noop() {} + if ( target === undefined || target === null ) { -process.on = noop; -process.addListener = noop; -process.once = noop; -process.off = noop; -process.removeListener = noop; -process.removeAllListeners = noop; -process.emit = noop; -process.prependListener = noop; -process.prependOnceListener = noop; + throw new TypeError( 'Cannot convert undefined or null to object' ); -process.listeners = function (name) { return [] } + } -process.binding = function (name) { - throw new Error('process.binding is not supported'); -}; + var output = Object( target ); -process.cwd = function () { return '/' }; -process.chdir = function (dir) { - throw new Error('process.chdir is not supported'); -}; -process.umask = function() { return 0; }; + for ( var index = 1; index < arguments.length; index ++ ) { + var source = arguments[ index ]; -/***/ }), -/* 5 */ -/***/ (function(module, exports, __webpack_require__) { + if ( source !== undefined && source !== null ) { -"use strict"; + for ( var nextKey in source ) { + if ( Object.prototype.hasOwnProperty.call( source, nextKey ) ) { -/** - * Copyright (c) 2013-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * - */ + output[ nextKey ] = source[ nextKey ]; -function makeEmptyFunction(arg) { - return function () { - return arg; - }; -} + } -/** - * This function accepts and discards inputs; it has no side effects. This is - * primarily useful idiomatically for overridable function endpoints which - * always need to be callable, since JS lacks a null-call idiom ala Cocoa. - */ -var emptyFunction = function emptyFunction() {}; + } -emptyFunction.thatReturns = makeEmptyFunction; -emptyFunction.thatReturnsFalse = makeEmptyFunction(false); -emptyFunction.thatReturnsTrue = makeEmptyFunction(true); -emptyFunction.thatReturnsNull = makeEmptyFunction(null); -emptyFunction.thatReturnsThis = function () { - return this; -}; -emptyFunction.thatReturnsArgument = function (arg) { - return arg; -}; + } -module.exports = emptyFunction; + } -/***/ }), -/* 6 */ -/***/ (function(module, exports, __webpack_require__) { + return output; -"use strict"; -/* WEBPACK VAR INJECTION */(function(process) {/** - * Copyright (c) 2013-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - */ + }; + } )(); +} /** - * Use invariant() to assert state which your program assumes to be true. - * - * Provide sprintf-style format (only %s is supported) and arguments - * to provide information about what broke and what you were - * expecting. - * - * The invariant message will be stripped in production, but the invariant - * will remain to ensure logic does not differ in production. + * https://github.com/mrdoob/eventdispatcher.js/ */ -var validateFormat = function validateFormat(format) {}; - -if (process.env.NODE_ENV !== 'production') { - validateFormat = function validateFormat(format) { - if (format === undefined) { - throw new Error('invariant requires an error message argument'); - } - }; -} +function EventDispatcher() {} -function invariant(condition, format, a, b, c, d, e, f) { - validateFormat(format); +Object.assign( EventDispatcher.prototype, { - if (!condition) { - var error; - if (format === undefined) { - error = new Error('Minified exception occurred; use the non-minified dev environment ' + 'for the full error message and additional helpful warnings.'); - } else { - var args = [a, b, c, d, e, f]; - var argIndex = 0; - error = new Error(format.replace(/%s/g, function () { - return args[argIndex++]; - })); - error.name = 'Invariant Violation'; - } + addEventListener: function ( type, listener ) { - error.framesToPop = 1; // we don't care about invariant's own frame - throw error; - } -} + if ( this._listeners === undefined ) this._listeners = {}; -module.exports = invariant; -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(4))) + var listeners = this._listeners; -/***/ }), -/* 7 */ -/***/ (function(module, exports, __webpack_require__) { + if ( listeners[ type ] === undefined ) { -"use strict"; -/* WEBPACK VAR INJECTION */(function(process) {/** - * Copyright (c) 2014-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - */ + listeners[ type ] = []; + } + if ( listeners[ type ].indexOf( listener ) === - 1 ) { -var emptyFunction = __webpack_require__(5); + listeners[ type ].push( listener ); -/** - * Similar to invariant but only logs a warning if the condition is not met. - * This can be used to log issues in development environments in critical - * paths. Removing the logging code for production environments will keep the - * same logic and follow the same code paths. - */ + } -var warning = emptyFunction; + }, -if (process.env.NODE_ENV !== 'production') { - var printWarning = function printWarning(format) { - for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { - args[_key - 1] = arguments[_key]; - } + hasEventListener: function ( type, listener ) { - var argIndex = 0; - var message = 'Warning: ' + format.replace(/%s/g, function () { - return args[argIndex++]; - }); - if (typeof console !== 'undefined') { - console.error(message); - } - try { - // --- Welcome to debugging React --- - // This error was thrown as a convenience so that you can use this stack - // to find the callsite that caused this warning to fire. - throw new Error(message); - } catch (x) {} - }; + if ( this._listeners === undefined ) return false; - warning = function warning(condition, format) { - if (format === undefined) { - throw new Error('`warning(condition, format, ...args)` requires a warning ' + 'message argument'); - } + var listeners = this._listeners; - if (format.indexOf('Failed Composite propType: ') === 0) { - return; // Ignore CompositeComponent proptype check. - } + return listeners[ type ] !== undefined && listeners[ type ].indexOf( listener ) !== - 1; - if (!condition) { - for (var _len2 = arguments.length, args = Array(_len2 > 2 ? _len2 - 2 : 0), _key2 = 2; _key2 < _len2; _key2++) { - args[_key2 - 2] = arguments[_key2]; - } + }, - printWarning.apply(undefined, [format].concat(args)); - } - }; -} + removeEventListener: function ( type, listener ) { -module.exports = warning; -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(4))) + if ( this._listeners === undefined ) return; -/***/ }), -/* 8 */ -/***/ (function(module, exports, __webpack_require__) { + var listeners = this._listeners; + var listenerArray = listeners[ type ]; -"use strict"; -/* -object-assign -(c) Sindre Sorhus -@license MIT -*/ + if ( listenerArray !== undefined ) { + var index = listenerArray.indexOf( listener ); -/* eslint-disable no-unused-vars */ -var getOwnPropertySymbols = Object.getOwnPropertySymbols; -var hasOwnProperty = Object.prototype.hasOwnProperty; -var propIsEnumerable = Object.prototype.propertyIsEnumerable; + if ( index !== - 1 ) { -function toObject(val) { - if (val === null || val === undefined) { - throw new TypeError('Object.assign cannot be called with null or undefined'); - } + listenerArray.splice( index, 1 ); - return Object(val); -} + } -function shouldUseNative() { - try { - if (!Object.assign) { - return false; } - // Detect buggy property enumeration order in older V8 versions. + }, - // https://bugs.chromium.org/p/v8/issues/detail?id=4118 - var test1 = new String('abc'); // eslint-disable-line no-new-wrappers - test1[5] = 'de'; - if (Object.getOwnPropertyNames(test1)[0] === '5') { - return false; - } + dispatchEvent: function ( event ) { - // https://bugs.chromium.org/p/v8/issues/detail?id=3056 - var test2 = {}; - for (var i = 0; i < 10; i++) { - test2['_' + String.fromCharCode(i)] = i; - } - var order2 = Object.getOwnPropertyNames(test2).map(function (n) { - return test2[n]; - }); - if (order2.join('') !== '0123456789') { - return false; - } + if ( this._listeners === undefined ) return; - // https://bugs.chromium.org/p/v8/issues/detail?id=3056 - var test3 = {}; - 'abcdefghijklmnopqrst'.split('').forEach(function (letter) { - test3[letter] = letter; - }); - if (Object.keys(Object.assign({}, test3)).join('') !== - 'abcdefghijklmnopqrst') { - return false; - } + var listeners = this._listeners; + var listenerArray = listeners[ event.type ]; - return true; - } catch (err) { - // We don't expect any of the above to throw, but better to be safe. - return false; - } -} + if ( listenerArray !== undefined ) { -module.exports = shouldUseNative() ? Object.assign : function (target, source) { - var from; - var to = toObject(target); - var symbols; + event.target = this; - for (var s = 1; s < arguments.length; s++) { - from = Object(arguments[s]); + var array = listenerArray.slice( 0 ); - for (var key in from) { - if (hasOwnProperty.call(from, key)) { - to[key] = from[key]; - } - } + for ( var i = 0, l = array.length; i < l; i ++ ) { + + array[ i ].call( this, event ); - if (getOwnPropertySymbols) { - symbols = getOwnPropertySymbols(from); - for (var i = 0; i < symbols.length; i++) { - if (propIsEnumerable.call(from, symbols[i])) { - to[symbols[i]] = from[symbols[i]]; - } } + } + } - return to; -}; +} ); +var REVISION = '100'; +var MOUSE = { LEFT: 0, MIDDLE: 1, RIGHT: 2 }; +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 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; +var SubtractiveBlending = 3; +var MultiplyBlending = 4; +var CustomBlending = 5; +var AddEquation = 100; +var SubtractEquation = 101; +var ReverseSubtractEquation = 102; +var MinEquation = 103; +var MaxEquation = 104; +var ZeroFactor = 200; +var OneFactor = 201; +var SrcColorFactor = 202; +var OneMinusSrcColorFactor = 203; +var SrcAlphaFactor = 204; +var OneMinusSrcAlphaFactor = 205; +var DstAlphaFactor = 206; +var OneMinusDstAlphaFactor = 207; +var DstColorFactor = 208; +var OneMinusDstColorFactor = 209; +var SrcAlphaSaturateFactor = 210; +var NeverDepth = 0; +var AlwaysDepth = 1; +var LessDepth = 2; +var LessEqualDepth = 3; +var EqualDepth = 4; +var GreaterEqualDepth = 5; +var GreaterDepth = 6; +var NotEqualDepth = 7; +var MultiplyOperation = 0; +var MixOperation = 1; +var AddOperation = 2; +var NoToneMapping = 0; +var LinearToneMapping = 1; +var ReinhardToneMapping = 2; +var Uncharted2ToneMapping = 3; +var CineonToneMapping = 4; +var ACESFilmicToneMapping = 5; -/***/ }), -/* 9 */ -/***/ (function(module, exports, __webpack_require__) { +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 NearestMipMapLinearFilter = 1005; +var LinearFilter = 1006; +var LinearMipMapNearestFilter = 1007; +var LinearMipMapLinearFilter = 1008; +var UnsignedByteType = 1009; +var ByteType = 1010; +var ShortType = 1011; +var UnsignedShortType = 1012; +var IntType = 1013; +var UnsignedIntType = 1014; +var FloatType = 1015; +var HalfFloatType = 1016; +var UnsignedShort4444Type = 1017; +var UnsignedShort5551Type = 1018; +var UnsignedShort565Type = 1019; +var UnsignedInt248Type = 1020; +var AlphaFormat = 1021; +var RGBFormat = 1022; +var RGBAFormat = 1023; +var LuminanceFormat = 1024; +var LuminanceAlphaFormat = 1025; +var RGBEFormat = RGBAFormat; +var DepthFormat = 1026; +var DepthStencilFormat = 1027; +var RedFormat = 1028; +var RGB_S3TC_DXT1_Format = 33776; +var RGBA_S3TC_DXT1_Format = 33777; +var RGBA_S3TC_DXT3_Format = 33778; +var RGBA_S3TC_DXT5_Format = 33779; +var RGB_PVRTC_4BPPV1_Format = 35840; +var RGB_PVRTC_2BPPV1_Format = 35841; +var RGBA_PVRTC_4BPPV1_Format = 35842; +var RGBA_PVRTC_2BPPV1_Format = 35843; +var RGB_ETC1_Format = 36196; +var RGBA_ASTC_4x4_Format = 37808; +var RGBA_ASTC_5x4_Format = 37809; +var RGBA_ASTC_5x5_Format = 37810; +var RGBA_ASTC_6x5_Format = 37811; +var RGBA_ASTC_6x6_Format = 37812; +var RGBA_ASTC_8x5_Format = 37813; +var RGBA_ASTC_8x6_Format = 37814; +var RGBA_ASTC_8x8_Format = 37815; +var RGBA_ASTC_10x5_Format = 37816; +var RGBA_ASTC_10x6_Format = 37817; +var RGBA_ASTC_10x8_Format = 37818; +var RGBA_ASTC_10x10_Format = 37819; +var RGBA_ASTC_12x10_Format = 37820; +var RGBA_ASTC_12x12_Format = 37821; +var LoopOnce = 2200; +var LoopRepeat = 2201; +var LoopPingPong = 2202; +var InterpolateDiscrete = 2300; +var InterpolateLinear = 2301; +var InterpolateSmooth = 2302; +var ZeroCurvatureEnding = 2400; +var ZeroSlopeEnding = 2401; +var WrapAroundEnding = 2402; +var TrianglesDrawMode = 0; +var TriangleStripDrawMode = 1; +var TriangleFanDrawMode = 2; +var LinearEncoding = 3000; +var sRGBEncoding = 3001; +var GammaEncoding = 3007; +var RGBEEncoding = 3002; +var LogLuvEncoding = 3003; +var RGBM7Encoding = 3004; +var RGBM16Encoding = 3005; +var RGBDEncoding = 3006; +var BasicDepthPacking = 3200; +var RGBADepthPacking = 3201; +var TangentSpaceNormalMap = 0; +var ObjectSpaceNormalMap = 1; -"use strict"; /** - * Copyright (c) 2013-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. + * @author alteredq / http://alteredqualia.com/ + * @author mrdoob / http://mrdoob.com/ */ +var _Math = { + DEG2RAD: Math.PI / 180, + RAD2DEG: 180 / Math.PI, -var ReactPropTypesSecret = 'SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED'; + generateUUID: ( function () { -module.exports = ReactPropTypesSecret; + // http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript/21963136#21963136 + var lut = []; -/***/ }), -/* 10 */ -/***/ (function(module, exports, __webpack_require__) { + for ( var i = 0; i < 256; i ++ ) { -"use strict"; -/** - * Copyright (c) 2013-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @typechecks - * - */ + lut[ i ] = ( i < 16 ? '0' : '' ) + ( i ).toString( 16 ); -/*eslint-disable no-self-compare */ + } + return function generateUUID() { + 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 ]; -var hasOwnProperty = Object.prototype.hasOwnProperty; + // .toUpperCase() here flattens concatenated strings to save heap memory space. + return uuid.toUpperCase(); -/** - * inlined Object.is polyfill to avoid requiring consumers ship their own - * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is - */ -function is(x, y) { - // SameValue algorithm - if (x === y) { - // Steps 1-5, 7-10 - // Steps 6.b-6.e: +0 != -0 - // Added the nonzero y check to make Flow happy, but it is redundant - return x !== 0 || y !== 0 || 1 / x === 1 / y; - } else { - // Step 6.a: NaN == NaN - return x !== x && y !== y; - } -} + }; -/** - * Performs equality by iterating through keys on an object and returning false - * when any key has values which are not strictly equal between the arguments. - * Returns true when the values of all keys are strictly equal. - */ -function shallowEqual(objA, objB) { - if (is(objA, objB)) { - return true; - } + } )(), - if (typeof objA !== 'object' || objA === null || typeof objB !== 'object' || objB === null) { - return false; - } + clamp: function ( value, min, max ) { - var keysA = Object.keys(objA); - var keysB = Object.keys(objB); + return Math.max( min, Math.min( max, value ) ); - if (keysA.length !== keysB.length) { - return false; - } + }, - // Test for A's keys different from B. - for (var i = 0; i < keysA.length; i++) { - if (!hasOwnProperty.call(objB, keysA[i]) || !is(objA[keysA[i]], objB[keysA[i]])) { - return false; - } - } + // compute euclidian modulo of m % n + // https://en.wikipedia.org/wiki/Modulo_operation - return true; -} + euclideanModulo: function ( n, m ) { -module.exports = shallowEqual; + return ( ( n % m ) + m ) % m; -/***/ }), -/* 11 */ -/***/ (function(module, exports, __webpack_require__) { + }, -"use strict"; -/* WEBPACK VAR INJECTION */(function(process) {/** - * Copyright (c) 2013-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ + // Linear mapping from range to range + mapLinear: function ( x, a1, a2, b1, b2 ) { + return b1 + ( x - a1 ) * ( b2 - b1 ) / ( a2 - a1 ); -if (process.env.NODE_ENV !== 'production') { - var invariant = __webpack_require__(6); - var warning = __webpack_require__(7); - var ReactPropTypesSecret = __webpack_require__(9); - var loggedTypeFailures = {}; -} + }, -/** - * Assert that the values match with the type specs. - * Error messages are memorized and will only be shown once. - * - * @param {object} typeSpecs Map of name to a ReactPropType - * @param {object} values Runtime values that need to be type-checked - * @param {string} location e.g. "prop", "context", "child context" - * @param {string} componentName Name of the component for error messages. - * @param {?Function} getStack Returns the component stack. - * @private - */ -function checkPropTypes(typeSpecs, values, location, componentName, getStack) { - if (process.env.NODE_ENV !== 'production') { - for (var typeSpecName in typeSpecs) { - if (typeSpecs.hasOwnProperty(typeSpecName)) { - var error; - // Prop type validation may throw. In case they do, we don't want to - // fail the render phase where it didn't fail before. So we log it. - // After these have been cleaned up, we'll let them throw. - try { - // This is intentionally an invariant that gets caught. It's the same - // behavior as without this statement except with a better message. - invariant(typeof typeSpecs[typeSpecName] === 'function', '%s: %s type `%s` is invalid; it must be a function, usually from ' + 'the `prop-types` package, but received `%s`.', componentName || 'React class', location, typeSpecName, typeof typeSpecs[typeSpecName]); - error = typeSpecs[typeSpecName](values, typeSpecName, componentName, location, null, ReactPropTypesSecret); - } catch (ex) { - error = ex; - } - warning(!error || error instanceof Error, '%s: type specification of %s `%s` is invalid; the type checker ' + 'function must return `null` or an `Error` but returned a %s. ' + 'You may have forgotten to pass an argument to the type checker ' + 'creator (arrayOf, instanceOf, objectOf, oneOf, oneOfType, and ' + 'shape all require an argument).', componentName || 'React class', location, typeSpecName, typeof error); - if (error instanceof Error && !(error.message in loggedTypeFailures)) { - // Only monitor this failure once because there tends to be a lot of the - // same error. - loggedTypeFailures[error.message] = true; + // https://en.wikipedia.org/wiki/Linear_interpolation - var stack = getStack ? getStack() : ''; + lerp: function ( x, y, t ) { - warning(false, 'Failed %s type: %s%s', location, error.message, stack != null ? stack : ''); - } - } - } - } -} + return ( 1 - t ) * x + t * y; -module.exports = checkPropTypes; + }, -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(4))) + // http://en.wikipedia.org/wiki/Smoothstep -/***/ }), -/* 12 */ -/***/ (function(module, exports, __webpack_require__) { + smoothstep: function ( x, min, max ) { -"use strict"; -/* WEBPACK VAR INJECTION */(function(process) { + if ( x <= min ) return 0; + if ( x >= max ) return 1; -function checkDCE() { - /* global __REACT_DEVTOOLS_GLOBAL_HOOK__ */ - if ( - typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ === 'undefined' || - typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE !== 'function' - ) { - return; - } - if (process.env.NODE_ENV !== 'production') { - // This branch is unreachable because this function is only called - // in production, but the condition is true only in development. - // Therefore if the branch is still here, dead code elimination wasn't - // properly applied. - // Don't change the message. React DevTools relies on it. Also make sure - // this message doesn't occur elsewhere in this function, or it will cause - // a false positive. - throw new Error('^_^'); - } - try { - // Verify that the code above has been dead code eliminated (DCE'd). - __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(checkDCE); - } catch (err) { - // DevTools shouldn't crash React, no matter what. - // We should still report in case we break this code. - console.error(err); - } -} + x = ( x - min ) / ( max - min ); -if (process.env.NODE_ENV === 'production') { - // DCE check should happen before ReactDOM bundle executes so that - // DevTools can report bad minification during injection. - checkDCE(); - module.exports = __webpack_require__(27); -} else { - module.exports = __webpack_require__(30); -} + return x * x * ( 3 - 2 * x ); -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(4))) + }, -/***/ }), -/* 13 */ -/***/ (function(module, exports, __webpack_require__) { + smootherstep: function ( x, min, max ) { -"use strict"; -/** - * Copyright (c) 2013-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - */ + if ( x <= min ) return 0; + if ( x >= max ) return 1; + x = ( x - min ) / ( max - min ); + return x * x * x * ( x * ( x * 6 - 15 ) + 10 ); -var canUseDOM = !!(typeof window !== 'undefined' && window.document && window.document.createElement); + }, -/** - * Simple, lightweight module assisting with the detection and context of - * Worker. Helps avoid circular dependencies and allows code to reason about - * whether or not they are in a Worker, even if they never include the main - * `ReactWorker` dependency. - */ -var ExecutionEnvironment = { + // Random integer from interval - canUseDOM: canUseDOM, + randInt: function ( low, high ) { - canUseWorkers: typeof Worker !== 'undefined', + return low + Math.floor( Math.random() * ( high - low + 1 ) ); - canUseEventListeners: canUseDOM && !!(window.addEventListener || window.attachEvent), + }, - canUseViewport: canUseDOM && !!window.screen, + // Random float from interval - isInWorker: !canUseDOM // For now, this is true - might change in the future. + randFloat: function ( low, high ) { -}; + return low + Math.random() * ( high - low ); -module.exports = ExecutionEnvironment; + }, -/***/ }), -/* 14 */ -/***/ (function(module, exports, __webpack_require__) { + // Random float from <-range/2, range/2> interval -"use strict"; -/* WEBPACK VAR INJECTION */(function(process) { + randFloatSpread: function ( range ) { -/** - * Copyright (c) 2013-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @typechecks - */ + return range * ( 0.5 - Math.random() ); -var emptyFunction = __webpack_require__(5); + }, -/** - * Upstream version of event listener. Does not take into account specific - * nature of platform. - */ -var EventListener = { - /** - * Listen to DOM events during the bubble phase. - * - * @param {DOMEventTarget} target DOM element to register listener on. - * @param {string} eventType Event type, e.g. 'click' or 'mouseover'. - * @param {function} callback Callback function. - * @return {object} Object with a `remove` method. - */ - listen: function listen(target, eventType, callback) { - if (target.addEventListener) { - target.addEventListener(eventType, callback, false); - return { - remove: function remove() { - target.removeEventListener(eventType, callback, false); - } - }; - } else if (target.attachEvent) { - target.attachEvent('on' + eventType, callback); - return { - remove: function remove() { - target.detachEvent('on' + eventType, callback); - } - }; - } - }, + degToRad: function ( degrees ) { - /** - * Listen to DOM events during the capture phase. - * - * @param {DOMEventTarget} target DOM element to register listener on. - * @param {string} eventType Event type, e.g. 'click' or 'mouseover'. - * @param {function} callback Callback function. - * @return {object} Object with a `remove` method. - */ - capture: function capture(target, eventType, callback) { - if (target.addEventListener) { - target.addEventListener(eventType, callback, true); - return { - remove: function remove() { - target.removeEventListener(eventType, callback, true); - } - }; - } else { - if (process.env.NODE_ENV !== 'production') { - console.error('Attempted to listen to events during the capture phase on a ' + 'browser that does not support the capture phase. Your application ' + 'will not receive some events.'); - } - return { - remove: emptyFunction - }; - } - }, + return degrees * _Math.DEG2RAD; - registerDefault: function registerDefault() {} -}; + }, -module.exports = EventListener; -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(4))) + radToDeg: function ( radians ) { -/***/ }), -/* 15 */ -/***/ (function(module, exports, __webpack_require__) { + return radians * _Math.RAD2DEG; -"use strict"; + }, + isPowerOfTwo: function ( value ) { -/** - * Copyright (c) 2013-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @typechecks - */ + return ( value & ( value - 1 ) ) === 0 && value !== 0; -/* eslint-disable fb-www/typeof-undefined */ + }, -/** - * Same as document.activeElement but wraps in a try-catch block. In IE it is - * not safe to call document.activeElement if there is nothing focused. - * - * The activeElement will be null only if the document or document body is not - * yet defined. - * - * @param {?DOMDocument} doc Defaults to current document. - * @return {?DOMElement} - */ -function getActiveElement(doc) /*?DOMElement*/{ - doc = doc || (typeof document !== 'undefined' ? document : undefined); - if (typeof doc === 'undefined') { - return null; - } - try { - return doc.activeElement || doc.body; - } catch (e) { - return doc.body; - } -} + ceilPowerOfTwo: function ( value ) { -module.exports = getActiveElement; + return Math.pow( 2, Math.ceil( Math.log( value ) / Math.LN2 ) ); -/***/ }), -/* 16 */ -/***/ (function(module, exports, __webpack_require__) { + }, -"use strict"; + floorPowerOfTwo: function ( value ) { + + return Math.pow( 2, Math.floor( Math.log( value ) / Math.LN2 ) ); + } + +}; /** - * Copyright (c) 2013-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * + * @author mrdoob / http://mrdoob.com/ + * @author philogb / http://blog.thejit.org/ + * @author egraether / http://egraether.com/ + * @author zz85 / http://www.lab4games.net/zz85/blog */ -var isTextNode = __webpack_require__(28); +function Vector2( x, y ) { -/*eslint-disable no-bitwise */ + this.x = x || 0; + this.y = y || 0; -/** - * Checks if a given DOM node contains or is another DOM node. - */ -function containsNode(outerNode, innerNode) { - if (!outerNode || !innerNode) { - return false; - } else if (outerNode === innerNode) { - return true; - } else if (isTextNode(outerNode)) { - return false; - } else if (isTextNode(innerNode)) { - return containsNode(outerNode, innerNode.parentNode); - } else if ('contains' in outerNode) { - return outerNode.contains(innerNode); - } else if (outerNode.compareDocumentPosition) { - return !!(outerNode.compareDocumentPosition(innerNode) & 16); - } else { - return false; - } } -module.exports = containsNode; +Object.defineProperties( Vector2.prototype, { -/***/ }), -/* 17 */ -/***/ (function(module, exports, __webpack_require__) { + "width": { -"use strict"; -/** - * Copyright (c) 2013-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - */ + get: function () { + return this.x; + }, -/** - * @param {DOMElement} node input/textarea to focus - */ + set: function ( value ) { -function focusNode(node) { - // IE8 can throw "Can't move focus to the control because it is invisible, - // not enabled, or of a type that does not accept the focus." for all kinds of - // reasons that are too expensive and fragile to test. - try { - node.focus(); - } catch (e) {} -} + this.x = value; -module.exports = focusNode; + } -/***/ }), -/* 18 */ -/***/ (function(module, exports, __webpack_require__) { + }, -"use strict"; -/* WEBPACK VAR INJECTION */(function(process) {/** - * Copyright (c) 2013-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - */ + "height": { + get: function () { + return this.y; -var emptyObject = {}; + }, -if (process.env.NODE_ENV !== 'production') { - Object.freeze(emptyObject); -} + set: function ( value ) { -module.exports = emptyObject; -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(4))) + this.y = value; -/***/ }), -/* 19 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { + } -"use strict"; -Object.defineProperty(__webpack_exports__, "__esModule", { value: true }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "WebGLRenderTargetCube", function() { return WebGLRenderTargetCube; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "WebGLRenderTarget", function() { return WebGLRenderTarget; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "WebGLRenderer", function() { return WebGLRenderer; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ShaderLib", function() { return ShaderLib; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "UniformsLib", function() { return UniformsLib; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "UniformsUtils", function() { return UniformsUtils; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ShaderChunk", function() { return ShaderChunk; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FogExp2", function() { return FogExp2; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Fog", function() { return Fog; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Scene", function() { return Scene; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Sprite", function() { return Sprite; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LOD", function() { return LOD; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SkinnedMesh", function() { return SkinnedMesh; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Skeleton", function() { return Skeleton; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Bone", function() { return Bone; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Mesh", function() { return Mesh; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LineSegments", function() { return LineSegments; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LineLoop", function() { return LineLoop; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Line", function() { return Line; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Points", function() { return Points; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Group", function() { return Group; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "VideoTexture", function() { return VideoTexture; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "DataTexture", function() { return DataTexture; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CompressedTexture", function() { return CompressedTexture; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CubeTexture", function() { return CubeTexture; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CanvasTexture", function() { return CanvasTexture; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "DepthTexture", function() { return DepthTexture; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Texture", function() { return Texture; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CompressedTextureLoader", function() { return CompressedTextureLoader; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "DataTextureLoader", function() { return DataTextureLoader; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CubeTextureLoader", function() { return CubeTextureLoader; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "TextureLoader", function() { return TextureLoader; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ObjectLoader", function() { return ObjectLoader; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MaterialLoader", function() { return MaterialLoader; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "BufferGeometryLoader", function() { return BufferGeometryLoader; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "DefaultLoadingManager", function() { return DefaultLoadingManager; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LoadingManager", function() { return LoadingManager; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "JSONLoader", function() { return JSONLoader; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ImageLoader", function() { return ImageLoader; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ImageBitmapLoader", function() { return ImageBitmapLoader; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FontLoader", function() { return FontLoader; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FileLoader", function() { return FileLoader; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Loader", function() { return Loader; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LoaderUtils", function() { return LoaderUtils; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Cache", function() { return Cache; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "AudioLoader", function() { return AudioLoader; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SpotLightShadow", function() { return SpotLightShadow; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SpotLight", function() { return SpotLight; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "PointLight", function() { return PointLight; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RectAreaLight", function() { return RectAreaLight; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "HemisphereLight", function() { return HemisphereLight; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "DirectionalLightShadow", function() { return DirectionalLightShadow; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "DirectionalLight", function() { return DirectionalLight; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "AmbientLight", function() { return AmbientLight; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LightShadow", function() { return LightShadow; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Light", function() { return Light; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "StereoCamera", function() { return StereoCamera; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "PerspectiveCamera", function() { return PerspectiveCamera; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "OrthographicCamera", function() { return OrthographicCamera; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CubeCamera", function() { return CubeCamera; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ArrayCamera", function() { return ArrayCamera; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Camera", function() { return Camera; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "AudioListener", function() { return AudioListener; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "PositionalAudio", function() { return PositionalAudio; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "AudioContext", function() { return AudioContext; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "AudioAnalyser", function() { return AudioAnalyser; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Audio", function() { return Audio; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "VectorKeyframeTrack", function() { return VectorKeyframeTrack; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "StringKeyframeTrack", function() { return StringKeyframeTrack; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "QuaternionKeyframeTrack", function() { return QuaternionKeyframeTrack; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "NumberKeyframeTrack", function() { return NumberKeyframeTrack; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ColorKeyframeTrack", function() { return ColorKeyframeTrack; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "BooleanKeyframeTrack", function() { return BooleanKeyframeTrack; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "PropertyMixer", function() { return PropertyMixer; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "PropertyBinding", function() { return PropertyBinding; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "KeyframeTrack", function() { return KeyframeTrack; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "AnimationUtils", function() { return AnimationUtils; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "AnimationObjectGroup", function() { return AnimationObjectGroup; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "AnimationMixer", function() { return AnimationMixer; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "AnimationClip", function() { return AnimationClip; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Uniform", function() { return Uniform; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "InstancedBufferGeometry", function() { return InstancedBufferGeometry; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "BufferGeometry", function() { return BufferGeometry; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Geometry", function() { return Geometry; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "InterleavedBufferAttribute", function() { return InterleavedBufferAttribute; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "InstancedInterleavedBuffer", function() { return InstancedInterleavedBuffer; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "InterleavedBuffer", function() { return InterleavedBuffer; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "InstancedBufferAttribute", function() { return InstancedBufferAttribute; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Face3", function() { return Face3; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Object3D", function() { return Object3D; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Raycaster", function() { return Raycaster; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Layers", function() { return Layers; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "EventDispatcher", function() { return EventDispatcher; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Clock", function() { return Clock; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "QuaternionLinearInterpolant", function() { return QuaternionLinearInterpolant; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LinearInterpolant", function() { return LinearInterpolant; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "DiscreteInterpolant", function() { return DiscreteInterpolant; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CubicInterpolant", function() { return CubicInterpolant; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Interpolant", function() { return Interpolant; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Triangle", function() { return Triangle; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Math", function() { return _Math; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Spherical", function() { return Spherical; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Cylindrical", function() { return Cylindrical; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Plane", function() { return Plane; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Frustum", function() { return Frustum; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Sphere", function() { return Sphere; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Ray", function() { return Ray; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Matrix4", function() { return Matrix4; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Matrix3", function() { return Matrix3; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Box3", function() { return Box3; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Box2", function() { return Box2; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Line3", function() { return Line3; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Euler", function() { return Euler; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Vector4", function() { return Vector4; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Vector3", function() { return Vector3; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Vector2", function() { return Vector2; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Quaternion", function() { return Quaternion; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Color", function() { return Color; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ImmediateRenderObject", function() { return ImmediateRenderObject; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "VertexNormalsHelper", function() { return VertexNormalsHelper; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SpotLightHelper", function() { return SpotLightHelper; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SkeletonHelper", function() { return SkeletonHelper; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "PointLightHelper", function() { return PointLightHelper; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RectAreaLightHelper", function() { return RectAreaLightHelper; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "HemisphereLightHelper", function() { return HemisphereLightHelper; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "GridHelper", function() { return GridHelper; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "PolarGridHelper", function() { return PolarGridHelper; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FaceNormalsHelper", function() { return FaceNormalsHelper; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "DirectionalLightHelper", function() { return DirectionalLightHelper; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CameraHelper", function() { return CameraHelper; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "BoxHelper", function() { return BoxHelper; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Box3Helper", function() { return Box3Helper; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "PlaneHelper", function() { return PlaneHelper; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ArrowHelper", function() { return ArrowHelper; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "AxesHelper", function() { return AxesHelper; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Shape", function() { return Shape; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Path", function() { return Path; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ShapePath", function() { return ShapePath; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Font", function() { return Font; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CurvePath", function() { return CurvePath; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Curve", function() { return Curve; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ShapeUtils", function() { return ShapeUtils; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "WebGLUtils", function() { return WebGLUtils; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "WireframeGeometry", function() { return WireframeGeometry; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ParametricGeometry", function() { return ParametricGeometry; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ParametricBufferGeometry", function() { return ParametricBufferGeometry; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "TetrahedronGeometry", function() { return TetrahedronGeometry; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "TetrahedronBufferGeometry", function() { return TetrahedronBufferGeometry; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "OctahedronGeometry", function() { return OctahedronGeometry; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "OctahedronBufferGeometry", function() { return OctahedronBufferGeometry; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "IcosahedronGeometry", function() { return IcosahedronGeometry; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "IcosahedronBufferGeometry", function() { return IcosahedronBufferGeometry; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "DodecahedronGeometry", function() { return DodecahedronGeometry; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "DodecahedronBufferGeometry", function() { return DodecahedronBufferGeometry; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "PolyhedronGeometry", function() { return PolyhedronGeometry; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "PolyhedronBufferGeometry", function() { return PolyhedronBufferGeometry; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "TubeGeometry", function() { return TubeGeometry; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "TubeBufferGeometry", function() { return TubeBufferGeometry; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "TorusKnotGeometry", function() { return TorusKnotGeometry; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "TorusKnotBufferGeometry", function() { return TorusKnotBufferGeometry; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "TorusGeometry", function() { return TorusGeometry; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "TorusBufferGeometry", function() { return TorusBufferGeometry; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "TextGeometry", function() { return TextGeometry; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "TextBufferGeometry", function() { return TextBufferGeometry; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SphereGeometry", function() { return SphereGeometry; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SphereBufferGeometry", function() { return SphereBufferGeometry; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RingGeometry", function() { return RingGeometry; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RingBufferGeometry", function() { return RingBufferGeometry; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "PlaneGeometry", function() { return PlaneGeometry; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "PlaneBufferGeometry", function() { return PlaneBufferGeometry; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LatheGeometry", function() { return LatheGeometry; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LatheBufferGeometry", function() { return LatheBufferGeometry; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ShapeGeometry", function() { return ShapeGeometry; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ShapeBufferGeometry", function() { return ShapeBufferGeometry; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ExtrudeGeometry", function() { return ExtrudeGeometry; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ExtrudeBufferGeometry", function() { return ExtrudeBufferGeometry; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "EdgesGeometry", function() { return EdgesGeometry; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ConeGeometry", function() { return ConeGeometry; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ConeBufferGeometry", function() { return ConeBufferGeometry; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CylinderGeometry", function() { return CylinderGeometry; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CylinderBufferGeometry", function() { return CylinderBufferGeometry; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CircleGeometry", function() { return CircleGeometry; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CircleBufferGeometry", function() { return CircleBufferGeometry; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "BoxGeometry", function() { return BoxGeometry; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "BoxBufferGeometry", function() { return BoxBufferGeometry; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ShadowMaterial", function() { return ShadowMaterial; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SpriteMaterial", function() { return SpriteMaterial; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RawShaderMaterial", function() { return RawShaderMaterial; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ShaderMaterial", function() { return ShaderMaterial; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "PointsMaterial", function() { return PointsMaterial; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MeshPhysicalMaterial", function() { return MeshPhysicalMaterial; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MeshStandardMaterial", function() { return MeshStandardMaterial; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MeshPhongMaterial", function() { return MeshPhongMaterial; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MeshToonMaterial", function() { return MeshToonMaterial; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MeshNormalMaterial", function() { return MeshNormalMaterial; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MeshLambertMaterial", function() { return MeshLambertMaterial; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MeshDepthMaterial", function() { return MeshDepthMaterial; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MeshDistanceMaterial", function() { return MeshDistanceMaterial; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MeshBasicMaterial", function() { return MeshBasicMaterial; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LineDashedMaterial", function() { return LineDashedMaterial; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LineBasicMaterial", function() { return LineBasicMaterial; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Material", function() { return Material; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Float64BufferAttribute", function() { return Float64BufferAttribute; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Float32BufferAttribute", function() { return Float32BufferAttribute; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Uint32BufferAttribute", function() { return Uint32BufferAttribute; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Int32BufferAttribute", function() { return Int32BufferAttribute; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Uint16BufferAttribute", function() { return Uint16BufferAttribute; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Int16BufferAttribute", function() { return Int16BufferAttribute; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Uint8ClampedBufferAttribute", function() { return Uint8ClampedBufferAttribute; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Uint8BufferAttribute", function() { return Uint8BufferAttribute; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Int8BufferAttribute", function() { return Int8BufferAttribute; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "BufferAttribute", function() { return BufferAttribute; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ArcCurve", function() { return ArcCurve; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CatmullRomCurve3", function() { return CatmullRomCurve3; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CubicBezierCurve", function() { return CubicBezierCurve; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CubicBezierCurve3", function() { return CubicBezierCurve3; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "EllipseCurve", function() { return EllipseCurve; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LineCurve", function() { return LineCurve; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LineCurve3", function() { return LineCurve3; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "QuadraticBezierCurve", function() { return QuadraticBezierCurve; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "QuadraticBezierCurve3", function() { return QuadraticBezierCurve3; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SplineCurve", function() { return SplineCurve; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "REVISION", function() { return REVISION; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MOUSE", function() { return MOUSE; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CullFaceNone", function() { return CullFaceNone; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CullFaceBack", function() { return CullFaceBack; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CullFaceFront", function() { return CullFaceFront; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CullFaceFrontBack", function() { return CullFaceFrontBack; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FrontFaceDirectionCW", function() { return FrontFaceDirectionCW; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FrontFaceDirectionCCW", function() { return FrontFaceDirectionCCW; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "BasicShadowMap", function() { return BasicShadowMap; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "PCFShadowMap", function() { return PCFShadowMap; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "PCFSoftShadowMap", function() { return PCFSoftShadowMap; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FrontSide", function() { return FrontSide; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "BackSide", function() { return BackSide; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "DoubleSide", function() { return DoubleSide; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FlatShading", function() { return FlatShading; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SmoothShading", function() { return SmoothShading; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "NoColors", function() { return NoColors; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FaceColors", function() { return FaceColors; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "VertexColors", function() { return VertexColors; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "NoBlending", function() { return NoBlending; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "NormalBlending", function() { return NormalBlending; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "AdditiveBlending", function() { return AdditiveBlending; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SubtractiveBlending", function() { return SubtractiveBlending; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MultiplyBlending", function() { return MultiplyBlending; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CustomBlending", function() { return CustomBlending; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "AddEquation", function() { return AddEquation; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SubtractEquation", function() { return SubtractEquation; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ReverseSubtractEquation", function() { return ReverseSubtractEquation; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MinEquation", function() { return MinEquation; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MaxEquation", function() { return MaxEquation; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ZeroFactor", function() { return ZeroFactor; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "OneFactor", function() { return OneFactor; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SrcColorFactor", function() { return SrcColorFactor; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "OneMinusSrcColorFactor", function() { return OneMinusSrcColorFactor; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SrcAlphaFactor", function() { return SrcAlphaFactor; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "OneMinusSrcAlphaFactor", function() { return OneMinusSrcAlphaFactor; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "DstAlphaFactor", function() { return DstAlphaFactor; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "OneMinusDstAlphaFactor", function() { return OneMinusDstAlphaFactor; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "DstColorFactor", function() { return DstColorFactor; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "OneMinusDstColorFactor", function() { return OneMinusDstColorFactor; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SrcAlphaSaturateFactor", function() { return SrcAlphaSaturateFactor; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "NeverDepth", function() { return NeverDepth; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "AlwaysDepth", function() { return AlwaysDepth; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LessDepth", function() { return LessDepth; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LessEqualDepth", function() { return LessEqualDepth; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "EqualDepth", function() { return EqualDepth; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "GreaterEqualDepth", function() { return GreaterEqualDepth; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "GreaterDepth", function() { return GreaterDepth; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "NotEqualDepth", function() { return NotEqualDepth; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MultiplyOperation", function() { return MultiplyOperation; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MixOperation", function() { return MixOperation; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "AddOperation", function() { return AddOperation; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "NoToneMapping", function() { return NoToneMapping; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LinearToneMapping", function() { return LinearToneMapping; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ReinhardToneMapping", function() { return ReinhardToneMapping; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Uncharted2ToneMapping", function() { return Uncharted2ToneMapping; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CineonToneMapping", function() { return CineonToneMapping; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "UVMapping", function() { return UVMapping; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CubeReflectionMapping", function() { return CubeReflectionMapping; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CubeRefractionMapping", function() { return CubeRefractionMapping; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "EquirectangularReflectionMapping", function() { return EquirectangularReflectionMapping; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "EquirectangularRefractionMapping", function() { return EquirectangularRefractionMapping; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SphericalReflectionMapping", function() { return SphericalReflectionMapping; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CubeUVReflectionMapping", function() { return CubeUVReflectionMapping; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CubeUVRefractionMapping", function() { return CubeUVRefractionMapping; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RepeatWrapping", function() { return RepeatWrapping; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ClampToEdgeWrapping", function() { return ClampToEdgeWrapping; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MirroredRepeatWrapping", function() { return MirroredRepeatWrapping; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "NearestFilter", function() { return NearestFilter; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "NearestMipMapNearestFilter", function() { return NearestMipMapNearestFilter; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "NearestMipMapLinearFilter", function() { return NearestMipMapLinearFilter; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LinearFilter", function() { return LinearFilter; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LinearMipMapNearestFilter", function() { return LinearMipMapNearestFilter; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LinearMipMapLinearFilter", function() { return LinearMipMapLinearFilter; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "UnsignedByteType", function() { return UnsignedByteType; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ByteType", function() { return ByteType; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ShortType", function() { return ShortType; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "UnsignedShortType", function() { return UnsignedShortType; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "IntType", function() { return IntType; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "UnsignedIntType", function() { return UnsignedIntType; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FloatType", function() { return FloatType; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "HalfFloatType", function() { return HalfFloatType; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "UnsignedShort4444Type", function() { return UnsignedShort4444Type; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "UnsignedShort5551Type", function() { return UnsignedShort5551Type; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "UnsignedShort565Type", function() { return UnsignedShort565Type; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "UnsignedInt248Type", function() { return UnsignedInt248Type; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "AlphaFormat", function() { return AlphaFormat; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RGBFormat", function() { return RGBFormat; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RGBAFormat", function() { return RGBAFormat; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LuminanceFormat", function() { return LuminanceFormat; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LuminanceAlphaFormat", function() { return LuminanceAlphaFormat; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RGBEFormat", function() { return RGBEFormat; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "DepthFormat", function() { return DepthFormat; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "DepthStencilFormat", function() { return DepthStencilFormat; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RGB_S3TC_DXT1_Format", function() { return RGB_S3TC_DXT1_Format; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RGBA_S3TC_DXT1_Format", function() { return RGBA_S3TC_DXT1_Format; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RGBA_S3TC_DXT3_Format", function() { return RGBA_S3TC_DXT3_Format; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RGBA_S3TC_DXT5_Format", function() { return RGBA_S3TC_DXT5_Format; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RGB_PVRTC_4BPPV1_Format", function() { return RGB_PVRTC_4BPPV1_Format; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RGB_PVRTC_2BPPV1_Format", function() { return RGB_PVRTC_2BPPV1_Format; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RGBA_PVRTC_4BPPV1_Format", function() { return RGBA_PVRTC_4BPPV1_Format; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RGBA_PVRTC_2BPPV1_Format", function() { return RGBA_PVRTC_2BPPV1_Format; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RGB_ETC1_Format", function() { return RGB_ETC1_Format; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RGBA_ASTC_4x4_Format", function() { return RGBA_ASTC_4x4_Format; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RGBA_ASTC_5x4_Format", function() { return RGBA_ASTC_5x4_Format; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RGBA_ASTC_5x5_Format", function() { return RGBA_ASTC_5x5_Format; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RGBA_ASTC_6x5_Format", function() { return RGBA_ASTC_6x5_Format; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RGBA_ASTC_6x6_Format", function() { return RGBA_ASTC_6x6_Format; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RGBA_ASTC_8x5_Format", function() { return RGBA_ASTC_8x5_Format; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RGBA_ASTC_8x6_Format", function() { return RGBA_ASTC_8x6_Format; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RGBA_ASTC_8x8_Format", function() { return RGBA_ASTC_8x8_Format; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RGBA_ASTC_10x5_Format", function() { return RGBA_ASTC_10x5_Format; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RGBA_ASTC_10x6_Format", function() { return RGBA_ASTC_10x6_Format; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RGBA_ASTC_10x8_Format", function() { return RGBA_ASTC_10x8_Format; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RGBA_ASTC_10x10_Format", function() { return RGBA_ASTC_10x10_Format; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RGBA_ASTC_12x10_Format", function() { return RGBA_ASTC_12x10_Format; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RGBA_ASTC_12x12_Format", function() { return RGBA_ASTC_12x12_Format; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LoopOnce", function() { return LoopOnce; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LoopRepeat", function() { return LoopRepeat; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LoopPingPong", function() { return LoopPingPong; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "InterpolateDiscrete", function() { return InterpolateDiscrete; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "InterpolateLinear", function() { return InterpolateLinear; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "InterpolateSmooth", function() { return InterpolateSmooth; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ZeroCurvatureEnding", function() { return ZeroCurvatureEnding; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ZeroSlopeEnding", function() { return ZeroSlopeEnding; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "WrapAroundEnding", function() { return WrapAroundEnding; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "TrianglesDrawMode", function() { return TrianglesDrawMode; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "TriangleStripDrawMode", function() { return TriangleStripDrawMode; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "TriangleFanDrawMode", function() { return TriangleFanDrawMode; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LinearEncoding", function() { return LinearEncoding; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "sRGBEncoding", function() { return sRGBEncoding; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "GammaEncoding", function() { return GammaEncoding; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RGBEEncoding", function() { return RGBEEncoding; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LogLuvEncoding", function() { return LogLuvEncoding; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RGBM7Encoding", function() { return RGBM7Encoding; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RGBM16Encoding", function() { return RGBM16Encoding; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RGBDEncoding", function() { return RGBDEncoding; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "BasicDepthPacking", function() { return BasicDepthPacking; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RGBADepthPacking", function() { return RGBADepthPacking; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CubeGeometry", function() { return BoxGeometry; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Face4", function() { return Face4; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LineStrip", function() { return LineStrip; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LinePieces", function() { return LinePieces; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MeshFaceMaterial", function() { return MeshFaceMaterial; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MultiMaterial", function() { return MultiMaterial; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "PointCloud", function() { return PointCloud; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Particle", function() { return Particle; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ParticleSystem", function() { return ParticleSystem; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "PointCloudMaterial", function() { return PointCloudMaterial; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ParticleBasicMaterial", function() { return ParticleBasicMaterial; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ParticleSystemMaterial", function() { return ParticleSystemMaterial; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Vertex", function() { return Vertex; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "DynamicBufferAttribute", function() { return DynamicBufferAttribute; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Int8Attribute", function() { return Int8Attribute; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Uint8Attribute", function() { return Uint8Attribute; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Uint8ClampedAttribute", function() { return Uint8ClampedAttribute; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Int16Attribute", function() { return Int16Attribute; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Uint16Attribute", function() { return Uint16Attribute; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Int32Attribute", function() { return Int32Attribute; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Uint32Attribute", function() { return Uint32Attribute; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Float32Attribute", function() { return Float32Attribute; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Float64Attribute", function() { return Float64Attribute; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ClosedSplineCurve3", function() { return ClosedSplineCurve3; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SplineCurve3", function() { return SplineCurve3; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Spline", function() { return Spline; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "AxisHelper", function() { return AxisHelper; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "BoundingBoxHelper", function() { return BoundingBoxHelper; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "EdgesHelper", function() { return EdgesHelper; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "WireframeHelper", function() { return WireframeHelper; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "XHRLoader", function() { return XHRLoader; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "BinaryTextureLoader", function() { return BinaryTextureLoader; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "GeometryUtils", function() { return GeometryUtils; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ImageUtils", function() { return ImageUtils; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Projector", function() { return Projector; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CanvasRenderer", function() { return CanvasRenderer; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SceneUtils", function() { return SceneUtils; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LensFlare", function() { return LensFlare; }); -// Polyfills + } -if ( Number.EPSILON === undefined ) { +} ); - Number.EPSILON = Math.pow( 2, - 52 ); +Object.assign( Vector2.prototype, { -} + isVector2: true, -if ( Number.isInteger === undefined ) { + set: function ( x, y ) { - // Missing in IE - // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isInteger + this.x = x; + this.y = y; - Number.isInteger = function ( value ) { + return this; - return typeof value === 'number' && isFinite( value ) && Math.floor( value ) === value; + }, - }; + setScalar: function ( scalar ) { -} + this.x = scalar; + this.y = scalar; -// + return this; -if ( Math.sign === undefined ) { + }, - // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/sign + setX: function ( x ) { - Math.sign = function ( x ) { + this.x = x; - return ( x < 0 ) ? - 1 : ( x > 0 ) ? 1 : + x; + return this; - }; + }, -} + setY: function ( y ) { -if ( 'name' in Function.prototype === false ) { + this.y = y; - // Missing in IE - // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/name + return this; - Object.defineProperty( Function.prototype, 'name', { + }, - get: function () { + setComponent: function ( index, value ) { - return this.toString().match( /^\s*function\s*([^\(\s]*)/ )[ 1 ]; + switch ( index ) { + + case 0: this.x = value; break; + case 1: this.y = value; break; + default: throw new Error( 'index is out of range: ' + index ); } - } ); + return this; -} + }, -if ( Object.assign === undefined ) { + getComponent: function ( index ) { - // Missing in IE - // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign + switch ( index ) { - ( function () { + case 0: return this.x; + case 1: return this.y; + default: throw new Error( 'index is out of range: ' + index ); - Object.assign = function ( target ) { + } - if ( target === undefined || target === null ) { + }, - throw new TypeError( 'Cannot convert undefined or null to object' ); + clone: function () { - } + return new this.constructor( this.x, this.y ); - var output = Object( target ); + }, - for ( var index = 1; index < arguments.length; index ++ ) { + copy: function ( v ) { - var source = arguments[ index ]; + this.x = v.x; + this.y = v.y; - if ( source !== undefined && source !== null ) { + return this; - for ( var nextKey in source ) { + }, - if ( Object.prototype.hasOwnProperty.call( source, nextKey ) ) { + add: function ( v, w ) { - output[ nextKey ] = source[ nextKey ]; + if ( w !== undefined ) { - } + console.warn( 'THREE.Vector2: .add() now only accepts one argument. Use .addVectors( a, b ) instead.' ); + return this.addVectors( v, w ); - } + } - } + this.x += v.x; + this.y += v.y; - } + return this; - return output; + }, - }; + addScalar: function ( s ) { - } )(); + this.x += s; + this.y += s; -} + return this; -/** - * https://github.com/mrdoob/eventdispatcher.js/ - */ + }, -function EventDispatcher() {} + addVectors: function ( a, b ) { -Object.assign( EventDispatcher.prototype, { + this.x = a.x + b.x; + this.y = a.y + b.y; - addEventListener: function ( type, listener ) { + return this; - if ( this._listeners === undefined ) this._listeners = {}; + }, - var listeners = this._listeners; + addScaledVector: function ( v, s ) { - if ( listeners[ type ] === undefined ) { + this.x += v.x * s; + this.y += v.y * s; - listeners[ type ] = []; + return this; - } + }, - if ( listeners[ type ].indexOf( listener ) === - 1 ) { + sub: function ( v, w ) { - listeners[ type ].push( listener ); + if ( w !== undefined ) { + + console.warn( 'THREE.Vector2: .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' ); + return this.subVectors( v, w ); } + this.x -= v.x; + this.y -= v.y; + + return this; + }, - hasEventListener: function ( type, listener ) { + subScalar: function ( s ) { - if ( this._listeners === undefined ) return false; + this.x -= s; + this.y -= s; - var listeners = this._listeners; + return this; - return listeners[ type ] !== undefined && listeners[ type ].indexOf( listener ) !== - 1; + }, + + subVectors: function ( a, b ) { + + this.x = a.x - b.x; + this.y = a.y - b.y; + + return this; }, - removeEventListener: function ( type, listener ) { + multiply: function ( v ) { - if ( this._listeners === undefined ) return; + this.x *= v.x; + this.y *= v.y; - var listeners = this._listeners; - var listenerArray = listeners[ type ]; + return this; - if ( listenerArray !== undefined ) { + }, - var index = listenerArray.indexOf( listener ); + multiplyScalar: function ( scalar ) { - if ( index !== - 1 ) { + this.x *= scalar; + this.y *= scalar; - listenerArray.splice( index, 1 ); + return this; - } + }, - } + divide: function ( v ) { + + this.x /= v.x; + this.y /= v.y; + + return this; }, - dispatchEvent: function ( event ) { + divideScalar: function ( scalar ) { - if ( this._listeners === undefined ) return; + return this.multiplyScalar( 1 / scalar ); - var listeners = this._listeners; - var listenerArray = listeners[ event.type ]; + }, - if ( listenerArray !== undefined ) { + applyMatrix3: function ( m ) { - event.target = this; + var x = this.x, y = this.y; + var e = m.elements; - var array = listenerArray.slice( 0 ); + this.x = e[ 0 ] * x + e[ 3 ] * y + e[ 6 ]; + this.y = e[ 1 ] * x + e[ 4 ] * y + e[ 7 ]; - for ( var i = 0, l = array.length; i < l; i ++ ) { + return this; - array[ i ].call( this, event ); + }, - } + min: function ( v ) { - } + this.x = Math.min( this.x, v.x ); + this.y = Math.min( this.y, v.y ); - } + return this; -} ); - -var REVISION = '90'; -var MOUSE = { LEFT: 0, MIDDLE: 1, RIGHT: 2 }; -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 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; -var SubtractiveBlending = 3; -var MultiplyBlending = 4; -var CustomBlending = 5; -var AddEquation = 100; -var SubtractEquation = 101; -var ReverseSubtractEquation = 102; -var MinEquation = 103; -var MaxEquation = 104; -var ZeroFactor = 200; -var OneFactor = 201; -var SrcColorFactor = 202; -var OneMinusSrcColorFactor = 203; -var SrcAlphaFactor = 204; -var OneMinusSrcAlphaFactor = 205; -var DstAlphaFactor = 206; -var OneMinusDstAlphaFactor = 207; -var DstColorFactor = 208; -var OneMinusDstColorFactor = 209; -var SrcAlphaSaturateFactor = 210; -var NeverDepth = 0; -var AlwaysDepth = 1; -var LessDepth = 2; -var LessEqualDepth = 3; -var EqualDepth = 4; -var GreaterEqualDepth = 5; -var GreaterDepth = 6; -var NotEqualDepth = 7; -var MultiplyOperation = 0; -var MixOperation = 1; -var AddOperation = 2; -var NoToneMapping = 0; -var LinearToneMapping = 1; -var ReinhardToneMapping = 2; -var Uncharted2ToneMapping = 3; -var CineonToneMapping = 4; -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 NearestMipMapLinearFilter = 1005; -var LinearFilter = 1006; -var LinearMipMapNearestFilter = 1007; -var LinearMipMapLinearFilter = 1008; -var UnsignedByteType = 1009; -var ByteType = 1010; -var ShortType = 1011; -var UnsignedShortType = 1012; -var IntType = 1013; -var UnsignedIntType = 1014; -var FloatType = 1015; -var HalfFloatType = 1016; -var UnsignedShort4444Type = 1017; -var UnsignedShort5551Type = 1018; -var UnsignedShort565Type = 1019; -var UnsignedInt248Type = 1020; -var AlphaFormat = 1021; -var RGBFormat = 1022; -var RGBAFormat = 1023; -var LuminanceFormat = 1024; -var LuminanceAlphaFormat = 1025; -var RGBEFormat = RGBAFormat; -var DepthFormat = 1026; -var DepthStencilFormat = 1027; -var RGB_S3TC_DXT1_Format = 33776; -var RGBA_S3TC_DXT1_Format = 33777; -var RGBA_S3TC_DXT3_Format = 33778; -var RGBA_S3TC_DXT5_Format = 33779; -var RGB_PVRTC_4BPPV1_Format = 35840; -var RGB_PVRTC_2BPPV1_Format = 35841; -var RGBA_PVRTC_4BPPV1_Format = 35842; -var RGBA_PVRTC_2BPPV1_Format = 35843; -var RGB_ETC1_Format = 36196; -var RGBA_ASTC_4x4_Format = 37808; -var RGBA_ASTC_5x4_Format = 37809; -var RGBA_ASTC_5x5_Format = 37810; -var RGBA_ASTC_6x5_Format = 37811; -var RGBA_ASTC_6x6_Format = 37812; -var RGBA_ASTC_8x5_Format = 37813; -var RGBA_ASTC_8x6_Format = 37814; -var RGBA_ASTC_8x8_Format = 37815; -var RGBA_ASTC_10x5_Format = 37816; -var RGBA_ASTC_10x6_Format = 37817; -var RGBA_ASTC_10x8_Format = 37818; -var RGBA_ASTC_10x10_Format = 37819; -var RGBA_ASTC_12x10_Format = 37820; -var RGBA_ASTC_12x12_Format = 37821; -var LoopOnce = 2200; -var LoopRepeat = 2201; -var LoopPingPong = 2202; -var InterpolateDiscrete = 2300; -var InterpolateLinear = 2301; -var InterpolateSmooth = 2302; -var ZeroCurvatureEnding = 2400; -var ZeroSlopeEnding = 2401; -var WrapAroundEnding = 2402; -var TrianglesDrawMode = 0; -var TriangleStripDrawMode = 1; -var TriangleFanDrawMode = 2; -var LinearEncoding = 3000; -var sRGBEncoding = 3001; -var GammaEncoding = 3007; -var RGBEEncoding = 3002; -var LogLuvEncoding = 3003; -var RGBM7Encoding = 3004; -var RGBM16Encoding = 3005; -var RGBDEncoding = 3006; -var BasicDepthPacking = 3200; -var RGBADepthPacking = 3201; - -/** - * @author alteredq / http://alteredqualia.com/ - * @author mrdoob / http://mrdoob.com/ - */ - -var _Math = { - - 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 lut = []; - - for ( var i = 0; i < 256; i ++ ) { - - lut[ i ] = ( i < 16 ? '0' : '' ) + ( i ).toString( 16 ).toUpperCase(); - - } - - return function generateUUID() { - - var d0 = Math.random() * 0xffffffff | 0; - var d1 = Math.random() * 0xffffffff | 0; - var d2 = Math.random() * 0xffffffff | 0; - var d3 = Math.random() * 0xffffffff | 0; - return 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 ]; - - }; - - } )(), - - clamp: function ( value, min, max ) { - - return Math.max( min, Math.min( max, value ) ); - - }, - - // compute euclidian modulo of m % n - // https://en.wikipedia.org/wiki/Modulo_operation - - euclideanModulo: function ( n, m ) { - - return ( ( n % m ) + m ) % m; - - }, - - // Linear mapping from range to range - - mapLinear: function ( x, a1, a2, b1, b2 ) { - - return b1 + ( x - a1 ) * ( b2 - b1 ) / ( a2 - a1 ); - - }, - - // https://en.wikipedia.org/wiki/Linear_interpolation - - lerp: function ( x, y, t ) { - - return ( 1 - t ) * x + t * y; - - }, - - // http://en.wikipedia.org/wiki/Smoothstep - - smoothstep: function ( x, min, max ) { - - if ( x <= min ) return 0; - if ( x >= max ) return 1; - - x = ( x - min ) / ( max - min ); - - return x * x * ( 3 - 2 * x ); - - }, - - smootherstep: function ( x, min, max ) { - - if ( x <= min ) return 0; - if ( x >= max ) return 1; - - x = ( x - min ) / ( max - min ); - - return x * x * x * ( x * ( x * 6 - 15 ) + 10 ); - - }, - - // Random integer from interval - - randInt: function ( low, high ) { - - return low + Math.floor( Math.random() * ( high - low + 1 ) ); - - }, - - // Random float from interval - - randFloat: function ( low, high ) { - - return low + Math.random() * ( high - low ); - - }, - - // Random float from <-range/2, range/2> interval - - randFloatSpread: function ( range ) { - - return range * ( 0.5 - Math.random() ); - - }, - - degToRad: function ( degrees ) { - - return degrees * _Math.DEG2RAD; - - }, - - radToDeg: function ( radians ) { - - return radians * _Math.RAD2DEG; - - }, - - isPowerOfTwo: function ( value ) { - - return ( value & ( value - 1 ) ) === 0 && value !== 0; - - }, - - ceilPowerOfTwo: function ( value ) { - - return Math.pow( 2, Math.ceil( Math.log( value ) / Math.LN2 ) ); - - }, - - floorPowerOfTwo: function ( value ) { - - return Math.pow( 2, Math.floor( Math.log( value ) / Math.LN2 ) ); - - } - -}; - -/** - * @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 ) { - - this.x = x || 0; - this.y = y || 0; - -} - -Object.defineProperties( Vector2.prototype, { - - "width": { - - get: function () { - - return this.x; - - }, - - set: function ( value ) { - - this.x = value; - - } - - }, - - "height": { - - get: function () { - - return this.y; - - }, - - set: function ( value ) { - - this.y = value; - - } - - } - -} ); - -Object.assign( Vector2.prototype, { - - isVector2: true, - - set: function ( x, y ) { - - this.x = x; - this.y = y; - - return this; - - }, - - setScalar: function ( scalar ) { - - this.x = scalar; - this.y = scalar; - - return this; - - }, - - setX: function ( x ) { - - this.x = x; - - return this; - - }, - - setY: function ( y ) { - - this.y = y; - - return this; - - }, - - setComponent: function ( index, value ) { - - switch ( index ) { - - case 0: this.x = value; break; - case 1: this.y = value; break; - default: throw new Error( 'index is out of range: ' + index ); - - } - - return this; - - }, - - getComponent: function ( index ) { - - switch ( index ) { - - case 0: return this.x; - case 1: return this.y; - default: throw new Error( 'index is out of range: ' + index ); - - } - - }, - - clone: function () { - - return new this.constructor( this.x, this.y ); - - }, - - copy: function ( v ) { - - this.x = v.x; - this.y = v.y; - - return this; - - }, - - add: function ( v, w ) { - - if ( w !== undefined ) { - - console.warn( 'THREE.Vector2: .add() now only accepts one argument. Use .addVectors( a, b ) instead.' ); - return this.addVectors( v, w ); - - } - - this.x += v.x; - this.y += v.y; - - return this; - - }, - - addScalar: function ( s ) { - - this.x += s; - this.y += s; - - return this; - - }, - - addVectors: function ( a, b ) { - - this.x = a.x + b.x; - this.y = a.y + b.y; - - return this; - - }, - - addScaledVector: function ( v, s ) { - - this.x += v.x * s; - this.y += v.y * s; - - return this; - - }, - - sub: function ( v, w ) { - - if ( w !== undefined ) { - - console.warn( 'THREE.Vector2: .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' ); - return this.subVectors( v, w ); - - } - - this.x -= v.x; - this.y -= v.y; - - return this; - - }, - - subScalar: function ( s ) { - - this.x -= s; - this.y -= s; - - return this; - - }, - - subVectors: function ( a, b ) { - - this.x = a.x - b.x; - this.y = a.y - b.y; - - return this; - - }, - - multiply: function ( v ) { - - this.x *= v.x; - this.y *= v.y; - - return this; - - }, - - multiplyScalar: function ( scalar ) { - - this.x *= scalar; - this.y *= scalar; - - return this; - - }, - - divide: function ( v ) { - - this.x /= v.x; - this.y /= v.y; - - return this; - - }, - - divideScalar: function ( scalar ) { - - return this.multiplyScalar( 1 / scalar ); - - }, - - applyMatrix3: function ( m ) { - - var x = this.x, y = this.y; - var e = m.elements; - - this.x = e[ 0 ] * x + e[ 3 ] * y + e[ 6 ]; - this.y = e[ 1 ] * x + e[ 4 ] * y + e[ 7 ]; - - return this; - - }, - - min: function ( v ) { - - this.x = Math.min( this.x, v.x ); - this.y = Math.min( this.y, v.y ); - - return this; - - }, + }, max: function ( v ) { @@ -3778,6 +2281,12 @@ Object.assign( Vector2.prototype, { }, + cross: function ( v ) { + + return this.x * v.y - this.y * v.x; + + }, + lengthSq: function () { return this.x * this.x + this.y * this.y; @@ -4039,6 +2548,8 @@ Object.assign( Matrix4.prototype, { return function extractRotation( m ) { + // this method does not support reflection matrices + var te = this.elements; var me = m.elements; @@ -4049,14 +2560,22 @@ Object.assign( Matrix4.prototype, { 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; @@ -4177,12 +2696,12 @@ Object.assign( Matrix4.prototype, { } - // last column + // bottom row te[ 3 ] = 0; te[ 7 ] = 0; te[ 11 ] = 0; - // bottom row + // last column te[ 12 ] = 0; te[ 13 ] = 0; te[ 14 ] = 0; @@ -4192,42 +2711,18 @@ Object.assign( Matrix4.prototype, { }, - makeRotationFromQuaternion: function ( q ) { - - var te = this.elements; - - var x = q._x, y = q._y, z = q._z, w = q._w; - var x2 = x + x, y2 = y + y, z2 = z + z; - var xx = x * x2, xy = x * y2, xz = x * z2; - var yy = y * y2, yz = y * z2, zz = z * z2; - var wx = w * x2, wy = w * y2, wz = w * z2; - - te[ 0 ] = 1 - ( yy + zz ); - te[ 4 ] = xy - wz; - te[ 8 ] = xz + wy; - - te[ 1 ] = xy + wz; - te[ 5 ] = 1 - ( xx + zz ); - te[ 9 ] = yz - wx; + makeRotationFromQuaternion: function () { - te[ 2 ] = xz - wy; - te[ 6 ] = yz + wx; - te[ 10 ] = 1 - ( xx + yy ); + var zero = new Vector3( 0, 0, 0 ); + var one = new Vector3( 1, 1, 1 ); - // last column - te[ 3 ] = 0; - te[ 7 ] = 0; - te[ 11 ] = 0; + return function makeRotationFromQuaternion( q ) { - // bottom row - te[ 12 ] = 0; - te[ 13 ] = 0; - te[ 14 ] = 0; - te[ 15 ] = 1; + return this.compose( zero, q, one ); - return this; + }; - }, + }(), lookAt: function () { @@ -4668,11 +3163,37 @@ Object.assign( Matrix4.prototype, { compose: function ( position, quaternion, scale ) { - this.makeRotationFromQuaternion( quaternion ); - this.scale( scale ); - this.setPosition( position ); + var te = this.elements; - return this; + 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; + + te[ 0 ] = ( 1 - ( yy + zz ) ) * sx; + te[ 1 ] = ( xy + wz ) * sx; + te[ 2 ] = ( xz - wy ) * sx; + te[ 3 ] = 0; + + te[ 4 ] = ( xy - wz ) * sy; + te[ 5 ] = ( 1 - ( xx + zz ) ) * sy; + te[ 6 ] = ( yz + wx ) * sy; + te[ 7 ] = 0; + + te[ 8 ] = ( xz + wy ) * sz; + te[ 9 ] = ( yz - wx ) * sz; + te[ 10 ] = ( 1 - ( xx + yy ) ) * sz; + te[ 11 ] = 0; + + te[ 12 ] = position.x; + te[ 13 ] = position.y; + te[ 14 ] = position.z; + te[ 15 ] = 1; + + return this; }, @@ -4998,6 +3519,8 @@ Object.defineProperties( Quaternion.prototype, { Object.assign( Quaternion.prototype, { + isQuaternion: true, + set: function ( x, y, z, w ) { this._x = x; @@ -5229,6 +3752,26 @@ Object.assign( Quaternion.prototype, { }(), + angleTo: function ( q ) { + + return 2 * Math.acos( Math.abs( _Math.clamp( this.dot( q ), - 1, 1 ) ) ); + + }, + + rotateTowards: function ( q, step ) { + + var angle = this.angleTo( q ); + + if ( angle === 0 ) return this; + + var t = Math.min( 1, step / angle ); + + this.slerp( q, t ); + + return this; + + }, + inverse: function () { // quaternion is assumed to have unit length @@ -5369,19 +3912,21 @@ Object.assign( Quaternion.prototype, { } - var sinHalfTheta = Math.sqrt( 1.0 - cosHalfTheta * cosHalfTheta ); + var sqrSinHalfTheta = 1.0 - cosHalfTheta * cosHalfTheta; - if ( Math.abs( sinHalfTheta ) < 0.001 ) { + if ( sqrSinHalfTheta <= Number.EPSILON ) { - this._w = 0.5 * ( w + this._w ); - this._x = 0.5 * ( x + this._x ); - this._y = 0.5 * ( y + this._y ); - this._z = 0.5 * ( z + this._z ); + 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; - return this; + return this.normalize(); } + 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; @@ -5754,18 +4299,11 @@ Object.assign( Vector3.prototype, { }, - project: function () { - - var matrix = new Matrix4(); - - return function project( camera ) { - - matrix.multiplyMatrices( camera.projectionMatrix, matrix.getInverse( camera.matrixWorld ) ); - return this.applyMatrix4( matrix ); + project: function ( camera ) { - }; + return this.applyMatrix4( camera.matrixWorldInverse ).applyMatrix4( camera.projectionMatrix ); - }(), + }, unproject: function () { @@ -5773,8 +4311,7 @@ Object.assign( Vector3.prototype, { return function unproject( camera ) { - matrix.multiplyMatrices( camera.matrixWorld, matrix.getInverse( camera.projectionMatrix ) ); - return this.applyMatrix4( matrix ); + return this.applyMatrix4( matrix.getInverse( camera.projectionMatrix ) ).applyMatrix4( camera.matrixWorld ); }; @@ -6067,11 +4604,17 @@ Object.assign( Vector3.prototype, { setFromSpherical: function ( s ) { - var sinPhiRadius = Math.sin( s.phi ) * s.radius; + return this.setFromSphericalCoords( s.radius, s.phi, s.theta ); + + }, + + setFromSphericalCoords: function ( radius, phi, theta ) { - this.x = sinPhiRadius * Math.sin( s.theta ); - this.y = Math.cos( s.phi ) * s.radius; - this.z = sinPhiRadius * Math.cos( s.theta ); + var sinPhiRadius = Math.sin( phi ) * radius; + + this.x = sinPhiRadius * Math.sin( theta ); + this.y = Math.cos( phi ) * radius; + this.z = sinPhiRadius * Math.cos( theta ); return this; @@ -6079,9 +4622,15 @@ Object.assign( Vector3.prototype, { setFromCylindrical: function ( c ) { - this.x = c.radius * Math.sin( c.theta ); - this.y = c.y; - this.z = c.radius * Math.cos( c.theta ); + return this.setFromCylindricalCoords( c.radius, c.theta, c.y ); + + }, + + setFromCylindricalCoords: function ( radius, theta, y ) { + + this.x = radius * Math.sin( theta ); + this.y = y; + this.z = radius * Math.cos( theta ); return this; @@ -6552,6 +5101,65 @@ Object.assign( Matrix3.prototype, { } ); +/** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + * @author szimek / https://github.com/szimek/ + */ + +var _canvas; + +var ImageUtils = { + + getDataURL: function ( image ) { + + var canvas; + + if ( typeof HTMLCanvasElement == 'undefined' ) { + + return image.src; + + } else if ( image instanceof HTMLCanvasElement ) { + + canvas = image; + + } else { + + if ( _canvas === undefined ) _canvas = document.createElementNS( 'http://www.w3.org/1999/xhtml', 'canvas' ); + + _canvas.width = image.width; + _canvas.height = image.height; + + var context = _canvas.getContext( '2d' ); + + if ( image instanceof ImageData ) { + + context.putImageData( image, 0, 0 ); + + } else { + + context.drawImage( image, 0, 0, image.width, image.height ); + + } + + canvas = _canvas; + + } + + if ( canvas.width > 2048 || canvas.height > 2048 ) { + + return canvas.toDataURL( 'image/jpeg', 0.6 ); + + } else { + + return canvas.toDataURL( 'image/png' ); + + } + + } + +}; + /** * @author mrdoob / http://mrdoob.com/ * @author alteredq / http://alteredqualia.com/ @@ -6617,6 +5225,12 @@ Texture.prototype = Object.assign( Object.create( EventDispatcher.prototype ), { isTexture: true, + updateMatrix: function () { + + this.matrix.setUvTransform( this.offset.x, this.offset.y, this.repeat.x, this.repeat.y, this.rotation, this.center.x, this.center.y ); + + }, + clone: function () { return new this.constructor().copy( this ); @@ -6671,47 +5285,8 @@ Texture.prototype = Object.assign( Object.create( EventDispatcher.prototype ), { } - function getDataURL( image ) { - - var canvas; - - if ( image instanceof HTMLCanvasElement ) { - - canvas = image; - - } else { - - canvas = document.createElementNS( 'http://www.w3.org/1999/xhtml', 'canvas' ); - canvas.width = image.width; - canvas.height = image.height; - - var context = canvas.getContext( '2d' ); - - if ( image instanceof ImageData ) { - - context.putImageData( image, 0, 0 ); - - } else { - - context.drawImage( image, 0, 0, image.width, image.height ); - - } - - } - - if ( canvas.width > 2048 || canvas.height > 2048 ) { - - return canvas.toDataURL( 'image/jpeg', 0.6 ); - - } else { - - return canvas.toDataURL( 'image/png' ); - - } - - } - var output = { + metadata: { version: 4.5, type: 'Texture', @@ -6730,11 +5305,19 @@ Texture.prototype = Object.assign( Object.create( EventDispatcher.prototype ), { wrap: [ this.wrapS, this.wrapT ], + format: this.format, + type: this.type, + encoding: this.encoding, + minFilter: this.minFilter, magFilter: this.magFilter, anisotropy: this.anisotropy, - flipY: this.flipY + flipY: this.flipY, + + premultiplyAlpha: this.premultiplyAlpha, + unpackAlignment: this.unpackAlignment + }; if ( this.image !== undefined ) { @@ -6751,9 +5334,31 @@ Texture.prototype = Object.assign( Object.create( EventDispatcher.prototype ), { if ( ! isRootObject && meta.images[ image.uuid ] === undefined ) { + var url; + + if ( Array.isArray( image ) ) { + + // process array of images e.g. CubeTexture + + url = []; + + for ( var i = 0, l = image.length; i < l; i ++ ) { + + url.push( ImageUtils.getDataURL( image[ i ] ) ); + + } + + } else { + + // process single image + + url = ImageUtils.getDataURL( image ); + + } + meta.images[ image.uuid ] = { uuid: image.uuid, - url: getDataURL( image ) + url: url }; } @@ -6780,7 +5385,7 @@ Texture.prototype = Object.assign( Object.create( EventDispatcher.prototype ), { transformUv: function ( uv ) { - if ( this.mapping !== UVMapping ) return; + if ( this.mapping !== UVMapping ) return uv; uv.applyMatrix3( this.matrix ); @@ -6852,6 +5457,8 @@ Texture.prototype = Object.assign( Object.create( EventDispatcher.prototype ), { } + return uv; + } } ); @@ -7506,8 +6113,6 @@ Object.assign( Vector4.prototype, { */ function WebGLRenderTarget( width, height, options ) { - this.uuid = _Math.generateUUID(); - this.width = width; this.height = height; @@ -7518,10 +6123,11 @@ function WebGLRenderTarget( width, height, options ) { options = options || {}; - if ( options.minFilter === undefined ) options.minFilter = LinearFilter; - this.texture = new Texture( undefined, undefined, options.wrapS, options.wrapT, options.magFilter, options.minFilter, options.format, options.type, options.anisotropy, options.encoding ); + this.texture.generateMipmaps = options.generateMipmaps !== undefined ? options.generateMipmaps : false; + this.texture.minFilter = options.minFilter !== undefined ? options.minFilter : LinearFilter; + this.depthBuffer = options.depthBuffer !== undefined ? options.depthBuffer : true; this.stencilBuffer = options.stencilBuffer !== undefined ? options.stencilBuffer : true; this.depthTexture = options.depthTexture !== undefined ? options.depthTexture : null; @@ -7624,1572 +6230,1386 @@ DataTexture.prototype.constructor = DataTexture; DataTexture.prototype.isDataTexture = true; /** - * @author mrdoob / http://mrdoob.com/ + * @author bhouston / http://clara.io + * @author WestLangley / http://github.com/WestLangley */ -function CubeTexture( images, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding ) { - - images = images !== undefined ? images : []; - mapping = mapping !== undefined ? mapping : CubeReflectionMapping; - - Texture.call( this, images, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding ); +function Box3( min, max ) { - this.flipY = false; + this.min = ( min !== undefined ) ? min : new Vector3( + Infinity, + Infinity, + Infinity ); + this.max = ( max !== undefined ) ? max : new Vector3( - Infinity, - Infinity, - Infinity ); } -CubeTexture.prototype = Object.create( Texture.prototype ); -CubeTexture.prototype.constructor = CubeTexture; +Object.assign( Box3.prototype, { -CubeTexture.prototype.isCubeTexture = true; + isBox3: true, -Object.defineProperty( CubeTexture.prototype, 'images', { + set: function ( min, max ) { - get: function () { + this.min.copy( min ); + this.max.copy( max ); - return this.image; + return this; }, - set: function ( value ) { - - this.image = value; + setFromArray: function ( array ) { - } + var minX = + Infinity; + var minY = + Infinity; + var minZ = + Infinity; -} ); + var maxX = - Infinity; + var maxY = - Infinity; + var maxZ = - Infinity; -/** - * @author tschw - * - * 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 - * - */ + for ( var i = 0, l = array.length; i < l; i += 3 ) { -var emptyTexture = new Texture(); -var emptyCubeTexture = new CubeTexture(); + var x = array[ i ]; + var y = array[ i + 1 ]; + var z = array[ i + 2 ]; -// --- Base for inner nodes (including the root) --- + if ( x < minX ) minX = x; + if ( y < minY ) minY = y; + if ( z < minZ ) minZ = z; -function UniformContainer() { + if ( x > maxX ) maxX = x; + if ( y > maxY ) maxY = y; + if ( z > maxZ ) maxZ = z; - this.seq = []; - this.map = {}; + } -} + this.min.set( minX, minY, minZ ); + this.max.set( maxX, maxY, maxZ ); -// --- Utilities --- + return this; -// Array Caches (provide typed arrays for temporary by size) + }, -var arrayCacheF32 = []; -var arrayCacheI32 = []; + setFromBufferAttribute: function ( attribute ) { -// Float32Array caches used for uploading Matrix uniforms + var minX = + Infinity; + var minY = + Infinity; + var minZ = + Infinity; -var mat4array = new Float32Array( 16 ); -var mat3array = new Float32Array( 9 ); + var maxX = - Infinity; + var maxY = - Infinity; + var maxZ = - Infinity; -// Flattening for arrays of vectors and matrices + for ( var i = 0, l = attribute.count; i < l; i ++ ) { -function flatten( array, nBlocks, blockSize ) { + var x = attribute.getX( i ); + var y = attribute.getY( i ); + var z = attribute.getZ( i ); - var firstElem = array[ 0 ]; + if ( x < minX ) minX = x; + if ( y < minY ) minY = y; + if ( z < minZ ) minZ = z; - if ( firstElem <= 0 || firstElem > 0 ) return array; - // unoptimized: ! isNaN( firstElem ) - // see http://jacksondunstan.com/articles/983 + if ( x > maxX ) maxX = x; + if ( y > maxY ) maxY = y; + if ( z > maxZ ) maxZ = z; - var n = nBlocks * blockSize, - r = arrayCacheF32[ n ]; + } - if ( r === undefined ) { + this.min.set( minX, minY, minZ ); + this.max.set( maxX, maxY, maxZ ); - r = new Float32Array( n ); - arrayCacheF32[ n ] = r; + return this; - } + }, - if ( nBlocks !== 0 ) { + setFromPoints: function ( points ) { - firstElem.toArray( r, 0 ); + this.makeEmpty(); - for ( var i = 1, offset = 0; i !== nBlocks; ++ i ) { + for ( var i = 0, il = points.length; i < il; i ++ ) { - offset += blockSize; - array[ i ].toArray( r, offset ); + this.expandByPoint( points[ i ] ); } - } + return this; - return r; + }, -} + setFromCenterAndSize: function () { -// Texture unit allocation + var v1 = new Vector3(); -function allocTexUnits( renderer, n ) { + return function setFromCenterAndSize( center, size ) { - var r = arrayCacheI32[ n ]; + var halfSize = v1.copy( size ).multiplyScalar( 0.5 ); - if ( r === undefined ) { + this.min.copy( center ).sub( halfSize ); + this.max.copy( center ).add( halfSize ); - r = new Int32Array( n ); - arrayCacheI32[ n ] = r; + return this; - } + }; - for ( var i = 0; i !== n; ++ i ) - r[ i ] = renderer.allocTextureUnit(); + }(), - return r; + setFromObject: function ( object ) { -} + this.makeEmpty(); -// --- Setters --- + return this.expandByObject( object ); -// Note: Defining these methods externally, because they come in a bunch -// and this way their names minify. + }, -// Single scalar + clone: function () { -function setValue1f( gl, v ) { + return new this.constructor().copy( this ); - gl.uniform1f( this.addr, v ); + }, -} + copy: function ( box ) { -function setValue1i( gl, v ) { + this.min.copy( box.min ); + this.max.copy( box.max ); - gl.uniform1i( this.addr, v ); + return this; -} + }, -// Single float vector (from flat array or THREE.VectorN) + makeEmpty: function () { -function setValue2fv( gl, v ) { + this.min.x = this.min.y = this.min.z = + Infinity; + this.max.x = this.max.y = this.max.z = - Infinity; - if ( v.x === undefined ) { + return this; - gl.uniform2fv( this.addr, v ); + }, - } else { + isEmpty: function () { - gl.uniform2f( this.addr, v.x, v.y ); + // this is a more robust check for empty than ( volume <= 0 ) because volume can get positive with two negative axes - } + return ( this.max.x < this.min.x ) || ( this.max.y < this.min.y ) || ( this.max.z < this.min.z ); -} + }, -function setValue3fv( gl, v ) { + getCenter: function ( target ) { - if ( v.x !== undefined ) { + if ( target === undefined ) { - gl.uniform3f( this.addr, v.x, v.y, v.z ); + console.warn( 'THREE.Box3: .getCenter() target is now required' ); + target = new Vector3(); - } else if ( v.r !== undefined ) { + } - gl.uniform3f( this.addr, v.r, v.g, v.b ); + return this.isEmpty() ? target.set( 0, 0, 0 ) : target.addVectors( this.min, this.max ).multiplyScalar( 0.5 ); - } else { + }, - gl.uniform3fv( this.addr, v ); + getSize: function ( target ) { - } + if ( target === undefined ) { -} + console.warn( 'THREE.Box3: .getSize() target is now required' ); + target = new Vector3(); -function setValue4fv( gl, v ) { + } - if ( v.x === undefined ) { + return this.isEmpty() ? target.set( 0, 0, 0 ) : target.subVectors( this.max, this.min ); - gl.uniform4fv( this.addr, v ); + }, - } else { + expandByPoint: function ( point ) { - gl.uniform4f( this.addr, v.x, v.y, v.z, v.w ); + this.min.min( point ); + this.max.max( point ); - } + return this; -} + }, -// Single matrix (from flat array or MatrixN) + expandByVector: function ( vector ) { -function setValue2fm( gl, v ) { + this.min.sub( vector ); + this.max.add( vector ); - gl.uniformMatrix2fv( this.addr, false, v.elements || v ); + return this; -} + }, -function setValue3fm( gl, v ) { + expandByScalar: function ( scalar ) { - if ( v.elements === undefined ) { + this.min.addScalar( - scalar ); + this.max.addScalar( scalar ); - gl.uniformMatrix3fv( this.addr, false, v ); + return this; - } else { + }, - mat3array.set( v.elements ); - gl.uniformMatrix3fv( this.addr, false, mat3array ); + expandByObject: function () { - } + // Computes the world-axis-aligned bounding box of an object (including its children), + // accounting for both the object's, and children's, world transforms -} + var scope, i, l; -function setValue4fm( gl, v ) { + var v1 = new Vector3(); - if ( v.elements === undefined ) { + function traverse( node ) { - gl.uniformMatrix4fv( this.addr, false, v ); + var geometry = node.geometry; - } else { + if ( geometry !== undefined ) { - mat4array.set( v.elements ); - gl.uniformMatrix4fv( this.addr, false, mat4array ); + if ( geometry.isGeometry ) { - } + var vertices = geometry.vertices; -} + for ( i = 0, l = vertices.length; i < l; i ++ ) { -// Single texture (2D / Cube) + v1.copy( vertices[ i ] ); + v1.applyMatrix4( node.matrixWorld ); -function setValueT1( gl, v, renderer ) { + scope.expandByPoint( v1 ); - var unit = renderer.allocTextureUnit(); - gl.uniform1i( this.addr, unit ); - renderer.setTexture2D( v || emptyTexture, unit ); + } -} + } else if ( geometry.isBufferGeometry ) { -function setValueT6( gl, v, renderer ) { + var attribute = geometry.attributes.position; - var unit = renderer.allocTextureUnit(); - gl.uniform1i( this.addr, unit ); - renderer.setTextureCube( v || emptyCubeTexture, unit ); + if ( attribute !== undefined ) { -} + for ( i = 0, l = attribute.count; i < l; i ++ ) { -// Integer / Boolean vectors or arrays thereof (always flat arrays) + v1.fromBufferAttribute( attribute, i ).applyMatrix4( node.matrixWorld ); -function setValue2iv( gl, v ) { + scope.expandByPoint( v1 ); - gl.uniform2iv( this.addr, v ); + } -} + } -function setValue3iv( gl, v ) { + } - gl.uniform3iv( this.addr, v ); + } -} + } -function setValue4iv( gl, v ) { + return function expandByObject( object ) { - gl.uniform4iv( this.addr, v ); + scope = this; -} + object.updateMatrixWorld( true ); -// Helper to pick the right setter for the singular case + object.traverse( traverse ); -function getSingularSetter( type ) { + return this; - switch ( type ) { + }; - case 0x1406: return setValue1f; // FLOAT - case 0x8b50: return setValue2fv; // _VEC2 - case 0x8b51: return setValue3fv; // _VEC3 - case 0x8b52: return setValue4fv; // _VEC4 + }(), - case 0x8b5a: return setValue2fm; // _MAT2 - case 0x8b5b: return setValue3fm; // _MAT3 - case 0x8b5c: return setValue4fm; // _MAT4 + containsPoint: function ( point ) { - case 0x8b5e: case 0x8d66: return setValueT1; // SAMPLER_2D, SAMPLER_EXTERNAL_OES - case 0x8b60: return setValueT6; // SAMPLER_CUBE + 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; - 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 + }, - } + 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 && + this.min.z <= box.min.z && box.max.z <= this.max.z; -// Array of scalars + }, -function setValue1fv( gl, v ) { + getParameter: function ( point, target ) { - gl.uniform1fv( this.addr, v ); - -} -function setValue1iv( gl, v ) { - - gl.uniform1iv( this.addr, v ); - -} + // This can potentially have a divide by zero if the box + // has a size dimension of 0. -// Array of vectors (flat or from THREE classes) + if ( target === undefined ) { -function setValueV2a( gl, v ) { + console.warn( 'THREE.Box3: .getParameter() target is now required' ); + target = new Vector3(); - gl.uniform2fv( this.addr, flatten( v, this.size, 2 ) ); + } -} + 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 ) + ); -function setValueV3a( gl, v ) { + }, - gl.uniform3fv( this.addr, flatten( v, this.size, 3 ) ); + intersectsBox: function ( box ) { -} + // using 6 splitting planes to rule out intersections. + return box.max.x < this.min.x || box.min.x > this.max.x || + box.max.y < this.min.y || box.min.y > this.max.y || + box.max.z < this.min.z || box.min.z > this.max.z ? false : true; -function setValueV4a( gl, v ) { + }, - gl.uniform4fv( this.addr, flatten( v, this.size, 4 ) ); + intersectsSphere: ( function () { -} + var closestPoint = new Vector3(); -// Array of matrices (flat or from THREE clases) + return function intersectsSphere( sphere ) { -function setValueM2a( gl, v ) { + // Find the point on the AABB closest to the sphere center. + this.clampPoint( sphere.center, closestPoint ); - gl.uniformMatrix2fv( this.addr, false, flatten( v, this.size, 4 ) ); + // If that point is inside the sphere, the AABB and sphere intersect. + return closestPoint.distanceToSquared( sphere.center ) <= ( sphere.radius * sphere.radius ); -} + }; -function setValueM3a( gl, v ) { + } )(), - gl.uniformMatrix3fv( this.addr, false, flatten( v, this.size, 9 ) ); + intersectsPlane: function ( plane ) { -} + // We compute the minimum and maximum dot product values. If those values + // are on the same side (back or front) of the plane, then there is no intersection. -function setValueM4a( gl, v ) { + var min, max; - gl.uniformMatrix4fv( this.addr, false, flatten( v, this.size, 16 ) ); + if ( plane.normal.x > 0 ) { -} + min = plane.normal.x * this.min.x; + max = plane.normal.x * this.max.x; -// Array of textures (2D / Cube) + } else { -function setValueT1a( gl, v, renderer ) { + min = plane.normal.x * this.max.x; + max = plane.normal.x * this.min.x; - var n = v.length, - units = allocTexUnits( renderer, n ); + } - gl.uniform1iv( this.addr, units ); + if ( plane.normal.y > 0 ) { - for ( var i = 0; i !== n; ++ i ) { + min += plane.normal.y * this.min.y; + max += plane.normal.y * this.max.y; - renderer.setTexture2D( v[ i ] || emptyTexture, units[ i ] ); + } else { - } + min += plane.normal.y * this.max.y; + max += plane.normal.y * this.min.y; -} + } -function setValueT6a( gl, v, renderer ) { + if ( plane.normal.z > 0 ) { - var n = v.length, - units = allocTexUnits( renderer, n ); + min += plane.normal.z * this.min.z; + max += plane.normal.z * this.max.z; - gl.uniform1iv( this.addr, units ); + } else { - for ( var i = 0; i !== n; ++ i ) { + min += plane.normal.z * this.max.z; + max += plane.normal.z * this.min.z; - renderer.setTextureCube( v[ i ] || emptyCubeTexture, units[ i ] ); + } - } + return ( min <= - plane.constant && max >= - plane.constant ); -} + }, -// Helper to pick the right setter for a pure (bottom-level) array + intersectsTriangle: ( function () { -function getPureArraySetter( type ) { + // triangle centered vertices + var v0 = new Vector3(); + var v1 = new Vector3(); + var v2 = new Vector3(); - switch ( type ) { + // triangle edge vectors + var f0 = new Vector3(); + var f1 = new Vector3(); + var f2 = new Vector3(); - case 0x1406: return setValue1fv; // FLOAT - case 0x8b50: return setValueV2a; // _VEC2 - case 0x8b51: return setValueV3a; // _VEC3 - case 0x8b52: return setValueV4a; // _VEC4 + var testAxis = new Vector3(); - case 0x8b5a: return setValueM2a; // _MAT2 - case 0x8b5b: return setValueM3a; // _MAT3 - case 0x8b5c: return setValueM4a; // _MAT4 + var center = new Vector3(); + var extents = new Vector3(); - case 0x8b5e: return setValueT1a; // SAMPLER_2D - case 0x8b60: return setValueT6a; // SAMPLER_CUBE + var triangleNormal = new Vector3(); - 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 + function satForAxes( axes ) { - } + var i, j; -} + for ( i = 0, j = axes.length - 3; i <= j; i += 3 ) { -// --- Uniform Classes --- + 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 ) { -function SingleUniform( id, activeInfo, addr ) { + // points of the projected triangle are outside the projected half-length of the aabb + // the axis is seperating and we can exit + return false; - this.id = id; - this.addr = addr; - this.setValue = getSingularSetter( activeInfo.type ); + } - // this.path = activeInfo.name; // DEBUG + } -} + return true; -function PureArrayUniform( id, activeInfo, addr ) { + } - this.id = id; - this.addr = addr; - this.size = activeInfo.size; - this.setValue = getPureArraySetter( activeInfo.type ); + return function intersectsTriangle( triangle ) { - // this.path = activeInfo.name; // DEBUG + if ( this.isEmpty() ) { -} + return false; -function StructuredUniform( id ) { + } - this.id = id; + // compute box center and extents + this.getCenter( center ); + extents.subVectors( this.max, center ); - UniformContainer.call( this ); // mix-in + // 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 ); -StructuredUniform.prototype.setValue = function ( gl, value ) { + // 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 ) ) { - // Note: Don't need an extra 'renderer' parameter, since samplers - // are not allowed in structured uniforms. + return false; - var seq = this.seq; + } - for ( var i = 0, n = seq.length; i !== n; ++ i ) { + // test 3 face normals from the aabb + axes = [ 1, 0, 0, 0, 1, 0, 0, 0, 1 ]; + if ( ! satForAxes( axes ) ) { - var u = seq[ i ]; - u.setValue( gl, value[ u.id ] ); + 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 ); -// --- Top-level --- + }; -// Parser - builds up the property tree from the path strings + } )(), -var RePathPart = /([\w\d_]+)(\])?(\[|\.)?/g; + clampPoint: function ( point, target ) { -// 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. + if ( target === undefined ) { -function addUniform( container, uniformObject ) { + console.warn( 'THREE.Box3: .clampPoint() target is now required' ); + target = new Vector3(); - container.seq.push( uniformObject ); - container.map[ uniformObject.id ] = uniformObject; + } -} + return target.copy( point ).clamp( this.min, this.max ); -function parseUniform( activeInfo, addr, container ) { + }, - var path = activeInfo.name, - pathLength = path.length; + distanceToPoint: function () { - // reset RegExp object, because of the early exit of a previous run - RePathPart.lastIndex = 0; + var v1 = new Vector3(); - for ( ; ; ) { + return function distanceToPoint( point ) { - var match = RePathPart.exec( path ), - matchEnd = RePathPart.lastIndex, + var clampedPoint = v1.copy( point ).clamp( this.min, this.max ); + return clampedPoint.sub( point ).length(); - id = match[ 1 ], - idIsIndex = match[ 2 ] === ']', - subscript = match[ 3 ]; + }; - if ( idIsIndex ) id = id | 0; // convert to integer + }(), - if ( subscript === undefined || subscript === '[' && matchEnd + 2 === pathLength ) { + getBoundingSphere: function () { - // bare name or "pure" bottom-level array "[0]" suffix + var v1 = new Vector3(); - addUniform( container, subscript === undefined ? - new SingleUniform( id, activeInfo, addr ) : - new PureArrayUniform( id, activeInfo, addr ) ); + return function getBoundingSphere( target ) { - break; + if ( target === undefined ) { - } else { + console.warn( 'THREE.Box3: .getBoundingSphere() target is now required' ); + target = new Sphere(); - // step into inner node / create it in case it doesn't exist + } - var map = container.map, next = map[ id ]; + this.getCenter( target.center ); - if ( next === undefined ) { + target.radius = this.getSize( v1 ).length() * 0.5; - next = new StructuredUniform( id ); - addUniform( container, next ); + return target; - } + }; - container = next; + }(), - } + intersect: function ( box ) { - } + this.min.max( box.min ); + this.max.min( box.max ); -} + // ensure that if there is no overlap, the result is fully empty, not slightly empty with non-inf/+inf values that will cause subsequence intersects to erroneously return valid values. + if ( this.isEmpty() ) this.makeEmpty(); -// Root Container + return this; -function WebGLUniforms( gl, program, renderer ) { + }, - UniformContainer.call( this ); + union: function ( box ) { - this.renderer = renderer; + this.min.min( box.min ); + this.max.max( box.max ); - var n = gl.getProgramParameter( program, gl.ACTIVE_UNIFORMS ); + return this; - for ( var i = 0; i < n; ++ i ) { + }, - var info = gl.getActiveUniform( program, i ), - path = info.name, - addr = gl.getUniformLocation( program, path ); + applyMatrix4: function () { - parseUniform( info, addr, this ); + var points = [ + new Vector3(), + new Vector3(), + new Vector3(), + new Vector3(), + new Vector3(), + new Vector3(), + new Vector3(), + new Vector3() + ]; - } + return function applyMatrix4( matrix ) { -} + // transform of empty box is an empty box. + if ( this.isEmpty() ) return this; -WebGLUniforms.prototype.setValue = function ( gl, name, value ) { + // 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 - var u = this.map[ name ]; + this.setFromPoints( points ); - if ( u !== undefined ) u.setValue( gl, value, this.renderer ); + return this; -}; + }; -WebGLUniforms.prototype.setOptional = function ( gl, object, name ) { + }(), - var v = object[ name ]; + translate: function ( offset ) { - if ( v !== undefined ) this.setValue( gl, name, v ); + this.min.add( offset ); + this.max.add( offset ); -}; + return this; + }, -// Static interface + equals: function ( box ) { -WebGLUniforms.upload = function ( gl, seq, values, renderer ) { + return box.min.equals( this.min ) && box.max.equals( this.max ); - for ( var i = 0, n = seq.length; i !== n; ++ i ) { + } - var u = seq[ i ], - v = values[ u.id ]; +} ); - if ( v.needsUpdate !== false ) { +/** + * @author bhouston / http://clara.io + * @author mrdoob / http://mrdoob.com/ + */ - // note: always updating when .needsUpdate is undefined - u.setValue( gl, v.value, renderer ); +function Sphere( center, radius ) { - } + this.center = ( center !== undefined ) ? center : new Vector3(); + this.radius = ( radius !== undefined ) ? radius : 0; - } +} -}; +Object.assign( Sphere.prototype, { -WebGLUniforms.seqWithValue = function ( seq, values ) { + set: function ( center, radius ) { - var r = []; + this.center.copy( center ); + this.radius = radius; - for ( var i = 0, n = seq.length; i !== n; ++ i ) { + return this; - var u = seq[ i ]; - if ( u.id in values ) r.push( u ); + }, - } + setFromPoints: function () { - return r; + var box = new Box3(); -}; + return function setFromPoints( points, optionalCenter ) { -/** - * @author mrdoob / http://mrdoob.com/ - */ + var center = this.center; -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 }; + if ( optionalCenter !== undefined ) { -function Color( r, g, b ) { + center.copy( optionalCenter ); - if ( g === undefined && b === undefined ) { + } else { - // r is THREE.Color, hex or string - return this.set( r ); + box.setFromPoints( points ).getCenter( center ); - } + } - return this.setRGB( r, g, b ); + var maxRadiusSq = 0; -} + for ( var i = 0, il = points.length; i < il; i ++ ) { -Object.assign( Color.prototype, { + maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( points[ i ] ) ); - isColor: true, + } - r: 1, g: 1, b: 1, + this.radius = Math.sqrt( maxRadiusSq ); - set: function ( value ) { + return this; - if ( value && value.isColor ) { + }; - this.copy( value ); + }(), - } else if ( typeof value === 'number' ) { + clone: function () { - this.setHex( value ); + return new this.constructor().copy( this ); - } else if ( typeof value === 'string' ) { + }, - this.setStyle( value ); + copy: function ( sphere ) { - } + this.center.copy( sphere.center ); + this.radius = sphere.radius; return this; }, - setScalar: function ( scalar ) { - - this.r = scalar; - this.g = scalar; - this.b = scalar; + empty: function () { - return this; + return ( this.radius <= 0 ); }, - setHex: function ( hex ) { + containsPoint: function ( point ) { - hex = Math.floor( hex ); + return ( point.distanceToSquared( this.center ) <= ( this.radius * this.radius ) ); - this.r = ( hex >> 16 & 255 ) / 255; - this.g = ( hex >> 8 & 255 ) / 255; - this.b = ( hex & 255 ) / 255; + }, - return this; + distanceToPoint: function ( point ) { + + return ( point.distanceTo( this.center ) - this.radius ); }, - setRGB: function ( r, g, b ) { + intersectsSphere: function ( sphere ) { - this.r = r; - this.g = g; - this.b = b; + var radiusSum = this.radius + sphere.radius; - return this; + return sphere.center.distanceToSquared( this.center ) <= ( radiusSum * radiusSum ); }, - setHSL: function () { - - function hue2rgb( p, q, t ) { + intersectsBox: function ( box ) { - 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 box.intersectsSphere( this ); - } + }, - return function setHSL( h, s, l ) { + intersectsPlane: function ( plane ) { - // 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 ); + return Math.abs( plane.distanceToPoint( this.center ) ) <= this.radius; - if ( s === 0 ) { + }, - this.r = this.g = this.b = l; + clampPoint: function ( point, target ) { - } else { + var deltaLengthSq = this.center.distanceToSquared( point ); - var p = l <= 0.5 ? l * ( 1 + s ) : l + s - ( l * s ); - var q = ( 2 * l ) - p; + if ( target === undefined ) { - this.r = hue2rgb( q, p, h + 1 / 3 ); - this.g = hue2rgb( q, p, h ); - this.b = hue2rgb( q, p, h - 1 / 3 ); + console.warn( 'THREE.Sphere: .clampPoint() target is now required' ); + target = new Vector3(); - } + } - return this; + target.copy( point ); - }; + if ( deltaLengthSq > ( this.radius * this.radius ) ) { - }(), + target.sub( this.center ).normalize(); + target.multiplyScalar( this.radius ).add( this.center ); - setStyle: function ( style ) { + } - function handleAlpha( string ) { + return target; - if ( string === undefined ) return; + }, - if ( parseFloat( string ) < 1 ) { + getBoundingBox: function ( target ) { - console.warn( 'THREE.Color: Alpha component of ' + style + ' will be ignored.' ); + if ( target === undefined ) { - } + console.warn( 'THREE.Sphere: .getBoundingBox() target is now required' ); + target = new Box3(); } + target.set( this.center, this.center ); + target.expandByScalar( this.radius ); - var m; + return target; - if ( m = /^((?:rgb|hsl)a?)\(\s*([^\)]*)\)/.exec( style ) ) { + }, - // rgb / hsl + applyMatrix4: function ( matrix ) { - var color; - var name = m[ 1 ]; - var components = m[ 2 ]; + this.center.applyMatrix4( matrix ); + this.radius = this.radius * matrix.getMaxScaleOnAxis(); - switch ( name ) { + return this; - case 'rgb': - case 'rgba': + }, - if ( color = /^(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(,\s*([0-9]*\.?[0-9]+)\s*)?$/.exec( components ) ) { + translate: function ( offset ) { - // 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; + this.center.add( offset ); - handleAlpha( color[ 5 ] ); + return this; - return this; - - } - - if ( color = /^(\d+)\%\s*,\s*(\d+)\%\s*,\s*(\d+)\%\s*(,\s*([0-9]*\.?[0-9]+)\s*)?$/.exec( components ) ) { - - // rgb(100%,0%,0%) rgba(100%,0%,0%,0.5) - this.r = Math.min( 100, parseInt( color[ 1 ], 10 ) ) / 100; - this.g = Math.min( 100, parseInt( color[ 2 ], 10 ) ) / 100; - this.b = Math.min( 100, parseInt( color[ 3 ], 10 ) ) / 100; - - handleAlpha( color[ 5 ] ); - - return this; + }, - } + equals: function ( sphere ) { - break; + return sphere.center.equals( this.center ) && ( sphere.radius === this.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 ) ) { +} ); - // 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; +/** + * @author bhouston / http://clara.io + */ - handleAlpha( color[ 5 ] ); +function Plane( normal, constant ) { - return this.setHSL( h, s, l ); + // normal is assumed to be normalized - } + this.normal = ( normal !== undefined ) ? normal : new Vector3( 1, 0, 0 ); + this.constant = ( constant !== undefined ) ? constant : 0; - break; +} - } +Object.assign( Plane.prototype, { - } else if ( m = /^\#([A-Fa-f0-9]+)$/.exec( style ) ) { + set: function ( normal, constant ) { - // hex color + this.normal.copy( normal ); + this.constant = constant; - var hex = m[ 1 ]; - var size = hex.length; + return this; - if ( size === 3 ) { + }, - // #ff0 - this.r = parseInt( hex.charAt( 0 ) + hex.charAt( 0 ), 16 ) / 255; - this.g = parseInt( hex.charAt( 1 ) + hex.charAt( 1 ), 16 ) / 255; - this.b = parseInt( hex.charAt( 2 ) + hex.charAt( 2 ), 16 ) / 255; + setComponents: function ( x, y, z, w ) { - return this; + this.normal.set( x, y, z ); + this.constant = w; - } else if ( size === 6 ) { + return this; - // #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; + setFromNormalAndCoplanarPoint: function ( normal, point ) { - } + this.normal.copy( normal ); + this.constant = - point.dot( this.normal ); - } + return this; - if ( style && style.length > 0 ) { + }, - // color keywords - var hex = ColorKeywords[ style ]; + setFromCoplanarPoints: function () { - if ( hex !== undefined ) { + var v1 = new Vector3(); + var v2 = new Vector3(); - // red - this.setHex( hex ); + return function setFromCoplanarPoints( a, b, c ) { - } else { + var normal = v1.subVectors( c, b ).cross( v2.subVectors( a, b ) ).normalize(); - // unknown color - console.warn( 'THREE.Color: Unknown color ' + style ); + // Q: should an error be thrown if normal is zero (e.g. degenerate plane)? - } + this.setFromNormalAndCoplanarPoint( normal, a ); - } + return this; - return this; + }; - }, + }(), clone: function () { - return new this.constructor( this.r, this.g, this.b ); + return new this.constructor().copy( this ); }, - copy: function ( color ) { + copy: function ( plane ) { - this.r = color.r; - this.g = color.g; - this.b = color.b; + this.normal.copy( plane.normal ); + this.constant = plane.constant; return this; }, - copyGammaToLinear: function ( color, gammaFactor ) { + normalize: function () { - if ( gammaFactor === undefined ) gammaFactor = 2.0; + // Note: will lead to a divide by zero if the plane is invalid. - this.r = Math.pow( color.r, gammaFactor ); - this.g = Math.pow( color.g, gammaFactor ); - this.b = Math.pow( color.b, gammaFactor ); + var inverseNormalLength = 1.0 / this.normal.length(); + this.normal.multiplyScalar( inverseNormalLength ); + this.constant *= inverseNormalLength; return this; }, - copyLinearToGamma: function ( color, gammaFactor ) { - - if ( gammaFactor === undefined ) gammaFactor = 2.0; - - var safeInverse = ( gammaFactor > 0 ) ? ( 1.0 / gammaFactor ) : 1.0; + negate: function () { - this.r = Math.pow( color.r, safeInverse ); - this.g = Math.pow( color.g, safeInverse ); - this.b = Math.pow( color.b, safeInverse ); + this.constant *= - 1; + this.normal.negate(); return this; }, - convertGammaToLinear: function () { - - var r = this.r, g = this.g, b = this.b; - - this.r = r * r; - this.g = g * g; - this.b = b * b; + distanceToPoint: function ( point ) { - return this; + return this.normal.dot( point ) + this.constant; }, - convertLinearToGamma: function () { - - this.r = Math.sqrt( this.r ); - this.g = Math.sqrt( this.g ); - this.b = Math.sqrt( this.b ); + distanceToSphere: function ( sphere ) { - return this; + return this.distanceToPoint( sphere.center ) - sphere.radius; }, - getHex: function () { + projectPoint: function ( point, target ) { - return ( this.r * 255 ) << 16 ^ ( this.g * 255 ) << 8 ^ ( this.b * 255 ) << 0; + if ( target === undefined ) { - }, + console.warn( 'THREE.Plane: .projectPoint() target is now required' ); + target = new Vector3(); - getHexString: function () { + } - return ( '000000' + this.getHex().toString( 16 ) ).slice( - 6 ); + return target.copy( this.normal ).multiplyScalar( - this.distanceToPoint( point ) ).add( point ); }, - getHSL: function ( optionalTarget ) { + intersectLine: function () { - // h,s,l ranges are in 0.0 - 1.0 + var v1 = new Vector3(); - var hsl = optionalTarget || { h: 0, s: 0, l: 0 }; + return function intersectLine( line, target ) { - var r = this.r, g = this.g, b = this.b; + if ( target === undefined ) { - var max = Math.max( r, g, b ); - var min = Math.min( r, g, b ); + console.warn( 'THREE.Plane: .intersectLine() target is now required' ); + target = new Vector3(); - var hue, saturation; - var lightness = ( min + max ) / 2.0; + } - if ( min === max ) { + var direction = line.delta( v1 ); - hue = 0; - saturation = 0; + var denominator = this.normal.dot( direction ); - } else { + if ( denominator === 0 ) { - var delta = max - min; + // line is coplanar, return origin + if ( this.distanceToPoint( line.start ) === 0 ) { - saturation = lightness <= 0.5 ? delta / ( max + min ) : delta / ( 2 - max - min ); + return target.copy( line.start ); - 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; + // Unsure if this is the correct method to handle this case. + return undefined; } - hue /= 6; - - } - - hsl.h = hue; - hsl.s = saturation; - hsl.l = lightness; - - return hsl; - - }, - - getStyle: function () { - - return 'rgb(' + ( ( this.r * 255 ) | 0 ) + ',' + ( ( this.g * 255 ) | 0 ) + ',' + ( ( this.b * 255 ) | 0 ) + ')'; + var t = - ( line.start.dot( this.normal ) + this.constant ) / denominator; - }, + if ( t < 0 || t > 1 ) { - offsetHSL: function ( h, s, l ) { + return undefined; - var hsl = this.getHSL(); + } - hsl.h += h; hsl.s += s; hsl.l += l; + return target.copy( direction ).multiplyScalar( t ).add( line.start ); - this.setHSL( hsl.h, hsl.s, hsl.l ); + }; - return this; + }(), - }, + intersectsLine: function ( line ) { - add: function ( color ) { + // Note: this tests if a line intersects the plane, not whether it (or its end-points) are coplanar with it. - this.r += color.r; - this.g += color.g; - this.b += color.b; + var startSign = this.distanceToPoint( line.start ); + var endSign = this.distanceToPoint( line.end ); - return this; + return ( startSign < 0 && endSign > 0 ) || ( endSign < 0 && startSign > 0 ); }, - addColors: function ( color1, color2 ) { - - this.r = color1.r + color2.r; - this.g = color1.g + color2.g; - this.b = color1.b + color2.b; + intersectsBox: function ( box ) { - return this; + return box.intersectsPlane( this ); }, - addScalar: function ( s ) { - - this.r += s; - this.g += s; - this.b += s; + intersectsSphere: function ( sphere ) { - return this; + return sphere.intersectsPlane( this ); }, - sub: function ( color ) { - - this.r = Math.max( 0, this.r - color.r ); - this.g = Math.max( 0, this.g - color.g ); - this.b = Math.max( 0, this.b - color.b ); - - return this; + coplanarPoint: function ( target ) { - }, + if ( target === undefined ) { - multiply: function ( color ) { + console.warn( 'THREE.Plane: .coplanarPoint() target is now required' ); + target = new Vector3(); - this.r *= color.r; - this.g *= color.g; - this.b *= color.b; + } - return this; + return target.copy( this.normal ).multiplyScalar( - this.constant ); }, - multiplyScalar: function ( s ) { - - this.r *= s; - this.g *= s; - this.b *= s; - - return this; + applyMatrix4: function () { - }, + var v1 = new Vector3(); + var m1 = new Matrix3(); - lerp: function ( color, alpha ) { + return function applyMatrix4( matrix, optionalNormalMatrix ) { - this.r += ( color.r - this.r ) * alpha; - this.g += ( color.g - this.g ) * alpha; - this.b += ( color.b - this.b ) * alpha; + var normalMatrix = optionalNormalMatrix || m1.getNormalMatrix( matrix ); - return this; + var referencePoint = this.coplanarPoint( v1 ).applyMatrix4( matrix ); - }, + var normal = this.normal.applyMatrix3( normalMatrix ).normalize(); - equals: function ( c ) { + this.constant = - referencePoint.dot( normal ); - return ( c.r === this.r ) && ( c.g === this.g ) && ( c.b === this.b ); + return this; - }, + }; - fromArray: function ( array, offset ) { + }(), - if ( offset === undefined ) offset = 0; + translate: function ( offset ) { - this.r = array[ offset ]; - this.g = array[ offset + 1 ]; - this.b = array[ offset + 2 ]; + this.constant -= offset.dot( this.normal ); return this; }, - toArray: function ( array, offset ) { - - if ( array === undefined ) array = []; - if ( offset === undefined ) offset = 0; - - array[ offset ] = this.r; - array[ offset + 1 ] = this.g; - array[ offset + 2 ] = this.b; - - return array; - - }, - - toJSON: function () { + equals: function ( plane ) { - return this.getHex(); + return plane.normal.equals( this.normal ) && ( plane.constant === this.constant ); } } ); /** - * Uniforms library for shared webgl shaders + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + * @author bhouston / http://clara.io */ -var UniformsLib = { - - common: { +function Frustum( p0, p1, p2, p3, p4, p5 ) { - diffuse: { value: new Color( 0xeeeeee ) }, - opacity: { value: 1.0 }, + this.planes = [ - map: { value: null }, - uvTransform: { value: new Matrix3() }, + ( 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() - alphaMap: { value: null }, + ]; - }, +} - specularmap: { +Object.assign( Frustum.prototype, { - specularMap: { value: null }, + set: function ( p0, p1, p2, p3, p4, p5 ) { - }, + var planes = this.planes; - envmap: { + planes[ 0 ].copy( p0 ); + planes[ 1 ].copy( p1 ); + planes[ 2 ].copy( p2 ); + planes[ 3 ].copy( p3 ); + planes[ 4 ].copy( p4 ); + planes[ 5 ].copy( p5 ); - envMap: { value: null }, - flipEnvMap: { value: - 1 }, - reflectivity: { value: 1.0 }, - refractionRatio: { value: 0.98 } + return this; }, - aomap: { + clone: function () { - aoMap: { value: null }, - aoMapIntensity: { value: 1 } + return new this.constructor().copy( this ); }, - lightmap: { - - lightMap: { value: null }, - lightMapIntensity: { value: 1 } - - }, + copy: function ( frustum ) { - emissivemap: { + var planes = this.planes; - emissiveMap: { value: null } + for ( var i = 0; i < 6; i ++ ) { - }, + planes[ i ].copy( frustum.planes[ i ] ); - bumpmap: { + } - bumpMap: { value: null }, - bumpScale: { value: 1 } + return this; }, - normalmap: { - - normalMap: { value: null }, - normalScale: { value: new Vector2( 1, 1 ) } + setFromMatrix: function ( m ) { - }, + var planes = this.planes; + var me = m.elements; + var me0 = me[ 0 ], me1 = me[ 1 ], me2 = me[ 2 ], me3 = me[ 3 ]; + var me4 = me[ 4 ], me5 = me[ 5 ], me6 = me[ 6 ], me7 = me[ 7 ]; + var me8 = me[ 8 ], me9 = me[ 9 ], me10 = me[ 10 ], me11 = me[ 11 ]; + var me12 = me[ 12 ], me13 = me[ 13 ], me14 = me[ 14 ], me15 = me[ 15 ]; - displacementmap: { + 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(); - displacementMap: { value: null }, - displacementScale: { value: 1 }, - displacementBias: { value: 0 } + return this; }, - roughnessmap: { + intersectsObject: function () { - roughnessMap: { value: null } + var sphere = new Sphere(); - }, + return function intersectsObject( object ) { - metalnessmap: { + var geometry = object.geometry; - metalnessMap: { value: null } + if ( geometry.boundingSphere === null ) + geometry.computeBoundingSphere(); - }, + sphere.copy( geometry.boundingSphere ) + .applyMatrix4( object.matrixWorld ); - gradientmap: { + return this.intersectsSphere( sphere ); - gradientMap: { value: null } + }; - }, + }(), - fog: { + intersectsSprite: function () { - fogDensity: { value: 0.00025 }, - fogNear: { value: 1 }, - fogFar: { value: 2000 }, - fogColor: { value: new Color( 0xffffff ) } + var sphere = new Sphere(); - }, + return function intersectsSprite( sprite ) { - lights: { + sphere.center.set( 0, 0, 0 ); + sphere.radius = 0.7071067811865476; + sphere.applyMatrix4( sprite.matrixWorld ); - ambientLightColor: { value: [] }, + return this.intersectsSphere( sphere ); - directionalLights: { value: [], properties: { - direction: {}, - color: {}, + }; - shadow: {}, - shadowBias: {}, - shadowRadius: {}, - shadowMapSize: {} - } }, + }(), - directionalShadowMap: { value: [] }, - directionalShadowMatrix: { value: [] }, + intersectsSphere: function ( sphere ) { - spotLights: { value: [], properties: { - color: {}, - position: {}, - direction: {}, - distance: {}, - coneCos: {}, - penumbraCos: {}, - decay: {}, + var planes = this.planes; + var center = sphere.center; + var negRadius = - sphere.radius; - shadow: {}, - shadowBias: {}, - shadowRadius: {}, - shadowMapSize: {} - } }, + for ( var i = 0; i < 6; i ++ ) { - spotShadowMap: { value: [] }, - spotShadowMatrix: { value: [] }, + var distance = planes[ i ].distanceToPoint( center ); - pointLights: { value: [], properties: { - color: {}, - position: {}, - decay: {}, - distance: {}, + if ( distance < negRadius ) { - shadow: {}, - shadowBias: {}, - shadowRadius: {}, - shadowMapSize: {}, - shadowCameraNear: {}, - shadowCameraFar: {} - } }, + return false; - 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: {} - } } + return true; }, - points: { - - diffuse: { value: new Color( 0xeeeeee ) }, - opacity: { value: 1.0 }, - size: { value: 1.0 }, - scale: { value: 1.0 }, - map: { value: null }, - uvTransform: { value: new Matrix3() } + intersectsBox: function () { - } + var p = new Vector3(); -}; + return function intersectsBox( box ) { -/** - * Uniform Utilities - */ + var planes = this.planes; -var UniformsUtils = { + for ( var i = 0; i < 6; i ++ ) { - merge: function ( uniforms ) { + var plane = planes[ i ]; - var merged = {}; + // corner at max distance - for ( var u = 0; u < uniforms.length; u ++ ) { + 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; - var tmp = this.clone( uniforms[ u ] ); + if ( plane.distanceToPoint( p ) < 0 ) { - for ( var p in tmp ) { + return false; - merged[ p ] = tmp[ p ]; + } } - } - - return merged; - - }, - - clone: function ( uniforms_src ) { - - var uniforms_dst = {}; - - for ( var u in uniforms_src ) { - - uniforms_dst[ u ] = {}; - - for ( var p in uniforms_src[ u ] ) { - - var parameter_src = uniforms_src[ u ][ p ]; + return true; - 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(); + }(), - } else if ( Array.isArray( parameter_src ) ) { + containsPoint: function ( point ) { - uniforms_dst[ u ][ p ] = parameter_src.slice(); + var planes = this.planes; - } else { + for ( var i = 0; i < 6; i ++ ) { - uniforms_dst[ u ][ p ] = parameter_src; + if ( planes[ i ].distanceToPoint( point ) < 0 ) { - } + return false; } } - return uniforms_dst; + return true; } -}; +} ); -var alphamap_fragment = "#ifdef USE_ALPHAMAP\n\tdiffuseColor.a *= texture2D( alphaMap, vUv ).g;\n#endif\n"; +var alphamap_fragment = "#ifdef USE_ALPHAMAP\n\tdiffuseColor.a *= texture2D( alphaMap, vUv ).g;\n#endif"; -var alphamap_pars_fragment = "#ifdef USE_ALPHAMAP\n\tuniform sampler2D alphaMap;\n#endif\n"; +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\n"; +var alphatest_fragment = "#ifdef ALPHATEST\n\tif ( diffuseColor.a < ALPHATEST ) discard;\n#endif"; -var aomap_fragment = "#ifdef USE_AOMAP\n\tfloat ambientOcclusion = ( texture2D( aoMap, vUv2 ).r - 1.0 ) * aoMapIntensity + 1.0;\n\treflectedLight.indirectDiffuse *= ambientOcclusion;\n\t#if defined( USE_ENVMAP ) && defined( 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"; +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"; var aomap_pars_fragment = "#ifdef USE_AOMAP\n\tuniform sampler2D aoMap;\n\tuniform float aoMapIntensity;\n#endif"; -var begin_vertex = "\nvec3 transformed = vec3( position );\n"; +var begin_vertex = "vec3 transformed = vec3( position );"; -var beginnormal_vertex = "\nvec3 objectNormal = vec3( normal );\n"; +var beginnormal_vertex = "vec3 objectNormal = vec3( normal );"; -var bsdfs = "float punctualLightIntensityToIrradianceFactor( const in float lightDistance, const in float cutoffDistance, const in float decayExponent ) {\n\tif( decayExponent > 0.0 ) {\n#if defined ( PHYSICALLY_CORRECT_LIGHTS )\n\t\tfloat distanceFalloff = 1.0 / max( pow( lightDistance, decayExponent ), 0.01 );\n\t\tfloat maxDistanceCutoffFactor = pow2( saturate( 1.0 - pow4( lightDistance / cutoffDistance ) ) );\n\t\treturn distanceFalloff * maxDistanceCutoffFactor;\n#else\n\t\treturn pow( saturate( -lightDistance / cutoffDistance + 1.0 ), decayExponent );\n#endif\n\t}\n\treturn 1.0;\n}\nvec3 BRDF_Diffuse_Lambert( const in vec3 diffuseColor ) {\n\treturn RECIPROCAL_PI * diffuseColor;\n}\nvec3 F_Schlick( const in vec3 specularColor, const in float dotLH ) {\n\tfloat fresnel = exp2( ( -5.55473 * dotLH - 6.98316 ) * dotLH );\n\treturn ( 1.0 - specularColor ) * fresnel + specularColor;\n}\nfloat G_GGX_Smith( const in float alpha, const in float dotNL, const in float dotNV ) {\n\tfloat a2 = pow2( alpha );\n\tfloat gl = dotNL + sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNL ) );\n\tfloat gv = dotNV + sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNV ) );\n\treturn 1.0 / ( gl * gv );\n}\nfloat G_GGX_SmithCorrelated( const in float alpha, const in float dotNL, const in float dotNV ) {\n\tfloat a2 = pow2( alpha );\n\tfloat gv = dotNL * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNV ) );\n\tfloat gl = dotNV * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNL ) );\n\treturn 0.5 / max( gv + gl, EPSILON );\n}\nfloat D_GGX( const in float alpha, const in float dotNH ) {\n\tfloat a2 = pow2( alpha );\n\tfloat denom = pow2( dotNH ) * ( a2 - 1.0 ) + 1.0;\n\treturn RECIPROCAL_PI * a2 / pow2( denom );\n}\nvec3 BRDF_Specular_GGX( const in IncidentLight incidentLight, const in GeometricContext geometry, const in vec3 specularColor, const in float roughness ) {\n\tfloat alpha = pow2( roughness );\n\tvec3 halfDir = normalize( incidentLight.direction + geometry.viewDir );\n\tfloat dotNL = saturate( dot( geometry.normal, incidentLight.direction ) );\n\tfloat dotNV = saturate( dot( geometry.normal, geometry.viewDir ) );\n\tfloat dotNH = saturate( dot( geometry.normal, halfDir ) );\n\tfloat dotLH = saturate( dot( incidentLight.direction, halfDir ) );\n\tvec3 F = F_Schlick( specularColor, dotLH );\n\tfloat G = G_GGX_SmithCorrelated( alpha, dotNL, dotNV );\n\tfloat D = D_GGX( alpha, dotNH );\n\treturn F * ( G * D );\n}\nvec2 LTC_Uv( const in vec3 N, const in vec3 V, const in float roughness ) {\n\tconst float LUT_SIZE = 64.0;\n\tconst float LUT_SCALE = ( LUT_SIZE - 1.0 ) / LUT_SIZE;\n\tconst float LUT_BIAS = 0.5 / LUT_SIZE;\n\tfloat 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"; +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}"; -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\tvec3 vGrad = sign( fDet ) * ( dHdxy.x * R1 + dHdxy.y * R2 );\n\t\treturn normalize( abs( fDet ) * surf_norm - vGrad );\n\t}\n#endif\n"; +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"; -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_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"; -var clipping_planes_pars_fragment = "#if NUM_CLIPPING_PLANES > 0\n\t#if ! defined( PHYSICAL ) && ! defined( PHONG )\n\t\tvarying vec3 vViewPosition;\n\t#endif\n\tuniform vec4 clippingPlanes[ NUM_CLIPPING_PLANES ];\n#endif\n"; +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"; -var clipping_planes_pars_vertex = "#if NUM_CLIPPING_PLANES > 0 && ! defined( PHYSICAL ) && ! defined( PHONG )\n\tvarying vec3 vViewPosition;\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"; -var clipping_planes_vertex = "#if NUM_CLIPPING_PLANES > 0 && ! defined( PHYSICAL ) && ! defined( PHONG )\n\tvViewPosition = - mvPosition.xyz;\n#endif\n"; +var clipping_planes_vertex = "#if NUM_CLIPPING_PLANES > 0 && ! defined( PHYSICAL ) && ! defined( PHONG ) && ! defined( MATCAP )\n\tvViewPosition = - mvPosition.xyz;\n#endif"; var color_fragment = "#ifdef USE_COLOR\n\tdiffuseColor.rgb *= vColor;\n#endif"; -var color_pars_fragment = "#ifdef USE_COLOR\n\tvarying vec3 vColor;\n#endif\n"; +var color_pars_fragment = "#ifdef USE_COLOR\n\tvarying vec3 vColor;\n#endif"; 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 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 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}"; -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(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"; +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"; -var defaultnormal_vertex = "vec3 transformedNormal = normalMatrix * objectNormal;\n#ifdef FLIP_SIDED\n\ttransformedNormal = - transformedNormal;\n#endif\n"; +var defaultnormal_vertex = "vec3 transformedNormal = normalMatrix * objectNormal;\n#ifdef FLIP_SIDED\n\ttransformedNormal = - transformedNormal;\n#endif"; -var displacementmap_pars_vertex = "#ifdef USE_DISPLACEMENTMAP\n\tuniform sampler2D displacementMap;\n\tuniform float displacementScale;\n\tuniform float displacementBias;\n#endif\n"; +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, uv ).x * displacementScale + displacementBias );\n#endif\n"; +var displacementmap_vertex = "#ifdef USE_DISPLACEMENTMAP\n\ttransformed += normalize( objectNormal ) * ( texture2D( displacementMap, uv ).x * displacementScale + displacementBias );\n#endif"; -var emissivemap_fragment = "#ifdef USE_EMISSIVEMAP\n\tvec4 emissiveColor = texture2D( emissiveMap, vUv );\n\temissiveColor.rgb = emissiveMapTexelToLinear( emissiveColor ).rgb;\n\ttotalEmissiveRadiance *= emissiveColor.rgb;\n#endif\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"; -var emissivemap_pars_fragment = "#ifdef USE_EMISSIVEMAP\n\tuniform sampler2D emissiveMap;\n#endif\n"; +var emissivemap_pars_fragment = "#ifdef USE_EMISSIVEMAP\n\tuniform sampler2D emissiveMap;\n#endif"; -var encodings_fragment = " gl_FragColor = linearToOutputTexel( gl_FragColor );\n"; +var encodings_fragment = "gl_FragColor = linearToOutputTexel( gl_FragColor );"; -var encodings_pars_fragment = "\nvec4 LinearToLinear( in vec4 value ) {\n\treturn value;\n}\nvec4 GammaToLinear( in vec4 value, in float gammaFactor ) {\n\treturn vec4( pow( value.xyz, vec3( gammaFactor ) ), value.w );\n}\nvec4 LinearToGamma( in vec4 value, in float gammaFactor ) {\n\treturn vec4( pow( value.xyz, vec3( 1.0 / gammaFactor ) ), value.w );\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.w );\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.w );\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.xyz * value.w * maxRange, 1.0 );\n}\nvec4 LinearToRGBM( in vec4 value, in float maxRange ) {\n\tfloat maxRGB = max( value.x, 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.x, 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"; +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}"; -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"; +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"; -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\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"; +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"; -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_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"; -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 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"; -var fog_vertex = "\n#ifdef USE_FOG\nfogDepth = -mvPosition.z;\n#endif"; +var fog_vertex = "#ifdef USE_FOG\n\tfogDepth = -mvPosition.z;\n#endif"; -var fog_pars_vertex = "#ifdef USE_FOG\n varying float fogDepth;\n#endif\n"; +var fog_pars_vertex = "#ifdef USE_FOG\n\tvarying float fogDepth;\n#endif"; -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"; +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"; -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 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 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"; +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"; -var lightmap_fragment = "#ifdef USE_LIGHTMAP\n\treflectedLight.indirectDiffuse += PI * texture2D( lightMap, vUv2 ).xyz * lightMapIntensity;\n#endif\n"; +var lightmap_fragment = "#ifdef USE_LIGHTMAP\n\treflectedLight.indirectDiffuse += PI * texture2D( lightMap, vUv2 ).xyz * lightMapIntensity;\n#endif"; var lightmap_pars_fragment = "#ifdef USE_LIGHTMAP\n\tuniform sampler2D lightMap;\n\tuniform float lightMapIntensity;\n#endif"; -var lights_lambert_vertex = "vec3 diffuse = vec3( 1.0 );\nGeometricContext geometry;\ngeometry.position = mvPosition.xyz;\ngeometry.normal = normalize( transformedNormal );\ngeometry.viewDir = 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 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"; -var lights_pars = "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#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( 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(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_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"; -var lights_phong_fragment = "BlinnPhongMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb;\nmaterial.specularColor = specular;\nmaterial.specularShininess = shininess;\nmaterial.specularStrength = specularStrength;\n"; +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"; -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_phong_fragment = "BlinnPhongMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb;\nmaterial.specularColor = specular;\nmaterial.specularShininess = shininess;\nmaterial.specularStrength = specularStrength;"; -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_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)"; -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"; +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"; -var lights_template = "\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#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 ( 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\t#if defined( USE_ENVMAP ) && defined( PHYSICAL ) && defined( ENVMAP_TYPE_CUBE_UV )\n\t\tirradiance += getLightProbeIndirectIrradiance( geometry, 8 );\n\t#endif\n\tRE_IndirectDiffuse( irradiance, geometry, material, reflectedLight );\n#endif\n#if defined( USE_ENVMAP ) && defined( RE_IndirectSpecular )\n\tvec3 radiance = getLightProbeIndirectRadiance( geometry, Material_BlinnShininessExponent( material ), 8 );\n\t#ifndef STANDARD\n\t\tvec3 clearCoatRadiance = getLightProbeIndirectRadiance( geometry, Material_ClearCoat_BlinnShininessExponent( material ), 8 );\n\t#else\n\t\tvec3 clearCoatRadiance = vec3( 0.0 );\n\t#endif\n\tRE_IndirectSpecular( radiance, clearCoatRadiance, geometry, material, reflectedLight );\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}"; -var logdepthbuf_fragment = "#if defined( USE_LOGDEPTHBUF ) && defined( USE_LOGDEPTHBUF_EXT )\n\tgl_FragDepthEXT = log2( vFragDepth ) * logDepthBufFC * 0.5;\n#endif"; +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"; -var logdepthbuf_pars_fragment = "#ifdef USE_LOGDEPTHBUF\n\tuniform float logDepthBufFC;\n\t#ifdef USE_LOGDEPTHBUF_EXT\n\t\tvarying float vFragDepth;\n\t#endif\n#endif\n"; +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"; -var logdepthbuf_pars_vertex = "#ifdef USE_LOGDEPTHBUF\n\t#ifdef USE_LOGDEPTHBUF_EXT\n\t\tvarying float vFragDepth;\n\t#endif\n\tuniform float logDepthBufFC;\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, clearCoatRadiance, geometry, material, reflectedLight );\n#endif"; -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"; +var logdepthbuf_fragment = "#if defined( USE_LOGDEPTHBUF ) && defined( USE_LOGDEPTHBUF_EXT )\n\tgl_FragDepthEXT = log2( vFragDepth ) * logDepthBufFC * 0.5;\n#endif"; -var map_fragment = "#ifdef USE_MAP\n\tvec4 texelColor = texture2D( map, vUv );\n\ttexelColor = mapTexelToLinear( texelColor );\n\tdiffuseColor *= texelColor;\n#endif\n"; +var logdepthbuf_pars_fragment = "#if defined( USE_LOGDEPTHBUF ) && defined( USE_LOGDEPTHBUF_EXT )\n\tuniform float logDepthBufFC;\n\tvarying float vFragDepth;\n#endif"; -var map_pars_fragment = "#ifdef USE_MAP\n\tuniform sampler2D map;\n#endif\n"; +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"; -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"; +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"; -var map_particle_pars_fragment = "#ifdef USE_MAP\n\tuniform mat3 uvTransform;\n\tuniform sampler2D map;\n#endif\n"; +var map_fragment = "#ifdef USE_MAP\n\tvec4 texelColor = texture2D( map, vUv );\n\ttexelColor = mapTexelToLinear( texelColor );\n\tdiffuseColor *= texelColor;\n#endif"; -var metalnessmap_fragment = "float metalnessFactor = metalness;\n#ifdef USE_METALNESSMAP\n\tvec4 texelMetalness = texture2D( metalnessMap, vUv );\n\tmetalnessFactor *= texelMetalness.b;\n#endif\n"; +var map_pars_fragment = "#ifdef USE_MAP\n\tuniform sampler2D map;\n#endif"; + +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"; + +var map_particle_pars_fragment = "#ifdef USE_MAP\n\tuniform mat3 uvTransform;\n\tuniform sampler2D map;\n#endif"; + +var metalnessmap_fragment = "float metalnessFactor = metalness;\n#ifdef USE_METALNESSMAP\n\tvec4 texelMetalness = texture2D( metalnessMap, vUv );\n\tmetalnessFactor *= texelMetalness.b;\n#endif"; var metalnessmap_pars_fragment = "#ifdef USE_METALNESSMAP\n\tuniform sampler2D metalnessMap;\n#endif"; -var morphnormal_vertex = "#ifdef USE_MORPHNORMALS\n\tobjectNormal += ( 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"; +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"; 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"; -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 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"; + +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"; -var normal_fragment = "#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#ifdef USE_NORMALMAP\n\tnormal = perturbNormal2Arb( -vViewPosition, normal );\n#elif defined( USE_BUMPMAP )\n\tnormal = perturbNormalArb( -vViewPosition, normal, dHdxy_fwd() );\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"; -var normalmap_pars_fragment = "#ifdef USE_NORMALMAP\n\tuniform sampler2D normalMap;\n\tuniform vec2 normalScale;\n\tvec3 perturbNormal2Arb( vec3 eye_pos, vec3 surf_norm ) {\n\t\tvec3 q0 = vec3( dFdx( eye_pos.x ), dFdx( eye_pos.y ), dFdx( eye_pos.z ) );\n\t\tvec3 q1 = vec3( dFdy( eye_pos.x ), dFdy( eye_pos.y ), dFdy( eye_pos.z ) );\n\t\tvec2 st0 = dFdx( vUv.st );\n\t\tvec2 st1 = dFdy( vUv.st );\n\t\tvec3 S = normalize( q0 * st1.t - q1 * st0.t );\n\t\tvec3 T = normalize( -q0 * st1.s + q1 * st0.s );\n\t\tvec3 N = normalize( surf_norm );\n\t\tvec3 mapN = texture2D( normalMap, vUv ).xyz * 2.0 - 1.0;\n\t\tmapN.xy = normalScale * mapN.xy;\n\t\tmat3 tsn = mat3( S, T, N );\n\t\treturn normalize( tsn * mapN );\n\t}\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"; -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 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}"; -var premultiplied_alpha_fragment = "#ifdef PREMULTIPLIED_ALPHA\n\tgl_FragColor.rgb *= gl_FragColor.a;\n#endif\n"; +var premultiplied_alpha_fragment = "#ifdef PREMULTIPLIED_ALPHA\n\tgl_FragColor.rgb *= gl_FragColor.a;\n#endif"; -var project_vertex = "vec4 mvPosition = modelViewMatrix * vec4( transformed, 1.0 );\ngl_Position = projectionMatrix * mvPosition;\n"; +var project_vertex = "vec4 mvPosition = modelViewMatrix * vec4( transformed, 1.0 );\ngl_Position = projectionMatrix * mvPosition;"; -var dithering_fragment = "#if defined( DITHERING )\n gl_FragColor.rgb = dithering( gl_FragColor.rgb );\n#endif\n"; +var dithering_fragment = "#if defined( DITHERING )\n gl_FragColor.rgb = dithering( gl_FragColor.rgb );\n#endif"; -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"; +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"; -var roughnessmap_fragment = "float roughnessFactor = roughness;\n#ifdef USE_ROUGHNESSMAP\n\tvec4 texelRoughness = texture2D( roughnessMap, vUv );\n\troughnessFactor *= texelRoughness.g;\n#endif\n"; +var roughnessmap_fragment = "float roughnessFactor = roughness;\n#ifdef USE_ROUGHNESSMAP\n\tvec4 texelRoughness = texture2D( roughnessMap, vUv );\n\troughnessFactor *= texelRoughness.g;\n#endif"; var roughnessmap_pars_fragment = "#ifdef USE_ROUGHNESSMAP\n\tuniform sampler2D roughnessMap;\n#endif"; -var shadowmap_pars_fragment = "#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_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"; +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"; -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"; +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"; -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"; +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"; -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 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}"; 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"; +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"; -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"; +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#endif\n"; +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"; 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 gl_FragColor.rgb = toneMapping( gl_FragColor.rgb );\n#endif\n"; +var tonemapping_fragment = "#if defined( TONE_MAPPING )\n gl_FragColor.rgb = toneMapping( gl_FragColor.rgb );\n#endif"; -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"; +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}\nvec3 ACESFilmicToneMapping( vec3 color ) {\n\tcolor *= toneMappingExposure;\n\treturn saturate( ( color * ( 2.51 * color + 0.03 ) ) / ( color * ( 2.43 * color + 0.59 ) + 0.14 ) );\n}"; 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"; -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"; +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"; 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"; @@ -9199,55 +7619,67 @@ var uv2_pars_vertex = "#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\tat var uv2_vertex = "#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\tvUv2 = uv2;\n#endif"; -var worldpos_vertex = "#if defined( USE_ENVMAP ) || defined( DISTANCE ) || defined ( USE_SHADOWMAP )\n\tvec4 worldPosition = modelMatrix * vec4( transformed, 1.0 );\n#endif\n"; +var worldpos_vertex = "#if defined( USE_ENVMAP ) || defined( DISTANCE ) || defined ( USE_SHADOWMAP )\n\tvec4 worldPosition = modelMatrix * vec4( transformed, 1.0 );\n#endif"; + +var background_frag = "uniform sampler2D t2D;\nvarying vec2 vUv;\nvoid main() {\n\tvec4 texColor = texture2D( t2D, vUv );\n\tgl_FragColor = mapTexelToLinear( texColor );\n\t#include \n\t#include \n}"; + +var background_vert = "varying vec2 vUv;\nuniform mat3 uvTransform;\nvoid main() {\n\tvUv = ( uvTransform * vec3( uv, 1 ) ).xy;\n\tgl_Position = vec4( position.xy, 1.0, 1.0 );\n}"; + +var cube_frag = "uniform samplerCube tCube;\nuniform float tFlip;\nuniform float opacity;\nvarying vec3 vWorldDirection;\nvoid main() {\n\tvec4 texColor = textureCube( tCube, vec3( tFlip * vWorldDirection.x, vWorldDirection.yz ) );\n\tgl_FragColor = mapTexelToLinear( texColor );\n\tgl_FragColor.a *= opacity;\n\t#include \n\t#include \n}"; + +var cube_vert = "varying vec3 vWorldDirection;\n#include \nvoid main() {\n\tvWorldDirection = transformDirection( position, modelMatrix );\n\t#include \n\t#include \n\tgl_Position.z = gl_Position.w;\n}"; -var cube_frag = "uniform samplerCube tCube;\nuniform float tFlip;\nuniform float opacity;\nvarying vec3 vWorldPosition;\nvoid main() {\n\tgl_FragColor = textureCube( tCube, vec3( tFlip * vWorldPosition.x, vWorldPosition.yz ) );\n\tgl_FragColor.a *= opacity;\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}"; -var cube_vert = "varying vec3 vWorldPosition;\n#include \nvoid main() {\n\tvWorldPosition = transformDirection( position, modelMatrix );\n\t#include \n\t#include \n\tgl_Position.z = gl_Position.w;\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}"; -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( gl_FragCoord.z ), opacity );\n\t#elif DEPTH_PACKING == 3201\n\t\tgl_FragColor = packDepthToRGBA( gl_FragCoord.z );\n\t#endif\n}\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}"; -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 distanceRGBA_vert = "#define DISTANCE\nvarying vec3 vWorldPosition;\n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#ifdef USE_DISPLACEMENTMAP\n\t\t#include \n\t\t#include \n\t\t#include \n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvWorldPosition = worldPosition.xyz;\n}"; -var 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 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\tvec4 texColor = texture2D( tEquirect, sampleUV );\n\tgl_FragColor = mapTexelToLinear( texColor );\n\t#include \n\t#include \n}"; -var distanceRGBA_vert = "#define DISTANCE\nvarying vec3 vWorldPosition;\n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#ifdef USE_DISPLACEMENTMAP\n\t\t#include \n\t\t#include \n\t\t#include \n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvWorldPosition = worldPosition.xyz;\n}\n"; +var equirect_vert = "varying vec3 vWorldDirection;\n#include \nvoid main() {\n\tvWorldDirection = transformDirection( position, modelMatrix );\n\t#include \n\t#include \n}"; -var equirect_frag = "uniform sampler2D tEquirect;\nvarying vec3 vWorldPosition;\n#include \nvoid main() {\n\tvec3 direction = normalize( vWorldPosition );\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"; +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}"; -var equirect_vert = "varying vec3 vWorldPosition;\n#include \nvoid main() {\n\tvWorldPosition = transformDirection( position, modelMatrix );\n\t#include \n\t#include \n}\n"; +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}"; -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"; +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}"; -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 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}"; -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 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}"; -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"; +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}"; -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"; +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\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}"; -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_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}"; -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\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"; +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}"; -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"; +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}"; -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 \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\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"; +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}"; -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"; +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}"; -var normal_frag = "#define NORMAL\nuniform float opacity;\n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( USE_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\tgl_FragColor = vec4( packNormalToRGB( normal ), opacity );\n}\n"; +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}"; -var normal_vert = "#define NORMAL\n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( USE_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 )\n\tvViewPosition = - mvPosition.xyz;\n#endif\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}"; -var points_frag = "uniform vec3 diffuse;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec3 outgoingLight = vec3( 0.0 );\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\t#include \n\t#include \n\t#include \n\toutgoingLight = diffuseColor.rgb;\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include \n\t#include \n\t#include \n\t#include \n}\n"; +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}"; -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#ifdef USE_SIZEATTENUATION\n\t\tgl_PointSize = size * ( scale / - mvPosition.z );\n\t#else\n\t\tgl_PointSize = size;\n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}\n"; +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}"; -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"; +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}"; -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 shadow_vert = "#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; + +var sprite_frag = "uniform vec3 diffuse;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \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}"; + +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}"; var ShaderChunk = { alphamap_fragment: alphamap_fragment, @@ -9279,6 +7711,7 @@ var ShaderChunk = { 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, @@ -9288,12 +7721,14 @@ var ShaderChunk = { lightmap_fragment: lightmap_fragment, lightmap_pars_fragment: lightmap_pars_fragment, lights_lambert_vertex: lights_lambert_vertex, - lights_pars: lights_pars, + 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_template: lights_template, + 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, @@ -9307,7 +7742,8 @@ var ShaderChunk = { morphnormal_vertex: morphnormal_vertex, morphtarget_pars_vertex: morphtarget_pars_vertex, morphtarget_vertex: morphtarget_vertex, - normal_fragment: normal_fragment, + 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, @@ -9336,6 +7772,8 @@ var ShaderChunk = { 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, @@ -9350,6 +7788,8 @@ var ShaderChunk = { 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, @@ -9359,2116 +7799,2042 @@ var ShaderChunk = { points_frag: points_frag, points_vert: points_vert, shadow_frag: shadow_frag, - shadow_vert: shadow_vert + shadow_vert: shadow_vert, + sprite_frag: sprite_frag, + sprite_vert: sprite_vert }; /** - * @author alteredq / http://alteredqualia.com/ - * @author mrdoob / http://mrdoob.com/ - * @author mikael emtinger / http://gomo.se/ + * Uniform Utilities */ -var ShaderLib = { - - basic: { - - uniforms: UniformsUtils.merge( [ - UniformsLib.common, - UniformsLib.specularmap, - UniformsLib.envmap, - UniformsLib.aomap, - UniformsLib.lightmap, - UniformsLib.fog - ] ), +function cloneUniforms( src ) { - vertexShader: ShaderChunk.meshbasic_vert, - fragmentShader: ShaderChunk.meshbasic_frag + var dst = {}; - }, + for ( var u in src ) { - lambert: { + dst[ u ] = {}; - uniforms: UniformsUtils.merge( [ - UniformsLib.common, - UniformsLib.specularmap, - UniformsLib.envmap, - UniformsLib.aomap, - UniformsLib.lightmap, - UniformsLib.emissivemap, - UniformsLib.fog, - UniformsLib.lights, - { - emissive: { value: new Color( 0x000000 ) } - } - ] ), + for ( var p in src[ u ] ) { - vertexShader: ShaderChunk.meshlambert_vert, - fragmentShader: ShaderChunk.meshlambert_frag + var property = src[ u ][ p ]; - }, + if ( property && ( property.isColor || + property.isMatrix3 || property.isMatrix4 || + property.isVector2 || property.isVector3 || property.isVector4 || + property.isTexture ) ) { - phong: { + dst[ u ][ p ] = property.clone(); - 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 } - } - ] ), + } else if ( Array.isArray( property ) ) { - vertexShader: ShaderChunk.meshphong_vert, - fragmentShader: ShaderChunk.meshphong_frag + dst[ u ][ p ] = property.slice(); - }, + } else { - standard: { + dst[ u ][ p ] = property; - 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 } - ] ), - - vertexShader: ShaderChunk.meshphysical_vert, - fragmentShader: ShaderChunk.meshphysical_frag - - }, - - points: { - uniforms: UniformsUtils.merge( [ - UniformsLib.points, - UniformsLib.fog - ] ), + } - vertexShader: ShaderChunk.points_vert, - fragmentShader: ShaderChunk.points_frag + } - }, + return dst; - dashed: { +} - uniforms: UniformsUtils.merge( [ - UniformsLib.common, - UniformsLib.fog, - { - scale: { value: 1 }, - dashSize: { value: 1 }, - totalSize: { value: 2 } - } - ] ), +function mergeUniforms( uniforms ) { - vertexShader: ShaderChunk.linedashed_vert, - fragmentShader: ShaderChunk.linedashed_frag + var merged = {}; - }, + for ( var u = 0; u < uniforms.length; u ++ ) { - depth: { + var tmp = cloneUniforms( uniforms[ u ] ); - uniforms: UniformsUtils.merge( [ - UniformsLib.common, - UniformsLib.displacementmap - ] ), + for ( var p in tmp ) { - vertexShader: ShaderChunk.depth_vert, - fragmentShader: ShaderChunk.depth_frag + merged[ p ] = tmp[ p ]; - }, + } - normal: { + } - uniforms: UniformsUtils.merge( [ - UniformsLib.common, - UniformsLib.bumpmap, - UniformsLib.normalmap, - UniformsLib.displacementmap, - { - opacity: { value: 1.0 } - } - ] ), + return merged; - vertexShader: ShaderChunk.normal_vert, - fragmentShader: ShaderChunk.normal_frag +} - }, +// Legacy - /* ------------------------------------------------------------------------- - // Cube map shader - ------------------------------------------------------------------------- */ +var UniformsUtils = { clone: cloneUniforms, merge: mergeUniforms }; - cube: { +/** + * @author mrdoob / http://mrdoob.com/ + */ - uniforms: { - tCube: { value: null }, - tFlip: { value: - 1 }, - opacity: { value: 1.0 } - }, +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 }; - vertexShader: ShaderChunk.cube_vert, - fragmentShader: ShaderChunk.cube_frag +function Color( r, g, b ) { - }, + if ( g === undefined && b === undefined ) { - equirect: { + // r is THREE.Color, hex or string + return this.set( r ); - uniforms: { - tEquirect: { value: null }, - }, + } - vertexShader: ShaderChunk.equirect_vert, - fragmentShader: ShaderChunk.equirect_frag + return this.setRGB( r, g, b ); - }, +} - distanceRGBA: { +Object.assign( Color.prototype, { - uniforms: UniformsUtils.merge( [ - UniformsLib.common, - UniformsLib.displacementmap, - { - referencePosition: { value: new Vector3() }, - nearDistance: { value: 1 }, - farDistance: { value: 1000 } - } - ] ), + isColor: true, - vertexShader: ShaderChunk.distanceRGBA_vert, - fragmentShader: ShaderChunk.distanceRGBA_frag + r: 1, g: 1, b: 1, - }, + set: function ( value ) { - shadow: { + if ( value && value.isColor ) { - uniforms: UniformsUtils.merge( [ - UniformsLib.lights, - UniformsLib.fog, - { - color: { value: new Color( 0x00000 ) }, - opacity: { value: 1.0 } - }, - ] ), + this.copy( value ); - vertexShader: ShaderChunk.shadow_vert, - fragmentShader: ShaderChunk.shadow_frag + } else if ( typeof value === 'number' ) { - } + this.setHex( value ); -}; + } else if ( typeof value === 'string' ) { -ShaderLib.physical = { + this.setStyle( value ); - uniforms: UniformsUtils.merge( [ - ShaderLib.standard.uniforms, - { - clearCoat: { value: 0 }, - clearCoatRoughness: { value: 0 } } - ] ), - - vertexShader: ShaderChunk.meshphysical_vert, - fragmentShader: ShaderChunk.meshphysical_frag -}; + return this; -/** - * @author mrdoob / http://mrdoob.com/ - */ + }, -function CanvasTexture( canvas, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ) { + setScalar: function ( scalar ) { - Texture.call( this, canvas, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ); + this.r = scalar; + this.g = scalar; + this.b = scalar; - this.needsUpdate = true; + return this; -} + }, -CanvasTexture.prototype = Object.create( Texture.prototype ); -CanvasTexture.prototype.constructor = CanvasTexture; + setHex: function ( hex ) { -/** - * @author mikael emtinger / http://gomo.se/ - * @author alteredq / http://alteredqualia.com/ - */ + hex = Math.floor( hex ); -function WebGLSpriteRenderer( renderer, gl, state, textures, capabilities ) { + this.r = ( hex >> 16 & 255 ) / 255; + this.g = ( hex >> 8 & 255 ) / 255; + this.b = ( hex & 255 ) / 255; - var vertexBuffer, elementBuffer; - var program, attributes, uniforms; + return this; - var texture; + }, - // decompose matrixWorld + setRGB: function ( r, g, b ) { - var spritePosition = new Vector3(); - var spriteRotation = new Quaternion(); - var spriteScale = new Vector3(); + this.r = r; + this.g = g; + this.b = b; - function init() { + return this; - var vertices = new Float32Array( [ - - 0.5, - 0.5, 0, 0, - 0.5, - 0.5, 1, 0, - 0.5, 0.5, 1, 1, - - 0.5, 0.5, 0, 1 - ] ); + }, - var faces = new Uint16Array( [ - 0, 1, 2, - 0, 2, 3 - ] ); + setHSL: function () { - vertexBuffer = gl.createBuffer(); - elementBuffer = gl.createBuffer(); + function hue2rgb( p, q, t ) { - gl.bindBuffer( gl.ARRAY_BUFFER, vertexBuffer ); - gl.bufferData( gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW ); + 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; - gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, elementBuffer ); - gl.bufferData( gl.ELEMENT_ARRAY_BUFFER, faces, gl.STATIC_DRAW ); + } - program = createProgram(); + return function setHSL( h, s, l ) { - attributes = { - position: gl.getAttribLocation( program, 'position' ), - uv: gl.getAttribLocation( program, 'uv' ) - }; + // 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 ); - uniforms = { - uvOffset: gl.getUniformLocation( program, 'uvOffset' ), - uvScale: gl.getUniformLocation( program, 'uvScale' ), + if ( s === 0 ) { - rotation: gl.getUniformLocation( program, 'rotation' ), - center: gl.getUniformLocation( program, 'center' ), - scale: gl.getUniformLocation( program, 'scale' ), + this.r = this.g = this.b = l; - color: gl.getUniformLocation( program, 'color' ), - map: gl.getUniformLocation( program, 'map' ), - opacity: gl.getUniformLocation( program, 'opacity' ), + } else { - modelViewMatrix: gl.getUniformLocation( program, 'modelViewMatrix' ), - projectionMatrix: gl.getUniformLocation( program, 'projectionMatrix' ), + var p = l <= 0.5 ? l * ( 1 + s ) : l + s - ( l * s ); + var q = ( 2 * l ) - p; - fogType: gl.getUniformLocation( program, 'fogType' ), - fogDensity: gl.getUniformLocation( program, 'fogDensity' ), - fogNear: gl.getUniformLocation( program, 'fogNear' ), - fogFar: gl.getUniformLocation( program, 'fogFar' ), - fogColor: gl.getUniformLocation( program, 'fogColor' ), - fogDepth: gl.getUniformLocation( program, 'fogDepth' ), + this.r = hue2rgb( q, p, h + 1 / 3 ); + this.g = hue2rgb( q, p, h ); + this.b = hue2rgb( q, p, h - 1 / 3 ); - alphaTest: gl.getUniformLocation( program, 'alphaTest' ) - }; + } - var canvas = document.createElementNS( 'http://www.w3.org/1999/xhtml', 'canvas' ); - canvas.width = 8; - canvas.height = 8; + return this; - var context = canvas.getContext( '2d' ); - context.fillStyle = 'white'; - context.fillRect( 0, 0, 8, 8 ); + }; - texture = new CanvasTexture( canvas ); + }(), - } + setStyle: function ( style ) { - this.render = function ( sprites, scene, camera ) { + function handleAlpha( string ) { - if ( sprites.length === 0 ) return; + if ( string === undefined ) return; - // setup gl + if ( parseFloat( string ) < 1 ) { - if ( program === undefined ) { + console.warn( 'THREE.Color: Alpha component of ' + style + ' will be ignored.' ); - init(); + } } - state.useProgram( program ); - state.initAttributes(); - state.enableAttribute( attributes.position ); - state.enableAttribute( attributes.uv ); - state.disableUnusedAttributes(); + var m; - state.disable( gl.CULL_FACE ); - state.enable( gl.BLEND ); + if ( m = /^((?:rgb|hsl)a?)\(\s*([^\)]*)\)/.exec( style ) ) { - gl.bindBuffer( gl.ARRAY_BUFFER, vertexBuffer ); - gl.vertexAttribPointer( attributes.position, 2, gl.FLOAT, false, 2 * 8, 0 ); - gl.vertexAttribPointer( attributes.uv, 2, gl.FLOAT, false, 2 * 8, 8 ); + // rgb / hsl - gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, elementBuffer ); + var color; + var name = m[ 1 ]; + var components = m[ 2 ]; - gl.uniformMatrix4fv( uniforms.projectionMatrix, false, camera.projectionMatrix.elements ); + switch ( name ) { - state.activeTexture( gl.TEXTURE0 ); - gl.uniform1i( uniforms.map, 0 ); + case 'rgb': + case 'rgba': - var oldFogType = 0; - var sceneFogType = 0; - var fog = scene.fog; + if ( color = /^(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(,\s*([0-9]*\.?[0-9]+)\s*)?$/.exec( components ) ) { - if ( fog ) { + // 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; - gl.uniform3f( uniforms.fogColor, fog.color.r, fog.color.g, fog.color.b ); + handleAlpha( color[ 5 ] ); - if ( fog.isFog ) { + return this; - gl.uniform1f( uniforms.fogNear, fog.near ); - gl.uniform1f( uniforms.fogFar, fog.far ); + } - gl.uniform1i( uniforms.fogType, 1 ); - oldFogType = 1; - sceneFogType = 1; + if ( color = /^(\d+)\%\s*,\s*(\d+)\%\s*,\s*(\d+)\%\s*(,\s*([0-9]*\.?[0-9]+)\s*)?$/.exec( components ) ) { - } else if ( fog.isFogExp2 ) { + // 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; - gl.uniform1f( uniforms.fogDensity, fog.density ); + handleAlpha( color[ 5 ] ); - gl.uniform1i( uniforms.fogType, 2 ); - oldFogType = 2; - sceneFogType = 2; + return this; - } + } - } else { + break; - gl.uniform1i( uniforms.fogType, 0 ); - oldFogType = 0; - sceneFogType = 0; + 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 ) ) { + // 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; - // update positions and sort + handleAlpha( color[ 5 ] ); - for ( var i = 0, l = sprites.length; i < l; i ++ ) { + return this.setHSL( h, s, l ); - var sprite = sprites[ i ]; + } - sprite.modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, sprite.matrixWorld ); - sprite.z = - sprite.modelViewMatrix.elements[ 14 ]; + break; - } + } - sprites.sort( painterSortStable ); + } else if ( m = /^\#([A-Fa-f0-9]+)$/.exec( style ) ) { - // render all sprites + // hex color - var scale = []; - var center = []; + var hex = m[ 1 ]; + var size = hex.length; - for ( var i = 0, l = sprites.length; i < l; i ++ ) { + if ( size === 3 ) { - var sprite = sprites[ i ]; - var material = sprite.material; + // #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; - if ( material.visible === false ) continue; + return this; - sprite.onBeforeRender( renderer, scene, camera, undefined, material, undefined ); + } else if ( size === 6 ) { - gl.uniform1f( uniforms.alphaTest, material.alphaTest ); - gl.uniformMatrix4fv( uniforms.modelViewMatrix, false, sprite.modelViewMatrix.elements ); + // #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; - sprite.matrixWorld.decompose( spritePosition, spriteRotation, spriteScale ); + return this; - scale[ 0 ] = spriteScale.x; - scale[ 1 ] = spriteScale.y; + } - center[ 0 ] = sprite.center.x - 0.5; - center[ 1 ] = sprite.center.y - 0.5; + } - var fogType = 0; + if ( style && style.length > 0 ) { - if ( scene.fog && material.fog ) { + // color keywords + var hex = ColorKeywords[ style ]; - fogType = sceneFogType; + if ( hex !== undefined ) { - } + // red + this.setHex( hex ); - if ( oldFogType !== fogType ) { + } else { - gl.uniform1i( uniforms.fogType, fogType ); - oldFogType = fogType; + // unknown color + console.warn( 'THREE.Color: Unknown color ' + style ); } - if ( material.map !== null ) { + } - gl.uniform2f( uniforms.uvOffset, material.map.offset.x, material.map.offset.y ); - gl.uniform2f( uniforms.uvScale, material.map.repeat.x, material.map.repeat.y ); + return this; - } else { + }, - gl.uniform2f( uniforms.uvOffset, 0, 0 ); - gl.uniform2f( uniforms.uvScale, 1, 1 ); + clone: function () { - } + return new this.constructor( this.r, this.g, this.b ); - gl.uniform1f( uniforms.opacity, material.opacity ); - gl.uniform3f( uniforms.color, material.color.r, material.color.g, material.color.b ); + }, - gl.uniform1f( uniforms.rotation, material.rotation ); - gl.uniform2fv( uniforms.center, center ); - gl.uniform2fv( uniforms.scale, scale ); + copy: function ( color ) { - state.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst, material.blendEquationAlpha, material.blendSrcAlpha, material.blendDstAlpha, material.premultipliedAlpha ); - state.buffers.depth.setTest( material.depthTest ); - state.buffers.depth.setMask( material.depthWrite ); - state.buffers.color.setMask( material.colorWrite ); + this.r = color.r; + this.g = color.g; + this.b = color.b; - textures.setTexture2D( material.map || texture, 0 ); + return this; - gl.drawElements( gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0 ); + }, - sprite.onAfterRender( renderer, scene, camera, undefined, material, undefined ); + copyGammaToLinear: function ( color, gammaFactor ) { - } + if ( gammaFactor === undefined ) gammaFactor = 2.0; - // restore gl + this.r = Math.pow( color.r, gammaFactor ); + this.g = Math.pow( color.g, gammaFactor ); + this.b = Math.pow( color.b, gammaFactor ); - state.enable( gl.CULL_FACE ); + return this; - state.reset(); + }, - }; + copyLinearToGamma: function ( color, gammaFactor ) { - function createProgram() { + if ( gammaFactor === undefined ) gammaFactor = 2.0; - var program = gl.createProgram(); + var safeInverse = ( gammaFactor > 0 ) ? ( 1.0 / gammaFactor ) : 1.0; - var vertexShader = gl.createShader( gl.VERTEX_SHADER ); - var fragmentShader = gl.createShader( gl.FRAGMENT_SHADER ); + this.r = Math.pow( color.r, safeInverse ); + this.g = Math.pow( color.g, safeInverse ); + this.b = Math.pow( color.b, safeInverse ); - gl.shaderSource( vertexShader, [ + return this; - 'precision ' + capabilities.precision + ' float;', + }, - '#define SHADER_NAME ' + 'SpriteMaterial', + convertGammaToLinear: function ( gammaFactor ) { - 'uniform mat4 modelViewMatrix;', - 'uniform mat4 projectionMatrix;', - 'uniform float rotation;', - 'uniform vec2 center;', - 'uniform vec2 scale;', - 'uniform vec2 uvOffset;', - 'uniform vec2 uvScale;', + this.copyGammaToLinear( this, gammaFactor ); - 'attribute vec2 position;', - 'attribute vec2 uv;', + return this; - 'varying vec2 vUV;', - 'varying float fogDepth;', + }, - 'void main() {', + convertLinearToGamma: function ( gammaFactor ) { - ' vUV = uvOffset + uv * uvScale;', + this.copyLinearToGamma( this, gammaFactor ); - ' vec2 alignedPosition = ( position - center ) * scale;', + return this; - ' vec2 rotatedPosition;', - ' rotatedPosition.x = cos( rotation ) * alignedPosition.x - sin( rotation ) * alignedPosition.y;', - ' rotatedPosition.y = sin( rotation ) * alignedPosition.x + cos( rotation ) * alignedPosition.y;', + }, - ' vec4 mvPosition;', + copySRGBToLinear: function () { - ' mvPosition = modelViewMatrix * vec4( 0.0, 0.0, 0.0, 1.0 );', - ' mvPosition.xy += rotatedPosition;', + function SRGBToLinear( c ) { - ' gl_Position = projectionMatrix * mvPosition;', + return ( c < 0.04045 ) ? c * 0.0773993808 : Math.pow( c * 0.9478672986 + 0.0521327014, 2.4 ); - ' fogDepth = - mvPosition.z;', + } - '}' + return function copySRGBToLinear( color ) { - ].join( '\n' ) ); + this.r = SRGBToLinear( color.r ); + this.g = SRGBToLinear( color.g ); + this.b = SRGBToLinear( color.b ); - gl.shaderSource( fragmentShader, [ + return this; - 'precision ' + capabilities.precision + ' float;', + }; - '#define SHADER_NAME ' + 'SpriteMaterial', + }(), - 'uniform vec3 color;', - 'uniform sampler2D map;', - 'uniform float opacity;', + copyLinearToSRGB: function () { - 'uniform int fogType;', - 'uniform vec3 fogColor;', - 'uniform float fogDensity;', - 'uniform float fogNear;', - 'uniform float fogFar;', - 'uniform float alphaTest;', + function LinearToSRGB( c ) { - 'varying vec2 vUV;', - 'varying float fogDepth;', + return ( c < 0.0031308 ) ? c * 12.92 : 1.055 * ( Math.pow( c, 0.41666 ) ) - 0.055; - 'void main() {', + } - ' vec4 texture = texture2D( map, vUV );', + return function copyLinearToSRGB( color ) { - ' gl_FragColor = vec4( color * texture.xyz, texture.a * opacity );', + this.r = LinearToSRGB( color.r ); + this.g = LinearToSRGB( color.g ); + this.b = LinearToSRGB( color.b ); - ' if ( gl_FragColor.a < alphaTest ) discard;', + return this; - ' if ( fogType > 0 ) {', + }; - ' float fogFactor = 0.0;', + }(), - ' if ( fogType == 1 ) {', + convertSRGBToLinear: function () { - ' fogFactor = smoothstep( fogNear, fogFar, fogDepth );', + this.copySRGBToLinear( this ); - ' } else {', + return this; - ' const float LOG2 = 1.442695;', - ' fogFactor = exp2( - fogDensity * fogDensity * fogDepth * fogDepth * LOG2 );', - ' fogFactor = 1.0 - clamp( fogFactor, 0.0, 1.0 );', + }, - ' }', + convertLinearToSRGB: function () { - ' gl_FragColor.rgb = mix( gl_FragColor.rgb, fogColor, fogFactor );', + this.copyLinearToSRGB( this ); - ' }', + return this; - '}' + }, - ].join( '\n' ) ); + getHex: function () { - gl.compileShader( vertexShader ); - gl.compileShader( fragmentShader ); + return ( this.r * 255 ) << 16 ^ ( this.g * 255 ) << 8 ^ ( this.b * 255 ) << 0; - gl.attachShader( program, vertexShader ); - gl.attachShader( program, fragmentShader ); + }, - gl.linkProgram( program ); + getHexString: function () { - return program; + return ( '000000' + this.getHex().toString( 16 ) ).slice( - 6 ); - } + }, - function painterSortStable( a, b ) { + getHSL: function ( target ) { - if ( a.renderOrder !== b.renderOrder ) { + // h,s,l ranges are in 0.0 - 1.0 - return a.renderOrder - b.renderOrder; + if ( target === undefined ) { - } else if ( a.z !== b.z ) { + console.warn( 'THREE.Color: .getHSL() target is now required' ); + target = { h: 0, s: 0, l: 0 }; - return b.z - a.z; + } - } else { + var r = this.r, g = this.g, b = this.b; - return b.id - a.id; + var max = Math.max( r, g, b ); + var min = Math.min( r, g, b ); - } + var hue, saturation; + var lightness = ( min + max ) / 2.0; - } + if ( min === max ) { -} + hue = 0; + saturation = 0; -/** - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - */ + } else { -var materialId = 0; + var delta = max - min; -function Material() { + saturation = lightness <= 0.5 ? delta / ( max + min ) : delta / ( 2 - max - min ); - Object.defineProperty( this, 'id', { value: materialId ++ } ); + switch ( max ) { - this.uuid = _Math.generateUUID(); + 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; - this.name = ''; - this.type = 'Material'; + } - this.fog = true; - this.lights = true; + hue /= 6; - this.blending = NormalBlending; - this.side = FrontSide; - this.flatShading = false; - this.vertexColors = NoColors; // THREE.NoColors, THREE.VertexColors, THREE.FaceColors + } - this.opacity = 1; - this.transparent = false; + target.h = hue; + target.s = saturation; + target.l = lightness; - this.blendSrc = SrcAlphaFactor; - this.blendDst = OneMinusSrcAlphaFactor; - this.blendEquation = AddEquation; - this.blendSrcAlpha = null; - this.blendDstAlpha = null; - this.blendEquationAlpha = null; + return target; - this.depthFunc = LessEqualDepth; - this.depthTest = true; - this.depthWrite = true; + }, - this.clippingPlanes = null; - this.clipIntersection = false; - this.clipShadows = false; + getStyle: function () { - this.shadowSide = null; + return 'rgb(' + ( ( this.r * 255 ) | 0 ) + ',' + ( ( this.g * 255 ) | 0 ) + ',' + ( ( this.b * 255 ) | 0 ) + ')'; - this.colorWrite = true; + }, - this.precision = null; // override the renderer's default precision for this material + offsetHSL: function () { - this.polygonOffset = false; - this.polygonOffsetFactor = 0; - this.polygonOffsetUnits = 0; + var hsl = {}; - this.dithering = false; + return function ( h, s, l ) { - this.alphaTest = 0; - this.premultipliedAlpha = false; + this.getHSL( hsl ); - this.overdraw = 0; // Overdrawn pixels (typically between 0 and 1) for fixing antialiasing gaps in CanvasRenderer + hsl.h += h; hsl.s += s; hsl.l += l; - this.visible = true; + this.setHSL( hsl.h, hsl.s, hsl.l ); - this.userData = {}; + return this; - this.needsUpdate = true; + }; -} + }(), -Material.prototype = Object.assign( Object.create( EventDispatcher.prototype ), { + add: function ( color ) { - constructor: Material, - - isMaterial: true, + this.r += color.r; + this.g += color.g; + this.b += color.b; - onBeforeCompile: function () {}, + return this; - setValues: function ( values ) { + }, - if ( values === undefined ) return; + addColors: function ( color1, color2 ) { - for ( var key in values ) { + this.r = color1.r + color2.r; + this.g = color1.g + color2.g; + this.b = color1.b + color2.b; - var newValue = values[ key ]; + return this; - if ( newValue === undefined ) { + }, - console.warn( "THREE.Material: '" + key + "' parameter is undefined." ); - continue; + addScalar: function ( s ) { - } + this.r += s; + this.g += s; + this.b += s; - // for backward compatability if shading is set in the constructor - if ( key === 'shading' ) { + return this; - console.warn( 'THREE.' + this.type + ': .shading has been removed. Use the boolean .flatShading instead.' ); - this.flatShading = ( newValue === FlatShading ) ? true : false; - continue; + }, - } + sub: function ( color ) { - var currentValue = this[ key ]; + 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 ( currentValue === undefined ) { + return this; - console.warn( "THREE." + this.type + ": '" + key + "' is not a property of this material." ); - continue; + }, - } + multiply: function ( color ) { - if ( currentValue && currentValue.isColor ) { + this.r *= color.r; + this.g *= color.g; + this.b *= color.b; - currentValue.set( newValue ); + return this; - } else if ( ( currentValue && currentValue.isVector3 ) && ( newValue && newValue.isVector3 ) ) { + }, - currentValue.copy( newValue ); + multiplyScalar: function ( s ) { - } else if ( key === 'overdraw' ) { + this.r *= s; + this.g *= s; + this.b *= s; - // ensure overdraw is backwards-compatible with legacy boolean type - this[ key ] = Number( newValue ); + return this; - } else { + }, - this[ key ] = newValue; + lerp: function ( color, alpha ) { - } + this.r += ( color.r - this.r ) * alpha; + this.g += ( color.g - this.g ) * alpha; + this.b += ( color.b - this.b ) * alpha; - } + return this; }, - toJSON: function ( meta ) { + lerpHSL: function () { - var isRoot = ( meta === undefined || typeof meta === 'string' ); + var hslA = { h: 0, s: 0, l: 0 }; + var hslB = { h: 0, s: 0, l: 0 }; - if ( isRoot ) { + return function lerpHSL( color, alpha ) { - meta = { - textures: {}, - images: {} - }; + this.getHSL( hslA ); + color.getHSL( hslB ); - } + 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 ); + + this.setHSL( h, s, l ); + + return this; - var data = { - metadata: { - version: 4.5, - type: 'Material', - generator: 'Material.toJSON' - } }; - // standard Material serialization - data.uuid = this.uuid; - data.type = this.type; + }(), - if ( this.name !== '' ) data.name = this.name; + equals: function ( c ) { - if ( this.color && this.color.isColor ) data.color = this.color.getHex(); + return ( c.r === this.r ) && ( c.g === this.g ) && ( c.b === this.b ); - if ( this.roughness !== undefined ) data.roughness = this.roughness; - if ( this.metalness !== undefined ) data.metalness = this.metalness; + }, - if ( this.emissive && this.emissive.isColor ) data.emissive = this.emissive.getHex(); - if ( this.emissiveIntensity !== 1 ) data.emissiveIntensity = this.emissiveIntensity; + fromArray: function ( array, offset ) { - 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; + if ( offset === undefined ) offset = 0; - 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; - if ( this.bumpMap && this.bumpMap.isTexture ) { + this.r = array[ offset ]; + this.g = array[ offset + 1 ]; + this.b = array[ offset + 2 ]; - data.bumpMap = this.bumpMap.toJSON( meta ).uuid; - data.bumpScale = this.bumpScale; + return this; - } - if ( this.normalMap && this.normalMap.isTexture ) { + }, - data.normalMap = this.normalMap.toJSON( meta ).uuid; - data.normalScale = this.normalScale.toArray(); + toArray: function ( array, offset ) { - } - if ( this.displacementMap && this.displacementMap.isTexture ) { + if ( array === undefined ) array = []; + if ( offset === undefined ) offset = 0; - data.displacementMap = this.displacementMap.toJSON( meta ).uuid; - data.displacementScale = this.displacementScale; - data.displacementBias = this.displacementBias; + array[ offset ] = this.r; + array[ offset + 1 ] = this.g; + array[ offset + 2 ] = this.b; - } - 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; + return array; - if ( this.emissiveMap && this.emissiveMap.isTexture ) data.emissiveMap = this.emissiveMap.toJSON( meta ).uuid; - if ( this.specularMap && this.specularMap.isTexture ) data.specularMap = this.specularMap.toJSON( meta ).uuid; + }, - if ( this.envMap && this.envMap.isTexture ) { + toJSON: function () { - data.envMap = this.envMap.toJSON( meta ).uuid; - data.reflectivity = this.reflectivity; // Scale behind envMap + return this.getHex(); - } + } - if ( this.gradientMap && this.gradientMap.isTexture ) { +} ); - data.gradientMap = this.gradientMap.toJSON( meta ).uuid; +/** + * Uniforms library for shared webgl shaders + */ - } +var UniformsLib = { - if ( this.size !== undefined ) data.size = this.size; - if ( this.sizeAttenuation !== undefined ) data.sizeAttenuation = this.sizeAttenuation; + common: { - 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; + diffuse: { value: new Color( 0xeeeeee ) }, + opacity: { value: 1.0 }, - if ( this.opacity < 1 ) data.opacity = this.opacity; - if ( this.transparent === true ) data.transparent = this.transparent; + map: { value: null }, + uvTransform: { value: new Matrix3() }, - data.depthFunc = this.depthFunc; - data.depthTest = this.depthTest; - data.depthWrite = this.depthWrite; + alphaMap: { value: null }, - // rotation (SpriteMaterial) - if ( this.rotation !== 0 ) data.rotation = this.rotation; + }, - 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; + specularmap: { - if ( this.dithering === true ) data.dithering = true; + specularMap: { value: null }, - if ( this.alphaTest > 0 ) data.alphaTest = this.alphaTest; - if ( this.premultipliedAlpha === true ) data.premultipliedAlpha = this.premultipliedAlpha; + }, - if ( this.wireframe === true ) data.wireframe = this.wireframe; - if ( this.wireframeLinewidth > 1 ) data.wireframeLinewidth = this.wireframeLinewidth; - if ( this.wireframeLinecap !== 'round' ) data.wireframeLinecap = this.wireframeLinecap; - if ( this.wireframeLinejoin !== 'round' ) data.wireframeLinejoin = this.wireframeLinejoin; + envmap: { - if ( this.morphTargets === true ) data.morphTargets = true; - if ( this.skinning === true ) data.skinning = true; + envMap: { value: null }, + flipEnvMap: { value: - 1 }, + reflectivity: { value: 1.0 }, + refractionRatio: { value: 0.98 }, + maxMipLevel: { value: 0 } - if ( this.visible === false ) data.visible = false; - if ( JSON.stringify( this.userData ) !== '{}' ) data.userData = this.userData; + }, - // TODO: Copied from Object3D.toJSON + aomap: { - function extractFromCache( cache ) { + aoMap: { value: null }, + aoMapIntensity: { value: 1 } - var values = []; + }, - for ( var key in cache ) { + lightmap: { - var data = cache[ key ]; - delete data.metadata; - values.push( data ); + lightMap: { value: null }, + lightMapIntensity: { value: 1 } - } + }, - return values; + emissivemap: { - } + emissiveMap: { value: null } - if ( isRoot ) { + }, - var textures = extractFromCache( meta.textures ); - var images = extractFromCache( meta.images ); + bumpmap: { - if ( textures.length > 0 ) data.textures = textures; - if ( images.length > 0 ) data.images = images; + bumpMap: { value: null }, + bumpScale: { value: 1 } - } + }, - return data; + normalmap: { + + normalMap: { value: null }, + normalScale: { value: new Vector2( 1, 1 ) } }, - clone: function () { + displacementmap: { - return new this.constructor().copy( this ); + displacementMap: { value: null }, + displacementScale: { value: 1 }, + displacementBias: { value: 0 } }, - copy: function ( source ) { + roughnessmap: { - this.name = source.name; + roughnessMap: { value: null } - this.fog = source.fog; - this.lights = source.lights; + }, - this.blending = source.blending; - this.side = source.side; - this.flatShading = source.flatShading; - this.vertexColors = source.vertexColors; + metalnessmap: { - this.opacity = source.opacity; - this.transparent = source.transparent; + metalnessMap: { value: null } - this.blendSrc = source.blendSrc; - this.blendDst = source.blendDst; - this.blendEquation = source.blendEquation; - this.blendSrcAlpha = source.blendSrcAlpha; - this.blendDstAlpha = source.blendDstAlpha; - this.blendEquationAlpha = source.blendEquationAlpha; + }, - this.depthFunc = source.depthFunc; - this.depthTest = source.depthTest; - this.depthWrite = source.depthWrite; + gradientmap: { - this.colorWrite = source.colorWrite; + gradientMap: { value: null } - this.precision = source.precision; + }, - this.polygonOffset = source.polygonOffset; - this.polygonOffsetFactor = source.polygonOffsetFactor; - this.polygonOffsetUnits = source.polygonOffsetUnits; + fog: { - this.dithering = source.dithering; + fogDensity: { value: 0.00025 }, + fogNear: { value: 1 }, + fogFar: { value: 2000 }, + fogColor: { value: new Color( 0xffffff ) } - this.alphaTest = source.alphaTest; - this.premultipliedAlpha = source.premultipliedAlpha; + }, - this.overdraw = source.overdraw; + lights: { - this.visible = source.visible; - this.userData = JSON.parse( JSON.stringify( source.userData ) ); + ambientLightColor: { value: [] }, - this.clipShadows = source.clipShadows; - this.clipIntersection = source.clipIntersection; + directionalLights: { value: [], properties: { + direction: {}, + color: {}, - var srcPlanes = source.clippingPlanes, - dstPlanes = null; + shadow: {}, + shadowBias: {}, + shadowRadius: {}, + shadowMapSize: {} + } }, - if ( srcPlanes !== null ) { + directionalShadowMap: { value: [] }, + directionalShadowMatrix: { value: [] }, - var n = srcPlanes.length; - dstPlanes = new Array( n ); + spotLights: { value: [], properties: { + color: {}, + position: {}, + direction: {}, + distance: {}, + coneCos: {}, + penumbraCos: {}, + decay: {}, - for ( var i = 0; i !== n; ++ i ) - dstPlanes[ i ] = srcPlanes[ i ].clone(); + shadow: {}, + shadowBias: {}, + shadowRadius: {}, + shadowMapSize: {} + } }, - } + spotShadowMap: { value: [] }, + spotShadowMatrix: { value: [] }, - this.clippingPlanes = dstPlanes; + pointLights: { value: [], properties: { + color: {}, + position: {}, + decay: {}, + distance: {}, - this.shadowSide = source.shadowSide; + shadow: {}, + shadowBias: {}, + shadowRadius: {}, + shadowMapSize: {}, + shadowCameraNear: {}, + shadowCameraFar: {} + } }, - return this; + 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: {} + } } }, - dispose: function () { + points: { - this.dispatchEvent( { type: 'dispose' } ); + 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: { + + 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() } } -} ); +}; /** - * @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: - * } + * @author mrdoob / http://mrdoob.com/ + * @author mikael emtinger / http://gomo.se/ */ -function MeshDepthMaterial( parameters ) { +var ShaderLib = { - Material.call( this ); + basic: { - this.type = 'MeshDepthMaterial'; + uniforms: mergeUniforms( [ + UniformsLib.common, + UniformsLib.specularmap, + UniformsLib.envmap, + UniformsLib.aomap, + UniformsLib.lightmap, + UniformsLib.fog + ] ), - this.depthPacking = BasicDepthPacking; + vertexShader: ShaderChunk.meshbasic_vert, + fragmentShader: ShaderChunk.meshbasic_frag - this.skinning = false; - this.morphTargets = false; + }, - this.map = null; + lambert: { - this.alphaMap = null; + uniforms: mergeUniforms( [ + UniformsLib.common, + UniformsLib.specularmap, + UniformsLib.envmap, + UniformsLib.aomap, + UniformsLib.lightmap, + UniformsLib.emissivemap, + UniformsLib.fog, + UniformsLib.lights, + { + emissive: { value: new Color( 0x000000 ) } + } + ] ), - this.displacementMap = null; - this.displacementScale = 1; - this.displacementBias = 0; + vertexShader: ShaderChunk.meshlambert_vert, + fragmentShader: ShaderChunk.meshlambert_frag - this.wireframe = false; - this.wireframeLinewidth = 1; + }, - this.fog = false; - this.lights = false; + phong: { - this.setValues( parameters ); + uniforms: mergeUniforms( [ + 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 } + } + ] ), -} + vertexShader: ShaderChunk.meshphong_vert, + fragmentShader: ShaderChunk.meshphong_frag -MeshDepthMaterial.prototype = Object.create( Material.prototype ); -MeshDepthMaterial.prototype.constructor = MeshDepthMaterial; + }, -MeshDepthMaterial.prototype.isMeshDepthMaterial = true; + standard: { -MeshDepthMaterial.prototype.copy = function ( source ) { + 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: 0.5 }, + metalness: { value: 0.5 }, + envMapIntensity: { value: 1 } // temporary + } + ] ), - Material.prototype.copy.call( this, source ); + vertexShader: ShaderChunk.meshphysical_vert, + fragmentShader: ShaderChunk.meshphysical_frag - this.depthPacking = source.depthPacking; + }, - this.skinning = source.skinning; - this.morphTargets = source.morphTargets; + matcap: { - this.map = source.map; + uniforms: mergeUniforms( [ + UniformsLib.common, + UniformsLib.bumpmap, + UniformsLib.normalmap, + UniformsLib.displacementmap, + UniformsLib.fog, + { + matcap: { value: null } + } + ] ), - this.alphaMap = source.alphaMap; + vertexShader: ShaderChunk.meshmatcap_vert, + fragmentShader: ShaderChunk.meshmatcap_frag - this.displacementMap = source.displacementMap; - this.displacementScale = source.displacementScale; - this.displacementBias = source.displacementBias; + }, - this.wireframe = source.wireframe; - this.wireframeLinewidth = source.wireframeLinewidth; + points: { - return this; + uniforms: mergeUniforms( [ + UniformsLib.points, + UniformsLib.fog + ] ), -}; + vertexShader: ShaderChunk.points_vert, + fragmentShader: ShaderChunk.points_frag -/** - * @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: - * - * } - */ + }, -function MeshDistanceMaterial( parameters ) { + dashed: { - Material.call( this ); + uniforms: mergeUniforms( [ + UniformsLib.common, + UniformsLib.fog, + { + scale: { value: 1 }, + dashSize: { value: 1 }, + totalSize: { value: 2 } + } + ] ), - this.type = 'MeshDistanceMaterial'; + vertexShader: ShaderChunk.linedashed_vert, + fragmentShader: ShaderChunk.linedashed_frag - this.referencePosition = new Vector3(); - this.nearDistance = 1; - this.farDistance = 1000; + }, - this.skinning = false; - this.morphTargets = false; + depth: { - this.map = null; + uniforms: mergeUniforms( [ + UniformsLib.common, + UniformsLib.displacementmap + ] ), - this.alphaMap = null; + vertexShader: ShaderChunk.depth_vert, + fragmentShader: ShaderChunk.depth_frag - this.displacementMap = null; - this.displacementScale = 1; - this.displacementBias = 0; + }, - this.fog = false; - this.lights = false; + normal: { - this.setValues( parameters ); + uniforms: mergeUniforms( [ + UniformsLib.common, + UniformsLib.bumpmap, + UniformsLib.normalmap, + UniformsLib.displacementmap, + { + opacity: { value: 1.0 } + } + ] ), -} + vertexShader: ShaderChunk.normal_vert, + fragmentShader: ShaderChunk.normal_frag -MeshDistanceMaterial.prototype = Object.create( Material.prototype ); -MeshDistanceMaterial.prototype.constructor = MeshDistanceMaterial; + }, -MeshDistanceMaterial.prototype.isMeshDistanceMaterial = true; + sprite: { -MeshDistanceMaterial.prototype.copy = function ( source ) { + uniforms: mergeUniforms( [ + UniformsLib.sprite, + UniformsLib.fog + ] ), - Material.prototype.copy.call( this, source ); + vertexShader: ShaderChunk.sprite_vert, + fragmentShader: ShaderChunk.sprite_frag - this.referencePosition.copy( source.referencePosition ); - this.nearDistance = source.nearDistance; - this.farDistance = source.farDistance; + }, - this.skinning = source.skinning; - this.morphTargets = source.morphTargets; + background: { - this.map = source.map; + uniforms: { + uvTransform: { value: new Matrix3() }, + t2D: { value: null }, + }, - this.alphaMap = source.alphaMap; + vertexShader: ShaderChunk.background_vert, + fragmentShader: ShaderChunk.background_frag - this.displacementMap = source.displacementMap; - this.displacementScale = source.displacementScale; - this.displacementBias = source.displacementBias; + }, + /* ------------------------------------------------------------------------- + // Cube map shader + ------------------------------------------------------------------------- */ - return this; + cube: { -}; + uniforms: { + tCube: { value: null }, + tFlip: { value: - 1 }, + opacity: { value: 1.0 } + }, -/** - * @author bhouston / http://clara.io - * @author WestLangley / http://github.com/WestLangley - */ + vertexShader: ShaderChunk.cube_vert, + fragmentShader: ShaderChunk.cube_frag -function Box3( min, max ) { + }, - this.min = ( min !== undefined ) ? min : new Vector3( + Infinity, + Infinity, + Infinity ); - this.max = ( max !== undefined ) ? max : new Vector3( - Infinity, - Infinity, - Infinity ); + equirect: { -} + uniforms: { + tEquirect: { value: null }, + }, -Object.assign( Box3.prototype, { + vertexShader: ShaderChunk.equirect_vert, + fragmentShader: ShaderChunk.equirect_frag - isBox3: true, + }, - set: function ( min, max ) { + distanceRGBA: { - this.min.copy( min ); - this.max.copy( max ); + uniforms: mergeUniforms( [ + UniformsLib.common, + UniformsLib.displacementmap, + { + referencePosition: { value: new Vector3() }, + nearDistance: { value: 1 }, + farDistance: { value: 1000 } + } + ] ), - return this; + vertexShader: ShaderChunk.distanceRGBA_vert, + fragmentShader: ShaderChunk.distanceRGBA_frag }, - setFromArray: function ( array ) { - - var minX = + Infinity; - var minY = + Infinity; - var minZ = + Infinity; + shadow: { - var maxX = - Infinity; - var maxY = - Infinity; - var maxZ = - Infinity; + uniforms: mergeUniforms( [ + UniformsLib.lights, + UniformsLib.fog, + { + color: { value: new Color( 0x00000 ) }, + opacity: { value: 1.0 } + }, + ] ), - for ( var i = 0, l = array.length; i < l; i += 3 ) { + vertexShader: ShaderChunk.shadow_vert, + fragmentShader: ShaderChunk.shadow_frag - var x = array[ i ]; - var y = array[ i + 1 ]; - var z = array[ i + 2 ]; + } - if ( x < minX ) minX = x; - if ( y < minY ) minY = y; - if ( z < minZ ) minZ = z; +}; - if ( x > maxX ) maxX = x; - if ( y > maxY ) maxY = y; - if ( z > maxZ ) maxZ = z; +ShaderLib.physical = { + uniforms: mergeUniforms( [ + ShaderLib.standard.uniforms, + { + clearCoat: { value: 0 }, + clearCoatRoughness: { value: 0 } } + ] ), - this.min.set( minX, minY, minZ ); - this.max.set( maxX, maxY, maxZ ); + vertexShader: ShaderChunk.meshphysical_vert, + fragmentShader: ShaderChunk.meshphysical_frag - return this; +}; - }, +/** + * @author mrdoob / http://mrdoob.com/ + */ - setFromBufferAttribute: function ( attribute ) { +function WebGLAnimation() { - var minX = + Infinity; - var minY = + Infinity; - var minZ = + Infinity; + var context = null; + var isAnimating = false; + var animationLoop = null; - var maxX = - Infinity; - var maxY = - Infinity; - var maxZ = - Infinity; + function onAnimationFrame( time, frame ) { - for ( var i = 0, l = attribute.count; i < l; i ++ ) { + if ( isAnimating === false ) return; - var x = attribute.getX( i ); - var y = attribute.getY( i ); - var z = attribute.getZ( i ); + animationLoop( time, frame ); - if ( x < minX ) minX = x; - if ( y < minY ) minY = y; - if ( z < minZ ) minZ = z; + context.requestAnimationFrame( onAnimationFrame ); - if ( x > maxX ) maxX = x; - if ( y > maxY ) maxY = y; - if ( z > maxZ ) maxZ = z; + } - } + return { - this.min.set( minX, minY, minZ ); - this.max.set( maxX, maxY, maxZ ); + start: function () { - return this; + if ( isAnimating === true ) return; + if ( animationLoop === null ) return; - }, + context.requestAnimationFrame( onAnimationFrame ); - setFromPoints: function ( points ) { + isAnimating = true; - this.makeEmpty(); + }, - for ( var i = 0, il = points.length; i < il; i ++ ) { + stop: function () { - this.expandByPoint( points[ i ] ); + isAnimating = false; - } + }, - return this; + setAnimationLoop: function ( callback ) { - }, + animationLoop = callback; - setFromCenterAndSize: function () { + }, - var v1 = new Vector3(); + setContext: function ( value ) { - return function setFromCenterAndSize( center, size ) { + context = value; - var halfSize = v1.copy( size ).multiplyScalar( 0.5 ); + } - this.min.copy( center ).sub( halfSize ); - this.max.copy( center ).add( halfSize ); + }; - return this; +} - }; +/** + * @author mrdoob / http://mrdoob.com/ + */ - }(), +function WebGLAttributes( gl ) { - setFromObject: function ( object ) { + var buffers = new WeakMap(); - this.makeEmpty(); + function createBuffer( attribute, bufferType ) { - return this.expandByObject( object ); + var array = attribute.array; + var usage = attribute.dynamic ? 35048 : 35044; - }, + var buffer = gl.createBuffer(); - clone: function () { + gl.bindBuffer( bufferType, buffer ); + gl.bufferData( bufferType, array, usage ); - return new this.constructor().copy( this ); + attribute.onUploadCallback(); - }, + var type = 5126; - copy: function ( box ) { + if ( array instanceof Float32Array ) { - this.min.copy( box.min ); - this.max.copy( box.max ); + type = 5126; - return this; + } else if ( array instanceof Float64Array ) { - }, + console.warn( 'THREE.WebGLAttributes: Unsupported data buffer format: Float64Array.' ); - makeEmpty: function () { + } else if ( array instanceof Uint16Array ) { - this.min.x = this.min.y = this.min.z = + Infinity; - this.max.x = this.max.y = this.max.z = - Infinity; + type = 5123; - return this; + } else if ( array instanceof Int16Array ) { - }, + type = 5122; - isEmpty: function () { + } else if ( array instanceof Uint32Array ) { - // this is a more robust check for empty than ( volume <= 0 ) because volume can get positive with two negative axes + type = 5125; - return ( this.max.x < this.min.x ) || ( this.max.y < this.min.y ) || ( this.max.z < this.min.z ); + } else if ( array instanceof Int32Array ) { - }, + type = 5124; - getCenter: function ( optionalTarget ) { + } else if ( array instanceof Int8Array ) { - var result = optionalTarget || new Vector3(); - return this.isEmpty() ? result.set( 0, 0, 0 ) : result.addVectors( this.min, this.max ).multiplyScalar( 0.5 ); + type = 5120; - }, + } else if ( array instanceof Uint8Array ) { - getSize: function ( optionalTarget ) { + type = 5121; - var result = optionalTarget || new Vector3(); - return this.isEmpty() ? result.set( 0, 0, 0 ) : result.subVectors( this.max, this.min ); + } - }, + return { + buffer: buffer, + type: type, + bytesPerElement: array.BYTES_PER_ELEMENT, + version: attribute.version + }; - expandByPoint: function ( point ) { + } - this.min.min( point ); - this.max.max( point ); + function updateBuffer( buffer, attribute, bufferType ) { - return this; + var array = attribute.array; + var updateRange = attribute.updateRange; - }, + gl.bindBuffer( bufferType, buffer ); - expandByVector: function ( vector ) { + if ( attribute.dynamic === false ) { - this.min.sub( vector ); - this.max.add( vector ); + gl.bufferData( bufferType, array, 35044 ); - return this; + } else if ( updateRange.count === - 1 ) { - }, + // Not using update ranges - expandByScalar: function ( scalar ) { + gl.bufferSubData( bufferType, 0, array ); - this.min.addScalar( - scalar ); - this.max.addScalar( scalar ); + } else if ( updateRange.count === 0 ) { - return this; + 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.' ); - }, + } else { - expandByObject: function () { + gl.bufferSubData( bufferType, updateRange.offset * array.BYTES_PER_ELEMENT, + array.subarray( updateRange.offset, updateRange.offset + updateRange.count ) ); - // Computes the world-axis-aligned bounding box of an object (including its children), - // accounting for both the object's, and children's, world transforms + updateRange.count = - 1; // reset range - var scope, i, l; + } - var v1 = new Vector3(); + } - function traverse( node ) { + // - var geometry = node.geometry; + function get( attribute ) { - if ( geometry !== undefined ) { + if ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data; - if ( geometry.isGeometry ) { + return buffers.get( attribute ); - var vertices = geometry.vertices; + } - for ( i = 0, l = vertices.length; i < l; i ++ ) { + function remove( attribute ) { - v1.copy( vertices[ i ] ); - v1.applyMatrix4( node.matrixWorld ); + if ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data; - scope.expandByPoint( v1 ); + var data = buffers.get( attribute ); - } + if ( data ) { - } else if ( geometry.isBufferGeometry ) { + gl.deleteBuffer( data.buffer ); - var attribute = geometry.attributes.position; + buffers.delete( attribute ); - if ( attribute !== undefined ) { + } - for ( i = 0, l = attribute.count; i < l; i ++ ) { + } - v1.fromBufferAttribute( attribute, i ).applyMatrix4( node.matrixWorld ); + function update( attribute, bufferType ) { - scope.expandByPoint( v1 ); + if ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data; - } + var data = buffers.get( attribute ); - } + if ( data === undefined ) { - } + buffers.set( attribute, createBuffer( attribute, bufferType ) ); - } + } else if ( data.version < attribute.version ) { - } + updateBuffer( data.buffer, attribute, bufferType ); - return function expandByObject( object ) { + data.version = attribute.version; - scope = this; + } - object.updateMatrixWorld( true ); + } - object.traverse( traverse ); + return { - return this; + get: get, + remove: remove, + update: update - }; + }; - }(), +} - containsPoint: function ( point ) { +/** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + */ - 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; +function Face3( a, b, c, normal, color, materialIndex ) { - }, + this.a = a; + this.b = b; + this.c = c; - containsBox: function ( box ) { + this.normal = ( normal && normal.isVector3 ) ? normal : new Vector3(); + this.vertexNormals = Array.isArray( normal ) ? normal : []; - 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; + this.color = ( color && color.isColor ) ? color : new Color(); + this.vertexColors = Array.isArray( color ) ? color : []; - }, + this.materialIndex = materialIndex !== undefined ? materialIndex : 0; - getParameter: function ( point, optionalTarget ) { +} - // This can potentially have a divide by zero if the box - // has a size dimension of 0. +Object.assign( Face3.prototype, { - var result = optionalTarget || new Vector3(); + clone: function () { - return result.set( - ( point.x - this.min.x ) / ( this.max.x - this.min.x ), - ( point.y - this.min.y ) / ( this.max.y - this.min.y ), - ( point.z - this.min.z ) / ( this.max.z - this.min.z ) - ); + return new this.constructor().copy( this ); }, - intersectsBox: function ( box ) { - - // using 6 splitting planes to rule out intersections. - return box.max.x < this.min.x || box.min.x > this.max.x || - box.max.y < this.min.y || box.min.y > this.max.y || - box.max.z < this.min.z || box.min.z > this.max.z ? false : true; + copy: function ( source ) { - }, + this.a = source.a; + this.b = source.b; + this.c = source.c; - intersectsSphere: ( function () { + this.normal.copy( source.normal ); + this.color.copy( source.color ); - var closestPoint = new Vector3(); + this.materialIndex = source.materialIndex; - return function intersectsSphere( sphere ) { + for ( var i = 0, il = source.vertexNormals.length; i < il; i ++ ) { - // Find the point on the AABB closest to the sphere center. - this.clampPoint( sphere.center, closestPoint ); + this.vertexNormals[ i ] = source.vertexNormals[ i ].clone(); - // If that point is inside the sphere, the AABB and sphere intersect. - return closestPoint.distanceToSquared( sphere.center ) <= ( sphere.radius * sphere.radius ); + } - }; + for ( var i = 0, il = source.vertexColors.length; i < il; i ++ ) { - } )(), + this.vertexColors[ i ] = source.vertexColors[ i ].clone(); - intersectsPlane: function ( plane ) { + } - // We compute the minimum and maximum dot product values. If those values - // are on the same side (back or front) of the plane, then there is no intersection. + return this; - var min, max; + } - if ( plane.normal.x > 0 ) { +} ); - min = plane.normal.x * this.min.x; - max = plane.normal.x * this.max.x; +/** + * @author mrdoob / http://mrdoob.com/ + * @author WestLangley / http://github.com/WestLangley + * @author bhouston / http://clara.io + */ - } else { +function Euler( x, y, z, order ) { - min = plane.normal.x * this.max.x; - max = plane.normal.x * this.min.x; + this._x = x || 0; + this._y = y || 0; + this._z = z || 0; + this._order = order || Euler.DefaultOrder; - } +} - if ( plane.normal.y > 0 ) { +Euler.RotationOrders = [ 'XYZ', 'YZX', 'ZXY', 'XZY', 'YXZ', 'ZYX' ]; - min += plane.normal.y * this.min.y; - max += plane.normal.y * this.max.y; +Euler.DefaultOrder = 'XYZ'; - } else { +Object.defineProperties( Euler.prototype, { - min += plane.normal.y * this.max.y; - max += plane.normal.y * this.min.y; + x: { - } + get: function () { - if ( plane.normal.z > 0 ) { + return this._x; - min += plane.normal.z * this.min.z; - max += plane.normal.z * this.max.z; + }, - } else { + set: function ( value ) { - min += plane.normal.z * this.max.z; - max += plane.normal.z * this.min.z; + this._x = value; + this.onChangeCallback(); } - return ( min <= plane.constant && max >= plane.constant ); - }, - intersectsTriangle: ( function () { + y: { - // triangle centered vertices - var v0 = new Vector3(); - var v1 = new Vector3(); - var v2 = new Vector3(); + get: function () { - // triangle edge vectors - var f0 = new Vector3(); - var f1 = new Vector3(); - var f2 = new Vector3(); + return this._y; - var testAxis = new Vector3(); + }, - var center = new Vector3(); - var extents = new Vector3(); + set: function ( value ) { - var triangleNormal = new Vector3(); + this._y = value; + this.onChangeCallback(); - function satForAxes( axes ) { + } - var i, j; + }, - for ( i = 0, j = axes.length - 3; i <= j; i += 3 ) { + z: { - 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 ) { + get: function () { - // 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 this._z; - } + }, - } + set: function ( value ) { - return true; + this._z = value; + this.onChangeCallback(); } - return function intersectsTriangle( triangle ) { + }, - if ( this.isEmpty() ) { + order: { - return false; + get: function () { - } + return this._order; - // compute box center and extents - this.getCenter( center ); - extents.subVectors( this.max, center ); + }, - // translate triangle to aabb origin - v0.subVectors( triangle.a, center ); - v1.subVectors( triangle.b, center ); - v2.subVectors( triangle.c, center ); + set: function ( value ) { - // compute edge vectors for triangle - f0.subVectors( v1, v0 ); - f1.subVectors( v2, v1 ); - f2.subVectors( v0, v2 ); + this._order = value; + this.onChangeCallback(); - // 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 ) ) { + } - return false; + } - } +} ); - // test 3 face normals from the aabb - axes = [ 1, 0, 0, 0, 1, 0, 0, 0, 1 ]; - if ( ! satForAxes( axes ) ) { +Object.assign( Euler.prototype, { - return false; + isEuler: true, - } + set: function ( x, y, z, order ) { - // 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 ); + this._x = x; + this._y = y; + this._z = z; + this._order = order || this._order; - }; + this.onChangeCallback(); - } )(), + return this; - clampPoint: function ( point, optionalTarget ) { + }, - var result = optionalTarget || new Vector3(); - return result.copy( point ).clamp( this.min, this.max ); + clone: function () { - }, + return new this.constructor( this._x, this._y, this._z, this._order ); - distanceToPoint: function () { + }, - var v1 = new Vector3(); + copy: function ( euler ) { - return function distanceToPoint( point ) { + this._x = euler._x; + this._y = euler._y; + this._z = euler._z; + this._order = euler._order; - var clampedPoint = v1.copy( point ).clamp( this.min, this.max ); - return clampedPoint.sub( point ).length(); + this.onChangeCallback(); - }; + return this; - }(), + }, - getBoundingSphere: function () { + setFromRotationMatrix: function ( m, order, update ) { - var v1 = new Vector3(); + var clamp = _Math.clamp; - return function getBoundingSphere( optionalTarget ) { + // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) - var result = optionalTarget || new Sphere(); + 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.getCenter( result.center ); + order = order || this._order; - result.radius = this.getSize( v1 ).length() * 0.5; + if ( order === 'XYZ' ) { - return result; + this._y = Math.asin( clamp( m13, - 1, 1 ) ); - }; + if ( Math.abs( m13 ) < 0.99999 ) { - }(), + this._x = Math.atan2( - m23, m33 ); + this._z = Math.atan2( - m12, m11 ); - intersect: function ( box ) { + } else { - this.min.max( box.min ); - this.max.min( box.max ); + this._x = Math.atan2( m32, m22 ); + this._z = 0; - // 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; + } else if ( order === 'YXZ' ) { - }, + this._x = Math.asin( - clamp( m23, - 1, 1 ) ); - union: function ( box ) { + if ( Math.abs( m23 ) < 0.99999 ) { - this.min.min( box.min ); - this.max.max( box.max ); + this._y = Math.atan2( m13, m33 ); + this._z = Math.atan2( m21, m22 ); - return this; + } else { - }, + this._y = Math.atan2( - m31, m11 ); + this._z = 0; - applyMatrix4: function () { + } - var points = [ - new Vector3(), - new Vector3(), - new Vector3(), - new Vector3(), - new Vector3(), - new Vector3(), - new Vector3(), - new Vector3() - ]; + } else if ( order === 'ZXY' ) { - return function applyMatrix4( matrix ) { + this._x = Math.asin( clamp( m32, - 1, 1 ) ); - // transform of empty box is an empty box. - if ( this.isEmpty() ) return this; + if ( Math.abs( m32 ) < 0.99999 ) { - // 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._y = Math.atan2( - m31, m33 ); + this._z = Math.atan2( - m12, m22 ); - this.setFromPoints( points ); + } else { - return this; + this._y = 0; + this._z = Math.atan2( m21, m11 ); - }; + } - }(), + } else if ( order === 'ZYX' ) { - translate: function ( offset ) { + this._y = Math.asin( - clamp( m31, - 1, 1 ) ); - this.min.add( offset ); - this.max.add( offset ); + if ( Math.abs( m31 ) < 0.99999 ) { - return this; + this._x = Math.atan2( m32, m33 ); + this._z = Math.atan2( m21, m11 ); - }, + } else { - equals: function ( box ) { + this._x = 0; + this._z = Math.atan2( - m12, m22 ); - return box.min.equals( this.min ) && box.max.equals( this.max ); + } - } + } else if ( order === 'YZX' ) { -} ); + this._z = Math.asin( clamp( m21, - 1, 1 ) ); -/** - * @author bhouston / http://clara.io - * @author mrdoob / http://mrdoob.com/ - */ + if ( Math.abs( m21 ) < 0.99999 ) { -function Sphere( center, radius ) { + this._x = Math.atan2( - m23, m22 ); + this._y = Math.atan2( - m31, m11 ); - this.center = ( center !== undefined ) ? center : new Vector3(); - this.radius = ( radius !== undefined ) ? radius : 0; + } else { -} + this._x = 0; + this._y = Math.atan2( m13, m33 ); -Object.assign( Sphere.prototype, { + } - set: function ( center, radius ) { + } else if ( order === 'XZY' ) { - this.center.copy( center ); - this.radius = radius; + 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 ); - setFromPoints: function () { + } else { - var box = new Box3(); + this._x = Math.atan2( - m23, m33 ); + this._y = 0; - return function setFromPoints( points, optionalCenter ) { + } - var center = this.center; + } else { - if ( optionalCenter !== undefined ) { + console.warn( 'THREE.Euler: .setFromRotationMatrix() given unsupported order: ' + order ); - center.copy( optionalCenter ); + } - } else { + this._order = order; - box.setFromPoints( points ).getCenter( center ); + if ( update !== false ) this.onChangeCallback(); - } + return this; - var maxRadiusSq = 0; + }, - for ( var i = 0, il = points.length; i < il; i ++ ) { + setFromQuaternion: function () { - maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( points[ i ] ) ); + var matrix = new Matrix4(); - } + return function setFromQuaternion( q, order, update ) { - this.radius = Math.sqrt( maxRadiusSq ); + matrix.makeRotationFromQuaternion( q ); - return this; + return this.setFromRotationMatrix( matrix, order, update ); }; }(), - clone: function () { + setFromVector3: function ( v, order ) { - return new this.constructor().copy( this ); + return this.set( v.x, v.y, v.z, order || this._order ); }, - copy: function ( sphere ) { + reorder: function () { - this.center.copy( sphere.center ); - this.radius = sphere.radius; + // WARNING: this discards revolution information -bhouston - return this; + var q = new Quaternion(); - }, + return function reorder( newOrder ) { - empty: function () { + q.setFromEuler( this ); - return ( this.radius <= 0 ); + return this.setFromQuaternion( q, newOrder ); - }, + }; - containsPoint: function ( point ) { + }(), - return ( point.distanceToSquared( this.center ) <= ( this.radius * this.radius ) ); + equals: function ( euler ) { + + return ( euler._x === this._x ) && ( euler._y === this._y ) && ( euler._z === this._z ) && ( euler._order === this._order ); }, - distanceToPoint: function ( point ) { + fromArray: function ( array ) { - return ( point.distanceTo( this.center ) - this.radius ); + this._x = array[ 0 ]; + this._y = array[ 1 ]; + this._z = array[ 2 ]; + if ( array[ 3 ] !== undefined ) this._order = array[ 3 ]; + + this.onChangeCallback(); + + return this; }, - intersectsSphere: function ( sphere ) { + toArray: function ( array, offset ) { - var radiusSum = this.radius + sphere.radius; + if ( array === undefined ) array = []; + if ( offset === undefined ) offset = 0; - return sphere.center.distanceToSquared( this.center ) <= ( radiusSum * radiusSum ); + array[ offset ] = this._x; + array[ offset + 1 ] = this._y; + array[ offset + 2 ] = this._z; + array[ offset + 3 ] = this._order; + + return array; }, - intersectsBox: function ( box ) { + toVector3: function ( optionalResult ) { - return box.intersectsSphere( this ); + if ( optionalResult ) { - }, + return optionalResult.set( this._x, this._y, this._z ); - intersectsPlane: function ( plane ) { + } else { - return Math.abs( plane.distanceToPoint( this.center ) ) <= this.radius; + return new Vector3( this._x, this._y, this._z ); + + } }, - clampPoint: function ( point, optionalTarget ) { + onChange: function ( callback ) { - var deltaLengthSq = this.center.distanceToSquared( point ); + this.onChangeCallback = callback; - var result = optionalTarget || new Vector3(); + return this; - result.copy( point ); + }, - if ( deltaLengthSq > ( this.radius * this.radius ) ) { + onChangeCallback: function () {} - result.sub( this.center ).normalize(); - result.multiplyScalar( this.radius ).add( this.center ); +} ); - } +/** + * @author mrdoob / http://mrdoob.com/ + */ - return result; +function Layers() { - }, + this.mask = 1 | 0; - getBoundingBox: function ( optionalTarget ) { +} - var box = optionalTarget || new Box3(); +Object.assign( Layers.prototype, { - box.set( this.center, this.center ); - box.expandByScalar( this.radius ); + set: function ( channel ) { - return box; + this.mask = 1 << channel | 0; }, - applyMatrix4: function ( matrix ) { - - this.center.applyMatrix4( matrix ); - this.radius = this.radius * matrix.getMaxScaleOnAxis(); + enable: function ( channel ) { - return this; + this.mask |= 1 << channel | 0; }, - translate: function ( offset ) { + toggle: function ( channel ) { - this.center.add( offset ); + this.mask ^= 1 << channel | 0; - return this; + }, + + disable: function ( channel ) { + + this.mask &= ~ ( 1 << channel | 0 ); }, - equals: function ( sphere ) { + test: function ( layers ) { - return sphere.center.equals( this.center ) && ( sphere.radius === this.radius ); + return ( this.mask & layers.mask ) !== 0; } } ); /** - * @author bhouston / http://clara.io + * @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 */ -function Plane( normal, constant ) { - - // normal is assumed to be normalized +var object3DId = 0; - this.normal = ( normal !== undefined ) ? normal : new Vector3( 1, 0, 0 ); - this.constant = ( constant !== undefined ) ? constant : 0; +function Object3D() { -} + Object.defineProperty( this, 'id', { value: object3DId ++ } ); -Object.assign( Plane.prototype, { + this.uuid = _Math.generateUUID(); - set: function ( normal, constant ) { + this.name = ''; + this.type = 'Object3D'; - this.normal.copy( normal ); - this.constant = constant; + this.parent = null; + this.children = []; - return this; + this.up = Object3D.DefaultUp.clone(); - }, + var position = new Vector3(); + var rotation = new Euler(); + var quaternion = new Quaternion(); + var scale = new Vector3( 1, 1, 1 ); - setComponents: function ( x, y, z, w ) { + function onRotationChange() { - this.normal.set( x, y, z ); - this.constant = w; + quaternion.setFromEuler( rotation, false ); - return this; + } - }, + function onQuaternionChange() { - setFromNormalAndCoplanarPoint: function ( normal, point ) { + rotation.setFromQuaternion( quaternion, undefined, false ); - this.normal.copy( normal ); - this.constant = - point.dot( this.normal ); + } - return this; + 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() + } + } ); - setFromCoplanarPoints: function () { + this.matrix = new Matrix4(); + this.matrixWorld = new Matrix4(); - var v1 = new Vector3(); - var v2 = new Vector3(); + this.matrixAutoUpdate = Object3D.DefaultMatrixAutoUpdate; + this.matrixWorldNeedsUpdate = false; - return function setFromCoplanarPoints( a, b, c ) { + this.layers = new Layers(); + this.visible = true; - var normal = v1.subVectors( c, b ).cross( v2.subVectors( a, b ) ).normalize(); + this.castShadow = false; + this.receiveShadow = false; - // Q: should an error be thrown if normal is zero (e.g. degenerate plane)? + this.frustumCulled = true; + this.renderOrder = 0; - this.setFromNormalAndCoplanarPoint( normal, a ); + this.userData = {}; - return this; +} - }; +Object3D.DefaultUp = new Vector3( 0, 1, 0 ); +Object3D.DefaultMatrixAutoUpdate = true; - }(), +Object3D.prototype = Object.assign( Object.create( EventDispatcher.prototype ), { - clone: function () { + constructor: Object3D, - return new this.constructor().copy( this ); + isObject3D: true, - }, + onBeforeRender: function () {}, + onAfterRender: function () {}, - copy: function ( plane ) { + applyMatrix: function ( matrix ) { - this.normal.copy( plane.normal ); - this.constant = plane.constant; + this.matrix.multiplyMatrices( matrix, this.matrix ); - return this; + this.matrix.decompose( this.position, this.quaternion, this.scale ); }, - normalize: function () { - - // Note: will lead to a divide by zero if the plane is invalid. + applyQuaternion: function ( q ) { - var inverseNormalLength = 1.0 / this.normal.length(); - this.normal.multiplyScalar( inverseNormalLength ); - this.constant *= inverseNormalLength; + this.quaternion.premultiply( q ); return this; }, - negate: function () { + setRotationFromAxisAngle: function ( axis, angle ) { - this.constant *= - 1; - this.normal.negate(); + // assumes axis is normalized - return this; + this.quaternion.setFromAxisAngle( axis, angle ); }, - distanceToPoint: function ( point ) { + setRotationFromEuler: function ( euler ) { - return this.normal.dot( point ) + this.constant; + this.quaternion.setFromEuler( euler, true ); }, - distanceToSphere: function ( sphere ) { + setRotationFromMatrix: function ( m ) { - return this.distanceToPoint( sphere.center ) - sphere.radius; + // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) + + this.quaternion.setFromRotationMatrix( m ); }, - projectPoint: function ( point, optionalTarget ) { + setRotationFromQuaternion: function ( q ) { - var result = optionalTarget || new Vector3(); + // assumes q is normalized - return result.copy( this.normal ).multiplyScalar( - this.distanceToPoint( point ) ).add( point ); + this.quaternion.copy( q ); }, - intersectLine: function () { + rotateOnAxis: function () { - var v1 = new Vector3(); + // rotate object on axis in object space + // axis is assumed to be normalized - return function intersectLine( line, optionalTarget ) { + var q1 = new Quaternion(); - var result = optionalTarget || new Vector3(); + return function rotateOnAxis( axis, angle ) { - var direction = line.delta( v1 ); + q1.setFromAxisAngle( axis, angle ); - var denominator = this.normal.dot( direction ); + this.quaternion.multiply( q1 ); - if ( denominator === 0 ) { + return this; - // line is coplanar, return origin - if ( this.distanceToPoint( line.start ) === 0 ) { + }; - return result.copy( line.start ); + }(), - } + rotateOnWorldAxis: function () { - // Unsure if this is the correct method to handle this case. - return undefined; - - } + // rotate object on axis in world space + // axis is assumed to be normalized + // method assumes no rotated parent - var t = - ( line.start.dot( this.normal ) + this.constant ) / denominator; + var q1 = new Quaternion(); - if ( t < 0 || t > 1 ) { + return function rotateOnWorldAxis( axis, angle ) { - return undefined; + q1.setFromAxisAngle( axis, angle ); - } + this.quaternion.premultiply( q1 ); - return result.copy( direction ).multiplyScalar( t ).add( line.start ); + return this; }; }(), - intersectsLine: function ( line ) { + rotateX: function () { - // Note: this tests if a line intersects the plane, not whether it (or its end-points) are coplanar with it. + var v1 = new Vector3( 1, 0, 0 ); - var startSign = this.distanceToPoint( line.start ); - var endSign = this.distanceToPoint( line.end ); + return function rotateX( angle ) { - return ( startSign < 0 && endSign > 0 ) || ( endSign < 0 && startSign > 0 ); + return this.rotateOnAxis( v1, angle ); - }, + }; - intersectsBox: function ( box ) { + }(), - return box.intersectsPlane( this ); + rotateY: function () { - }, + var v1 = new Vector3( 0, 1, 0 ); - intersectsSphere: function ( sphere ) { + return function rotateY( angle ) { - return sphere.intersectsPlane( this ); + return this.rotateOnAxis( v1, angle ); - }, + }; - coplanarPoint: function ( optionalTarget ) { + }(), - var result = optionalTarget || new Vector3(); + rotateZ: function () { - return result.copy( this.normal ).multiplyScalar( - this.constant ); + var v1 = new Vector3( 0, 0, 1 ); - }, + return function rotateZ( angle ) { - applyMatrix4: function () { + return this.rotateOnAxis( v1, angle ); - var v1 = new Vector3(); - var m1 = new Matrix3(); + }; - return function applyMatrix4( matrix, optionalNormalMatrix ) { + }(), - var normalMatrix = optionalNormalMatrix || m1.getNormalMatrix( matrix ); + translateOnAxis: function () { - var referencePoint = this.coplanarPoint( v1 ).applyMatrix4( matrix ); + // translate object by distance along axis in object space + // axis is assumed to be normalized - var normal = this.normal.applyMatrix3( normalMatrix ).normalize(); + var v1 = new Vector3(); - this.constant = - referencePoint.dot( normal ); + return function translateOnAxis( axis, distance ) { + + v1.copy( axis ).applyQuaternion( this.quaternion ); + + this.position.add( v1.multiplyScalar( distance ) ); return this; @@ -11476,5811 +9842,5653 @@ Object.assign( Plane.prototype, { }(), - translate: function ( offset ) { - - this.constant -= offset.dot( this.normal ); - - return this; + translateX: function () { - }, + var v1 = new Vector3( 1, 0, 0 ); - equals: function ( plane ) { + return function translateX( distance ) { - return plane.normal.equals( this.normal ) && ( plane.constant === this.constant ); + return this.translateOnAxis( v1, distance ); - } + }; -} ); + }(), -/** - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - * @author bhouston / http://clara.io - */ + translateY: function () { -function Frustum( p0, p1, p2, p3, p4, p5 ) { + var v1 = new Vector3( 0, 1, 0 ); - this.planes = [ + return function translateY( distance ) { - ( 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() + return this.translateOnAxis( v1, distance ); - ]; + }; -} + }(), -Object.assign( Frustum.prototype, { + translateZ: function () { - set: function ( p0, p1, p2, p3, p4, p5 ) { + var v1 = new Vector3( 0, 0, 1 ); - var planes = this.planes; + return function translateZ( distance ) { - planes[ 0 ].copy( p0 ); - planes[ 1 ].copy( p1 ); - planes[ 2 ].copy( p2 ); - planes[ 3 ].copy( p3 ); - planes[ 4 ].copy( p4 ); - planes[ 5 ].copy( p5 ); + return this.translateOnAxis( v1, distance ); - return this; + }; - }, + }(), - clone: function () { + localToWorld: function ( vector ) { - return new this.constructor().copy( this ); + return vector.applyMatrix4( this.matrixWorld ); }, - copy: function ( frustum ) { + worldToLocal: function () { - var planes = this.planes; + var m1 = new Matrix4(); - for ( var i = 0; i < 6; i ++ ) { + return function worldToLocal( vector ) { - planes[ i ].copy( frustum.planes[ i ] ); + return vector.applyMatrix4( m1.getInverse( this.matrixWorld ) ); - } + }; - return this; + }(), - }, + lookAt: function () { - setFromMatrix: function ( m ) { + // This method does not support objects having non-uniformly-scaled parent(s) - 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 ]; + var q1 = new Quaternion(); + var m1 = new Matrix4(); + var target = new Vector3(); + var position = new Vector3(); - 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 function lookAt( x, y, z ) { - return this; + if ( x.isVector3 ) { - }, + target.copy( x ); - intersectsObject: function () { + } else { - var sphere = new Sphere(); + target.set( x, y, z ); - return function intersectsObject( object ) { + } - var geometry = object.geometry; + var parent = this.parent; - if ( geometry.boundingSphere === null ) - geometry.computeBoundingSphere(); + this.updateWorldMatrix( true, false ); - sphere.copy( geometry.boundingSphere ) - .applyMatrix4( object.matrixWorld ); + position.setFromMatrixPosition( this.matrixWorld ); - return this.intersectsSphere( sphere ); + if ( this.isCamera || this.isLight ) { - }; + m1.lookAt( position, target, this.up ); - }(), + } else { - intersectsSprite: function () { + m1.lookAt( target, position, this.up ); - var sphere = new Sphere(); + } - return function intersectsSprite( sprite ) { + this.quaternion.setFromRotationMatrix( m1 ); - sphere.center.set( 0, 0, 0 ); - sphere.radius = 0.7071067811865476; - sphere.applyMatrix4( sprite.matrixWorld ); + if ( parent ) { - return this.intersectsSphere( sphere ); + m1.extractRotation( parent.matrixWorld ); + q1.setFromRotationMatrix( m1 ); + this.quaternion.premultiply( q1.inverse() ); + + } }; }(), - intersectsSphere: function ( sphere ) { + add: function ( object ) { - var planes = this.planes; - var center = sphere.center; - var negRadius = - sphere.radius; + if ( arguments.length > 1 ) { - for ( var i = 0; i < 6; i ++ ) { + for ( var i = 0; i < arguments.length; i ++ ) { - var distance = planes[ i ].distanceToPoint( center ); + this.add( arguments[ i ] ); - if ( distance < negRadius ) { + } - return false; + return this; - } + } + + if ( object === this ) { + + console.error( "THREE.Object3D.add: object can't be added as a child of itself.", object ); + return this; } - return true; + if ( ( object && object.isObject3D ) ) { - }, + if ( object.parent !== null ) { - intersectsBox: function () { + object.parent.remove( object ); - var p1 = new Vector3(), - p2 = new Vector3(); + } - return function intersectsBox( box ) { + object.parent = this; + object.dispatchEvent( { type: 'added' } ); - var planes = this.planes; + this.children.push( object ); - for ( var i = 0; i < 6; i ++ ) { + } else { - var plane = planes[ i ]; + console.error( "THREE.Object3D.add: object not an instance of THREE.Object3D.", object ); - p1.x = plane.normal.x > 0 ? box.min.x : box.max.x; - p2.x = plane.normal.x > 0 ? box.max.x : box.min.x; - p1.y = plane.normal.y > 0 ? box.min.y : box.max.y; - p2.y = plane.normal.y > 0 ? box.max.y : box.min.y; - p1.z = plane.normal.z > 0 ? box.min.z : box.max.z; - p2.z = plane.normal.z > 0 ? box.max.z : box.min.z; + } - var d1 = plane.distanceToPoint( p1 ); - var d2 = plane.distanceToPoint( p2 ); + return this; - // if both outside plane, no intersection + }, - if ( d1 < 0 && d2 < 0 ) { + remove: function ( object ) { - return false; + if ( arguments.length > 1 ) { - } + for ( var i = 0; i < arguments.length; i ++ ) { + + this.remove( arguments[ i ] ); } - return true; + return this; - }; + } - }(), + var index = this.children.indexOf( object ); - containsPoint: function ( point ) { + if ( index !== - 1 ) { - var planes = this.planes; + object.parent = null; - for ( var i = 0; i < 6; i ++ ) { + object.dispatchEvent( { type: 'removed' } ); - if ( planes[ i ].distanceToPoint( point ) < 0 ) { + this.children.splice( index, 1 ); - return false; + } - } + return this; - } + }, - return true; + getObjectById: function ( id ) { - } + return this.getObjectByProperty( 'id', id ); -} ); + }, -/** - * @author alteredq / http://alteredqualia.com/ - * @author mrdoob / http://mrdoob.com/ - */ + getObjectByName: function ( name ) { -function WebGLShadowMap( _renderer, _objects, maxTextureSize ) { + return this.getObjectByProperty( 'name', name ); - var _frustum = new Frustum(), - _projScreenMatrix = new Matrix4(), + }, - _shadowMapSize = new Vector2(), - _maxShadowMapSize = new Vector2( maxTextureSize, maxTextureSize ), + getObjectByProperty: function ( name, value ) { - _lookTarget = new Vector3(), - _lightPositionWorld = new Vector3(), + if ( this[ name ] === value ) return this; - _MorphingFlag = 1, - _SkinningFlag = 2, + for ( var i = 0, l = this.children.length; i < l; i ++ ) { - _NumberOfMaterialVariants = ( _MorphingFlag | _SkinningFlag ) + 1, + var child = this.children[ i ]; + var object = child.getObjectByProperty( name, value ); - _depthMaterials = new Array( _NumberOfMaterialVariants ), - _distanceMaterials = new Array( _NumberOfMaterialVariants ), + if ( object !== undefined ) { - _materialCache = {}; + return object; - var shadowSide = { 0: BackSide, 1: FrontSide, 2: DoubleSide }; + } - 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 ) - ]; + } - 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 ) - ]; + return undefined; - var cube2DViewPorts = [ - new Vector4(), new Vector4(), new Vector4(), - new Vector4(), new Vector4(), new Vector4() - ]; + }, - // init + getWorldPosition: function ( target ) { - for ( var i = 0; i !== _NumberOfMaterialVariants; ++ i ) { + if ( target === undefined ) { - var useMorphing = ( i & _MorphingFlag ) !== 0; - var useSkinning = ( i & _SkinningFlag ) !== 0; + console.warn( 'THREE.Object3D: .getWorldPosition() target is now required' ); + target = new Vector3(); - var depthMaterial = new MeshDepthMaterial( { + } - depthPacking: RGBADepthPacking, + this.updateMatrixWorld( true ); - morphTargets: useMorphing, - skinning: useSkinning + return target.setFromMatrixPosition( this.matrixWorld ); - } ); + }, - _depthMaterials[ i ] = depthMaterial; + getWorldQuaternion: function () { - // + var position = new Vector3(); + var scale = new Vector3(); - var distanceMaterial = new MeshDistanceMaterial( { + return function getWorldQuaternion( target ) { - morphTargets: useMorphing, - skinning: useSkinning + if ( target === undefined ) { - } ); + console.warn( 'THREE.Object3D: .getWorldQuaternion() target is now required' ); + target = new Quaternion(); - _distanceMaterials[ i ] = distanceMaterial; + } - } + this.updateMatrixWorld( true ); - // + this.matrixWorld.decompose( position, target, scale ); - var scope = this; + return target; - this.enabled = false; + }; - this.autoUpdate = true; - this.needsUpdate = false; + }(), - this.type = PCFShadowMap; + getWorldScale: function () { - this.render = function ( lights, scene, camera ) { + var position = new Vector3(); + var quaternion = new Quaternion(); - if ( scope.enabled === false ) return; - if ( scope.autoUpdate === false && scope.needsUpdate === false ) return; + return function getWorldScale( target ) { - if ( lights.length === 0 ) return; + if ( target === undefined ) { - // TODO Clean up (needed in case of contextlost) - var _gl = _renderer.context; - var _state = _renderer.state; + console.warn( 'THREE.Object3D: .getWorldScale() target is now required' ); + target = new Vector3(); - // Set GL state for depth map. - _state.disable( _gl.BLEND ); - _state.buffers.color.setClear( 1, 1, 1, 1 ); - _state.buffers.depth.setTest( true ); - _state.setScissorTest( false ); + } - // render depth map + this.updateMatrixWorld( true ); - var faceCount; + this.matrixWorld.decompose( position, quaternion, target ); - for ( var i = 0, il = lights.length; i < il; i ++ ) { + return target; - var light = lights[ i ]; - var shadow = light.shadow; - var isPointLight = light && light.isPointLight; + }; - if ( shadow === undefined ) { + }(), - console.warn( 'THREE.WebGLShadowMap:', light, 'has no shadow.' ); - continue; + getWorldDirection: function ( target ) { - } + if ( target === undefined ) { - var shadowCamera = shadow.camera; + console.warn( 'THREE.Object3D: .getWorldDirection() target is now required' ); + target = new Vector3(); - _shadowMapSize.copy( shadow.mapSize ); - _shadowMapSize.min( _maxShadowMapSize ); + } - if ( isPointLight ) { + this.updateMatrixWorld( true ); - var vpWidth = _shadowMapSize.x; - var vpHeight = _shadowMapSize.y; + var e = this.matrixWorld.elements; - // 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 + return target.set( e[ 8 ], e[ 9 ], e[ 10 ] ).normalize(); - // 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; + raycast: function () {}, - } + traverse: function ( callback ) { - if ( shadow.map === null ) { + callback( this ); - var pars = { minFilter: NearestFilter, magFilter: NearestFilter, format: RGBAFormat }; + var children = this.children; - shadow.map = new WebGLRenderTarget( _shadowMapSize.x, _shadowMapSize.y, pars ); - shadow.map.texture.name = light.name + ".shadowMap"; + for ( var i = 0, l = children.length; i < l; i ++ ) { - shadowCamera.updateProjectionMatrix(); + children[ i ].traverse( callback ); - } + } - if ( shadow.isSpotLightShadow ) { + }, - shadow.update( light ); + traverseVisible: function ( callback ) { - } + if ( this.visible === false ) return; - var shadowMap = shadow.map; - var shadowMatrix = shadow.matrix; + callback( this ); - _lightPositionWorld.setFromMatrixPosition( light.matrixWorld ); - shadowCamera.position.copy( _lightPositionWorld ); + var children = this.children; - if ( isPointLight ) { + for ( var i = 0, l = children.length; i < l; i ++ ) { - faceCount = 6; + children[ i ].traverseVisible( callback ); - // for point lights we set the shadow matrix to be a translation-only matrix - // equal to inverse of the light's position + } - shadowMatrix.makeTranslation( - _lightPositionWorld.x, - _lightPositionWorld.y, - _lightPositionWorld.z ); + }, - } else { + traverseAncestors: function ( callback ) { - faceCount = 1; + var parent = this.parent; - _lookTarget.setFromMatrixPosition( light.target.matrixWorld ); - shadowCamera.lookAt( _lookTarget ); - shadowCamera.updateMatrixWorld(); + if ( parent !== null ) { - // compute shadow matrix + callback( parent ); - 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 - ); + parent.traverseAncestors( callback ); - shadowMatrix.multiply( shadowCamera.projectionMatrix ); - shadowMatrix.multiply( shadowCamera.matrixWorldInverse ); + } - } + }, - _renderer.setRenderTarget( shadowMap ); - _renderer.clear(); + updateMatrix: function () { - // render shadow map for each cube face (if omni-directional) or - // run a single pass if not + this.matrix.compose( this.position, this.quaternion, this.scale ); - for ( var face = 0; face < faceCount; face ++ ) { + this.matrixWorldNeedsUpdate = true; - if ( isPointLight ) { + }, - _lookTarget.copy( shadowCamera.position ); - _lookTarget.add( cubeDirections[ face ] ); - shadowCamera.up.copy( cubeUps[ face ] ); - shadowCamera.lookAt( _lookTarget ); - shadowCamera.updateMatrixWorld(); + updateMatrixWorld: function ( force ) { - var vpDimensions = cube2DViewPorts[ face ]; - _state.viewport( vpDimensions ); + if ( this.matrixAutoUpdate ) this.updateMatrix(); - } + if ( this.matrixWorldNeedsUpdate || force ) { - // update camera matrices and frustum + if ( this.parent === null ) { - _projScreenMatrix.multiplyMatrices( shadowCamera.projectionMatrix, shadowCamera.matrixWorldInverse ); - _frustum.setFromMatrix( _projScreenMatrix ); + this.matrixWorld.copy( this.matrix ); - // set object matrices & frustum culling + } else { - renderObject( scene, camera, shadowCamera, isPointLight ); + this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix ); } + this.matrixWorldNeedsUpdate = false; + + force = true; + } - scope.needsUpdate = false; + // update children - }; + var children = this.children; - function getDepthMaterial( object, material, isPointLight, lightPositionWorld, shadowCameraNear, shadowCameraFar ) { + for ( var i = 0, l = children.length; i < l; i ++ ) { - var geometry = object.geometry; + children[ i ].updateMatrixWorld( force ); - var result = null; + } - var materialVariants = _depthMaterials; - var customMaterial = object.customDepthMaterial; + }, - if ( isPointLight ) { + updateWorldMatrix: function ( updateParents, updateChildren ) { - materialVariants = _distanceMaterials; - customMaterial = object.customDistanceMaterial; + var parent = this.parent; - } + if ( updateParents === true && parent !== null ) { - if ( ! customMaterial ) { + parent.updateWorldMatrix( true, false ); - var useMorphing = false; + } - if ( material.morphTargets ) { + if ( this.matrixAutoUpdate ) this.updateMatrix(); - if ( geometry && geometry.isBufferGeometry ) { + if ( this.parent === null ) { - useMorphing = geometry.morphAttributes && geometry.morphAttributes.position && geometry.morphAttributes.position.length > 0; + this.matrixWorld.copy( this.matrix ); - } else if ( geometry && geometry.isGeometry ) { + } else { - useMorphing = geometry.morphTargets && geometry.morphTargets.length > 0; + this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix ); - } + } - } + // update children - if ( object.isSkinnedMesh && material.skinning === false ) { + if ( updateChildren === true ) { - console.warn( 'THREE.WebGLShadowMap: THREE.SkinnedMesh with material.skinning set to false:', object ); + var children = this.children; + + for ( var i = 0, l = children.length; i < l; i ++ ) { + + children[ i ].updateWorldMatrix( false, true ); } - var useSkinning = object.isSkinnedMesh && material.skinning; + } - var variantIndex = 0; + }, - if ( useMorphing ) variantIndex |= _MorphingFlag; - if ( useSkinning ) variantIndex |= _SkinningFlag; + toJSON: function ( meta ) { - result = materialVariants[ variantIndex ]; + // meta is a string when called from JSON.stringify + var isRootObject = ( meta === undefined || typeof meta === 'string' ); - } else { + var output = {}; - result = customMaterial; + // meta is a hash used to collect geometries, materials. + // not providing it implies that this is the root object + // being serialized. + if ( isRootObject ) { + + // initialize meta obj + meta = { + geometries: {}, + materials: {}, + textures: {}, + images: {}, + shapes: {} + }; + + output.metadata = { + version: 4.5, + type: 'Object', + generator: 'Object3D.toJSON' + }; } - if ( _renderer.localClippingEnabled && - material.clipShadows === true && - material.clippingPlanes.length !== 0 ) { + // standard Object3D serialization - // in this case we need a unique material instance reflecting the - // appropriate state + var object = {}; - var keyA = result.uuid, keyB = material.uuid; + object.uuid = this.uuid; + object.type = this.type; - var materialsForVariant = _materialCache[ keyA ]; + 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 ( materialsForVariant === undefined ) { + object.layers = this.layers.mask; + object.matrix = this.matrix.toArray(); - materialsForVariant = {}; - _materialCache[ keyA ] = materialsForVariant; + if ( this.matrixAutoUpdate === false ) object.matrixAutoUpdate = false; - } + // - var cachedMaterial = materialsForVariant[ keyB ]; + function serialize( library, element ) { - if ( cachedMaterial === undefined ) { + if ( library[ element.uuid ] === undefined ) { - cachedMaterial = result.clone(); - materialsForVariant[ keyB ] = cachedMaterial; + library[ element.uuid ] = element.toJSON( meta ); } - result = cachedMaterial; + return element.uuid; } - result.visible = material.visible; - result.wireframe = material.wireframe; + if ( this.isMesh || this.isLine || this.isPoints ) { - result.side = ( material.shadowSide != null ) ? material.shadowSide : shadowSide[ material.side ]; + object.geometry = serialize( meta.geometries, this.geometry ); - result.clipShadows = material.clipShadows; - result.clippingPlanes = material.clippingPlanes; - result.clipIntersection = material.clipIntersection; + var parameters = this.geometry.parameters; - result.wireframeLinewidth = material.wireframeLinewidth; - result.linewidth = material.linewidth; + if ( parameters !== undefined && parameters.shapes !== undefined ) { - if ( isPointLight && result.isMeshDistanceMaterial ) { + var shapes = parameters.shapes; - result.referencePosition.copy( lightPositionWorld ); - result.nearDistance = shadowCameraNear; - result.farDistance = shadowCameraFar; + if ( Array.isArray( shapes ) ) { - } + for ( var i = 0, l = shapes.length; i < l; i ++ ) { - return result; + var shape = shapes[ i ]; - } + serialize( meta.shapes, shape ); - function renderObject( object, camera, shadowCamera, isPointLight ) { + } - if ( object.visible === false ) return; + } else { - var visible = object.layers.test( camera.layers ); + serialize( meta.shapes, shapes ); - if ( visible && ( object.isMesh || object.isLine || object.isPoints ) ) { + } - if ( object.castShadow && ( ! object.frustumCulled || _frustum.intersectsObject( object ) ) ) { + } - object.modelViewMatrix.multiplyMatrices( shadowCamera.matrixWorldInverse, object.matrixWorld ); + } - var geometry = _objects.update( object ); - var material = object.material; + if ( this.material !== undefined ) { - if ( Array.isArray( material ) ) { + if ( Array.isArray( this.material ) ) { - var groups = geometry.groups; + var uuids = []; - for ( var k = 0, kl = groups.length; k < kl; k ++ ) { + for ( var i = 0, l = this.material.length; i < l; i ++ ) { - var group = groups[ k ]; - var groupMaterial = material[ group.materialIndex ]; + uuids.push( serialize( meta.materials, this.material[ i ] ) ); - if ( groupMaterial && groupMaterial.visible ) { + } - var depthMaterial = getDepthMaterial( object, groupMaterial, isPointLight, _lightPositionWorld, shadowCamera.near, shadowCamera.far ); - _renderer.renderBufferDirect( shadowCamera, null, geometry, depthMaterial, object, group ); + object.material = uuids; - } + } else { - } + object.material = serialize( meta.materials, this.material ); - } else if ( material.visible ) { + } - var depthMaterial = getDepthMaterial( object, material, isPointLight, _lightPositionWorld, shadowCamera.near, shadowCamera.far ); - _renderer.renderBufferDirect( shadowCamera, null, geometry, depthMaterial, object, null ); + } - } + // + + if ( this.children.length > 0 ) { + + object.children = []; + + for ( var i = 0; i < this.children.length; i ++ ) { + + object.children.push( this.children[ i ].toJSON( meta ).object ); } } - var children = object.children; + if ( isRootObject ) { - for ( var i = 0, l = children.length; i < l; i ++ ) { + 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 ); - renderObject( children[ i ], camera, shadowCamera, isPointLight ); + 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; } - } - -} + output.object = object; -/** - * @author mrdoob / http://mrdoob.com/ - */ + return output; -function WebGLAttributes( gl ) { + // extract data from the cache hash + // remove metadata on each item + // and return as array + function extractFromCache( cache ) { - var buffers = {}; + var values = []; + for ( var key in cache ) { - function createBuffer( attribute, bufferType ) { + var data = cache[ key ]; + delete data.metadata; + values.push( data ); - var array = attribute.array; - var usage = attribute.dynamic ? gl.DYNAMIC_DRAW : gl.STATIC_DRAW; + } + return values; - var buffer = gl.createBuffer(); + } - gl.bindBuffer( bufferType, buffer ); - gl.bufferData( bufferType, array, usage ); + }, - attribute.onUploadCallback(); + clone: function ( recursive ) { - var type = gl.FLOAT; + return new this.constructor().copy( this, recursive ); - if ( array instanceof Float32Array ) { + }, - type = gl.FLOAT; + copy: function ( source, recursive ) { - } else if ( array instanceof Float64Array ) { + if ( recursive === undefined ) recursive = true; - console.warn( 'THREE.WebGLAttributes: Unsupported data buffer format: Float64Array.' ); + this.name = source.name; - } else if ( array instanceof Uint16Array ) { + this.up.copy( source.up ); - type = gl.UNSIGNED_SHORT; + this.position.copy( source.position ); + this.quaternion.copy( source.quaternion ); + this.scale.copy( source.scale ); - } else if ( array instanceof Int16Array ) { + this.matrix.copy( source.matrix ); + this.matrixWorld.copy( source.matrixWorld ); - type = gl.SHORT; + this.matrixAutoUpdate = source.matrixAutoUpdate; + this.matrixWorldNeedsUpdate = source.matrixWorldNeedsUpdate; - } else if ( array instanceof Uint32Array ) { + this.layers.mask = source.layers.mask; + this.visible = source.visible; - type = gl.UNSIGNED_INT; + this.castShadow = source.castShadow; + this.receiveShadow = source.receiveShadow; - } else if ( array instanceof Int32Array ) { + this.frustumCulled = source.frustumCulled; + this.renderOrder = source.renderOrder; - type = gl.INT; + this.userData = JSON.parse( JSON.stringify( source.userData ) ); - } else if ( array instanceof Int8Array ) { + if ( recursive === true ) { - type = gl.BYTE; + for ( var i = 0; i < source.children.length; i ++ ) { - } else if ( array instanceof Uint8Array ) { + var child = source.children[ i ]; + this.add( child.clone() ); - type = gl.UNSIGNED_BYTE; + } } - return { - buffer: buffer, - type: type, - bytesPerElement: array.BYTES_PER_ELEMENT, - version: attribute.version - }; + return this; } - function updateBuffer( buffer, attribute, bufferType ) { - - var array = attribute.array; - var updateRange = attribute.updateRange; - - gl.bindBuffer( bufferType, buffer ); +} ); - if ( attribute.dynamic === false ) { +/** + * @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 + */ - gl.bufferData( bufferType, array, gl.STATIC_DRAW ); +var geometryId = 0; // Geometry uses even numbers as Id - } else if ( updateRange.count === - 1 ) { +function Geometry() { - // Not using update ranges + Object.defineProperty( this, 'id', { value: geometryId += 2 } ); - gl.bufferSubData( bufferType, 0, array ); + this.uuid = _Math.generateUUID(); - } else if ( updateRange.count === 0 ) { + this.name = ''; + this.type = 'Geometry'; - 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.' ); + this.vertices = []; + this.colors = []; + this.faces = []; + this.faceVertexUvs = [[]]; - } else { + this.morphTargets = []; + this.morphNormals = []; - gl.bufferSubData( bufferType, updateRange.offset * array.BYTES_PER_ELEMENT, - array.subarray( updateRange.offset, updateRange.offset + updateRange.count ) ); + this.skinWeights = []; + this.skinIndices = []; - updateRange.count = - 1; // reset range + this.lineDistances = []; - } + this.boundingBox = null; + this.boundingSphere = null; - } + // update flags - // + this.elementsNeedUpdate = false; + this.verticesNeedUpdate = false; + this.uvsNeedUpdate = false; + this.normalsNeedUpdate = false; + this.colorsNeedUpdate = false; + this.lineDistancesNeedUpdate = false; + this.groupsNeedUpdate = false; - function get( attribute ) { +} - if ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data; +Geometry.prototype = Object.assign( Object.create( EventDispatcher.prototype ), { - return buffers[ attribute.uuid ]; + constructor: Geometry, - } + isGeometry: true, - function remove( attribute ) { + applyMatrix: function ( matrix ) { - if ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data; + var normalMatrix = new Matrix3().getNormalMatrix( matrix ); - var data = buffers[ attribute.uuid ]; + for ( var i = 0, il = this.vertices.length; i < il; i ++ ) { - if ( data ) { + var vertex = this.vertices[ i ]; + vertex.applyMatrix4( matrix ); - gl.deleteBuffer( data.buffer ); + } - delete buffers[ attribute.uuid ]; + for ( var i = 0, il = this.faces.length; i < il; i ++ ) { - } + var face = this.faces[ i ]; + face.normal.applyMatrix3( normalMatrix ).normalize(); - } + for ( var j = 0, jl = face.vertexNormals.length; j < jl; j ++ ) { - function update( attribute, bufferType ) { + face.vertexNormals[ j ].applyMatrix3( normalMatrix ).normalize(); - if ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data; + } - var data = buffers[ attribute.uuid ]; + } - if ( data === undefined ) { + if ( this.boundingBox !== null ) { - buffers[ attribute.uuid ] = createBuffer( attribute, bufferType ); + this.computeBoundingBox(); - } else if ( data.version < attribute.version ) { + } - updateBuffer( data.buffer, attribute, bufferType ); + if ( this.boundingSphere !== null ) { - data.version = attribute.version; + this.computeBoundingSphere(); } - } - - return { + this.verticesNeedUpdate = true; + this.normalsNeedUpdate = true; - get: get, - remove: remove, - update: update + return this; - }; + }, -} + rotateX: function () { -/** - * @author mrdoob / http://mrdoob.com/ - * @author WestLangley / http://github.com/WestLangley - * @author bhouston / http://clara.io - */ + // rotate geometry around world x-axis -function Euler( x, y, z, order ) { + var m1 = new Matrix4(); - this._x = x || 0; - this._y = y || 0; - this._z = z || 0; - this._order = order || Euler.DefaultOrder; + return function rotateX( angle ) { -} + m1.makeRotationX( angle ); -Euler.RotationOrders = [ 'XYZ', 'YZX', 'ZXY', 'XZY', 'YXZ', 'ZYX' ]; + this.applyMatrix( m1 ); -Euler.DefaultOrder = 'XYZ'; + return this; -Object.defineProperties( Euler.prototype, { + }; - x: { + }(), - get: function () { + rotateY: function () { - return this._x; + // rotate geometry around world y-axis - }, + var m1 = new Matrix4(); - set: function ( value ) { + return function rotateY( angle ) { - this._x = value; - this.onChangeCallback(); + m1.makeRotationY( angle ); - } + this.applyMatrix( m1 ); - }, + return this; - y: { + }; - get: function () { + }(), - return this._y; + rotateZ: function () { - }, + // rotate geometry around world z-axis - set: function ( value ) { + var m1 = new Matrix4(); - this._y = value; - this.onChangeCallback(); + return function rotateZ( angle ) { - } + m1.makeRotationZ( angle ); - }, + this.applyMatrix( m1 ); - z: { + return this; - get: function () { + }; - return this._z; + }(), - }, + translate: function () { - set: function ( value ) { + // translate geometry - this._z = value; - this.onChangeCallback(); + var m1 = new Matrix4(); - } + return function translate( x, y, z ) { - }, + m1.makeTranslation( x, y, z ); - order: { + this.applyMatrix( m1 ); - get: function () { + return this; - return this._order; + }; - }, + }(), - set: function ( value ) { + scale: function () { - this._order = value; - this.onChangeCallback(); + // scale geometry - } + var m1 = new Matrix4(); - } + return function scale( x, y, z ) { -} ); + m1.makeScale( x, y, z ); -Object.assign( Euler.prototype, { + this.applyMatrix( m1 ); - isEuler: true, + return this; - set: function ( x, y, z, order ) { + }; - this._x = x; - this._y = y; - this._z = z; - this._order = order || this._order; + }(), - this.onChangeCallback(); + lookAt: function () { - return this; + var obj = new Object3D(); - }, + return function lookAt( vector ) { - clone: function () { + obj.lookAt( vector ); - return new this.constructor( this._x, this._y, this._z, this._order ); + obj.updateMatrix(); - }, + this.applyMatrix( obj.matrix ); - copy: function ( euler ) { + }; - this._x = euler._x; - this._y = euler._y; - this._z = euler._z; - this._order = euler._order; + }(), - this.onChangeCallback(); + fromBufferGeometry: function ( geometry ) { - return this; + var scope = this; - }, + var indices = geometry.index !== null ? geometry.index.array : undefined; + var attributes = geometry.attributes; - setFromRotationMatrix: function ( m, order, update ) { + 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; - var clamp = _Math.clamp; + if ( uvs2 !== undefined ) this.faceVertexUvs[ 1 ] = []; - // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) + for ( var i = 0, j = 0; i < positions.length; i += 3, j += 2 ) { - 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 ]; + scope.vertices.push( new Vector3().fromArray( positions, i ) ); - order = order || this._order; + if ( colors !== undefined ) { - if ( order === 'XYZ' ) { + scope.colors.push( new Color().fromArray( colors, i ) ); - this._y = Math.asin( clamp( m13, - 1, 1 ) ); + } - if ( Math.abs( m13 ) < 0.99999 ) { + } - this._x = Math.atan2( - m23, m33 ); - this._z = Math.atan2( - m12, m11 ); + function addFace( a, b, c, materialIndex ) { - } else { + var vertexColors = ( colors === undefined ) ? [] : [ + scope.colors[ a ].clone(), + scope.colors[ b ].clone(), + scope.colors[ c ].clone() ]; - this._x = Math.atan2( m32, m22 ); - this._z = 0; + 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 ); - } else if ( order === 'YXZ' ) { + scope.faces.push( face ); - this._x = Math.asin( - clamp( m23, - 1, 1 ) ); + if ( uvs !== undefined ) { - if ( Math.abs( m23 ) < 0.99999 ) { + scope.faceVertexUvs[ 0 ].push( [ + new Vector2().fromArray( uvs, a * 2 ), + new Vector2().fromArray( uvs, b * 2 ), + new Vector2().fromArray( uvs, c * 2 ) + ] ); - this._y = Math.atan2( m13, m33 ); - this._z = Math.atan2( m21, m22 ); + } - } else { + if ( uvs2 !== undefined ) { - this._y = Math.atan2( - m31, m11 ); - this._z = 0; + scope.faceVertexUvs[ 1 ].push( [ + new Vector2().fromArray( uvs2, a * 2 ), + new Vector2().fromArray( uvs2, b * 2 ), + new Vector2().fromArray( uvs2, c * 2 ) + ] ); } - } else if ( order === 'ZXY' ) { + } - this._x = Math.asin( clamp( m32, - 1, 1 ) ); + var groups = geometry.groups; - if ( Math.abs( m32 ) < 0.99999 ) { + if ( groups.length > 0 ) { - this._y = Math.atan2( - m31, m33 ); - this._z = Math.atan2( - m12, m22 ); + for ( var i = 0; i < groups.length; i ++ ) { - } else { + var group = groups[ i ]; - this._y = 0; - this._z = Math.atan2( m21, m11 ); + var start = group.start; + var count = group.count; - } + for ( var j = start, jl = start + count; j < jl; j += 3 ) { - } else if ( order === 'ZYX' ) { + if ( indices !== undefined ) { - this._y = Math.asin( - clamp( m31, - 1, 1 ) ); + addFace( indices[ j ], indices[ j + 1 ], indices[ j + 2 ], group.materialIndex ); - if ( Math.abs( m31 ) < 0.99999 ) { + } else { - this._x = Math.atan2( m32, m33 ); - this._z = Math.atan2( m21, m11 ); + addFace( j, j + 1, j + 2, group.materialIndex ); - } else { + } - this._x = 0; - this._z = Math.atan2( - m12, m22 ); + } } - } else if ( order === 'YZX' ) { + } else { - this._z = Math.asin( clamp( m21, - 1, 1 ) ); + if ( indices !== undefined ) { - if ( Math.abs( m21 ) < 0.99999 ) { + for ( var i = 0; i < indices.length; i += 3 ) { - this._x = Math.atan2( - m23, m22 ); - this._y = Math.atan2( - m31, m11 ); + addFace( indices[ i ], indices[ i + 1 ], indices[ i + 2 ] ); + + } } else { - this._x = 0; - this._y = Math.atan2( m13, m33 ); + for ( var i = 0; i < positions.length / 3; i += 3 ) { - } + addFace( i, i + 1, i + 2 ); - } else if ( order === 'XZY' ) { + } - this._z = Math.asin( - clamp( m12, - 1, 1 ) ); + } - if ( Math.abs( m12 ) < 0.99999 ) { + } - this._x = Math.atan2( m32, m22 ); - this._y = Math.atan2( m13, m11 ); + this.computeFaceNormals(); - } else { + if ( geometry.boundingBox !== null ) { - this._x = Math.atan2( - m23, m33 ); - this._y = 0; + this.boundingBox = geometry.boundingBox.clone(); - } + } - } else { + if ( geometry.boundingSphere !== null ) { - console.warn( 'THREE.Euler: .setFromRotationMatrix() given unsupported order: ' + order ); + this.boundingSphere = geometry.boundingSphere.clone(); } - this._order = order; - - if ( update !== false ) this.onChangeCallback(); - return this; }, - setFromQuaternion: function () { + center: function () { - var matrix = new Matrix4(); + var offset = new Vector3(); - return function setFromQuaternion( q, order, update ) { + return function center() { - matrix.makeRotationFromQuaternion( q ); + this.computeBoundingBox(); - return this.setFromRotationMatrix( matrix, order, update ); + this.boundingBox.getCenter( offset ).negate(); + + this.translate( offset.x, offset.y, offset.z ); + + return this; }; }(), - setFromVector3: function ( v, order ) { - - return this.set( v.x, v.y, v.z, order || this._order ); + normalize: function () { - }, + this.computeBoundingSphere(); - reorder: function () { + var center = this.boundingSphere.center; + var radius = this.boundingSphere.radius; - // WARNING: this discards revolution information -bhouston + var s = radius === 0 ? 1 : 1.0 / radius; - var q = new Quaternion(); + 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 + ); - return function reorder( newOrder ) { + this.applyMatrix( matrix ); - q.setFromEuler( this ); + return this; - return this.setFromQuaternion( q, newOrder ); + }, - }; + computeFaceNormals: function () { - }(), + var cb = new Vector3(), ab = new Vector3(); - equals: function ( euler ) { + for ( var f = 0, fl = this.faces.length; f < fl; f ++ ) { - return ( euler._x === this._x ) && ( euler._y === this._y ) && ( euler._z === this._z ) && ( euler._order === this._order ); + var face = this.faces[ f ]; - }, + var vA = this.vertices[ face.a ]; + var vB = this.vertices[ face.b ]; + var vC = this.vertices[ face.c ]; - fromArray: function ( array ) { + cb.subVectors( vC, vB ); + ab.subVectors( vA, vB ); + cb.cross( ab ); - this._x = array[ 0 ]; - this._y = array[ 1 ]; - this._z = array[ 2 ]; - if ( array[ 3 ] !== undefined ) this._order = array[ 3 ]; + cb.normalize(); - this.onChangeCallback(); + face.normal.copy( cb ); - return this; + } }, - toArray: function ( array, offset ) { - - if ( array === undefined ) array = []; - if ( offset === undefined ) offset = 0; - - array[ offset ] = this._x; - array[ offset + 1 ] = this._y; - array[ offset + 2 ] = this._z; - array[ offset + 3 ] = this._order; + computeVertexNormals: function ( areaWeighted ) { - return array; + if ( areaWeighted === undefined ) areaWeighted = true; - }, + var v, vl, f, fl, face, vertices; - toVector3: function ( optionalResult ) { + vertices = new Array( this.vertices.length ); - if ( optionalResult ) { + for ( v = 0, vl = this.vertices.length; v < vl; v ++ ) { - return optionalResult.set( this._x, this._y, this._z ); + vertices[ v ] = new Vector3(); - } else { + } - return new Vector3( this._x, this._y, this._z ); + if ( areaWeighted ) { - } + // 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(); - onChange: function ( callback ) { + for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { - this.onChangeCallback = callback; + 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 ); - onChangeCallback: function () {} + vertices[ face.a ].add( cb ); + vertices[ face.b ].add( cb ); + vertices[ face.c ].add( cb ); -} ); + } -/** - * @author mrdoob / http://mrdoob.com/ - */ + } else { -function Layers() { + this.computeFaceNormals(); - this.mask = 1 | 0; + for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { -} + face = this.faces[ f ]; -Object.assign( Layers.prototype, { + vertices[ face.a ].add( face.normal ); + vertices[ face.b ].add( face.normal ); + vertices[ face.c ].add( face.normal ); - set: function ( channel ) { + } - this.mask = 1 << channel | 0; + } - }, + for ( v = 0, vl = this.vertices.length; v < vl; v ++ ) { - enable: function ( channel ) { + vertices[ v ].normalize(); - this.mask |= 1 << channel | 0; + } - }, + for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { - toggle: function ( channel ) { + face = this.faces[ f ]; - this.mask ^= 1 << channel | 0; + var vertexNormals = face.vertexNormals; - }, + if ( vertexNormals.length === 3 ) { - disable: function ( channel ) { + vertexNormals[ 0 ].copy( vertices[ face.a ] ); + vertexNormals[ 1 ].copy( vertices[ face.b ] ); + vertexNormals[ 2 ].copy( vertices[ face.c ] ); - this.mask &= ~ ( 1 << channel | 0 ); + } else { - }, + vertexNormals[ 0 ] = vertices[ face.a ].clone(); + vertexNormals[ 1 ] = vertices[ face.b ].clone(); + vertexNormals[ 2 ] = vertices[ face.c ].clone(); - test: function ( layers ) { + } - return ( this.mask & layers.mask ) !== 0; + } - } + if ( this.faces.length > 0 ) { -} ); + this.normalsNeedUpdate = true; -/** - * @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 object3DId = 0; + }, -function Object3D() { + computeFlatVertexNormals: function () { - Object.defineProperty( this, 'id', { value: object3DId ++ } ); + var f, fl, face; - this.uuid = _Math.generateUUID(); + this.computeFaceNormals(); - this.name = ''; - this.type = 'Object3D'; + for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { - this.parent = null; - this.children = []; + face = this.faces[ f ]; - this.up = Object3D.DefaultUp.clone(); + var vertexNormals = face.vertexNormals; - var position = new Vector3(); - var rotation = new Euler(); - var quaternion = new Quaternion(); - var scale = new Vector3( 1, 1, 1 ); + if ( vertexNormals.length === 3 ) { - function onRotationChange() { + vertexNormals[ 0 ].copy( face.normal ); + vertexNormals[ 1 ].copy( face.normal ); + vertexNormals[ 2 ].copy( face.normal ); - quaternion.setFromEuler( rotation, false ); + } else { - } + vertexNormals[ 0 ] = face.normal.clone(); + vertexNormals[ 1 ] = face.normal.clone(); + vertexNormals[ 2 ] = face.normal.clone(); - function onQuaternionChange() { + } - rotation.setFromQuaternion( quaternion, undefined, false ); + } - } + if ( this.faces.length > 0 ) { - rotation.onChange( onRotationChange ); - quaternion.onChange( onQuaternionChange ); + this.normalsNeedUpdate = true; - Object.defineProperties( this, { - position: { - enumerable: true, - value: position - }, - rotation: { - enumerable: true, - value: rotation - }, - quaternion: { - enumerable: true, - value: quaternion - }, - scale: { - enumerable: true, - value: scale - }, - modelViewMatrix: { - value: new Matrix4() - }, - normalMatrix: { - value: new Matrix3() } - } ); - this.matrix = new Matrix4(); - this.matrixWorld = new Matrix4(); + }, - this.matrixAutoUpdate = Object3D.DefaultMatrixAutoUpdate; - this.matrixWorldNeedsUpdate = false; + computeMorphNormals: function () { - this.layers = new Layers(); - this.visible = true; + var i, il, f, fl, face; - this.castShadow = false; - this.receiveShadow = false; + // save original normals + // - create temp variables on first access + // otherwise just copy (for faster repeated calls) - this.frustumCulled = true; - this.renderOrder = 0; + for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { - this.userData = {}; + face = this.faces[ f ]; -} + if ( ! face.__originalFaceNormal ) { -Object3D.DefaultUp = new Vector3( 0, 1, 0 ); -Object3D.DefaultMatrixAutoUpdate = true; + face.__originalFaceNormal = face.normal.clone(); -Object3D.prototype = Object.assign( Object.create( EventDispatcher.prototype ), { + } else { - constructor: Object3D, + face.__originalFaceNormal.copy( face.normal ); - isObject3D: true, + } - onBeforeRender: function () {}, - onAfterRender: function () {}, + if ( ! face.__originalVertexNormals ) face.__originalVertexNormals = []; - applyMatrix: function ( matrix ) { + for ( i = 0, il = face.vertexNormals.length; i < il; i ++ ) { - this.matrix.multiplyMatrices( matrix, this.matrix ); + if ( ! face.__originalVertexNormals[ i ] ) { - this.matrix.decompose( this.position, this.quaternion, this.scale ); + face.__originalVertexNormals[ i ] = face.vertexNormals[ i ].clone(); - }, + } else { - applyQuaternion: function ( q ) { + face.__originalVertexNormals[ i ].copy( face.vertexNormals[ i ] ); - this.quaternion.premultiply( q ); + } - return this; + } - }, + } - setRotationFromAxisAngle: function ( axis, angle ) { + // use temp geometry to compute face and vertex normals for each morph - // assumes axis is normalized + var tmpGeo = new Geometry(); + tmpGeo.faces = this.faces; - this.quaternion.setFromAxisAngle( axis, angle ); + for ( i = 0, il = this.morphTargets.length; i < il; i ++ ) { - }, + // create on first access - setRotationFromEuler: function ( euler ) { + if ( ! this.morphNormals[ i ] ) { - this.quaternion.setFromEuler( euler, true ); + this.morphNormals[ i ] = {}; + this.morphNormals[ i ].faceNormals = []; + this.morphNormals[ i ].vertexNormals = []; - }, + var dstNormalsFace = this.morphNormals[ i ].faceNormals; + var dstNormalsVertex = this.morphNormals[ i ].vertexNormals; - setRotationFromMatrix: function ( m ) { + var faceNormal, vertexNormals; - // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) + for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { - this.quaternion.setFromRotationMatrix( m ); + faceNormal = new Vector3(); + vertexNormals = { a: new Vector3(), b: new Vector3(), c: new Vector3() }; - }, + dstNormalsFace.push( faceNormal ); + dstNormalsVertex.push( vertexNormals ); - setRotationFromQuaternion: function ( q ) { + } - // assumes q is normalized + } - this.quaternion.copy( q ); + var morphNormals = this.morphNormals[ i ]; - }, + // set vertices to morph target - rotateOnAxis: function () { + tmpGeo.vertices = this.morphTargets[ i ].vertices; - // rotate object on axis in object space - // axis is assumed to be normalized + // compute morph normals - var q1 = new Quaternion(); + tmpGeo.computeFaceNormals(); + tmpGeo.computeVertexNormals(); - return function rotateOnAxis( axis, angle ) { + // store morph normals - q1.setFromAxisAngle( axis, angle ); + var faceNormal, vertexNormals; - this.quaternion.multiply( q1 ); + for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { - return this; + face = this.faces[ f ]; - }; + faceNormal = morphNormals.faceNormals[ f ]; + vertexNormals = morphNormals.vertexNormals[ f ]; - }(), + faceNormal.copy( face.normal ); - rotateOnWorldAxis: function () { + vertexNormals.a.copy( face.vertexNormals[ 0 ] ); + vertexNormals.b.copy( face.vertexNormals[ 1 ] ); + vertexNormals.c.copy( face.vertexNormals[ 2 ] ); - // rotate object on axis in world space - // axis is assumed to be normalized - // method assumes no rotated parent + } - var q1 = new Quaternion(); + } - return function rotateOnWorldAxis( axis, angle ) { + // restore original normals - q1.setFromAxisAngle( axis, angle ); + for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { - this.quaternion.premultiply( q1 ); + face = this.faces[ f ]; - return this; + face.normal = face.__originalFaceNormal; + face.vertexNormals = face.__originalVertexNormals; - }; + } - }(), + }, - rotateX: function () { + computeBoundingBox: function () { - var v1 = new Vector3( 1, 0, 0 ); + if ( this.boundingBox === null ) { - return function rotateX( angle ) { + this.boundingBox = new Box3(); - return this.rotateOnAxis( v1, angle ); + } - }; + this.boundingBox.setFromPoints( this.vertices ); - }(), + }, - rotateY: function () { + computeBoundingSphere: function () { - var v1 = new Vector3( 0, 1, 0 ); + if ( this.boundingSphere === null ) { - return function rotateY( angle ) { + this.boundingSphere = new Sphere(); - return this.rotateOnAxis( v1, angle ); + } - }; + this.boundingSphere.setFromPoints( this.vertices ); - }(), + }, - rotateZ: function () { + merge: function ( geometry, matrix, materialIndexOffset ) { - var v1 = new Vector3( 0, 0, 1 ); + if ( ! ( geometry && geometry.isGeometry ) ) { - return function rotateZ( angle ) { + console.error( 'THREE.Geometry.merge(): geometry not an instance of THREE.Geometry.', geometry ); + return; - return this.rotateOnAxis( v1, angle ); + } - }; + 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; - }(), + if ( materialIndexOffset === undefined ) materialIndexOffset = 0; - translateOnAxis: function () { + if ( matrix !== undefined ) { - // translate object by distance along axis in object space - // axis is assumed to be normalized + normalMatrix = new Matrix3().getNormalMatrix( matrix ); - var v1 = new Vector3(); + } - return function translateOnAxis( axis, distance ) { + // vertices - v1.copy( axis ).applyQuaternion( this.quaternion ); + for ( var i = 0, il = vertices2.length; i < il; i ++ ) { - this.position.add( v1.multiplyScalar( distance ) ); + var vertex = vertices2[ i ]; - return this; + var vertexCopy = vertex.clone(); - }; + if ( matrix !== undefined ) vertexCopy.applyMatrix4( matrix ); - }(), + vertices1.push( vertexCopy ); - translateX: function () { + } - var v1 = new Vector3( 1, 0, 0 ); + // colors - return function translateX( distance ) { + for ( var i = 0, il = colors2.length; i < il; i ++ ) { - return this.translateOnAxis( v1, distance ); + colors1.push( colors2[ i ].clone() ); - }; + } - }(), + // faces - translateY: function () { + for ( i = 0, il = faces2.length; i < il; i ++ ) { - var v1 = new Vector3( 0, 1, 0 ); + var face = faces2[ i ], faceCopy, normal, color, + faceVertexNormals = face.vertexNormals, + faceVertexColors = face.vertexColors; - return function translateY( distance ) { + faceCopy = new Face3( face.a + vertexOffset, face.b + vertexOffset, face.c + vertexOffset ); + faceCopy.normal.copy( face.normal ); - return this.translateOnAxis( v1, distance ); + if ( normalMatrix !== undefined ) { - }; + faceCopy.normal.applyMatrix3( normalMatrix ).normalize(); - }(), + } - translateZ: function () { + for ( var j = 0, jl = faceVertexNormals.length; j < jl; j ++ ) { - var v1 = new Vector3( 0, 0, 1 ); + normal = faceVertexNormals[ j ].clone(); - return function translateZ( distance ) { - - return this.translateOnAxis( v1, distance ); + if ( normalMatrix !== undefined ) { - }; + normal.applyMatrix3( normalMatrix ).normalize(); - }(), + } - localToWorld: function ( vector ) { + faceCopy.vertexNormals.push( normal ); - return vector.applyMatrix4( this.matrixWorld ); + } - }, + faceCopy.color.copy( face.color ); - worldToLocal: function () { + for ( var j = 0, jl = faceVertexColors.length; j < jl; j ++ ) { - var m1 = new Matrix4(); + color = faceVertexColors[ j ]; + faceCopy.vertexColors.push( color.clone() ); - return function worldToLocal( vector ) { + } - return vector.applyMatrix4( m1.getInverse( this.matrixWorld ) ); + faceCopy.materialIndex = face.materialIndex + materialIndexOffset; - }; + faces1.push( faceCopy ); - }(), + } - lookAt: function () { + // uvs - // This method does not support objects with rotated and/or translated parent(s) + for ( i = 0, il = uvs2.length; i < il; i ++ ) { - var m1 = new Matrix4(); - var vector = new Vector3(); + var uv = uvs2[ i ], uvCopy = []; - return function lookAt( x, y, z ) { + if ( uv === undefined ) { - if ( x.isVector3 ) { + continue; - vector.copy( x ); + } - } else { + for ( var j = 0, jl = uv.length; j < jl; j ++ ) { - vector.set( x, y, z ); + uvCopy.push( uv[ j ].clone() ); } - if ( this.isCamera ) { - - m1.lookAt( this.position, vector, this.up ); + uvs1.push( uvCopy ); - } else { + } - m1.lookAt( vector, this.position, this.up ); + }, - } + mergeMesh: function ( mesh ) { - this.quaternion.setFromRotationMatrix( m1 ); + if ( ! ( mesh && mesh.isMesh ) ) { - }; + console.error( 'THREE.Geometry.mergeMesh(): mesh not an instance of THREE.Mesh.', mesh ); + return; - }(), + } - add: function ( object ) { + if ( mesh.matrixAutoUpdate ) mesh.updateMatrix(); - if ( arguments.length > 1 ) { + this.merge( mesh.geometry, mesh.matrix ); - for ( var i = 0; i < arguments.length; i ++ ) { + }, - this.add( arguments[ i ] ); + /* + * Checks for duplicate vertices with hashmap. + * Duplicated vertices are removed + * and faces' vertices are updated. + */ - } + mergeVertices: function () { - return this; + var verticesMap = {}; // Hashmap for looking up vertices by position coordinates (and making sure they are unique) + var unique = [], changes = []; - } + 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; - if ( object === this ) { + for ( i = 0, il = this.vertices.length; i < il; i ++ ) { - console.error( "THREE.Object3D.add: object can't be added as a child of itself.", object ); - return this; + 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 ( ( object && object.isObject3D ) ) { + verticesMap[ key ] = i; + unique.push( this.vertices[ i ] ); + changes[ i ] = unique.length - 1; - if ( object.parent !== null ) { + } else { - object.parent.remove( object ); + //console.log('Duplicate vertex found. ', i, ' could be using ', verticesMap[key]); + changes[ i ] = changes[ verticesMap[ key ] ]; } - object.parent = this; - object.dispatchEvent( { type: 'added' } ); + } - this.children.push( object ); - } else { + // if faces are completely degenerate after merging vertices, we + // have to remove them from the geometry. + var faceIndicesToRemove = []; - console.error( "THREE.Object3D.add: object not an instance of THREE.Object3D.", object ); + for ( i = 0, il = this.faces.length; i < il; i ++ ) { - } + face = this.faces[ i ]; - return this; + face.a = changes[ face.a ]; + face.b = changes[ face.b ]; + face.c = changes[ face.c ]; - }, + indices = [ face.a, face.b, face.c ]; - remove: function ( object ) { + // 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 ( arguments.length > 1 ) { + if ( indices[ n ] === indices[ ( n + 1 ) % 3 ] ) { - for ( var i = 0; i < arguments.length; i ++ ) { + faceIndicesToRemove.push( i ); + break; - this.remove( arguments[ i ] ); + } } - return this; - } - var index = this.children.indexOf( object ); + for ( i = faceIndicesToRemove.length - 1; i >= 0; i -- ) { - if ( index !== - 1 ) { + var idx = faceIndicesToRemove[ i ]; - object.parent = null; + this.faces.splice( idx, 1 ); - object.dispatchEvent( { type: 'removed' } ); + for ( j = 0, jl = this.faceVertexUvs.length; j < jl; j ++ ) { - this.children.splice( index, 1 ); + this.faceVertexUvs[ j ].splice( idx, 1 ); + + } } - return this; + // Use unique set of vertices + + var diff = this.vertices.length - unique.length; + this.vertices = unique; + return diff; }, - getObjectById: function ( id ) { + setFromPoints: function ( points ) { - return this.getObjectByProperty( 'id', id ); + this.vertices = []; - }, + for ( var i = 0, l = points.length; i < l; i ++ ) { - getObjectByName: function ( name ) { + var point = points[ i ]; + this.vertices.push( new Vector3( point.x, point.y, point.z || 0 ) ); - return this.getObjectByProperty( 'name', name ); + } + + return this; }, - getObjectByProperty: function ( name, value ) { + sortFacesByMaterialIndex: function () { - if ( this[ name ] === value ) return this; + var faces = this.faces; + var length = faces.length; - for ( var i = 0, l = this.children.length; i < l; i ++ ) { + // tag faces - var child = this.children[ i ]; - var object = child.getObjectByProperty( name, value ); + for ( var i = 0; i < length; i ++ ) { - if ( object !== undefined ) { + faces[ i ]._id = i; - return object; + } - } + // sort faces - } + function materialIndexSort( a, b ) { - return undefined; + return a.materialIndex - b.materialIndex; - }, + } - getWorldPosition: function ( optionalTarget ) { + faces.sort( materialIndexSort ); - var result = optionalTarget || new Vector3(); + // sort uvs - this.updateMatrixWorld( true ); + var uvs1 = this.faceVertexUvs[ 0 ]; + var uvs2 = this.faceVertexUvs[ 1 ]; - return result.setFromMatrixPosition( this.matrixWorld ); + var newUvs1, newUvs2; - }, + if ( uvs1 && uvs1.length === length ) newUvs1 = []; + if ( uvs2 && uvs2.length === length ) newUvs2 = []; - getWorldQuaternion: function () { + for ( var i = 0; i < length; i ++ ) { - var position = new Vector3(); - var scale = new Vector3(); + var id = faces[ i ]._id; - return function getWorldQuaternion( optionalTarget ) { + if ( newUvs1 ) newUvs1.push( uvs1[ id ] ); + if ( newUvs2 ) newUvs2.push( uvs2[ id ] ); - var result = optionalTarget || new Quaternion(); + } - this.updateMatrixWorld( true ); + if ( newUvs1 ) this.faceVertexUvs[ 0 ] = newUvs1; + if ( newUvs2 ) this.faceVertexUvs[ 1 ] = newUvs2; - this.matrixWorld.decompose( position, result, scale ); + }, - return result; + toJSON: function () { + var data = { + metadata: { + version: 4.5, + type: 'Geometry', + generator: 'Geometry.toJSON' + } }; - }(), + // standard Geometry serialization - getWorldRotation: function () { + data.uuid = this.uuid; + data.type = this.type; + if ( this.name !== '' ) data.name = this.name; - var quaternion = new Quaternion(); + if ( this.parameters !== undefined ) { - return function getWorldRotation( optionalTarget ) { + var parameters = this.parameters; - var result = optionalTarget || new Euler(); + for ( var key in parameters ) { - this.getWorldQuaternion( quaternion ); + if ( parameters[ key ] !== undefined ) data[ key ] = parameters[ key ]; - return result.setFromQuaternion( quaternion, this.rotation.order, false ); + } - }; + return data; - }(), + } - getWorldScale: function () { + var vertices = []; - var position = new Vector3(); - var quaternion = new Quaternion(); + for ( var i = 0; i < this.vertices.length; i ++ ) { - return function getWorldScale( optionalTarget ) { + var vertex = this.vertices[ i ]; + vertices.push( vertex.x, vertex.y, vertex.z ); - var result = optionalTarget || new Vector3(); + } - this.updateMatrixWorld( true ); + var faces = []; + var normals = []; + var normalsHash = {}; + var colors = []; + var colorsHash = {}; + var uvs = []; + var uvsHash = {}; + + for ( var i = 0; i < this.faces.length; i ++ ) { - this.matrixWorld.decompose( position, quaternion, result ); + var face = this.faces[ i ]; - return result; + 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; - }(), + 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 ); - getWorldDirection: function () { + faces.push( faceType ); + faces.push( face.a, face.b, face.c ); + faces.push( face.materialIndex ); - var quaternion = new Quaternion(); + if ( hasFaceVertexUv ) { - return function getWorldDirection( optionalTarget ) { + var faceVertexUvs = this.faceVertexUvs[ 0 ][ i ]; - var result = optionalTarget || new Vector3(); + faces.push( + getUvIndex( faceVertexUvs[ 0 ] ), + getUvIndex( faceVertexUvs[ 1 ] ), + getUvIndex( faceVertexUvs[ 2 ] ) + ); - this.getWorldQuaternion( quaternion ); + } - return result.set( 0, 0, 1 ).applyQuaternion( quaternion ); + if ( hasFaceNormal ) { - }; + faces.push( getNormalIndex( face.normal ) ); - }(), + } - raycast: function () {}, + if ( hasFaceVertexNormal ) { - traverse: function ( callback ) { + var vertexNormals = face.vertexNormals; - callback( this ); + faces.push( + getNormalIndex( vertexNormals[ 0 ] ), + getNormalIndex( vertexNormals[ 1 ] ), + getNormalIndex( vertexNormals[ 2 ] ) + ); - var children = this.children; + } - for ( var i = 0, l = children.length; i < l; i ++ ) { + if ( hasFaceColor ) { - children[ i ].traverse( callback ); + faces.push( getColorIndex( face.color ) ); - } + } - }, + if ( hasFaceVertexColor ) { - traverseVisible: function ( callback ) { + var vertexColors = face.vertexColors; - if ( this.visible === false ) return; + faces.push( + getColorIndex( vertexColors[ 0 ] ), + getColorIndex( vertexColors[ 1 ] ), + getColorIndex( vertexColors[ 2 ] ) + ); - callback( this ); + } - var children = this.children; + } - for ( var i = 0, l = children.length; i < l; i ++ ) { + function setBit( value, position, enabled ) { - children[ i ].traverseVisible( callback ); + return enabled ? value | ( 1 << position ) : value & ( ~ ( 1 << position ) ); } - }, + function getNormalIndex( normal ) { - traverseAncestors: function ( callback ) { + var hash = normal.x.toString() + normal.y.toString() + normal.z.toString(); - var parent = this.parent; + if ( normalsHash[ hash ] !== undefined ) { - if ( parent !== null ) { + return normalsHash[ hash ]; - callback( parent ); + } - parent.traverseAncestors( callback ); + normalsHash[ hash ] = normals.length / 3; + normals.push( normal.x, normal.y, normal.z ); + + return normalsHash[ hash ]; } - }, + function getColorIndex( color ) { - updateMatrix: function () { + var hash = color.r.toString() + color.g.toString() + color.b.toString(); - this.matrix.compose( this.position, this.quaternion, this.scale ); + if ( colorsHash[ hash ] !== undefined ) { - this.matrixWorldNeedsUpdate = true; + return colorsHash[ hash ]; - }, + } - updateMatrixWorld: function ( force ) { + colorsHash[ hash ] = colors.length; + colors.push( color.getHex() ); - if ( this.matrixAutoUpdate ) this.updateMatrix(); + return colorsHash[ hash ]; - if ( this.matrixWorldNeedsUpdate || force ) { + } - if ( this.parent === null ) { + function getUvIndex( uv ) { - this.matrixWorld.copy( this.matrix ); + var hash = uv.x.toString() + uv.y.toString(); - } else { + if ( uvsHash[ hash ] !== undefined ) { - this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix ); + return uvsHash[ hash ]; } - this.matrixWorldNeedsUpdate = false; + uvsHash[ hash ] = uvs.length / 2; + uvs.push( uv.x, uv.y ); - force = true; + return uvsHash[ hash ]; } - // update children - - var children = this.children; - - for ( var i = 0, l = children.length; i < l; i ++ ) { + data.data = {}; - children[ i ].updateMatrixWorld( force ); + 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; - } + return data; }, - toJSON: function ( meta ) { + clone: function () { - // meta is a string when called from JSON.stringify - var isRootObject = ( meta === undefined || typeof meta === 'string' ); + /* + // Handle primitives - var output = {}; + var parameters = this.parameters; - // meta is a hash used to collect geometries, materials. - // not providing it implies that this is the root object - // being serialized. - if ( isRootObject ) { + if ( parameters !== undefined ) { - // initialize meta obj - meta = { - geometries: {}, - materials: {}, - textures: {}, - images: {}, - shapes: {} - }; + var values = []; - output.metadata = { - version: 4.5, - type: 'Object', - generator: 'Object3D.toJSON' - }; + for ( var key in parameters ) { - } + values.push( parameters[ key ] ); - // standard Object3D serialization + } - var object = {}; + var geometry = Object.create( this.constructor.prototype ); + this.constructor.apply( geometry, values ); + return geometry; - 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 ( JSON.stringify( this.userData ) !== '{}' ) object.userData = this.userData; + return new this.constructor().copy( this ); + */ - object.matrix = this.matrix.toArray(); + return new Geometry().copy( this ); - // + }, - function serialize( library, element ) { + copy: function ( source ) { - if ( library[ element.uuid ] === undefined ) { + var i, il, j, jl, k, kl; - library[ element.uuid ] = element.toJSON( meta ); + // reset - } + this.vertices = []; + this.colors = []; + this.faces = []; + this.faceVertexUvs = [[]]; + this.morphTargets = []; + this.morphNormals = []; + this.skinWeights = []; + this.skinIndices = []; + this.lineDistances = []; + this.boundingBox = null; + this.boundingSphere = null; - return element.uuid; + // name - } + this.name = source.name; - if ( this.geometry !== undefined ) { + // vertices - object.geometry = serialize( meta.geometries, this.geometry ); + var vertices = source.vertices; - var parameters = this.geometry.parameters; + for ( i = 0, il = vertices.length; i < il; i ++ ) { - if ( parameters !== undefined && parameters.shapes !== undefined ) { + this.vertices.push( vertices[ i ].clone() ); - var shapes = parameters.shapes; + } - if ( Array.isArray( shapes ) ) { + // colors - for ( var i = 0, l = shapes.length; i < l; i ++ ) { + var colors = source.colors; - var shape = shapes[ i ]; + for ( i = 0, il = colors.length; i < il; i ++ ) { - serialize( meta.shapes, shape ); + this.colors.push( colors[ i ].clone() ); - } + } - } else { + // faces - serialize( meta.shapes, shapes ); + var faces = source.faces; - } + for ( i = 0, il = faces.length; i < il; i ++ ) { - } + this.faces.push( faces[ i ].clone() ); } - if ( this.material !== undefined ) { + // face vertex uvs - if ( Array.isArray( this.material ) ) { + for ( i = 0, il = source.faceVertexUvs.length; i < il; i ++ ) { - var uuids = []; + var faceVertexUvs = source.faceVertexUvs[ i ]; - for ( var i = 0, l = this.material.length; i < l; i ++ ) { + if ( this.faceVertexUvs[ i ] === undefined ) { - uuids.push( serialize( meta.materials, this.material[ i ] ) ); + this.faceVertexUvs[ i ] = []; - } + } - object.material = uuids; + for ( j = 0, jl = faceVertexUvs.length; j < jl; j ++ ) { - } else { + var uvs = faceVertexUvs[ j ], uvsCopy = []; - object.material = serialize( meta.materials, this.material ); + for ( k = 0, kl = uvs.length; k < kl; k ++ ) { + + var uv = uvs[ k ]; + + uvsCopy.push( uv.clone() ); + + } + + this.faceVertexUvs[ i ].push( uvsCopy ); } } - // + // morph targets - if ( this.children.length > 0 ) { + var morphTargets = source.morphTargets; - object.children = []; + for ( i = 0, il = morphTargets.length; i < il; i ++ ) { - for ( var i = 0; i < this.children.length; i ++ ) { + var morphTarget = {}; + morphTarget.name = morphTargets[ i ].name; - object.children.push( this.children[ i ].toJSON( meta ).object ); + // vertices - } + if ( morphTargets[ i ].vertices !== undefined ) { - } + morphTarget.vertices = []; - if ( isRootObject ) { + for ( j = 0, jl = morphTargets[ i ].vertices.length; j < jl; j ++ ) { - 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 ); + morphTarget.vertices.push( morphTargets[ i ].vertices[ j ].clone() ); - 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; + } - } + } - output.object = object; + // normals - return output; + if ( morphTargets[ i ].normals !== undefined ) { - // extract data from the cache hash - // remove metadata on each item - // and return as array - function extractFromCache( cache ) { + morphTarget.normals = []; - var values = []; - for ( var key in cache ) { + for ( j = 0, jl = morphTargets[ i ].normals.length; j < jl; j ++ ) { - var data = cache[ key ]; - delete data.metadata; - values.push( data ); + morphTarget.normals.push( morphTargets[ i ].normals[ j ].clone() ); + + } } - return values; + + this.morphTargets.push( morphTarget ); } - }, + // morph normals - clone: function ( recursive ) { + var morphNormals = source.morphNormals; - return new this.constructor().copy( this, recursive ); + for ( i = 0, il = morphNormals.length; i < il; i ++ ) { - }, + var morphNormal = {}; - copy: function ( source, recursive ) { + // vertex normals - if ( recursive === undefined ) recursive = true; + if ( morphNormals[ i ].vertexNormals !== undefined ) { - this.name = source.name; + morphNormal.vertexNormals = []; - this.up.copy( source.up ); + for ( j = 0, jl = morphNormals[ i ].vertexNormals.length; j < jl; j ++ ) { - this.position.copy( source.position ); - this.quaternion.copy( source.quaternion ); - this.scale.copy( source.scale ); + var srcVertexNormal = morphNormals[ i ].vertexNormals[ j ]; + var destVertexNormal = {}; - this.matrix.copy( source.matrix ); - this.matrixWorld.copy( source.matrixWorld ); + destVertexNormal.a = srcVertexNormal.a.clone(); + destVertexNormal.b = srcVertexNormal.b.clone(); + destVertexNormal.c = srcVertexNormal.c.clone(); - this.matrixAutoUpdate = source.matrixAutoUpdate; - this.matrixWorldNeedsUpdate = source.matrixWorldNeedsUpdate; + morphNormal.vertexNormals.push( destVertexNormal ); - this.layers.mask = source.layers.mask; - this.visible = source.visible; + } - this.castShadow = source.castShadow; - this.receiveShadow = source.receiveShadow; + } - this.frustumCulled = source.frustumCulled; - this.renderOrder = source.renderOrder; + // face normals - this.userData = JSON.parse( JSON.stringify( source.userData ) ); + if ( morphNormals[ i ].faceNormals !== undefined ) { - if ( recursive === true ) { + morphNormal.faceNormals = []; - for ( var i = 0; i < source.children.length; i ++ ) { + for ( j = 0, jl = morphNormals[ i ].faceNormals.length; j < jl; j ++ ) { - var child = source.children[ i ]; - this.add( child.clone() ); + morphNormal.faceNormals.push( morphNormals[ i ].faceNormals[ j ].clone() ); + + } } + this.morphNormals.push( morphNormal ); + } - return this; + // skin weights - } + var skinWeights = source.skinWeights; -} ); + for ( i = 0, il = skinWeights.length; i < il; i ++ ) { -/** - * @author mrdoob / http://mrdoob.com/ - * @author mikael emtinger / http://gomo.se/ - * @author WestLangley / http://github.com/WestLangley -*/ + this.skinWeights.push( skinWeights[ i ].clone() ); -function Camera() { + } - Object3D.call( this ); + // skin indices - this.type = 'Camera'; + var skinIndices = source.skinIndices; - this.matrixWorldInverse = new Matrix4(); - this.projectionMatrix = new Matrix4(); + for ( i = 0, il = skinIndices.length; i < il; i ++ ) { -} + this.skinIndices.push( skinIndices[ i ].clone() ); -Camera.prototype = Object.assign( Object.create( Object3D.prototype ), { + } - constructor: Camera, + // line distances - isCamera: true, + var lineDistances = source.lineDistances; - copy: function ( source, recursive ) { + for ( i = 0, il = lineDistances.length; i < il; i ++ ) { - Object3D.prototype.copy.call( this, source, recursive ); + this.lineDistances.push( lineDistances[ i ] ); - this.matrixWorldInverse.copy( source.matrixWorldInverse ); - this.projectionMatrix.copy( source.projectionMatrix ); + } - return this; + // bounding box - }, + var boundingBox = source.boundingBox; - getWorldDirection: function () { + if ( boundingBox !== null ) { - var quaternion = new Quaternion(); + this.boundingBox = boundingBox.clone(); - return function getWorldDirection( optionalTarget ) { + } - var result = optionalTarget || new Vector3(); + // bounding sphere - this.getWorldQuaternion( quaternion ); + var boundingSphere = source.boundingSphere; - return result.set( 0, 0, - 1 ).applyQuaternion( quaternion ); + if ( boundingSphere !== null ) { - }; + this.boundingSphere = boundingSphere.clone(); - }(), + } - updateMatrixWorld: function ( force ) { + // update flags - Object3D.prototype.updateMatrixWorld.call( this, force ); + 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; - this.matrixWorldInverse.getInverse( this.matrixWorld ); + return this; }, - clone: function () { + dispose: function () { - return new this.constructor().copy( this ); + this.dispatchEvent( { type: 'dispose' } ); } } ); /** - * @author alteredq / http://alteredqualia.com/ - * @author arose / http://github.com/arose + * @author mrdoob / http://mrdoob.com/ */ -function OrthographicCamera( left, right, top, bottom, near, far ) { +function BufferAttribute( array, itemSize, normalized ) { - Camera.call( this ); + if ( Array.isArray( array ) ) { - this.type = 'OrthographicCamera'; + throw new TypeError( 'THREE.BufferAttribute: array should be a Typed Array.' ); - this.zoom = 1; - this.view = null; + } - this.left = left; - this.right = right; - this.top = top; - this.bottom = bottom; + this.name = ''; - this.near = ( near !== undefined ) ? near : 0.1; - this.far = ( far !== undefined ) ? far : 2000; + this.array = array; + this.itemSize = itemSize; + this.count = array !== undefined ? array.length / itemSize : 0; + this.normalized = normalized === true; - this.updateProjectionMatrix(); + this.dynamic = false; + this.updateRange = { offset: 0, count: - 1 }; -} + this.version = 0; -OrthographicCamera.prototype = Object.assign( Object.create( Camera.prototype ), { +} - constructor: OrthographicCamera, +Object.defineProperty( BufferAttribute.prototype, 'needsUpdate', { - isOrthographicCamera: true, + set: function ( value ) { - copy: function ( source, recursive ) { + if ( value === true ) this.version ++; - 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; +} ); - this.zoom = source.zoom; - this.view = source.view === null ? null : Object.assign( {}, source.view ); +Object.assign( BufferAttribute.prototype, { - return this; + isBufferAttribute: true, - }, + onUploadCallback: function () {}, - setViewOffset: function ( fullWidth, fullHeight, x, y, width, height ) { + setArray: function ( array ) { - if ( this.view === null ) { + if ( Array.isArray( array ) ) { - this.view = { - enabled: true, - fullWidth: 1, - fullHeight: 1, - offsetX: 0, - offsetY: 0, - width: 1, - height: 1 - }; + throw new TypeError( 'THREE.BufferAttribute: array should be a Typed Array.' ); } - this.view.enabled = true; - this.view.fullWidth = fullWidth; - this.view.fullHeight = fullHeight; - this.view.offsetX = x; - this.view.offsetY = y; - this.view.width = width; - this.view.height = height; + this.count = array !== undefined ? array.length / this.itemSize : 0; + this.array = array; - this.updateProjectionMatrix(); + return this; }, - clearViewOffset: function () { - - if ( this.view !== null ) { - - this.view.enabled = false; + setDynamic: function ( value ) { - } + this.dynamic = value; - this.updateProjectionMatrix(); + return this; }, - updateProjectionMatrix: function () { + copy: function ( source ) { - 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; + this.name = source.name; + this.array = new source.array.constructor( source.array ); + this.itemSize = source.itemSize; + this.count = source.count; + this.normalized = source.normalized; - var left = cx - dx; - var right = cx + dx; - var top = cy + dy; - var bottom = cy - dy; + this.dynamic = source.dynamic; - if ( this.view !== null && this.view.enabled ) { + return this; - 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; + }, - 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 ); + copyAt: function ( index1, attribute, index2 ) { - } + index1 *= this.itemSize; + index2 *= attribute.itemSize; - this.projectionMatrix.makeOrthographic( left, right, top, bottom, this.near, this.far ); + for ( var i = 0, l = this.itemSize; i < l; i ++ ) { - }, + this.array[ index1 + i ] = attribute.array[ index2 + i ]; - toJSON: function ( meta ) { + } - var data = Object3D.prototype.toJSON.call( this, meta ); + return this; - data.object.zoom = this.zoom; - data.object.left = this.left; - data.object.right = this.right; - data.object.top = this.top; - data.object.bottom = this.bottom; - data.object.near = this.near; - data.object.far = this.far; + }, - if ( this.view !== null ) data.object.view = Object.assign( {}, this.view ); + copyArray: function ( array ) { - return data; + this.array.set( array ); - } + return this; -} ); + }, -/** - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - */ + copyColorsArray: function ( colors ) { -function Face3( a, b, c, normal, color, materialIndex ) { + var array = this.array, offset = 0; - this.a = a; - this.b = b; - this.c = c; + for ( var i = 0, l = colors.length; i < l; i ++ ) { - this.normal = ( normal && normal.isVector3 ) ? normal : new Vector3(); - this.vertexNormals = Array.isArray( normal ) ? normal : []; + var color = colors[ i ]; - this.color = ( color && color.isColor ) ? color : new Color(); - this.vertexColors = Array.isArray( color ) ? color : []; + if ( color === undefined ) { - this.materialIndex = materialIndex !== undefined ? materialIndex : 0; + console.warn( 'THREE.BufferAttribute.copyColorsArray(): color is undefined', i ); + color = new Color(); -} + } -Object.assign( Face3.prototype, { + array[ offset ++ ] = color.r; + array[ offset ++ ] = color.g; + array[ offset ++ ] = color.b; - clone: function () { + } - return new this.constructor().copy( this ); + return this; }, - copy: function ( source ) { - - this.a = source.a; - this.b = source.b; - this.c = source.c; + copyVector2sArray: function ( vectors ) { - this.normal.copy( source.normal ); - this.color.copy( source.color ); + var array = this.array, offset = 0; - this.materialIndex = source.materialIndex; + for ( var i = 0, l = vectors.length; i < l; i ++ ) { - for ( var i = 0, il = source.vertexNormals.length; i < il; i ++ ) { + var vector = vectors[ i ]; - this.vertexNormals[ i ] = source.vertexNormals[ i ].clone(); + if ( vector === undefined ) { - } + console.warn( 'THREE.BufferAttribute.copyVector2sArray(): vector is undefined', i ); + vector = new Vector2(); - for ( var i = 0, il = source.vertexColors.length; i < il; i ++ ) { + } - this.vertexColors[ i ] = source.vertexColors[ i ].clone(); + array[ offset ++ ] = vector.x; + array[ offset ++ ] = vector.y; } return this; - } - -} ); - -/** - * @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 - */ - -var geometryId = 0; // Geometry uses even numbers as Id + }, -function Geometry() { + copyVector3sArray: function ( vectors ) { - Object.defineProperty( this, 'id', { value: geometryId += 2 } ); + var array = this.array, offset = 0; - this.uuid = _Math.generateUUID(); + for ( var i = 0, l = vectors.length; i < l; i ++ ) { - this.name = ''; - this.type = 'Geometry'; + var vector = vectors[ i ]; - this.vertices = []; - this.colors = []; - this.faces = []; - this.faceVertexUvs = [[]]; + if ( vector === undefined ) { - this.morphTargets = []; - this.morphNormals = []; + console.warn( 'THREE.BufferAttribute.copyVector3sArray(): vector is undefined', i ); + vector = new Vector3(); - this.skinWeights = []; - this.skinIndices = []; + } - this.lineDistances = []; + array[ offset ++ ] = vector.x; + array[ offset ++ ] = vector.y; + array[ offset ++ ] = vector.z; - this.boundingBox = null; - this.boundingSphere = null; + } - // update flags + return this; - this.elementsNeedUpdate = false; - this.verticesNeedUpdate = false; - this.uvsNeedUpdate = false; - this.normalsNeedUpdate = false; - this.colorsNeedUpdate = false; - this.lineDistancesNeedUpdate = false; - this.groupsNeedUpdate = false; + }, -} + copyVector4sArray: function ( vectors ) { -Geometry.prototype = Object.assign( Object.create( EventDispatcher.prototype ), { + var array = this.array, offset = 0; - constructor: Geometry, + for ( var i = 0, l = vectors.length; i < l; i ++ ) { - isGeometry: true, + var vector = vectors[ i ]; - applyMatrix: function ( matrix ) { + if ( vector === undefined ) { - var normalMatrix = new Matrix3().getNormalMatrix( matrix ); + console.warn( 'THREE.BufferAttribute.copyVector4sArray(): vector is undefined', i ); + vector = new Vector4(); - for ( var i = 0, il = this.vertices.length; i < il; i ++ ) { + } - var vertex = this.vertices[ i ]; - vertex.applyMatrix4( matrix ); + array[ offset ++ ] = vector.x; + array[ offset ++ ] = vector.y; + array[ offset ++ ] = vector.z; + array[ offset ++ ] = vector.w; } - for ( var i = 0, il = this.faces.length; i < il; i ++ ) { - - var face = this.faces[ i ]; - face.normal.applyMatrix3( normalMatrix ).normalize(); + return this; - for ( var j = 0, jl = face.vertexNormals.length; j < jl; j ++ ) { + }, - face.vertexNormals[ j ].applyMatrix3( normalMatrix ).normalize(); + set: function ( value, offset ) { - } + if ( offset === undefined ) offset = 0; - } + this.array.set( value, offset ); - if ( this.boundingBox !== null ) { + return this; - this.computeBoundingBox(); + }, - } + getX: function ( index ) { - if ( this.boundingSphere !== null ) { + return this.array[ index * this.itemSize ]; - this.computeBoundingSphere(); + }, - } + setX: function ( index, x ) { - this.verticesNeedUpdate = true; - this.normalsNeedUpdate = true; + this.array[ index * this.itemSize ] = x; return this; }, - rotateX: function () { + getY: function ( index ) { - // rotate geometry around world x-axis + return this.array[ index * this.itemSize + 1 ]; - var m1 = new Matrix4(); + }, - return function rotateX( angle ) { + setY: function ( index, y ) { - m1.makeRotationX( angle ); + this.array[ index * this.itemSize + 1 ] = y; - this.applyMatrix( m1 ); + return this; - return this; + }, - }; + getZ: function ( index ) { - }(), + return this.array[ index * this.itemSize + 2 ]; - rotateY: function () { + }, - // rotate geometry around world y-axis + setZ: function ( index, z ) { - var m1 = new Matrix4(); + this.array[ index * this.itemSize + 2 ] = z; - return function rotateY( angle ) { + return this; - m1.makeRotationY( angle ); + }, - this.applyMatrix( m1 ); + getW: function ( index ) { - return this; + return this.array[ index * this.itemSize + 3 ]; - }; + }, - }(), + setW: function ( index, w ) { - rotateZ: function () { + this.array[ index * this.itemSize + 3 ] = w; - // rotate geometry around world z-axis + return this; - var m1 = new Matrix4(); + }, - return function rotateZ( angle ) { + setXY: function ( index, x, y ) { - m1.makeRotationZ( angle ); + index *= this.itemSize; - this.applyMatrix( m1 ); + this.array[ index + 0 ] = x; + this.array[ index + 1 ] = y; - return this; + return this; - }; + }, - }(), + setXYZ: function ( index, x, y, z ) { - translate: function () { + index *= this.itemSize; - // translate geometry + this.array[ index + 0 ] = x; + this.array[ index + 1 ] = y; + this.array[ index + 2 ] = z; - var m1 = new Matrix4(); + return this; - return function translate( x, y, z ) { + }, - m1.makeTranslation( x, y, z ); + setXYZW: function ( index, x, y, z, w ) { - this.applyMatrix( m1 ); + index *= this.itemSize; - return this; + this.array[ index + 0 ] = x; + this.array[ index + 1 ] = y; + this.array[ index + 2 ] = z; + this.array[ index + 3 ] = w; - }; + return this; - }(), + }, - scale: function () { + onUpload: function ( callback ) { - // scale geometry + this.onUploadCallback = callback; - var m1 = new Matrix4(); + return this; - return function scale( x, y, z ) { + }, - m1.makeScale( x, y, z ); + clone: function () { - this.applyMatrix( m1 ); + return new this.constructor( this.array, this.itemSize ).copy( this ); - return this; + } - }; +} ); - }(), +// - lookAt: function () { +function Int8BufferAttribute( array, itemSize, normalized ) { - var obj = new Object3D(); + BufferAttribute.call( this, new Int8Array( array ), itemSize, normalized ); - return function lookAt( vector ) { +} - obj.lookAt( vector ); +Int8BufferAttribute.prototype = Object.create( BufferAttribute.prototype ); +Int8BufferAttribute.prototype.constructor = Int8BufferAttribute; - obj.updateMatrix(); - this.applyMatrix( obj.matrix ); +function Uint8BufferAttribute( array, itemSize, normalized ) { - }; + BufferAttribute.call( this, new Uint8Array( array ), itemSize, normalized ); - }(), +} - fromBufferGeometry: function ( geometry ) { +Uint8BufferAttribute.prototype = Object.create( BufferAttribute.prototype ); +Uint8BufferAttribute.prototype.constructor = Uint8BufferAttribute; - var scope = this; - var indices = geometry.index !== null ? geometry.index.array : undefined; - var attributes = geometry.attributes; +function Uint8ClampedBufferAttribute( array, itemSize, normalized ) { - 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; + BufferAttribute.call( this, new Uint8ClampedArray( array ), itemSize, normalized ); - if ( uvs2 !== undefined ) this.faceVertexUvs[ 1 ] = []; +} - var tempNormals = []; - var tempUVs = []; - var tempUVs2 = []; +Uint8ClampedBufferAttribute.prototype = Object.create( BufferAttribute.prototype ); +Uint8ClampedBufferAttribute.prototype.constructor = Uint8ClampedBufferAttribute; - for ( var i = 0, j = 0; i < positions.length; i += 3, j += 2 ) { - scope.vertices.push( new Vector3( positions[ i ], positions[ i + 1 ], positions[ i + 2 ] ) ); +function Int16BufferAttribute( array, itemSize, normalized ) { - if ( normals !== undefined ) { + BufferAttribute.call( this, new Int16Array( array ), itemSize, normalized ); - tempNormals.push( new Vector3( normals[ i ], normals[ i + 1 ], normals[ i + 2 ] ) ); +} - } +Int16BufferAttribute.prototype = Object.create( BufferAttribute.prototype ); +Int16BufferAttribute.prototype.constructor = Int16BufferAttribute; - if ( colors !== undefined ) { - scope.colors.push( new Color( colors[ i ], colors[ i + 1 ], colors[ i + 2 ] ) ); +function Uint16BufferAttribute( array, itemSize, normalized ) { - } + BufferAttribute.call( this, new Uint16Array( array ), itemSize, normalized ); - if ( uvs !== undefined ) { +} - tempUVs.push( new Vector2( uvs[ j ], uvs[ j + 1 ] ) ); +Uint16BufferAttribute.prototype = Object.create( BufferAttribute.prototype ); +Uint16BufferAttribute.prototype.constructor = Uint16BufferAttribute; - } - if ( uvs2 !== undefined ) { +function Int32BufferAttribute( array, itemSize, normalized ) { - tempUVs2.push( new Vector2( uvs2[ j ], uvs2[ j + 1 ] ) ); + BufferAttribute.call( this, new Int32Array( array ), itemSize, normalized ); - } +} - } +Int32BufferAttribute.prototype = Object.create( BufferAttribute.prototype ); +Int32BufferAttribute.prototype.constructor = Int32BufferAttribute; - function addFace( a, b, c, materialIndex ) { - var vertexNormals = normals !== undefined ? [ tempNormals[ a ].clone(), tempNormals[ b ].clone(), tempNormals[ c ].clone() ] : []; - var vertexColors = colors !== undefined ? [ scope.colors[ a ].clone(), scope.colors[ b ].clone(), scope.colors[ c ].clone() ] : []; +function Uint32BufferAttribute( array, itemSize, normalized ) { - var face = new Face3( a, b, c, vertexNormals, vertexColors, materialIndex ); + BufferAttribute.call( this, new Uint32Array( array ), itemSize, normalized ); - scope.faces.push( face ); +} - if ( uvs !== undefined ) { +Uint32BufferAttribute.prototype = Object.create( BufferAttribute.prototype ); +Uint32BufferAttribute.prototype.constructor = Uint32BufferAttribute; - scope.faceVertexUvs[ 0 ].push( [ tempUVs[ a ].clone(), tempUVs[ b ].clone(), tempUVs[ c ].clone() ] ); - } +function Float32BufferAttribute( array, itemSize, normalized ) { - if ( uvs2 !== undefined ) { + BufferAttribute.call( this, new Float32Array( array ), itemSize, normalized ); - scope.faceVertexUvs[ 1 ].push( [ tempUVs2[ a ].clone(), tempUVs2[ b ].clone(), tempUVs2[ c ].clone() ] ); +} - } +Float32BufferAttribute.prototype = Object.create( BufferAttribute.prototype ); +Float32BufferAttribute.prototype.constructor = Float32BufferAttribute; - } - var groups = geometry.groups; +function Float64BufferAttribute( array, itemSize, normalized ) { - if ( groups.length > 0 ) { + BufferAttribute.call( this, new Float64Array( array ), itemSize, normalized ); - for ( var i = 0; i < groups.length; i ++ ) { +} - var group = groups[ i ]; +Float64BufferAttribute.prototype = Object.create( BufferAttribute.prototype ); +Float64BufferAttribute.prototype.constructor = Float64BufferAttribute; - var start = group.start; - var count = group.count; +/** + * @author mrdoob / http://mrdoob.com/ + */ - for ( var j = start, jl = start + count; j < jl; j += 3 ) { +function DirectGeometry() { - if ( indices !== undefined ) { + this.vertices = []; + this.normals = []; + this.colors = []; + this.uvs = []; + this.uvs2 = []; - addFace( indices[ j ], indices[ j + 1 ], indices[ j + 2 ], group.materialIndex ); + this.groups = []; - } else { + this.morphTargets = {}; - addFace( j, j + 1, j + 2, group.materialIndex ); + this.skinWeights = []; + this.skinIndices = []; - } + // this.lineDistances = []; - } + this.boundingBox = null; + this.boundingSphere = null; - } + // update flags - } else { + this.verticesNeedUpdate = false; + this.normalsNeedUpdate = false; + this.colorsNeedUpdate = false; + this.uvsNeedUpdate = false; + this.groupsNeedUpdate = false; - if ( indices !== undefined ) { +} - for ( var i = 0; i < indices.length; i += 3 ) { +Object.assign( DirectGeometry.prototype, { - addFace( indices[ i ], indices[ i + 1 ], indices[ i + 2 ] ); + computeGroups: function ( geometry ) { - } + var group; + var groups = []; + var materialIndex = undefined; - } else { + var faces = geometry.faces; - for ( var i = 0; i < positions.length / 3; i += 3 ) { + for ( var i = 0; i < faces.length; i ++ ) { - addFace( i, i + 1, i + 2 ); + var face = faces[ i ]; - } + // materials - } + if ( face.materialIndex !== materialIndex ) { - } + materialIndex = face.materialIndex; - this.computeFaceNormals(); + if ( group !== undefined ) { - if ( geometry.boundingBox !== null ) { + group.count = ( i * 3 ) - group.start; + groups.push( group ); - this.boundingBox = geometry.boundingBox.clone(); + } + + group = { + start: i * 3, + materialIndex: materialIndex + }; + + } } - if ( geometry.boundingSphere !== null ) { + if ( group !== undefined ) { - this.boundingSphere = geometry.boundingSphere.clone(); + group.count = ( i * 3 ) - group.start; + groups.push( group ); } - return this; + this.groups = groups; }, - center: function () { - - this.computeBoundingBox(); + fromGeometry: function ( geometry ) { - var offset = this.boundingBox.getCenter().negate(); + var faces = geometry.faces; + var vertices = geometry.vertices; + var faceVertexUvs = geometry.faceVertexUvs; - this.translate( offset.x, offset.y, offset.z ); + var hasFaceVertexUv = faceVertexUvs[ 0 ] && faceVertexUvs[ 0 ].length > 0; + var hasFaceVertexUv2 = faceVertexUvs[ 1 ] && faceVertexUvs[ 1 ].length > 0; - return offset; + // morphs - }, + var morphTargets = geometry.morphTargets; + var morphTargetsLength = morphTargets.length; - normalize: function () { + var morphTargetsPosition; - this.computeBoundingSphere(); + if ( morphTargetsLength > 0 ) { - var center = this.boundingSphere.center; - var radius = this.boundingSphere.radius; + morphTargetsPosition = []; - var s = radius === 0 ? 1 : 1.0 / radius; + for ( var i = 0; i < morphTargetsLength; i ++ ) { - 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 - ); + morphTargetsPosition[ i ] = { + name: morphTargets[ i ].name, + data: [] + }; - this.applyMatrix( matrix ); + } - return this; + this.morphTargets.position = morphTargetsPosition; - }, + } - computeFaceNormals: function () { + var morphNormals = geometry.morphNormals; + var morphNormalsLength = morphNormals.length; - var cb = new Vector3(), ab = new Vector3(); + var morphTargetsNormal; - for ( var f = 0, fl = this.faces.length; f < fl; f ++ ) { + if ( morphNormalsLength > 0 ) { - var face = this.faces[ f ]; + morphTargetsNormal = []; - var vA = this.vertices[ face.a ]; - var vB = this.vertices[ face.b ]; - var vC = this.vertices[ face.c ]; + for ( var i = 0; i < morphNormalsLength; i ++ ) { - cb.subVectors( vC, vB ); - ab.subVectors( vA, vB ); - cb.cross( ab ); + morphTargetsNormal[ i ] = { + name: morphNormals[ i ].name, + data: [] + }; - cb.normalize(); + } - face.normal.copy( cb ); + this.morphTargets.normal = morphTargetsNormal; } - }, - - computeVertexNormals: function ( areaWeighted ) { + // skins - if ( areaWeighted === undefined ) areaWeighted = true; + var skinIndices = geometry.skinIndices; + var skinWeights = geometry.skinWeights; - var v, vl, f, fl, face, vertices; + var hasSkinIndices = skinIndices.length === vertices.length; + var hasSkinWeights = skinWeights.length === vertices.length; - vertices = new Array( this.vertices.length ); + // - for ( v = 0, vl = this.vertices.length; v < vl; v ++ ) { + if ( vertices.length > 0 && faces.length === 0 ) { - vertices[ v ] = new Vector3(); + console.error( 'THREE.DirectGeometry: Faceless geometries are not supported.' ); } - if ( areaWeighted ) { - - // vertex normals weighted by triangle areas - // http://www.iquilezles.org/www/articles/normals/normals.htm + for ( var i = 0; i < faces.length; i ++ ) { - var vA, vB, vC; - var cb = new Vector3(), ab = new Vector3(); + var face = faces[ i ]; - for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { + this.vertices.push( vertices[ face.a ], vertices[ face.b ], vertices[ face.c ] ); - face = this.faces[ f ]; + var vertexNormals = face.vertexNormals; - vA = this.vertices[ face.a ]; - vB = this.vertices[ face.b ]; - vC = this.vertices[ face.c ]; + if ( vertexNormals.length === 3 ) { - cb.subVectors( vC, vB ); - ab.subVectors( vA, vB ); - cb.cross( ab ); + this.normals.push( vertexNormals[ 0 ], vertexNormals[ 1 ], vertexNormals[ 2 ] ); - vertices[ face.a ].add( cb ); - vertices[ face.b ].add( cb ); - vertices[ face.c ].add( cb ); + } else { - } + var normal = face.normal; - } else { + this.normals.push( normal, normal, normal ); - this.computeFaceNormals(); + } - for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { + var vertexColors = face.vertexColors; - face = this.faces[ f ]; + if ( vertexColors.length === 3 ) { - vertices[ face.a ].add( face.normal ); - vertices[ face.b ].add( face.normal ); - vertices[ face.c ].add( face.normal ); + this.colors.push( vertexColors[ 0 ], vertexColors[ 1 ], vertexColors[ 2 ] ); - } + } else { - } + var color = face.color; - for ( v = 0, vl = this.vertices.length; v < vl; v ++ ) { + this.colors.push( color, color, color ); - vertices[ v ].normalize(); + } - } + if ( hasFaceVertexUv === true ) { - for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { + var vertexUvs = faceVertexUvs[ 0 ][ i ]; - face = this.faces[ f ]; + if ( vertexUvs !== undefined ) { - var vertexNormals = face.vertexNormals; + this.uvs.push( vertexUvs[ 0 ], vertexUvs[ 1 ], vertexUvs[ 2 ] ); - if ( vertexNormals.length === 3 ) { + } else { - vertexNormals[ 0 ].copy( vertices[ face.a ] ); - vertexNormals[ 1 ].copy( vertices[ face.b ] ); - vertexNormals[ 2 ].copy( vertices[ face.c ] ); + console.warn( 'THREE.DirectGeometry.fromGeometry(): Undefined vertexUv ', i ); - } else { + this.uvs.push( new Vector2(), new Vector2(), new Vector2() ); - vertexNormals[ 0 ] = vertices[ face.a ].clone(); - vertexNormals[ 1 ] = vertices[ face.b ].clone(); - vertexNormals[ 2 ] = vertices[ face.c ].clone(); + } } - } - - if ( this.faces.length > 0 ) { - - this.normalsNeedUpdate = true; + if ( hasFaceVertexUv2 === true ) { - } + var vertexUvs = faceVertexUvs[ 1 ][ i ]; - }, + if ( vertexUvs !== undefined ) { - computeFlatVertexNormals: function () { + this.uvs2.push( vertexUvs[ 0 ], vertexUvs[ 1 ], vertexUvs[ 2 ] ); - var f, fl, face; + } else { - this.computeFaceNormals(); + console.warn( 'THREE.DirectGeometry.fromGeometry(): Undefined vertexUv2 ', i ); - for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { + this.uvs2.push( new Vector2(), new Vector2(), new Vector2() ); - face = this.faces[ f ]; + } - var vertexNormals = face.vertexNormals; + } - if ( vertexNormals.length === 3 ) { + // morphs - vertexNormals[ 0 ].copy( face.normal ); - vertexNormals[ 1 ].copy( face.normal ); - vertexNormals[ 2 ].copy( face.normal ); + for ( var j = 0; j < morphTargetsLength; j ++ ) { - } else { + var morphTarget = morphTargets[ j ].vertices; - vertexNormals[ 0 ] = face.normal.clone(); - vertexNormals[ 1 ] = face.normal.clone(); - vertexNormals[ 2 ] = face.normal.clone(); + morphTargetsPosition[ j ].data.push( morphTarget[ face.a ], morphTarget[ face.b ], morphTarget[ face.c ] ); } - } + for ( var j = 0; j < morphNormalsLength; j ++ ) { - if ( this.faces.length > 0 ) { + var morphNormal = morphNormals[ j ].vertexNormals[ i ]; - this.normalsNeedUpdate = true; + morphTargetsNormal[ j ].data.push( morphNormal.a, morphNormal.b, morphNormal.c ); - } + } - }, + // skins - computeMorphNormals: function () { + if ( hasSkinIndices ) { - var i, il, f, fl, face; + this.skinIndices.push( skinIndices[ face.a ], skinIndices[ face.b ], skinIndices[ face.c ] ); - // 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 ++ ) { + if ( hasSkinWeights ) { - face = this.faces[ f ]; + this.skinWeights.push( skinWeights[ face.a ], skinWeights[ face.b ], skinWeights[ face.c ] ); - if ( ! face.__originalFaceNormal ) { + } - face.__originalFaceNormal = face.normal.clone(); + } - } else { + this.computeGroups( geometry ); - face.__originalFaceNormal.copy( face.normal ); + this.verticesNeedUpdate = geometry.verticesNeedUpdate; + this.normalsNeedUpdate = geometry.normalsNeedUpdate; + this.colorsNeedUpdate = geometry.colorsNeedUpdate; + this.uvsNeedUpdate = geometry.uvsNeedUpdate; + this.groupsNeedUpdate = geometry.groupsNeedUpdate; - } + return this; - if ( ! face.__originalVertexNormals ) face.__originalVertexNormals = []; + } - for ( i = 0, il = face.vertexNormals.length; i < il; i ++ ) { +} ); - if ( ! face.__originalVertexNormals[ i ] ) { +/** + * @author mrdoob / http://mrdoob.com/ + */ - face.__originalVertexNormals[ i ] = face.vertexNormals[ i ].clone(); +function arrayMax( array ) { - } else { + if ( array.length === 0 ) return - Infinity; - face.__originalVertexNormals[ i ].copy( face.vertexNormals[ i ] ); + var max = array[ 0 ]; - } + for ( var i = 1, l = array.length; i < l; ++ i ) { - } + if ( array[ i ] > max ) max = array[ i ]; - } + } - // use temp geometry to compute face and vertex normals for each morph + return max; - var tmpGeo = new Geometry(); - tmpGeo.faces = this.faces; +} - for ( i = 0, il = this.morphTargets.length; i < il; i ++ ) { +/** + * @author alteredq / http://alteredqualia.com/ + * @author mrdoob / http://mrdoob.com/ + */ - // create on first access +var bufferGeometryId = 1; // BufferGeometry uses odd numbers as Id - if ( ! this.morphNormals[ i ] ) { +function BufferGeometry() { - this.morphNormals[ i ] = {}; - this.morphNormals[ i ].faceNormals = []; - this.morphNormals[ i ].vertexNormals = []; + Object.defineProperty( this, 'id', { value: bufferGeometryId += 2 } ); - var dstNormalsFace = this.morphNormals[ i ].faceNormals; - var dstNormalsVertex = this.morphNormals[ i ].vertexNormals; + this.uuid = _Math.generateUUID(); - var faceNormal, vertexNormals; + this.name = ''; + this.type = 'BufferGeometry'; - for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { + this.index = null; + this.attributes = {}; - faceNormal = new Vector3(); - vertexNormals = { a: new Vector3(), b: new Vector3(), c: new Vector3() }; + this.morphAttributes = {}; - dstNormalsFace.push( faceNormal ); - dstNormalsVertex.push( vertexNormals ); + this.groups = []; - } + this.boundingBox = null; + this.boundingSphere = null; - } + this.drawRange = { start: 0, count: Infinity }; - var morphNormals = this.morphNormals[ i ]; + this.userData = {}; - // set vertices to morph target +} - tmpGeo.vertices = this.morphTargets[ i ].vertices; +BufferGeometry.prototype = Object.assign( Object.create( EventDispatcher.prototype ), { - // compute morph normals + constructor: BufferGeometry, - tmpGeo.computeFaceNormals(); - tmpGeo.computeVertexNormals(); + isBufferGeometry: true, - // store morph normals + getIndex: function () { - var faceNormal, vertexNormals; + return this.index; - for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { + }, - face = this.faces[ f ]; + setIndex: function ( index ) { - faceNormal = morphNormals.faceNormals[ f ]; - vertexNormals = morphNormals.vertexNormals[ f ]; + if ( Array.isArray( index ) ) { - faceNormal.copy( face.normal ); + this.index = new ( arrayMax( index ) > 65535 ? Uint32BufferAttribute : Uint16BufferAttribute )( index, 1 ); - vertexNormals.a.copy( face.vertexNormals[ 0 ] ); - vertexNormals.b.copy( face.vertexNormals[ 1 ] ); - vertexNormals.c.copy( face.vertexNormals[ 2 ] ); + } else { - } + this.index = index; } - // restore original normals + }, - for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { + addAttribute: function ( name, attribute ) { - face = this.faces[ f ]; + if ( ! ( attribute && attribute.isBufferAttribute ) && ! ( attribute && attribute.isInterleavedBufferAttribute ) ) { - face.normal = face.__originalFaceNormal; - face.vertexNormals = face.__originalVertexNormals; + console.warn( 'THREE.BufferGeometry: .addAttribute() now expects ( name, attribute ).' ); - } + return this.addAttribute( name, new BufferAttribute( arguments[ 1 ], arguments[ 2 ] ) ); - }, + } - computeBoundingBox: function () { + if ( name === 'index' ) { - if ( this.boundingBox === null ) { + console.warn( 'THREE.BufferGeometry.addAttribute: Use .setIndex() for index attribute.' ); + this.setIndex( attribute ); - this.boundingBox = new Box3(); + return this; } - this.boundingBox.setFromPoints( this.vertices ); + this.attributes[ name ] = attribute; + + return this; }, - computeBoundingSphere: function () { + getAttribute: function ( name ) { - if ( this.boundingSphere === null ) { + return this.attributes[ name ]; - this.boundingSphere = new Sphere(); + }, - } + removeAttribute: function ( name ) { - this.boundingSphere.setFromPoints( this.vertices ); + delete this.attributes[ name ]; + + return this; }, - merge: function ( geometry, matrix, materialIndexOffset ) { + addGroup: function ( start, count, materialIndex ) { - if ( ! ( geometry && geometry.isGeometry ) ) { + this.groups.push( { - console.error( 'THREE.Geometry.merge(): geometry not an instance of THREE.Geometry.', geometry ); - return; + start: start, + count: count, + materialIndex: materialIndex !== undefined ? materialIndex : 0 - } + } ); - 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; + }, - if ( materialIndexOffset === undefined ) materialIndexOffset = 0; + clearGroups: function () { - if ( matrix !== undefined ) { + this.groups = []; - normalMatrix = new Matrix3().getNormalMatrix( matrix ); + }, - } + setDrawRange: function ( start, count ) { - // vertices + this.drawRange.start = start; + this.drawRange.count = count; - for ( var i = 0, il = vertices2.length; i < il; i ++ ) { + }, - var vertex = vertices2[ i ]; + applyMatrix: function ( matrix ) { - var vertexCopy = vertex.clone(); + var position = this.attributes.position; - if ( matrix !== undefined ) vertexCopy.applyMatrix4( matrix ); + if ( position !== undefined ) { - vertices1.push( vertexCopy ); + matrix.applyToBufferAttribute( position ); + position.needsUpdate = true; } - // colors + var normal = this.attributes.normal; - for ( var i = 0, il = colors2.length; i < il; i ++ ) { + if ( normal !== undefined ) { - colors1.push( colors2[ i ].clone() ); + var normalMatrix = new Matrix3().getNormalMatrix( matrix ); + + normalMatrix.applyToBufferAttribute( normal ); + normal.needsUpdate = true; } - // faces + if ( this.boundingBox !== null ) { - for ( i = 0, il = faces2.length; i < il; i ++ ) { + this.computeBoundingBox(); - var face = faces2[ i ], faceCopy, normal, color, - faceVertexNormals = face.vertexNormals, - faceVertexColors = face.vertexColors; + } - faceCopy = new Face3( face.a + vertexOffset, face.b + vertexOffset, face.c + vertexOffset ); - faceCopy.normal.copy( face.normal ); + if ( this.boundingSphere !== null ) { - if ( normalMatrix !== undefined ) { + this.computeBoundingSphere(); - faceCopy.normal.applyMatrix3( normalMatrix ).normalize(); + } - } + return this; - for ( var j = 0, jl = faceVertexNormals.length; j < jl; j ++ ) { + }, - normal = faceVertexNormals[ j ].clone(); + rotateX: function () { - if ( normalMatrix !== undefined ) { + // rotate geometry around world x-axis - normal.applyMatrix3( normalMatrix ).normalize(); + var m1 = new Matrix4(); - } + return function rotateX( angle ) { - faceCopy.vertexNormals.push( normal ); + m1.makeRotationX( angle ); - } + this.applyMatrix( m1 ); - faceCopy.color.copy( face.color ); + return this; - for ( var j = 0, jl = faceVertexColors.length; j < jl; j ++ ) { + }; - color = faceVertexColors[ j ]; - faceCopy.vertexColors.push( color.clone() ); + }(), - } + rotateY: function () { - faceCopy.materialIndex = face.materialIndex + materialIndexOffset; + // rotate geometry around world y-axis - faces1.push( faceCopy ); + var m1 = new Matrix4(); - } + return function rotateY( angle ) { - // uvs + m1.makeRotationY( angle ); - for ( i = 0, il = uvs2.length; i < il; i ++ ) { + this.applyMatrix( m1 ); - var uv = uvs2[ i ], uvCopy = []; + return this; - if ( uv === undefined ) { + }; - continue; + }(), - } + rotateZ: function () { - for ( var j = 0, jl = uv.length; j < jl; j ++ ) { + // rotate geometry around world z-axis - uvCopy.push( uv[ j ].clone() ); + var m1 = new Matrix4(); - } + return function rotateZ( angle ) { - uvs1.push( uvCopy ); + m1.makeRotationZ( angle ); - } + this.applyMatrix( m1 ); - }, + return this; - mergeMesh: function ( mesh ) { + }; - if ( ! ( mesh && mesh.isMesh ) ) { + }(), - console.error( 'THREE.Geometry.mergeMesh(): mesh not an instance of THREE.Mesh.', mesh ); - return; + translate: function () { - } + // translate geometry - mesh.matrixAutoUpdate && mesh.updateMatrix(); + var m1 = new Matrix4(); - this.merge( mesh.geometry, mesh.matrix ); + return function translate( x, y, z ) { - }, + m1.makeTranslation( x, y, z ); - /* - * Checks for duplicate vertices with hashmap. - * Duplicated vertices are removed - * and faces' vertices are updated. - */ + this.applyMatrix( m1 ); - mergeVertices: function () { + return this; - var verticesMap = {}; // Hashmap for looking up vertices by position coordinates (and making sure they are unique) - var unique = [], changes = []; + }; - 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; + }(), - for ( i = 0, il = this.vertices.length; i < il; i ++ ) { + scale: function () { - v = this.vertices[ i ]; - key = Math.round( v.x * precision ) + '_' + Math.round( v.y * precision ) + '_' + Math.round( v.z * precision ); + // scale geometry - if ( verticesMap[ key ] === undefined ) { + var m1 = new Matrix4(); - verticesMap[ key ] = i; - unique.push( this.vertices[ i ] ); - changes[ i ] = unique.length - 1; + return function scale( x, y, z ) { - } else { + m1.makeScale( x, y, z ); - //console.log('Duplicate vertex found. ', i, ' could be using ', verticesMap[key]); - changes[ i ] = changes[ verticesMap[ key ] ]; + this.applyMatrix( m1 ); - } + return this; - } + }; + }(), - // if faces are completely degenerate after merging vertices, we - // have to remove them from the geometry. - var faceIndicesToRemove = []; + lookAt: function () { - for ( i = 0, il = this.faces.length; i < il; i ++ ) { + var obj = new Object3D(); - face = this.faces[ i ]; + return function lookAt( vector ) { - face.a = changes[ face.a ]; - face.b = changes[ face.b ]; - face.c = changes[ face.c ]; + obj.lookAt( vector ); - indices = [ face.a, face.b, face.c ]; + obj.updateMatrix(); - // 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 ++ ) { + this.applyMatrix( obj.matrix ); - if ( indices[ n ] === indices[ ( n + 1 ) % 3 ] ) { + }; - faceIndicesToRemove.push( i ); - break; + }(), - } + center: function () { - } + var offset = new Vector3(); - } + return function center() { - for ( i = faceIndicesToRemove.length - 1; i >= 0; i -- ) { + this.computeBoundingBox(); - var idx = faceIndicesToRemove[ i ]; + this.boundingBox.getCenter( offset ).negate(); - this.faces.splice( idx, 1 ); + this.translate( offset.x, offset.y, offset.z ); - for ( j = 0, jl = this.faceVertexUvs.length; j < jl; j ++ ) { + return this; - this.faceVertexUvs[ j ].splice( idx, 1 ); + }; - } + }(), - } + setFromObject: function ( object ) { - // Use unique set of vertices + // console.log( 'THREE.BufferGeometry.setFromObject(). Converting', object, this ); - var diff = this.vertices.length - unique.length; - this.vertices = unique; - return diff; + var geometry = object.geometry; - }, + if ( object.isPoints || object.isLine ) { - setFromPoints: function ( points ) { + var positions = new Float32BufferAttribute( geometry.vertices.length * 3, 3 ); + var colors = new Float32BufferAttribute( geometry.colors.length * 3, 3 ); - this.vertices = []; + this.addAttribute( 'position', positions.copyVector3sArray( geometry.vertices ) ); + this.addAttribute( 'color', colors.copyColorsArray( geometry.colors ) ); - for ( var i = 0, l = points.length; i < l; i ++ ) { + if ( geometry.lineDistances && geometry.lineDistances.length === geometry.vertices.length ) { - var point = points[ i ]; - this.vertices.push( new Vector3( point.x, point.y, point.z || 0 ) ); + var lineDistances = new Float32BufferAttribute( geometry.lineDistances.length, 1 ); - } + this.addAttribute( 'lineDistance', lineDistances.copyArray( geometry.lineDistances ) ); - return this; + } - }, + if ( geometry.boundingSphere !== null ) { - sortFacesByMaterialIndex: function () { + this.boundingSphere = geometry.boundingSphere.clone(); - var faces = this.faces; - var length = faces.length; + } - // tag faces + if ( geometry.boundingBox !== null ) { - for ( var i = 0; i < length; i ++ ) { + this.boundingBox = geometry.boundingBox.clone(); - faces[ i ]._id = i; + } - } + } else if ( object.isMesh ) { - // sort faces + if ( geometry && geometry.isGeometry ) { - function materialIndexSort( a, b ) { + this.fromGeometry( geometry ); - return a.materialIndex - b.materialIndex; + } } - faces.sort( materialIndexSort ); - - // sort uvs - - var uvs1 = this.faceVertexUvs[ 0 ]; - var uvs2 = this.faceVertexUvs[ 1 ]; + return this; - var newUvs1, newUvs2; + }, - if ( uvs1 && uvs1.length === length ) newUvs1 = []; - if ( uvs2 && uvs2.length === length ) newUvs2 = []; + setFromPoints: function ( points ) { - for ( var i = 0; i < length; i ++ ) { + var position = []; - var id = faces[ i ]._id; + for ( var i = 0, l = points.length; i < l; i ++ ) { - if ( newUvs1 ) newUvs1.push( uvs1[ id ] ); - if ( newUvs2 ) newUvs2.push( uvs2[ id ] ); + var point = points[ i ]; + position.push( point.x, point.y, point.z || 0 ); } - if ( newUvs1 ) this.faceVertexUvs[ 0 ] = newUvs1; - if ( newUvs2 ) this.faceVertexUvs[ 1 ] = newUvs2; + this.addAttribute( 'position', new Float32BufferAttribute( position, 3 ) ); + + return this; }, - toJSON: function () { + updateFromObject: function ( object ) { - var data = { - metadata: { - version: 4.5, - type: 'Geometry', - generator: 'Geometry.toJSON' - } - }; + var geometry = object.geometry; - // standard Geometry serialization + if ( object.isMesh ) { - data.uuid = this.uuid; - data.type = this.type; - if ( this.name !== '' ) data.name = this.name; + var direct = geometry.__directGeometry; - if ( this.parameters !== undefined ) { + if ( geometry.elementsNeedUpdate === true ) { - var parameters = this.parameters; + direct = undefined; + geometry.elementsNeedUpdate = false; - for ( var key in parameters ) { + } - if ( parameters[ key ] !== undefined ) data[ key ] = parameters[ key ]; + if ( direct === undefined ) { + + return this.fromGeometry( geometry ); } - return data; + 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; - var vertices = []; + geometry = direct; - for ( var i = 0; i < this.vertices.length; i ++ ) { + } - var vertex = this.vertices[ i ]; - vertices.push( vertex.x, vertex.y, vertex.z ); + var attribute; - } + if ( geometry.verticesNeedUpdate === true ) { - var faces = []; - var normals = []; - var normalsHash = {}; - var colors = []; - var colorsHash = {}; - var uvs = []; - var uvsHash = {}; + attribute = this.attributes.position; - for ( var i = 0; i < this.faces.length; i ++ ) { + if ( attribute !== undefined ) { - var face = this.faces[ i ]; + attribute.copyVector3sArray( geometry.vertices ); + attribute.needsUpdate = true; - 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; + geometry.verticesNeedUpdate = false; - 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 ); + } - faces.push( faceType ); - faces.push( face.a, face.b, face.c ); - faces.push( face.materialIndex ); + if ( geometry.normalsNeedUpdate === true ) { - if ( hasFaceVertexUv ) { + attribute = this.attributes.normal; - var faceVertexUvs = this.faceVertexUvs[ 0 ][ i ]; + if ( attribute !== undefined ) { - faces.push( - getUvIndex( faceVertexUvs[ 0 ] ), - getUvIndex( faceVertexUvs[ 1 ] ), - getUvIndex( faceVertexUvs[ 2 ] ) - ); + attribute.copyVector3sArray( geometry.normals ); + attribute.needsUpdate = true; } - if ( hasFaceNormal ) { + geometry.normalsNeedUpdate = false; - faces.push( getNormalIndex( face.normal ) ); + } - } + if ( geometry.colorsNeedUpdate === true ) { - if ( hasFaceVertexNormal ) { + attribute = this.attributes.color; - var vertexNormals = face.vertexNormals; + if ( attribute !== undefined ) { - faces.push( - getNormalIndex( vertexNormals[ 0 ] ), - getNormalIndex( vertexNormals[ 1 ] ), - getNormalIndex( vertexNormals[ 2 ] ) - ); + attribute.copyColorsArray( geometry.colors ); + attribute.needsUpdate = true; } - if ( hasFaceColor ) { + geometry.colorsNeedUpdate = false; - faces.push( getColorIndex( face.color ) ); + } - } + if ( geometry.uvsNeedUpdate ) { - if ( hasFaceVertexColor ) { + attribute = this.attributes.uv; - var vertexColors = face.vertexColors; + if ( attribute !== undefined ) { - faces.push( - getColorIndex( vertexColors[ 0 ] ), - getColorIndex( vertexColors[ 1 ] ), - getColorIndex( vertexColors[ 2 ] ) - ); + attribute.copyVector2sArray( geometry.uvs ); + attribute.needsUpdate = true; } + geometry.uvsNeedUpdate = false; + } - function setBit( value, position, enabled ) { + if ( geometry.lineDistancesNeedUpdate ) { - return enabled ? value | ( 1 << position ) : value & ( ~ ( 1 << position ) ); + attribute = this.attributes.lineDistance; - } + if ( attribute !== undefined ) { - function getNormalIndex( normal ) { + attribute.copyArray( geometry.lineDistances ); + attribute.needsUpdate = true; - var hash = normal.x.toString() + normal.y.toString() + normal.z.toString(); + } - if ( normalsHash[ hash ] !== undefined ) { + geometry.lineDistancesNeedUpdate = false; - return normalsHash[ hash ]; + } - } + if ( geometry.groupsNeedUpdate ) { - normalsHash[ hash ] = normals.length / 3; - normals.push( normal.x, normal.y, normal.z ); + geometry.computeGroups( object.geometry ); + this.groups = geometry.groups; - return normalsHash[ hash ]; + geometry.groupsNeedUpdate = false; } - function getColorIndex( color ) { + return this; - var hash = color.r.toString() + color.g.toString() + color.b.toString(); + }, - if ( colorsHash[ hash ] !== undefined ) { + fromGeometry: function ( geometry ) { - return colorsHash[ hash ]; + geometry.__directGeometry = new DirectGeometry().fromGeometry( geometry ); - } + return this.fromDirectGeometry( geometry.__directGeometry ); - colorsHash[ hash ] = colors.length; - colors.push( color.getHex() ); + }, - return colorsHash[ hash ]; + fromDirectGeometry: function ( geometry ) { - } + var positions = new Float32Array( geometry.vertices.length * 3 ); + this.addAttribute( 'position', new BufferAttribute( positions, 3 ).copyVector3sArray( geometry.vertices ) ); - function getUvIndex( uv ) { + if ( geometry.normals.length > 0 ) { - var hash = uv.x.toString() + uv.y.toString(); + var normals = new Float32Array( geometry.normals.length * 3 ); + this.addAttribute( 'normal', new BufferAttribute( normals, 3 ).copyVector3sArray( geometry.normals ) ); - if ( uvsHash[ hash ] !== undefined ) { + } - return uvsHash[ hash ]; + if ( geometry.colors.length > 0 ) { - } + var colors = new Float32Array( geometry.colors.length * 3 ); + this.addAttribute( 'color', new BufferAttribute( colors, 3 ).copyColorsArray( geometry.colors ) ); - uvsHash[ hash ] = uvs.length / 2; - uvs.push( uv.x, uv.y ); + } - return uvsHash[ hash ]; + if ( geometry.uvs.length > 0 ) { + + var uvs = new Float32Array( geometry.uvs.length * 2 ); + this.addAttribute( 'uv', new BufferAttribute( uvs, 2 ).copyVector2sArray( geometry.uvs ) ); } - data.data = {}; + if ( geometry.uvs2.length > 0 ) { - 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; + var uvs2 = new Float32Array( geometry.uvs2.length * 2 ); + this.addAttribute( 'uv2', new BufferAttribute( uvs2, 2 ).copyVector2sArray( geometry.uvs2 ) ); - return data; + } - }, + // groups - clone: function () { + this.groups = geometry.groups; - /* - // Handle primitives + // morphs - var parameters = this.parameters; + for ( var name in geometry.morphTargets ) { - if ( parameters !== undefined ) { + var array = []; + var morphTargets = geometry.morphTargets[ name ]; - var values = []; + for ( var i = 0, l = morphTargets.length; i < l; i ++ ) { - for ( var key in parameters ) { + var morphTarget = morphTargets[ i ]; - values.push( parameters[ key ] ); + var attribute = new Float32BufferAttribute( morphTarget.data.length * 3, 3 ); + attribute.name = morphTarget.name; - } + array.push( attribute.copyVector3sArray( morphTarget.data ) ); - var geometry = Object.create( this.constructor.prototype ); - this.constructor.apply( geometry, values ); - return geometry; - - } - - return new this.constructor().copy( this ); - */ + } - return new Geometry().copy( this ); + this.morphAttributes[ name ] = array; - }, + } - copy: function ( source ) { + // skinning - var i, il, j, jl, k, kl; + if ( geometry.skinIndices.length > 0 ) { - // reset + var skinIndices = new Float32BufferAttribute( geometry.skinIndices.length * 4, 4 ); + this.addAttribute( 'skinIndex', skinIndices.copyVector4sArray( geometry.skinIndices ) ); - this.vertices = []; - this.colors = []; - this.faces = []; - this.faceVertexUvs = [[]]; - this.morphTargets = []; - this.morphNormals = []; - this.skinWeights = []; - this.skinIndices = []; - this.lineDistances = []; - this.boundingBox = null; - this.boundingSphere = null; + } - // name + if ( geometry.skinWeights.length > 0 ) { - this.name = source.name; + var skinWeights = new Float32BufferAttribute( geometry.skinWeights.length * 4, 4 ); + this.addAttribute( 'skinWeight', skinWeights.copyVector4sArray( geometry.skinWeights ) ); - // vertices + } - var vertices = source.vertices; + // - for ( i = 0, il = vertices.length; i < il; i ++ ) { + if ( geometry.boundingSphere !== null ) { - this.vertices.push( vertices[ i ].clone() ); + this.boundingSphere = geometry.boundingSphere.clone(); } - // colors - - var colors = source.colors; - - for ( i = 0, il = colors.length; i < il; i ++ ) { + if ( geometry.boundingBox !== null ) { - this.colors.push( colors[ i ].clone() ); + this.boundingBox = geometry.boundingBox.clone(); } - // faces + return this; - var faces = source.faces; + }, - for ( i = 0, il = faces.length; i < il; i ++ ) { + computeBoundingBox: function () { - this.faces.push( faces[ i ].clone() ); + if ( this.boundingBox === null ) { + + this.boundingBox = new Box3(); } - // face vertex uvs + var position = this.attributes.position; - for ( i = 0, il = source.faceVertexUvs.length; i < il; i ++ ) { + if ( position !== undefined ) { - var faceVertexUvs = source.faceVertexUvs[ i ]; + this.boundingBox.setFromBufferAttribute( position ); - if ( this.faceVertexUvs[ i ] === undefined ) { + } else { - this.faceVertexUvs[ i ] = []; + this.boundingBox.makeEmpty(); - } + } - for ( j = 0, jl = faceVertexUvs.length; j < jl; j ++ ) { + if ( isNaN( this.boundingBox.min.x ) || isNaN( this.boundingBox.min.y ) || isNaN( this.boundingBox.min.z ) ) { - var uvs = faceVertexUvs[ j ], uvsCopy = []; + console.error( 'THREE.BufferGeometry.computeBoundingBox: Computed min/max have NaN values. The "position" attribute is likely to have NaN values.', this ); - for ( k = 0, kl = uvs.length; k < kl; k ++ ) { + } - var uv = uvs[ k ]; + }, - uvsCopy.push( uv.clone() ); + computeBoundingSphere: function () { - } + var box = new Box3(); + var vector = new Vector3(); - this.faceVertexUvs[ i ].push( uvsCopy ); + return function computeBoundingSphere() { - } + if ( this.boundingSphere === null ) { - } + this.boundingSphere = new Sphere(); - // morph targets + } - var morphTargets = source.morphTargets; + var position = this.attributes.position; - for ( i = 0, il = morphTargets.length; i < il; i ++ ) { + if ( position ) { - var morphTarget = {}; - morphTarget.name = morphTargets[ i ].name; + var center = this.boundingSphere.center; - // vertices + box.setFromBufferAttribute( position ); + box.getCenter( center ); - if ( morphTargets[ i ].vertices !== undefined ) { + // hoping to find a boundingSphere with a radius smaller than the + // boundingSphere of the boundingBox: sqrt(3) smaller in the best case - morphTarget.vertices = []; + var maxRadiusSq = 0; - for ( j = 0, jl = morphTargets[ i ].vertices.length; j < jl; j ++ ) { + for ( var i = 0, il = position.count; i < il; i ++ ) { - morphTarget.vertices.push( morphTargets[ i ].vertices[ j ].clone() ); + vector.x = position.getX( i ); + vector.y = position.getY( i ); + vector.z = position.getZ( i ); + maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( vector ) ); } - } + this.boundingSphere.radius = Math.sqrt( maxRadiusSq ); - // normals + if ( isNaN( this.boundingSphere.radius ) ) { - if ( morphTargets[ i ].normals !== undefined ) { + console.error( 'THREE.BufferGeometry.computeBoundingSphere(): Computed radius is NaN. The "position" attribute is likely to have NaN values.', this ); - morphTarget.normals = []; + } - for ( j = 0, jl = morphTargets[ i ].normals.length; j < jl; j ++ ) { + } - morphTarget.normals.push( morphTargets[ i ].normals[ j ].clone() ); + }; - } + }(), - } + computeFaceNormals: function () { - this.morphTargets.push( morphTarget ); + // backwards compatibility - } + }, - // morph normals + computeVertexNormals: function () { - var morphNormals = source.morphNormals; + var index = this.index; + var attributes = this.attributes; - for ( i = 0, il = morphNormals.length; i < il; i ++ ) { + if ( attributes.position ) { - var morphNormal = {}; + var positions = attributes.position.array; - // vertex normals + if ( attributes.normal === undefined ) { - if ( morphNormals[ i ].vertexNormals !== undefined ) { + this.addAttribute( 'normal', new BufferAttribute( new Float32Array( positions.length ), 3 ) ); - morphNormal.vertexNormals = []; + } else { - for ( j = 0, jl = morphNormals[ i ].vertexNormals.length; j < jl; j ++ ) { + // reset existing normals to zero - var srcVertexNormal = morphNormals[ i ].vertexNormals[ j ]; - var destVertexNormal = {}; + var array = attributes.normal.array; - destVertexNormal.a = srcVertexNormal.a.clone(); - destVertexNormal.b = srcVertexNormal.b.clone(); - destVertexNormal.c = srcVertexNormal.c.clone(); + for ( var i = 0, il = array.length; i < il; i ++ ) { - morphNormal.vertexNormals.push( destVertexNormal ); + array[ i ] = 0; } } - // face normals + var normals = attributes.normal.array; - if ( morphNormals[ i ].faceNormals !== undefined ) { + var vA, vB, vC; + var pA = new Vector3(), pB = new Vector3(), pC = new Vector3(); + var cb = new Vector3(), ab = new Vector3(); - morphNormal.faceNormals = []; + // indexed elements - for ( j = 0, jl = morphNormals[ i ].faceNormals.length; j < jl; j ++ ) { + if ( index ) { - morphNormal.faceNormals.push( morphNormals[ i ].faceNormals[ j ].clone() ); + var indices = index.array; - } + for ( var i = 0, il = index.count; i < il; i += 3 ) { - } + vA = indices[ i + 0 ] * 3; + vB = indices[ i + 1 ] * 3; + vC = indices[ i + 2 ] * 3; - this.morphNormals.push( morphNormal ); + pA.fromArray( positions, vA ); + pB.fromArray( positions, vB ); + pC.fromArray( positions, vC ); - } + cb.subVectors( pC, pB ); + ab.subVectors( pA, pB ); + cb.cross( ab ); - // skin weights + normals[ vA ] += cb.x; + normals[ vA + 1 ] += cb.y; + normals[ vA + 2 ] += cb.z; - var skinWeights = source.skinWeights; + normals[ vB ] += cb.x; + normals[ vB + 1 ] += cb.y; + normals[ vB + 2 ] += cb.z; - for ( i = 0, il = skinWeights.length; i < il; i ++ ) { + normals[ vC ] += cb.x; + normals[ vC + 1 ] += cb.y; + normals[ vC + 2 ] += cb.z; - this.skinWeights.push( skinWeights[ i ].clone() ); + } - } + } else { - // skin indices + // non-indexed elements (unconnected triangle soup) - var skinIndices = source.skinIndices; + for ( var i = 0, il = positions.length; i < il; i += 9 ) { - for ( i = 0, il = skinIndices.length; i < il; i ++ ) { + pA.fromArray( positions, i ); + pB.fromArray( positions, i + 3 ); + pC.fromArray( positions, i + 6 ); - this.skinIndices.push( skinIndices[ i ].clone() ); + cb.subVectors( pC, pB ); + ab.subVectors( pA, pB ); + cb.cross( ab ); - } + normals[ i ] = cb.x; + normals[ i + 1 ] = cb.y; + normals[ i + 2 ] = cb.z; - // line distances + normals[ i + 3 ] = cb.x; + normals[ i + 4 ] = cb.y; + normals[ i + 5 ] = cb.z; - var lineDistances = source.lineDistances; + normals[ i + 6 ] = cb.x; + normals[ i + 7 ] = cb.y; + normals[ i + 8 ] = cb.z; - for ( i = 0, il = lineDistances.length; i < il; i ++ ) { + } - this.lineDistances.push( lineDistances[ i ] ); + } + + this.normalizeNormals(); + + attributes.normal.needsUpdate = true; } - // bounding box + }, - var boundingBox = source.boundingBox; + merge: function ( geometry, offset ) { - if ( boundingBox !== null ) { + if ( ! ( geometry && geometry.isBufferGeometry ) ) { - this.boundingBox = boundingBox.clone(); + console.error( 'THREE.BufferGeometry.merge(): geometry not an instance of THREE.BufferGeometry.', geometry ); + return; } - // bounding sphere - - var boundingSphere = source.boundingSphere; + if ( offset === undefined ) { - if ( boundingSphere !== null ) { + offset = 0; - this.boundingSphere = boundingSphere.clone(); + console.warn( + 'THREE.BufferGeometry.merge(): Overwriting original geometry, starting at offset=0. ' + + 'Use BufferGeometryUtils.mergeBufferGeometries() for lossless merge.' + ); } - // update flags + var attributes = this.attributes; - 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; + for ( var key in attributes ) { - return this; + if ( geometry.attributes[ key ] === undefined ) continue; - }, + var attribute1 = attributes[ key ]; + var attributeArray1 = attribute1.array; - dispose: function () { + var attribute2 = geometry.attributes[ key ]; + var attributeArray2 = attribute2.array; - this.dispatchEvent( { type: 'dispose' } ); + var attributeSize = attribute2.itemSize; - } + for ( var i = 0, j = attributeSize * offset; i < attributeArray2.length; i ++, j ++ ) { -} ); + attributeArray1[ j ] = attributeArray2[ i ]; -/** - * @author mrdoob / http://mrdoob.com/ - */ + } -function BufferAttribute( array, itemSize, normalized ) { + } - if ( Array.isArray( array ) ) { + return this; - throw new TypeError( 'THREE.BufferAttribute: array should be a Typed Array.' ); + }, - } + normalizeNormals: function () { - this.uuid = _Math.generateUUID(); - this.name = ''; + var vector = new Vector3(); - this.array = array; - this.itemSize = itemSize; - this.count = array !== undefined ? array.length / itemSize : 0; - this.normalized = normalized === true; + return function normalizeNormals() { - this.dynamic = false; - this.updateRange = { offset: 0, count: - 1 }; + var normals = this.attributes.normal; - this.onUploadCallback = function () {}; + for ( var i = 0, il = normals.count; i < il; i ++ ) { - this.version = 0; + vector.x = normals.getX( i ); + vector.y = normals.getY( i ); + vector.z = normals.getZ( i ); -} + vector.normalize(); -Object.defineProperty( BufferAttribute.prototype, 'needsUpdate', { + normals.setXYZ( i, vector.x, vector.y, vector.z ); - set: function ( value ) { + } - if ( value === true ) this.version ++; + }; - } + }(), -} ); + toNonIndexed: function () { -Object.assign( BufferAttribute.prototype, { + if ( this.index === null ) { - isBufferAttribute: true, + console.warn( 'THREE.BufferGeometry.toNonIndexed(): Geometry is already non-indexed.' ); + return this; - setArray: function ( array ) { + } - if ( Array.isArray( array ) ) { + var geometry2 = new BufferGeometry(); - throw new TypeError( 'THREE.BufferAttribute: array should be a Typed Array.' ); + var indices = this.index.array; + var attributes = this.attributes; - } + for ( var name in attributes ) { - this.count = array !== undefined ? array.length / this.itemSize : 0; - this.array = array; + var attribute = attributes[ name ]; - }, + var array = attribute.array; + var itemSize = attribute.itemSize; - setDynamic: function ( value ) { + var array2 = new array.constructor( indices.length * itemSize ); - this.dynamic = value; + var index = 0, index2 = 0; - return this; + for ( var i = 0, l = indices.length; i < l; i ++ ) { - }, + index = indices[ i ] * itemSize; - copy: function ( source ) { + for ( var j = 0; j < itemSize; j ++ ) { - this.array = new source.array.constructor( source.array ); - this.itemSize = source.itemSize; - this.count = source.count; - this.normalized = source.normalized; + array2[ index2 ++ ] = array[ index ++ ]; - this.dynamic = source.dynamic; + } - return this; + } - }, + geometry2.addAttribute( name, new BufferAttribute( array2, itemSize ) ); - copyAt: function ( index1, attribute, index2 ) { + } - index1 *= this.itemSize; - index2 *= attribute.itemSize; + var groups = this.groups; - for ( var i = 0, l = this.itemSize; i < l; i ++ ) { + for ( var i = 0, l = groups.length; i < l; i ++ ) { - this.array[ index1 + i ] = attribute.array[ index2 + i ]; + var group = groups[ i ]; + geometry2.addGroup( group.start, group.count, group.materialIndex ); } - return this; + return geometry2; }, - copyArray: function ( array ) { - - this.array.set( array ); - - return this; + toJSON: function () { - }, + var data = { + metadata: { + version: 4.5, + type: 'BufferGeometry', + generator: 'BufferGeometry.toJSON' + } + }; - copyColorsArray: function ( colors ) { + // standard BufferGeometry serialization - var array = this.array, offset = 0; + 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; - for ( var i = 0, l = colors.length; i < l; i ++ ) { + if ( this.parameters !== undefined ) { - var color = colors[ i ]; + var parameters = this.parameters; - if ( color === undefined ) { + for ( var key in parameters ) { - console.warn( 'THREE.BufferAttribute.copyColorsArray(): color is undefined', i ); - color = new Color(); + if ( parameters[ key ] !== undefined ) data[ key ] = parameters[ key ]; } - array[ offset ++ ] = color.r; - array[ offset ++ ] = color.g; - array[ offset ++ ] = color.b; + return data; } - return this; + data.data = { attributes: {} }; - }, + var index = this.index; - copyIndicesArray: function ( indices ) { + if ( index !== null ) { - var array = this.array, offset = 0; + var array = Array.prototype.slice.call( index.array ); - for ( var i = 0, l = indices.length; i < l; i ++ ) { + data.data.index = { + type: index.array.constructor.name, + array: array + }; - var index = indices[ i ]; + } - array[ offset ++ ] = index.a; - array[ offset ++ ] = index.b; - array[ offset ++ ] = index.c; + var attributes = this.attributes; - } + for ( var key in attributes ) { - return this; + var attribute = attributes[ key ]; - }, + var array = Array.prototype.slice.call( attribute.array ); - copyVector2sArray: function ( vectors ) { + data.data.attributes[ key ] = { + itemSize: attribute.itemSize, + type: attribute.array.constructor.name, + array: array, + normalized: attribute.normalized + }; - var array = this.array, offset = 0; + } - for ( var i = 0, l = vectors.length; i < l; i ++ ) { + var groups = this.groups; - var vector = vectors[ i ]; + if ( groups.length > 0 ) { - if ( vector === undefined ) { + data.data.groups = JSON.parse( JSON.stringify( groups ) ); - console.warn( 'THREE.BufferAttribute.copyVector2sArray(): vector is undefined', i ); - vector = new Vector2(); + } - } + var boundingSphere = this.boundingSphere; - array[ offset ++ ] = vector.x; - array[ offset ++ ] = vector.y; + if ( boundingSphere !== null ) { + + data.data.boundingSphere = { + center: boundingSphere.center.toArray(), + radius: boundingSphere.radius + }; } - return this; + return data; }, - copyVector3sArray: function ( vectors ) { + clone: function () { - var array = this.array, offset = 0; + /* + // Handle primitives - for ( var i = 0, l = vectors.length; i < l; i ++ ) { + var parameters = this.parameters; - var vector = vectors[ i ]; + if ( parameters !== undefined ) { - if ( vector === undefined ) { + var values = []; - console.warn( 'THREE.BufferAttribute.copyVector3sArray(): vector is undefined', i ); - vector = new Vector3(); + for ( var key in parameters ) { - } + values.push( parameters[ key ] ); - array[ offset ++ ] = vector.x; - array[ offset ++ ] = vector.y; - array[ offset ++ ] = vector.z; + } - } + var geometry = Object.create( this.constructor.prototype ); + this.constructor.apply( geometry, values ); + return geometry; - return this; + } - }, + return new this.constructor().copy( this ); + */ - copyVector4sArray: function ( vectors ) { + return new BufferGeometry().copy( this ); - var array = this.array, offset = 0; + }, - for ( var i = 0, l = vectors.length; i < l; i ++ ) { + copy: function ( source ) { - var vector = vectors[ i ]; + var name, i, l; - if ( vector === undefined ) { + // reset - console.warn( 'THREE.BufferAttribute.copyVector4sArray(): vector is undefined', i ); - vector = new Vector4(); + this.index = null; + this.attributes = {}; + this.morphAttributes = {}; + this.groups = []; + this.boundingBox = null; + this.boundingSphere = null; - } + // name - array[ offset ++ ] = vector.x; - array[ offset ++ ] = vector.y; - array[ offset ++ ] = vector.z; - array[ offset ++ ] = vector.w; + this.name = source.name; - } + // index - return this; + var index = source.index; - }, + if ( index !== null ) { - set: function ( value, offset ) { + this.setIndex( index.clone() ); - if ( offset === undefined ) offset = 0; + } - this.array.set( value, offset ); + // attributes - return this; + var attributes = source.attributes; - }, + for ( name in attributes ) { - getX: function ( index ) { + var attribute = attributes[ name ]; + this.addAttribute( name, attribute.clone() ); - return this.array[ index * this.itemSize ]; + } - }, + // morph attributes - setX: function ( index, x ) { + var morphAttributes = source.morphAttributes; - this.array[ index * this.itemSize ] = x; + for ( name in morphAttributes ) { - return this; - - }, + var array = []; + var morphAttribute = morphAttributes[ name ]; // morphAttribute: array of Float32BufferAttributes - getY: function ( index ) { + for ( i = 0, l = morphAttribute.length; i < l; i ++ ) { - return this.array[ index * this.itemSize + 1 ]; + array.push( morphAttribute[ i ].clone() ); - }, + } - setY: function ( index, y ) { + this.morphAttributes[ name ] = array; - this.array[ index * this.itemSize + 1 ] = y; + } - return this; + // groups - }, + var groups = source.groups; - getZ: function ( index ) { + for ( i = 0, l = groups.length; i < l; i ++ ) { - return this.array[ index * this.itemSize + 2 ]; + var group = groups[ i ]; + this.addGroup( group.start, group.count, group.materialIndex ); - }, + } - setZ: function ( index, z ) { + // bounding box - this.array[ index * this.itemSize + 2 ] = z; + var boundingBox = source.boundingBox; - return this; + if ( boundingBox !== null ) { - }, + this.boundingBox = boundingBox.clone(); - getW: function ( index ) { + } - return this.array[ index * this.itemSize + 3 ]; + // bounding sphere - }, + var boundingSphere = source.boundingSphere; - setW: function ( index, w ) { + if ( boundingSphere !== null ) { - this.array[ index * this.itemSize + 3 ] = w; + this.boundingSphere = boundingSphere.clone(); - return this; + } - }, + // draw range - setXY: function ( index, x, y ) { + this.drawRange.start = source.drawRange.start; + this.drawRange.count = source.drawRange.count; - index *= this.itemSize; + // user data - this.array[ index + 0 ] = x; - this.array[ index + 1 ] = y; + this.userData = source.userData; return this; }, - setXYZ: function ( index, x, y, z ) { + dispose: function () { - index *= this.itemSize; + this.dispatchEvent( { type: 'dispose' } ); - this.array[ index + 0 ] = x; - this.array[ index + 1 ] = y; - this.array[ index + 2 ] = z; + } - return this; +} ); - }, +/** + * @author mrdoob / http://mrdoob.com/ + * @author Mugen87 / https://github.com/Mugen87 + */ - setXYZW: function ( index, x, y, z, w ) { +// BoxGeometry - index *= this.itemSize; +function BoxGeometry( width, height, depth, widthSegments, heightSegments, depthSegments ) { - this.array[ index + 0 ] = x; - this.array[ index + 1 ] = y; - this.array[ index + 2 ] = z; - this.array[ index + 3 ] = w; + Geometry.call( this ); - return this; + this.type = 'BoxGeometry'; - }, + this.parameters = { + width: width, + height: height, + depth: depth, + widthSegments: widthSegments, + heightSegments: heightSegments, + depthSegments: depthSegments + }; - onUpload: function ( callback ) { + this.fromBufferGeometry( new BoxBufferGeometry( width, height, depth, widthSegments, heightSegments, depthSegments ) ); + this.mergeVertices(); - this.onUploadCallback = callback; +} - return this; +BoxGeometry.prototype = Object.create( Geometry.prototype ); +BoxGeometry.prototype.constructor = BoxGeometry; - }, +// BoxBufferGeometry - clone: function () { +function BoxBufferGeometry( width, height, depth, widthSegments, heightSegments, depthSegments ) { - return new this.constructor( this.array, this.itemSize ).copy( this ); + BufferGeometry.call( this ); - } + this.type = 'BoxBufferGeometry'; -} ); + this.parameters = { + width: width, + height: height, + depth: depth, + widthSegments: widthSegments, + heightSegments: heightSegments, + depthSegments: depthSegments + }; -// + var scope = this; -function Int8BufferAttribute( array, itemSize, normalized ) { + width = width || 1; + height = height || 1; + depth = depth || 1; - BufferAttribute.call( this, new Int8Array( array ), itemSize, normalized ); + // segments -} + widthSegments = Math.floor( widthSegments ) || 1; + heightSegments = Math.floor( heightSegments ) || 1; + depthSegments = Math.floor( depthSegments ) || 1; -Int8BufferAttribute.prototype = Object.create( BufferAttribute.prototype ); -Int8BufferAttribute.prototype.constructor = Int8BufferAttribute; + // buffers + var indices = []; + var vertices = []; + var normals = []; + var uvs = []; -function Uint8BufferAttribute( array, itemSize, normalized ) { + // helper variables - BufferAttribute.call( this, new Uint8Array( array ), itemSize, normalized ); + var numberOfVertices = 0; + var groupStart = 0; -} + // build each side of the box geometry -Uint8BufferAttribute.prototype = Object.create( BufferAttribute.prototype ); -Uint8BufferAttribute.prototype.constructor = Uint8BufferAttribute; + 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 -function Uint8ClampedBufferAttribute( array, itemSize, normalized ) { + this.setIndex( indices ); + this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); + this.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); + this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); - BufferAttribute.call( this, new Uint8ClampedArray( array ), itemSize, normalized ); + function buildPlane( u, v, w, udir, vdir, width, height, depth, gridX, gridY, materialIndex ) { -} + var segmentWidth = width / gridX; + var segmentHeight = height / gridY; -Uint8ClampedBufferAttribute.prototype = Object.create( BufferAttribute.prototype ); -Uint8ClampedBufferAttribute.prototype.constructor = Uint8ClampedBufferAttribute; + var widthHalf = width / 2; + var heightHalf = height / 2; + var depthHalf = depth / 2; + var gridX1 = gridX + 1; + var gridY1 = gridY + 1; -function Int16BufferAttribute( array, itemSize, normalized ) { + var vertexCounter = 0; + var groupCount = 0; - BufferAttribute.call( this, new Int16Array( array ), itemSize, normalized ); + var ix, iy; -} + var vector = new Vector3(); -Int16BufferAttribute.prototype = Object.create( BufferAttribute.prototype ); -Int16BufferAttribute.prototype.constructor = Int16BufferAttribute; + // generate vertices, normals and uvs + for ( iy = 0; iy < gridY1; iy ++ ) { -function Uint16BufferAttribute( array, itemSize, normalized ) { + var y = iy * segmentHeight - heightHalf; - BufferAttribute.call( this, new Uint16Array( array ), itemSize, normalized ); + for ( ix = 0; ix < gridX1; ix ++ ) { -} + var x = ix * segmentWidth - widthHalf; -Uint16BufferAttribute.prototype = Object.create( BufferAttribute.prototype ); -Uint16BufferAttribute.prototype.constructor = Uint16BufferAttribute; + // set values to correct vector component + vector[ u ] = x * udir; + vector[ v ] = y * vdir; + vector[ w ] = depthHalf; -function Int32BufferAttribute( array, itemSize, normalized ) { + // now apply vector to vertex buffer - BufferAttribute.call( this, new Int32Array( array ), itemSize, normalized ); + vertices.push( vector.x, vector.y, vector.z ); -} + // set values to correct vector component -Int32BufferAttribute.prototype = Object.create( BufferAttribute.prototype ); -Int32BufferAttribute.prototype.constructor = Int32BufferAttribute; + vector[ u ] = 0; + vector[ v ] = 0; + vector[ w ] = depth > 0 ? 1 : - 1; + // now apply vector to normal buffer -function Uint32BufferAttribute( array, itemSize, normalized ) { + normals.push( vector.x, vector.y, vector.z ); - BufferAttribute.call( this, new Uint32Array( array ), itemSize, normalized ); + // uvs -} + uvs.push( ix / gridX ); + uvs.push( 1 - ( iy / gridY ) ); -Uint32BufferAttribute.prototype = Object.create( BufferAttribute.prototype ); -Uint32BufferAttribute.prototype.constructor = Uint32BufferAttribute; + // counters + vertexCounter += 1; -function Float32BufferAttribute( array, itemSize, normalized ) { + } - BufferAttribute.call( this, new Float32Array( array ), itemSize, normalized ); + } -} + // indices -Float32BufferAttribute.prototype = Object.create( BufferAttribute.prototype ); -Float32BufferAttribute.prototype.constructor = Float32BufferAttribute; + // 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 ( iy = 0; iy < gridY; iy ++ ) { -function Float64BufferAttribute( array, itemSize, normalized ) { + for ( ix = 0; ix < gridX; ix ++ ) { - BufferAttribute.call( this, new Float64Array( array ), itemSize, normalized ); + 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; -} + // faces -Float64BufferAttribute.prototype = Object.create( BufferAttribute.prototype ); -Float64BufferAttribute.prototype.constructor = Float64BufferAttribute; + indices.push( a, b, d ); + indices.push( b, c, d ); -/** - * @author mrdoob / http://mrdoob.com/ - */ + // increase counter -function DirectGeometry() { + groupCount += 6; - this.indices = []; - this.vertices = []; - this.normals = []; - this.colors = []; - this.uvs = []; - this.uvs2 = []; + } - this.groups = []; + } - this.morphTargets = {}; + // add a group to the geometry. this will ensure multi material support - this.skinWeights = []; - this.skinIndices = []; + scope.addGroup( groupStart, groupCount, materialIndex ); - // this.lineDistances = []; + // calculate new start value for groups - this.boundingBox = null; - this.boundingSphere = null; + groupStart += groupCount; - // update flags + // update total number of vertices - this.verticesNeedUpdate = false; - this.normalsNeedUpdate = false; - this.colorsNeedUpdate = false; - this.uvsNeedUpdate = false; - this.groupsNeedUpdate = false; + numberOfVertices += vertexCounter; -} + } -Object.assign( DirectGeometry.prototype, { +} - computeGroups: function ( geometry ) { +BoxBufferGeometry.prototype = Object.create( BufferGeometry.prototype ); +BoxBufferGeometry.prototype.constructor = BoxBufferGeometry; - var group; - var groups = []; - var materialIndex = undefined; +/** + * @author mrdoob / http://mrdoob.com/ + * @author Mugen87 / https://github.com/Mugen87 + */ - var faces = geometry.faces; +// PlaneGeometry - for ( var i = 0; i < faces.length; i ++ ) { +function PlaneGeometry( width, height, widthSegments, heightSegments ) { - var face = faces[ i ]; + Geometry.call( this ); - // materials + this.type = 'PlaneGeometry'; - if ( face.materialIndex !== materialIndex ) { + this.parameters = { + width: width, + height: height, + widthSegments: widthSegments, + heightSegments: heightSegments + }; - materialIndex = face.materialIndex; + this.fromBufferGeometry( new PlaneBufferGeometry( width, height, widthSegments, heightSegments ) ); + this.mergeVertices(); - if ( group !== undefined ) { +} - group.count = ( i * 3 ) - group.start; - groups.push( group ); +PlaneGeometry.prototype = Object.create( Geometry.prototype ); +PlaneGeometry.prototype.constructor = PlaneGeometry; - } +// PlaneBufferGeometry - group = { - start: i * 3, - materialIndex: materialIndex - }; +function PlaneBufferGeometry( width, height, widthSegments, heightSegments ) { - } + BufferGeometry.call( this ); - } + this.type = 'PlaneBufferGeometry'; - if ( group !== undefined ) { + this.parameters = { + width: width, + height: height, + widthSegments: widthSegments, + heightSegments: heightSegments + }; - group.count = ( i * 3 ) - group.start; - groups.push( group ); + width = width || 1; + height = height || 1; - } + var width_half = width / 2; + var height_half = height / 2; - this.groups = groups; + var gridX = Math.floor( widthSegments ) || 1; + var gridY = Math.floor( heightSegments ) || 1; - }, + var gridX1 = gridX + 1; + var gridY1 = gridY + 1; - fromGeometry: function ( geometry ) { + var segment_width = width / gridX; + var segment_height = height / gridY; - var faces = geometry.faces; - var vertices = geometry.vertices; - var faceVertexUvs = geometry.faceVertexUvs; + var ix, iy; - var hasFaceVertexUv = faceVertexUvs[ 0 ] && faceVertexUvs[ 0 ].length > 0; - var hasFaceVertexUv2 = faceVertexUvs[ 1 ] && faceVertexUvs[ 1 ].length > 0; + // buffers - // morphs + var indices = []; + var vertices = []; + var normals = []; + var uvs = []; - var morphTargets = geometry.morphTargets; - var morphTargetsLength = morphTargets.length; + // generate vertices, normals and uvs - var morphTargetsPosition; + for ( iy = 0; iy < gridY1; iy ++ ) { - if ( morphTargetsLength > 0 ) { + var y = iy * segment_height - height_half; - morphTargetsPosition = []; + for ( ix = 0; ix < gridX1; ix ++ ) { - for ( var i = 0; i < morphTargetsLength; i ++ ) { + var x = ix * segment_width - width_half; - morphTargetsPosition[ i ] = []; + vertices.push( x, - y, 0 ); - } + normals.push( 0, 0, 1 ); - this.morphTargets.position = morphTargetsPosition; + uvs.push( ix / gridX ); + uvs.push( 1 - ( iy / gridY ) ); } - var morphNormals = geometry.morphNormals; - var morphNormalsLength = morphNormals.length; - - var morphTargetsNormal; + } - if ( morphNormalsLength > 0 ) { + // indices - morphTargetsNormal = []; + for ( iy = 0; iy < gridY; iy ++ ) { - for ( var i = 0; i < morphNormalsLength; i ++ ) { + for ( ix = 0; ix < gridX; ix ++ ) { - morphTargetsNormal[ i ] = []; + var a = ix + gridX1 * iy; + var b = ix + gridX1 * ( iy + 1 ); + var c = ( ix + 1 ) + gridX1 * ( iy + 1 ); + var d = ( ix + 1 ) + gridX1 * iy; - } + // faces - this.morphTargets.normal = morphTargetsNormal; + indices.push( a, b, d ); + indices.push( b, c, d ); } - // skins - - var skinIndices = geometry.skinIndices; - var skinWeights = geometry.skinWeights; + } - var hasSkinIndices = skinIndices.length === vertices.length; - var hasSkinWeights = skinWeights.length === vertices.length; + // 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 ) ); - for ( var i = 0; i < faces.length; i ++ ) { +} - var face = faces[ i ]; +PlaneBufferGeometry.prototype = Object.create( BufferGeometry.prototype ); +PlaneBufferGeometry.prototype.constructor = PlaneBufferGeometry; - this.vertices.push( vertices[ face.a ], vertices[ face.b ], vertices[ face.c ] ); +/** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + */ - var vertexNormals = face.vertexNormals; +var materialId = 0; - if ( vertexNormals.length === 3 ) { +function Material() { - this.normals.push( vertexNormals[ 0 ], vertexNormals[ 1 ], vertexNormals[ 2 ] ); + Object.defineProperty( this, 'id', { value: materialId ++ } ); - } else { + this.uuid = _Math.generateUUID(); - var normal = face.normal; + this.name = ''; + this.type = 'Material'; - this.normals.push( normal, normal, normal ); + this.fog = true; + this.lights = true; - } + this.blending = NormalBlending; + this.side = FrontSide; + this.flatShading = false; + this.vertexColors = NoColors; // THREE.NoColors, THREE.VertexColors, THREE.FaceColors - var vertexColors = face.vertexColors; + this.opacity = 1; + this.transparent = false; - if ( vertexColors.length === 3 ) { + this.blendSrc = SrcAlphaFactor; + this.blendDst = OneMinusSrcAlphaFactor; + this.blendEquation = AddEquation; + this.blendSrcAlpha = null; + this.blendDstAlpha = null; + this.blendEquationAlpha = null; - this.colors.push( vertexColors[ 0 ], vertexColors[ 1 ], vertexColors[ 2 ] ); + this.depthFunc = LessEqualDepth; + this.depthTest = true; + this.depthWrite = true; - } else { + this.clippingPlanes = null; + this.clipIntersection = false; + this.clipShadows = false; - var color = face.color; + this.shadowSide = null; - this.colors.push( color, color, color ); + this.colorWrite = true; - } + this.precision = null; // override the renderer's default precision for this material - if ( hasFaceVertexUv === true ) { + this.polygonOffset = false; + this.polygonOffsetFactor = 0; + this.polygonOffsetUnits = 0; - var vertexUvs = faceVertexUvs[ 0 ][ i ]; + this.dithering = false; - if ( vertexUvs !== undefined ) { + this.alphaTest = 0; + this.premultipliedAlpha = false; - this.uvs.push( vertexUvs[ 0 ], vertexUvs[ 1 ], vertexUvs[ 2 ] ); + this.visible = true; - } else { + this.userData = {}; - console.warn( 'THREE.DirectGeometry.fromGeometry(): Undefined vertexUv ', i ); + this.needsUpdate = true; - this.uvs.push( new Vector2(), new Vector2(), new Vector2() ); +} - } +Material.prototype = Object.assign( Object.create( EventDispatcher.prototype ), { - } + constructor: Material, - if ( hasFaceVertexUv2 === true ) { + isMaterial: true, - var vertexUvs = faceVertexUvs[ 1 ][ i ]; + onBeforeCompile: function () {}, - if ( vertexUvs !== undefined ) { + setValues: function ( values ) { - this.uvs2.push( vertexUvs[ 0 ], vertexUvs[ 1 ], vertexUvs[ 2 ] ); + if ( values === undefined ) return; - } else { + for ( var key in values ) { - console.warn( 'THREE.DirectGeometry.fromGeometry(): Undefined vertexUv2 ', i ); + var newValue = values[ key ]; - this.uvs2.push( new Vector2(), new Vector2(), new Vector2() ); + if ( newValue === undefined ) { - } + console.warn( "THREE.Material: '" + key + "' parameter is undefined." ); + continue; } - // morphs - - for ( var j = 0; j < morphTargetsLength; j ++ ) { - - var morphTarget = morphTargets[ j ].vertices; + // for backward compatability if shading is set in the constructor + if ( key === 'shading' ) { - morphTargetsPosition[ j ].push( morphTarget[ face.a ], morphTarget[ face.b ], morphTarget[ face.c ] ); + console.warn( 'THREE.' + this.type + ': .shading has been removed. Use the boolean .flatShading instead.' ); + this.flatShading = ( newValue === FlatShading ) ? true : false; + continue; } - for ( var j = 0; j < morphNormalsLength; j ++ ) { + var currentValue = this[ key ]; - var morphNormal = morphNormals[ j ].vertexNormals[ i ]; + if ( currentValue === undefined ) { - morphTargetsNormal[ j ].push( morphNormal.a, morphNormal.b, morphNormal.c ); + console.warn( "THREE." + this.type + ": '" + key + "' is not a property of this material." ); + continue; } - // skins + if ( currentValue && currentValue.isColor ) { - if ( hasSkinIndices ) { + currentValue.set( newValue ); - this.skinIndices.push( skinIndices[ face.a ], skinIndices[ face.b ], skinIndices[ face.c ] ); + } else if ( ( currentValue && currentValue.isVector3 ) && ( newValue && newValue.isVector3 ) ) { - } + currentValue.copy( newValue ); - if ( hasSkinWeights ) { + } else { - this.skinWeights.push( skinWeights[ face.a ], skinWeights[ face.b ], skinWeights[ face.c ] ); + this[ key ] = newValue; } } - this.computeGroups( geometry ); - - this.verticesNeedUpdate = geometry.verticesNeedUpdate; - this.normalsNeedUpdate = geometry.normalsNeedUpdate; - this.colorsNeedUpdate = geometry.colorsNeedUpdate; - this.uvsNeedUpdate = geometry.uvsNeedUpdate; - this.groupsNeedUpdate = geometry.groupsNeedUpdate; - - return this; - - } + }, -} ); + toJSON: function ( meta ) { -/** - * @author mrdoob / http://mrdoob.com/ - */ + var isRoot = ( meta === undefined || typeof meta === 'string' ); -function arrayMax( array ) { + if ( isRoot ) { - if ( array.length === 0 ) return - Infinity; + meta = { + textures: {}, + images: {} + }; - var max = array[ 0 ]; + } - for ( var i = 1, l = array.length; i < l; ++ i ) { + var data = { + metadata: { + version: 4.5, + type: 'Material', + generator: 'Material.toJSON' + } + }; - if ( array[ i ] > max ) max = array[ i ]; + // standard Material serialization + data.uuid = this.uuid; + data.type = this.type; - } + if ( this.name !== '' ) data.name = this.name; - return max; + if ( this.color && this.color.isColor ) data.color = this.color.getHex(); -} + if ( this.roughness !== undefined ) data.roughness = this.roughness; + if ( this.metalness !== undefined ) data.metalness = this.metalness; -/** - * @author alteredq / http://alteredqualia.com/ - * @author mrdoob / http://mrdoob.com/ - */ + if ( this.emissive && this.emissive.isColor ) data.emissive = this.emissive.getHex(); + if ( this.emissiveIntensity !== 1 ) data.emissiveIntensity = this.emissiveIntensity; -var bufferGeometryId = 1; // BufferGeometry uses odd numbers as Id + 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 BufferGeometry() { + 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; - Object.defineProperty( this, 'id', { value: bufferGeometryId += 2 } ); + if ( this.aoMap && this.aoMap.isTexture ) { - this.uuid = _Math.generateUUID(); + data.aoMap = this.aoMap.toJSON( meta ).uuid; + data.aoMapIntensity = this.aoMapIntensity; - this.name = ''; - this.type = 'BufferGeometry'; + } - this.index = null; - this.attributes = {}; + if ( this.bumpMap && this.bumpMap.isTexture ) { - this.morphAttributes = {}; + data.bumpMap = this.bumpMap.toJSON( meta ).uuid; + data.bumpScale = this.bumpScale; - this.groups = []; + } - this.boundingBox = null; - this.boundingSphere = null; + if ( this.normalMap && this.normalMap.isTexture ) { - this.drawRange = { start: 0, count: Infinity }; + data.normalMap = this.normalMap.toJSON( meta ).uuid; + data.normalMapType = this.normalMapType; + data.normalScale = this.normalScale.toArray(); -} + } -BufferGeometry.prototype = Object.assign( Object.create( EventDispatcher.prototype ), { + if ( this.displacementMap && this.displacementMap.isTexture ) { - constructor: BufferGeometry, + data.displacementMap = this.displacementMap.toJSON( meta ).uuid; + data.displacementScale = this.displacementScale; + data.displacementBias = this.displacementBias; - isBufferGeometry: true, + } - getIndex: function () { + 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; - return this.index; + if ( this.emissiveMap && this.emissiveMap.isTexture ) data.emissiveMap = this.emissiveMap.toJSON( meta ).uuid; + if ( this.specularMap && this.specularMap.isTexture ) data.specularMap = this.specularMap.toJSON( meta ).uuid; - }, + if ( this.envMap && this.envMap.isTexture ) { - setIndex: function ( index ) { + data.envMap = this.envMap.toJSON( meta ).uuid; + data.reflectivity = this.reflectivity; // Scale behind envMap - if ( Array.isArray( index ) ) { + if ( this.combine !== undefined ) data.combine = this.combine; + if ( this.envMapIntensity !== undefined ) data.envMapIntensity = this.envMapIntensity; - this.index = new ( arrayMax( index ) > 65535 ? Uint32BufferAttribute : Uint16BufferAttribute )( index, 1 ); + } - } else { + if ( this.gradientMap && this.gradientMap.isTexture ) { - this.index = index; + data.gradientMap = this.gradientMap.toJSON( meta ).uuid; } - }, + if ( this.size !== undefined ) data.size = this.size; + if ( this.sizeAttenuation !== undefined ) data.sizeAttenuation = this.sizeAttenuation; - addAttribute: function ( name, attribute ) { + 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; - if ( ! ( attribute && attribute.isBufferAttribute ) && ! ( attribute && attribute.isInterleavedBufferAttribute ) ) { + if ( this.opacity < 1 ) data.opacity = this.opacity; + if ( this.transparent === true ) data.transparent = this.transparent; - console.warn( 'THREE.BufferGeometry: .addAttribute() now expects ( name, attribute ).' ); + data.depthFunc = this.depthFunc; + data.depthTest = this.depthTest; + data.depthWrite = this.depthWrite; - this.addAttribute( name, new BufferAttribute( arguments[ 1 ], arguments[ 2 ] ) ); + // rotation (SpriteMaterial) + if ( this.rotation !== 0 ) data.rotation = this.rotation; - return; + 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 !== 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 ( name === 'index' ) { + if ( this.dithering === true ) data.dithering = true; - console.warn( 'THREE.BufferGeometry.addAttribute: Use .setIndex() for index attribute.' ); - this.setIndex( attribute ); + if ( this.alphaTest > 0 ) data.alphaTest = this.alphaTest; + if ( this.premultipliedAlpha === true ) data.premultipliedAlpha = this.premultipliedAlpha; - return; + 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; - this.attributes[ name ] = attribute; + if ( this.visible === false ) data.visible = false; + if ( JSON.stringify( this.userData ) !== '{}' ) data.userData = this.userData; - return this; + // TODO: Copied from Object3D.toJSON - }, + function extractFromCache( cache ) { - getAttribute: function ( name ) { + var values = []; - return this.attributes[ name ]; + for ( var key in cache ) { - }, + var data = cache[ key ]; + delete data.metadata; + values.push( data ); - removeAttribute: function ( name ) { + } - delete this.attributes[ name ]; + return values; - return this; + } - }, + if ( isRoot ) { - addGroup: function ( start, count, materialIndex ) { + var textures = extractFromCache( meta.textures ); + var images = extractFromCache( meta.images ); - this.groups.push( { + if ( textures.length > 0 ) data.textures = textures; + if ( images.length > 0 ) data.images = images; - start: start, - count: count, - materialIndex: materialIndex !== undefined ? materialIndex : 0 + } - } ); + return data; }, - clearGroups: function () { + clone: function () { - this.groups = []; + return new this.constructor().copy( this ); }, - setDrawRange: function ( start, count ) { + copy: function ( source ) { - this.drawRange.start = start; - this.drawRange.count = count; + this.name = source.name; - }, + this.fog = source.fog; + this.lights = source.lights; - applyMatrix: function ( matrix ) { + this.blending = source.blending; + this.side = source.side; + this.flatShading = source.flatShading; + this.vertexColors = source.vertexColors; - var position = this.attributes.position; + this.opacity = source.opacity; + this.transparent = source.transparent; - if ( position !== undefined ) { + this.blendSrc = source.blendSrc; + this.blendDst = source.blendDst; + this.blendEquation = source.blendEquation; + this.blendSrcAlpha = source.blendSrcAlpha; + this.blendDstAlpha = source.blendDstAlpha; + this.blendEquationAlpha = source.blendEquationAlpha; - matrix.applyToBufferAttribute( position ); - position.needsUpdate = true; + this.depthFunc = source.depthFunc; + this.depthTest = source.depthTest; + this.depthWrite = source.depthWrite; - } + this.colorWrite = source.colorWrite; - var normal = this.attributes.normal; + this.precision = source.precision; - if ( normal !== undefined ) { + this.polygonOffset = source.polygonOffset; + this.polygonOffsetFactor = source.polygonOffsetFactor; + this.polygonOffsetUnits = source.polygonOffsetUnits; - var normalMatrix = new Matrix3().getNormalMatrix( matrix ); + this.dithering = source.dithering; - normalMatrix.applyToBufferAttribute( normal ); - normal.needsUpdate = true; + this.alphaTest = source.alphaTest; + this.premultipliedAlpha = source.premultipliedAlpha; - } + this.visible = source.visible; + this.userData = JSON.parse( JSON.stringify( source.userData ) ); - if ( this.boundingBox !== null ) { + this.clipShadows = source.clipShadows; + this.clipIntersection = source.clipIntersection; - this.computeBoundingBox(); + var srcPlanes = source.clippingPlanes, + dstPlanes = null; - } + if ( srcPlanes !== null ) { - if ( this.boundingSphere !== null ) { + var n = srcPlanes.length; + dstPlanes = new Array( n ); - this.computeBoundingSphere(); + for ( var i = 0; i !== n; ++ i ) + dstPlanes[ i ] = srcPlanes[ i ].clone(); } + this.clippingPlanes = dstPlanes; + + this.shadowSide = source.shadowSide; + return this; }, - rotateX: function () { + dispose: function () { - // rotate geometry around world x-axis + this.dispatchEvent( { type: 'dispose' } ); - var m1 = new Matrix4(); + } - return function rotateX( angle ) { +} ); - m1.makeRotationX( angle ); +/** + * @author alteredq / http://alteredqualia.com/ + * + * parameters = { + * defines: { "label" : "value" }, + * uniforms: { "parameter1": { value: 1.0 }, "parameter2": { value2: 2 } }, + * + * fragmentShader: , + * vertexShader: , + * + * wireframe: , + * wireframeLinewidth: , + * + * lights: , + * + * skinning: , + * morphTargets: , + * morphNormals: + * } + */ - this.applyMatrix( m1 ); +function ShaderMaterial( parameters ) { - return this; + Material.call( this ); - }; + this.type = 'ShaderMaterial'; - }(), + this.defines = {}; + this.uniforms = {}; - rotateY: function () { + 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}'; - // rotate geometry around world y-axis + this.linewidth = 1; - var m1 = new Matrix4(); + this.wireframe = false; + this.wireframeLinewidth = 1; - return function rotateY( angle ) { + this.fog = false; // set to use scene fog + this.lights = false; // set to use scene lights + this.clipping = false; // set to use user-defined clipping planes - m1.makeRotationY( angle ); + this.skinning = false; // set to use skinning attribute streams + this.morphTargets = false; // set to use morph targets + this.morphNormals = false; // set to use morph normals - this.applyMatrix( m1 ); + this.extensions = { + derivatives: false, // set to use derivatives + fragDepth: false, // set to use fragment depth values + drawBuffers: false, // set to use draw buffers + shaderTextureLOD: false // set to use shader texture LOD + }; - return this; + // When rendered geometry doesn't include these attributes but the material does, + // use these default values in WebGL. This avoids errors when buffer data is missing. + this.defaultAttributeValues = { + 'color': [ 1, 1, 1 ], + 'uv': [ 0, 0 ], + 'uv2': [ 0, 0 ] + }; - }; + this.index0AttributeName = undefined; + this.uniformsNeedUpdate = false; - }(), + if ( parameters !== undefined ) { - rotateZ: function () { + if ( parameters.attributes !== undefined ) { - // rotate geometry around world z-axis + console.error( 'THREE.ShaderMaterial: attributes should now be defined in THREE.BufferGeometry instead.' ); - var m1 = new Matrix4(); + } - return function rotateZ( angle ) { + this.setValues( parameters ); - m1.makeRotationZ( angle ); + } - this.applyMatrix( m1 ); +} - return this; +ShaderMaterial.prototype = Object.create( Material.prototype ); +ShaderMaterial.prototype.constructor = ShaderMaterial; - }; +ShaderMaterial.prototype.isShaderMaterial = true; - }(), +ShaderMaterial.prototype.copy = function ( source ) { - translate: function () { + Material.prototype.copy.call( this, source ); - // translate geometry + this.fragmentShader = source.fragmentShader; + this.vertexShader = source.vertexShader; - var m1 = new Matrix4(); + this.uniforms = cloneUniforms( source.uniforms ); - return function translate( x, y, z ) { + this.defines = Object.assign( {}, source.defines ); - m1.makeTranslation( x, y, z ); + this.wireframe = source.wireframe; + this.wireframeLinewidth = source.wireframeLinewidth; - this.applyMatrix( m1 ); + this.lights = source.lights; + this.clipping = source.clipping; - return this; + this.skinning = source.skinning; - }; + this.morphTargets = source.morphTargets; + this.morphNormals = source.morphNormals; - }(), + this.extensions = source.extensions; - scale: function () { + return this; - // scale geometry +}; - var m1 = new Matrix4(); +ShaderMaterial.prototype.toJSON = function ( meta ) { - return function scale( x, y, z ) { + var data = Material.prototype.toJSON.call( this, meta ); - m1.makeScale( x, y, z ); + data.uniforms = {}; - this.applyMatrix( m1 ); + for ( var name in this.uniforms ) { - return this; + var uniform = this.uniforms[ name ]; + var value = uniform.value; - }; + if ( value && value.isTexture ) { - }(), + data.uniforms[ name ] = { + type: 't', + value: value.toJSON( meta ).uuid + }; - lookAt: function () { + } else if ( value && value.isColor ) { - var obj = new Object3D(); + data.uniforms[ name ] = { + type: 'c', + value: value.getHex() + }; - return function lookAt( vector ) { + } else if ( value && value.isVector2 ) { - obj.lookAt( vector ); + data.uniforms[ name ] = { + type: 'v2', + value: value.toArray() + }; - obj.updateMatrix(); + } else if ( value && value.isVector3 ) { - this.applyMatrix( obj.matrix ); + data.uniforms[ name ] = { + type: 'v3', + value: value.toArray() + }; - }; + } else if ( value && value.isVector4 ) { - }(), + data.uniforms[ name ] = { + type: 'v4', + value: value.toArray() + }; - center: function () { + } else if ( value && value.isMatrix4 ) { - this.computeBoundingBox(); + data.uniforms[ name ] = { + type: 'm4', + value: value.toArray() + }; - var offset = this.boundingBox.getCenter().negate(); + } else { - this.translate( offset.x, offset.y, offset.z ); + data.uniforms[ name ] = { + value: value + }; - return offset; + // note: the array variants v2v, v3v, v4v, m4v and tv are not supported so far - }, + } - setFromObject: function ( object ) { + } - // console.log( 'THREE.BufferGeometry.setFromObject(). Converting', object, this ); + if ( Object.keys( this.defines ).length > 0 ) data.defines = this.defines; - var geometry = object.geometry; + data.vertexShader = this.vertexShader; + data.fragmentShader = this.fragmentShader; - if ( object.isPoints || object.isLine ) { + var extensions = {}; - var positions = new Float32BufferAttribute( geometry.vertices.length * 3, 3 ); - var colors = new Float32BufferAttribute( geometry.colors.length * 3, 3 ); + for ( var key in this.extensions ) { - this.addAttribute( 'position', positions.copyVector3sArray( geometry.vertices ) ); - this.addAttribute( 'color', colors.copyColorsArray( geometry.colors ) ); + if ( this.extensions[ key ] === true ) extensions[ key ] = true; - if ( geometry.lineDistances && geometry.lineDistances.length === geometry.vertices.length ) { + } - var lineDistances = new Float32BufferAttribute( geometry.lineDistances.length, 1 ); + if ( Object.keys( extensions ).length > 0 ) data.extensions = extensions; - this.addAttribute( 'lineDistance', lineDistances.copyArray( geometry.lineDistances ) ); + return data; - } +}; - if ( geometry.boundingSphere !== null ) { +/** + * @author bhouston / http://clara.io + */ - this.boundingSphere = geometry.boundingSphere.clone(); +function Ray( origin, direction ) { - } + this.origin = ( origin !== undefined ) ? origin : new Vector3(); + this.direction = ( direction !== undefined ) ? direction : new Vector3(); - if ( geometry.boundingBox !== null ) { +} - this.boundingBox = geometry.boundingBox.clone(); +Object.assign( Ray.prototype, { - } + set: function ( origin, direction ) { - } else if ( object.isMesh ) { + this.origin.copy( origin ); + this.direction.copy( direction ); - if ( geometry && geometry.isGeometry ) { + return this; - this.fromGeometry( geometry ); + }, - } + clone: function () { - } + return new this.constructor().copy( this ); + + }, + + copy: function ( ray ) { + + this.origin.copy( ray.origin ); + this.direction.copy( ray.direction ); return this; }, - setFromPoints: function ( points ) { - - var position = []; + at: function ( t, target ) { - for ( var i = 0, l = points.length; i < l; i ++ ) { + if ( target === undefined ) { - var point = points[ i ]; - position.push( point.x, point.y, point.z || 0 ); + console.warn( 'THREE.Ray: .at() target is now required' ); + target = new Vector3(); } - this.addAttribute( 'position', new Float32BufferAttribute( position, 3 ) ); - - return this; + return target.copy( this.direction ).multiplyScalar( t ).add( this.origin ); }, - updateFromObject: function ( object ) { + lookAt: function ( v ) { - var geometry = object.geometry; + this.direction.copy( v ).sub( this.origin ).normalize(); - if ( object.isMesh ) { + return this; - var direct = geometry.__directGeometry; + }, - if ( geometry.elementsNeedUpdate === true ) { + recast: function () { - direct = undefined; - geometry.elementsNeedUpdate = false; + var v1 = new Vector3(); - } + return function recast( t ) { - if ( direct === undefined ) { + this.origin.copy( this.at( t, v1 ) ); - return this.fromGeometry( geometry ); + return this; - } + }; - 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; + closestPointToPoint: function ( point, target ) { - geometry = direct; + if ( target === undefined ) { + + console.warn( 'THREE.Ray: .closestPointToPoint() target is now required' ); + target = new Vector3(); } - var attribute; + target.subVectors( point, this.origin ); - if ( geometry.verticesNeedUpdate === true ) { + var directionDistance = target.dot( this.direction ); - attribute = this.attributes.position; + if ( directionDistance < 0 ) { - if ( attribute !== undefined ) { + return target.copy( this.origin ); - attribute.copyVector3sArray( geometry.vertices ); - attribute.needsUpdate = true; + } - } + return target.copy( this.direction ).multiplyScalar( directionDistance ).add( this.origin ); - geometry.verticesNeedUpdate = false; + }, - } + distanceToPoint: function ( point ) { - if ( geometry.normalsNeedUpdate === true ) { + return Math.sqrt( this.distanceSqToPoint( point ) ); - attribute = this.attributes.normal; - - if ( attribute !== undefined ) { - - attribute.copyVector3sArray( geometry.normals ); - attribute.needsUpdate = true; + }, - } + distanceSqToPoint: function () { - geometry.normalsNeedUpdate = false; + var v1 = new Vector3(); - } + return function distanceSqToPoint( point ) { - if ( geometry.colorsNeedUpdate === true ) { + var directionDistance = v1.subVectors( point, this.origin ).dot( this.direction ); - attribute = this.attributes.color; + // point behind the ray - if ( attribute !== undefined ) { + if ( directionDistance < 0 ) { - attribute.copyColorsArray( geometry.colors ); - attribute.needsUpdate = true; + return this.origin.distanceToSquared( point ); } - geometry.colorsNeedUpdate = false; + v1.copy( this.direction ).multiplyScalar( directionDistance ).add( this.origin ); - } + return v1.distanceToSquared( point ); - if ( geometry.uvsNeedUpdate ) { + }; - attribute = this.attributes.uv; + }(), - if ( attribute !== undefined ) { + distanceSqToSegment: function () { - attribute.copyVector2sArray( geometry.uvs ); - attribute.needsUpdate = true; + var segCenter = new Vector3(); + var segDir = new Vector3(); + var diff = new Vector3(); - } + return function distanceSqToSegment( v0, v1, optionalPointOnRay, optionalPointOnSegment ) { - geometry.uvsNeedUpdate = false; + // 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 ); - if ( geometry.lineDistancesNeedUpdate ) { + 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; - attribute = this.attributes.lineDistance; + if ( det > 0 ) { - if ( attribute !== undefined ) { + // The ray and segment are not parallel. - attribute.copyArray( geometry.lineDistances ); - attribute.needsUpdate = true; + s0 = a01 * b1 - b0; + s1 = a01 * b0 - b1; + extDet = segExtent * det; - } + if ( s0 >= 0 ) { - geometry.lineDistancesNeedUpdate = false; + if ( s1 >= - extDet ) { - } + if ( s1 <= extDet ) { - if ( geometry.groupsNeedUpdate ) { + // region 0 + // Minimum at interior points of ray and segment. - geometry.computeGroups( object.geometry ); - this.groups = geometry.groups; + var invDet = 1 / det; + s0 *= invDet; + s1 *= invDet; + sqrDist = s0 * ( s0 + a01 * s1 + 2 * b0 ) + s1 * ( a01 * s0 + s1 + 2 * b1 ) + c; - geometry.groupsNeedUpdate = false; + } else { - } + // region 1 - return this; + s1 = segExtent; + s0 = Math.max( 0, - ( a01 * s1 + b0 ) ); + sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; - }, + } - fromGeometry: function ( geometry ) { + } else { - geometry.__directGeometry = new DirectGeometry().fromGeometry( geometry ); + // region 5 - return this.fromDirectGeometry( geometry.__directGeometry ); + s1 = - segExtent; + s0 = Math.max( 0, - ( a01 * s1 + b0 ) ); + sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; - }, + } - fromDirectGeometry: function ( geometry ) { + } else { - var positions = new Float32Array( geometry.vertices.length * 3 ); - this.addAttribute( 'position', new BufferAttribute( positions, 3 ).copyVector3sArray( geometry.vertices ) ); + if ( s1 <= - extDet ) { - if ( geometry.normals.length > 0 ) { + // region 4 - var normals = new Float32Array( geometry.normals.length * 3 ); - this.addAttribute( 'normal', new BufferAttribute( normals, 3 ).copyVector3sArray( geometry.normals ) ); + 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 ) { - if ( geometry.colors.length > 0 ) { + // region 3 - var colors = new Float32Array( geometry.colors.length * 3 ); - this.addAttribute( 'color', new BufferAttribute( colors, 3 ).copyColorsArray( geometry.colors ) ); + s0 = 0; + s1 = Math.min( Math.max( - segExtent, - b1 ), segExtent ); + sqrDist = s1 * ( s1 + 2 * b1 ) + c; - } + } else { - if ( geometry.uvs.length > 0 ) { + // region 2 - var uvs = new Float32Array( geometry.uvs.length * 2 ); - this.addAttribute( 'uv', new BufferAttribute( uvs, 2 ).copyVector2sArray( geometry.uvs ) ); + 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; - } + } - if ( geometry.uvs2.length > 0 ) { + } - var uvs2 = new Float32Array( geometry.uvs2.length * 2 ); - this.addAttribute( 'uv2', new BufferAttribute( uvs2, 2 ).copyVector2sArray( geometry.uvs2 ) ); + } else { - } + // Ray and segment are parallel. - if ( geometry.indices.length > 0 ) { + s1 = ( a01 > 0 ) ? - segExtent : segExtent; + s0 = Math.max( 0, - ( a01 * s1 + b0 ) ); + sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; - var TypeArray = arrayMax( geometry.indices ) > 65535 ? Uint32Array : Uint16Array; - var indices = new TypeArray( geometry.indices.length * 3 ); - this.setIndex( new BufferAttribute( indices, 1 ).copyIndicesArray( geometry.indices ) ); + } - } + if ( optionalPointOnRay ) { - // groups + optionalPointOnRay.copy( this.direction ).multiplyScalar( s0 ).add( this.origin ); - this.groups = geometry.groups; + } - // morphs + if ( optionalPointOnSegment ) { - for ( var name in geometry.morphTargets ) { + optionalPointOnSegment.copy( segDir ).multiplyScalar( s1 ).add( segCenter ); - var array = []; - var morphTargets = geometry.morphTargets[ name ]; + } - for ( var i = 0, l = morphTargets.length; i < l; i ++ ) { + return sqrDist; - var morphTarget = morphTargets[ i ]; + }; - var attribute = new Float32BufferAttribute( morphTarget.length * 3, 3 ); + }(), - array.push( attribute.copyVector3sArray( morphTarget ) ); + intersectSphere: function () { - } + var v1 = new Vector3(); - this.morphAttributes[ name ] = array; + return function intersectSphere( sphere, target ) { - } + 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; - // skinning + if ( d2 > radius2 ) return null; - if ( geometry.skinIndices.length > 0 ) { + var thc = Math.sqrt( radius2 - d2 ); - var skinIndices = new Float32BufferAttribute( geometry.skinIndices.length * 4, 4 ); - this.addAttribute( 'skinIndex', skinIndices.copyVector4sArray( geometry.skinIndices ) ); + // 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; - if ( geometry.skinWeights.length > 0 ) { + // test to see if both t0 and t1 are behind the ray - if so, return null + if ( t0 < 0 && t1 < 0 ) return null; - var skinWeights = new Float32BufferAttribute( geometry.skinWeights.length * 4, 4 ); - this.addAttribute( 'skinWeight', skinWeights.copyVector4sArray( geometry.skinWeights ) ); + // test to see if t0 is behind the ray: + // if it is, the ray is inside the sphere, so return the second exit point scaled by t1, + // in order to always return an intersect point that is in front of the ray. + if ( t0 < 0 ) return this.at( t1, target ); - } + // else t0 is in front of the ray, so return the first collision point scaled by t0 + return this.at( t0, target ); - // + }; - if ( geometry.boundingSphere !== null ) { + }(), - this.boundingSphere = geometry.boundingSphere.clone(); + intersectsSphere: function ( sphere ) { - } + return this.distanceSqToPoint( sphere.center ) <= ( sphere.radius * sphere.radius ); - if ( geometry.boundingBox !== null ) { + }, - this.boundingBox = geometry.boundingBox.clone(); + distanceToPlane: function ( plane ) { - } + var denominator = plane.normal.dot( this.direction ); - return this; + if ( denominator === 0 ) { - }, + // line is coplanar, return origin + if ( plane.distanceToPoint( this.origin ) === 0 ) { - computeBoundingBox: function () { + return 0; - if ( this.boundingBox === null ) { + } - this.boundingBox = new Box3(); + // Null is preferable to undefined since undefined means.... it is undefined + + return null; } - var position = this.attributes.position; + var t = - ( this.origin.dot( plane.normal ) + plane.constant ) / denominator; - if ( position !== undefined ) { + // Return if the ray never intersects the plane - this.boundingBox.setFromBufferAttribute( position ); + return t >= 0 ? t : null; - } else { + }, - this.boundingBox.makeEmpty(); + intersectPlane: function ( plane, target ) { - } + var t = this.distanceToPlane( plane ); - if ( isNaN( this.boundingBox.min.x ) || isNaN( this.boundingBox.min.y ) || isNaN( this.boundingBox.min.z ) ) { + if ( t === null ) { - console.error( 'THREE.BufferGeometry.computeBoundingBox: Computed min/max have NaN values. The "position" attribute is likely to have NaN values.', this ); + return null; } - }, - - computeBoundingSphere: function () { + return this.at( t, target ); - var box = new Box3(); - var vector = new Vector3(); + }, - return function computeBoundingSphere() { + intersectsPlane: function ( plane ) { - if ( this.boundingSphere === null ) { + // check if the ray lies on the plane first - this.boundingSphere = new Sphere(); + var distToPoint = plane.distanceToPoint( this.origin ); - } + if ( distToPoint === 0 ) { - var position = this.attributes.position; + return true; - if ( position ) { + } - var center = this.boundingSphere.center; + var denominator = plane.normal.dot( this.direction ); - box.setFromBufferAttribute( position ); - box.getCenter( center ); + if ( denominator * distToPoint < 0 ) { - // hoping to find a boundingSphere with a radius smaller than the - // boundingSphere of the boundingBox: sqrt(3) smaller in the best case + return true; - var maxRadiusSq = 0; + } - for ( var i = 0, il = position.count; i < il; i ++ ) { + // ray origin is behind the plane (and is pointing behind it) - vector.x = position.getX( i ); - vector.y = position.getY( i ); - vector.z = position.getZ( i ); - maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( vector ) ); + return false; - } + }, - this.boundingSphere.radius = Math.sqrt( maxRadiusSq ); + intersectBox: function ( box, target ) { - if ( isNaN( this.boundingSphere.radius ) ) { + var tmin, tmax, tymin, tymax, tzmin, tzmax; - console.error( 'THREE.BufferGeometry.computeBoundingSphere(): Computed radius is NaN. The "position" attribute is likely to have NaN values.', this ); + var invdirx = 1 / this.direction.x, + invdiry = 1 / this.direction.y, + invdirz = 1 / this.direction.z; - } + var origin = this.origin; - } + if ( invdirx >= 0 ) { - }; + tmin = ( box.min.x - origin.x ) * invdirx; + tmax = ( box.max.x - origin.x ) * invdirx; - }(), + } else { - computeFaceNormals: function () { + tmin = ( box.max.x - origin.x ) * invdirx; + tmax = ( box.min.x - origin.x ) * invdirx; - // backwards compatibility + } - }, + if ( invdiry >= 0 ) { - computeVertexNormals: function () { + tymin = ( box.min.y - origin.y ) * invdiry; + tymax = ( box.max.y - origin.y ) * invdiry; - var index = this.index; - var attributes = this.attributes; - var groups = this.groups; + } else { - if ( attributes.position ) { + tymin = ( box.max.y - origin.y ) * invdiry; + tymax = ( box.min.y - origin.y ) * invdiry; - var positions = attributes.position.array; + } - if ( attributes.normal === undefined ) { + if ( ( tmin > tymax ) || ( tymin > tmax ) ) return null; - this.addAttribute( 'normal', new BufferAttribute( new Float32Array( positions.length ), 3 ) ); + // These lines also handle the case where tmin or tmax is NaN + // (result of 0 * Infinity). x !== x returns true if x is NaN - } else { + if ( tymin > tmin || tmin !== tmin ) tmin = tymin; - // reset existing normals to zero + if ( tymax < tmax || tmax !== tmax ) tmax = tymax; - var array = attributes.normal.array; + if ( invdirz >= 0 ) { - for ( var i = 0, il = array.length; i < il; i ++ ) { + tzmin = ( box.min.z - origin.z ) * invdirz; + tzmax = ( box.max.z - origin.z ) * invdirz; - array[ i ] = 0; + } else { - } + tzmin = ( box.max.z - origin.z ) * invdirz; + tzmax = ( box.min.z - origin.z ) * invdirz; - } + } - var normals = attributes.normal.array; + if ( ( tmin > tzmax ) || ( tzmin > tmax ) ) return null; - var vA, vB, vC; - var pA = new Vector3(), pB = new Vector3(), pC = new Vector3(); - var cb = new Vector3(), ab = new Vector3(); + if ( tzmin > tmin || tmin !== tmin ) tmin = tzmin; - // indexed elements + if ( tzmax < tmax || tmax !== tmax ) tmax = tzmax; - if ( index ) { + //return point closest to the ray (positive side) - var indices = index.array; + if ( tmax < 0 ) return null; - if ( groups.length === 0 ) { + return this.at( tmin >= 0 ? tmin : tmax, target ); - this.addGroup( 0, indices.length ); + }, - } + intersectsBox: ( function () { - for ( var j = 0, jl = groups.length; j < jl; ++ j ) { + var v = new Vector3(); - var group = groups[ j ]; + return function intersectsBox( box ) { - var start = group.start; - var count = group.count; + return this.intersectBox( box, v ) !== null; - for ( var i = start, il = start + count; i < il; i += 3 ) { + }; - vA = indices[ i + 0 ] * 3; - vB = indices[ i + 1 ] * 3; - vC = indices[ i + 2 ] * 3; + } )(), - pA.fromArray( positions, vA ); - pB.fromArray( positions, vB ); - pC.fromArray( positions, vC ); + intersectTriangle: function () { - cb.subVectors( pC, pB ); - ab.subVectors( pA, pB ); - cb.cross( ab ); + // Compute the offset origin, edges, and normal. + var diff = new Vector3(); + var edge1 = new Vector3(); + var edge2 = new Vector3(); + var normal = new Vector3(); - normals[ vA ] += cb.x; - normals[ vA + 1 ] += cb.y; - normals[ vA + 2 ] += cb.z; + return function intersectTriangle( a, b, c, backfaceCulling, target ) { - normals[ vB ] += cb.x; - normals[ vB + 1 ] += cb.y; - normals[ vB + 2 ] += cb.z; + // from http://www.geometrictools.com/GTEngine/Include/Mathematics/GteIntrRay3Triangle3.h - normals[ vC ] += cb.x; - normals[ vC + 1 ] += cb.y; - normals[ vC + 2 ] += cb.z; + edge1.subVectors( b, a ); + edge2.subVectors( c, a ); + normal.crossVectors( edge1, edge2 ); - } + // Solve Q + t*D = b1*E1 + b2*E2 (Q = kDiff, D = ray direction, + // E1 = kEdge1, E2 = kEdge2, N = Cross(E1,E2)) by + // |Dot(D,N)|*b1 = sign(Dot(D,N))*Dot(D,Cross(Q,E2)) + // |Dot(D,N)|*b2 = sign(Dot(D,N))*Dot(D,Cross(E1,Q)) + // |Dot(D,N)|*t = -sign(Dot(D,N))*Dot(Q,N) + var DdN = this.direction.dot( normal ); + var sign; - } + if ( DdN > 0 ) { - } else { + if ( backfaceCulling ) return null; + sign = 1; - // non-indexed elements (unconnected triangle soup) + } else if ( DdN < 0 ) { - for ( var i = 0, il = positions.length; i < il; i += 9 ) { + sign = - 1; + DdN = - DdN; - pA.fromArray( positions, i ); - pB.fromArray( positions, i + 3 ); - pC.fromArray( positions, i + 6 ); + } else { - cb.subVectors( pC, pB ); - ab.subVectors( pA, pB ); - cb.cross( ab ); + return null; - normals[ i ] = cb.x; - normals[ i + 1 ] = cb.y; - normals[ i + 2 ] = cb.z; + } - normals[ i + 3 ] = cb.x; - normals[ i + 4 ] = cb.y; - normals[ i + 5 ] = cb.z; + diff.subVectors( this.origin, a ); + var DdQxE2 = sign * this.direction.dot( edge2.crossVectors( diff, edge2 ) ); - normals[ i + 6 ] = cb.x; - normals[ i + 7 ] = cb.y; - normals[ i + 8 ] = cb.z; + // b1 < 0, no intersection + if ( DdQxE2 < 0 ) { - } + return null; } - this.normalizeNormals(); + var DdE1xQ = sign * this.direction.dot( edge1.cross( diff ) ); - attributes.normal.needsUpdate = true; + // b2 < 0, no intersection + if ( DdE1xQ < 0 ) { - } + return null; - }, + } - merge: function ( geometry, offset ) { + // b1+b2 > 1, no intersection + if ( DdQxE2 + DdE1xQ > DdN ) { - if ( ! ( geometry && geometry.isBufferGeometry ) ) { + return null; - console.error( 'THREE.BufferGeometry.merge(): geometry not an instance of THREE.BufferGeometry.', geometry ); - return; + } - } + // Line intersects triangle, check if ray does. + var QdN = - sign * diff.dot( normal ); - if ( offset === undefined ) offset = 0; + // t < 0, no intersection + if ( QdN < 0 ) { - var attributes = this.attributes; + return null; - for ( var key in attributes ) { + } - if ( geometry.attributes[ key ] === undefined ) continue; + // Ray intersects triangle. + return this.at( QdN / DdN, target ); - var attribute1 = attributes[ key ]; - var attributeArray1 = attribute1.array; + }; - var attribute2 = geometry.attributes[ key ]; - var attributeArray2 = attribute2.array; + }(), - var attributeSize = attribute2.itemSize; + applyMatrix4: function ( matrix4 ) { - for ( var i = 0, j = attributeSize * offset; i < attributeArray2.length; i ++, j ++ ) { + this.origin.applyMatrix4( matrix4 ); + this.direction.transformDirection( matrix4 ); - attributeArray1[ j ] = attributeArray2[ i ]; + return this; - } + }, - } + equals: function ( ray ) { - return this; + return ray.origin.equals( this.origin ) && ray.direction.equals( this.direction ); - }, + } - normalizeNormals: function () { +} ); - var vector = new Vector3(); +/** + * @author bhouston / http://clara.io + * @author mrdoob / http://mrdoob.com/ + */ - return function normalizeNormals() { +function Triangle( a, b, c ) { - var normals = this.attributes.normal; + this.a = ( a !== undefined ) ? a : new Vector3(); + this.b = ( b !== undefined ) ? b : new Vector3(); + this.c = ( c !== undefined ) ? c : new Vector3(); - for ( var i = 0, il = normals.count; i < il; i ++ ) { +} - vector.x = normals.getX( i ); - vector.y = normals.getY( i ); - vector.z = normals.getZ( i ); +Object.assign( Triangle, { - vector.normalize(); + getNormal: function () { - normals.setXYZ( i, vector.x, vector.y, vector.z ); + var v0 = new Vector3(); - } + return function getNormal( a, b, c, target ) { - }; + if ( target === undefined ) { - }(), + console.warn( 'THREE.Triangle: .getNormal() target is now required' ); + target = new Vector3(); - toNonIndexed: function () { + } - if ( this.index === null ) { + target.subVectors( c, b ); + v0.subVectors( a, b ); + target.cross( v0 ); - console.warn( 'THREE.BufferGeometry.toNonIndexed(): Geometry is already non-indexed.' ); - return this; + var targetLengthSq = target.lengthSq(); + if ( targetLengthSq > 0 ) { - } + return target.multiplyScalar( 1 / Math.sqrt( targetLengthSq ) ); - var geometry2 = new BufferGeometry(); + } - var indices = this.index.array; - var attributes = this.attributes; + return target.set( 0, 0, 0 ); - for ( var name in attributes ) { + }; - var attribute = attributes[ name ]; + }(), - var array = attribute.array; - var itemSize = attribute.itemSize; + // static/instance method to calculate barycentric coordinates + // based on: http://www.blackpawn.com/texts/pointinpoly/default.html + getBarycoord: function () { - var array2 = new array.constructor( indices.length * itemSize ); + var v0 = new Vector3(); + var v1 = new Vector3(); + var v2 = new Vector3(); - var index = 0, index2 = 0; + return function getBarycoord( point, a, b, c, target ) { - for ( var i = 0, l = indices.length; i < l; i ++ ) { + v0.subVectors( c, a ); + v1.subVectors( b, a ); + v2.subVectors( point, a ); - index = indices[ i ] * itemSize; + 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 ); - for ( var j = 0; j < itemSize; j ++ ) { + var denom = ( dot00 * dot11 - dot01 * dot01 ); - array2[ index2 ++ ] = array[ index ++ ]; + if ( target === undefined ) { - } + console.warn( 'THREE.Triangle: .getBarycoord() target is now required' ); + target = new Vector3(); } - geometry2.addAttribute( name, new BufferAttribute( array2, itemSize ) ); - - } - - return geometry2; - - }, + // collinear or singular triangle + if ( denom === 0 ) { - toJSON: function () { + // arbitrary location outside of triangle? + // not sure if this is the best idea, maybe should be returning undefined + return target.set( - 2, - 1, - 1 ); - var data = { - metadata: { - version: 4.5, - type: 'BufferGeometry', - generator: 'BufferGeometry.toJSON' } - }; - - // standard BufferGeometry serialization - - data.uuid = this.uuid; - data.type = this.type; - if ( this.name !== '' ) data.name = this.name; - if ( this.parameters !== undefined ) { + var invDenom = 1 / denom; + var u = ( dot11 * dot02 - dot01 * dot12 ) * invDenom; + var v = ( dot00 * dot12 - dot01 * dot02 ) * invDenom; - var parameters = this.parameters; + // barycentric coordinates must always sum to 1 + return target.set( 1 - u - v, v, u ); - for ( var key in parameters ) { + }; - if ( parameters[ key ] !== undefined ) data[ key ] = parameters[ key ]; + }(), - } + containsPoint: function () { - return data; + var v1 = new Vector3(); - } + return function containsPoint( point, a, b, c ) { - data.data = { attributes: {} }; + Triangle.getBarycoord( point, a, b, c, v1 ); - var index = this.index; + return ( v1.x >= 0 ) && ( v1.y >= 0 ) && ( ( v1.x + v1.y ) <= 1 ); - if ( index !== null ) { + }; - var array = Array.prototype.slice.call( index.array ); + }(), - data.data.index = { - type: index.array.constructor.name, - array: array - }; + getUV: function () { - } + var barycoord = new Vector3(); - var attributes = this.attributes; + return function getUV( point, p1, p2, p3, uv1, uv2, uv3, target ) { - for ( var key in attributes ) { + this.getBarycoord( point, p1, p2, p3, barycoord ); - var attribute = attributes[ key ]; + target.set( 0, 0 ); + target.addScaledVector( uv1, barycoord.x ); + target.addScaledVector( uv2, barycoord.y ); + target.addScaledVector( uv3, barycoord.z ); - var array = Array.prototype.slice.call( attribute.array ); + return target; - data.data.attributes[ key ] = { - itemSize: attribute.itemSize, - type: attribute.array.constructor.name, - array: array, - normalized: attribute.normalized - }; + }; - } + }() - var groups = this.groups; +} ); - if ( groups.length > 0 ) { +Object.assign( Triangle.prototype, { - data.data.groups = JSON.parse( JSON.stringify( groups ) ); + set: function ( a, b, c ) { - } + this.a.copy( a ); + this.b.copy( b ); + this.c.copy( c ); - var boundingSphere = this.boundingSphere; + return this; - if ( boundingSphere !== null ) { + }, - data.data.boundingSphere = { - center: boundingSphere.center.toArray(), - radius: boundingSphere.radius - }; + setFromPointsAndIndices: function ( points, i0, i1, i2 ) { - } + this.a.copy( points[ i0 ] ); + this.b.copy( points[ i1 ] ); + this.c.copy( points[ i2 ] ); - return data; + return this; }, clone: function () { - /* - // Handle primitives - - var parameters = this.parameters; - - if ( parameters !== undefined ) { - - var values = []; - - for ( var key in parameters ) { - - values.push( parameters[ key ] ); - - } - - var geometry = Object.create( this.constructor.prototype ); - this.constructor.apply( geometry, values ); - return geometry; - - } - - return new this.constructor().copy( this ); - */ - - return new BufferGeometry().copy( this ); + return new this.constructor().copy( this ); }, - copy: function ( source ) { - - var name, i, l; - - // reset - - this.index = null; - this.attributes = {}; - this.morphAttributes = {}; - this.groups = []; - this.boundingBox = null; - this.boundingSphere = null; - - // name - - this.name = source.name; - - // index - - var index = source.index; - - if ( index !== null ) { - - this.setIndex( index.clone() ); - - } - - // attributes - - var attributes = source.attributes; - - for ( name in attributes ) { - - var attribute = attributes[ name ]; - this.addAttribute( name, attribute.clone() ); - - } + copy: function ( triangle ) { - // morph attributes + this.a.copy( triangle.a ); + this.b.copy( triangle.b ); + this.c.copy( triangle.c ); - var morphAttributes = source.morphAttributes; + return this; - for ( name in morphAttributes ) { + }, - var array = []; - var morphAttribute = morphAttributes[ name ]; // morphAttribute: array of Float32BufferAttributes + getArea: function () { - for ( i = 0, l = morphAttribute.length; i < l; i ++ ) { + var v0 = new Vector3(); + var v1 = new Vector3(); - array.push( morphAttribute[ i ].clone() ); + return function getArea() { - } + v0.subVectors( this.c, this.b ); + v1.subVectors( this.a, this.b ); - this.morphAttributes[ name ] = array; + return v0.cross( v1 ).length() * 0.5; - } + }; - // groups + }(), - var groups = source.groups; + getMidpoint: function ( target ) { - for ( i = 0, l = groups.length; i < l; i ++ ) { + if ( target === undefined ) { - var group = groups[ i ]; - this.addGroup( group.start, group.count, group.materialIndex ); + console.warn( 'THREE.Triangle: .getMidpoint() target is now required' ); + target = new Vector3(); } - // bounding box - - var boundingBox = source.boundingBox; + return target.addVectors( this.a, this.b ).add( this.c ).multiplyScalar( 1 / 3 ); - if ( boundingBox !== null ) { + }, - this.boundingBox = boundingBox.clone(); + getNormal: function ( target ) { - } + return Triangle.getNormal( this.a, this.b, this.c, target ); - // bounding sphere + }, - var boundingSphere = source.boundingSphere; + getPlane: function ( target ) { - if ( boundingSphere !== null ) { + if ( target === undefined ) { - this.boundingSphere = boundingSphere.clone(); + console.warn( 'THREE.Triangle: .getPlane() target is now required' ); + target = new Vector3(); } - // draw range - - this.drawRange.start = source.drawRange.start; - this.drawRange.count = source.drawRange.count; - - return this; + return target.setFromCoplanarPoints( this.a, this.b, this.c ); }, - dispose: function () { - - this.dispatchEvent( { type: 'dispose' } ); - - } - -} ); - -/** - * @author mrdoob / http://mrdoob.com/ - * @author Mugen87 / https://github.com/Mugen87 - */ - -// 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 ) { - - BufferGeometry.call( this ); - - this.type = 'BoxBufferGeometry'; - - this.parameters = { - width: width, - height: height, - depth: depth, - widthSegments: widthSegments, - heightSegments: heightSegments, - depthSegments: depthSegments - }; - - var scope = this; - - width = width || 1; - height = height || 1; - depth = depth || 1; - - // segments - - widthSegments = Math.floor( widthSegments ) || 1; - heightSegments = Math.floor( heightSegments ) || 1; - depthSegments = Math.floor( depthSegments ) || 1; - - // 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 + getBarycoord: function ( point, target ) { - 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 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; + return Triangle.getBarycoord( point, this.a, this.b, this.c, target ); - var vertexCounter = 0; - var groupCount = 0; - - var ix, iy; - - var vector = new Vector3(); - - // generate vertices, normals and uvs - - for ( iy = 0; iy < gridY1; iy ++ ) { - - var y = iy * segmentHeight - heightHalf; + }, - for ( ix = 0; ix < gridX1; ix ++ ) { + containsPoint: function ( point ) { - var x = ix * segmentWidth - widthHalf; + return Triangle.containsPoint( point, this.a, this.b, this.c ); - // set values to correct vector component + }, - vector[ u ] = x * udir; - vector[ v ] = y * vdir; - vector[ w ] = depthHalf; + getUV: function ( point, uv1, uv2, uv3, result ) { - // now apply vector to vertex buffer + return Triangle.getUV( point, this.a, this.b, this.c, uv1, uv2, uv3, result ); - vertices.push( vector.x, vector.y, vector.z ); + }, - // set values to correct vector component + intersectsBox: function ( box ) { - vector[ u ] = 0; - vector[ v ] = 0; - vector[ w ] = depth > 0 ? 1 : - 1; + return box.intersectsTriangle( this ); - // now apply vector to normal buffer + }, - normals.push( vector.x, vector.y, vector.z ); + closestPointToPoint: function () { - // uvs + var vab = new Vector3(); + var vac = new Vector3(); + var vbc = new Vector3(); + var vap = new Vector3(); + var vbp = new Vector3(); + var vcp = new Vector3(); - uvs.push( ix / gridX ); - uvs.push( 1 - ( iy / gridY ) ); + return function closestPointToPoint( p, target ) { - // counters + if ( target === undefined ) { - vertexCounter += 1; + console.warn( 'THREE.Triangle: .closestPointToPoint() target is now required' ); + target = new Vector3(); } - } - - // 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 ( iy = 0; iy < gridY; iy ++ ) { - - for ( ix = 0; ix < gridX; ix ++ ) { - - 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; + var a = this.a, b = this.b, c = this.c; + var v, w; - // faces - - indices.push( a, b, d ); - indices.push( b, c, d ); + // 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. - // increase counter + 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 ) { - groupCount += 6; + // vertex region of A; barycentric coords (1, 0, 0) + return target.copy( a ); } - } - - // 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; - -/** - * @author mrdoob / http://mrdoob.com/ - * @author Mugen87 / https://github.com/Mugen87 - */ - -// PlaneGeometry - -function PlaneGeometry( width, height, widthSegments, heightSegments ) { - - Geometry.call( this ); - - this.type = 'PlaneGeometry'; - - this.parameters = { - width: width, - height: height, - widthSegments: widthSegments, - heightSegments: heightSegments - }; - - this.fromBufferGeometry( new PlaneBufferGeometry( width, height, widthSegments, heightSegments ) ); - this.mergeVertices(); - -} - -PlaneGeometry.prototype = Object.create( Geometry.prototype ); -PlaneGeometry.prototype.constructor = PlaneGeometry; - -// PlaneBufferGeometry + vbp.subVectors( p, b ); + var d3 = vab.dot( vbp ); + var d4 = vac.dot( vbp ); + if ( d3 >= 0 && d4 <= d3 ) { -function PlaneBufferGeometry( width, height, widthSegments, heightSegments ) { - - BufferGeometry.call( this ); - - this.type = 'PlaneBufferGeometry'; - - this.parameters = { - width: width, - height: height, - widthSegments: widthSegments, - heightSegments: heightSegments - }; - - width = width || 1; - height = height || 1; - - var width_half = width / 2; - var height_half = height / 2; - - var gridX = Math.floor( widthSegments ) || 1; - var gridY = Math.floor( heightSegments ) || 1; - - var gridX1 = gridX + 1; - var gridY1 = gridY + 1; + // vertex region of B; barycentric coords (0, 1, 0) + return target.copy( b ); - var segment_width = width / gridX; - var segment_height = height / gridY; - - var ix, iy; - - // buffers - - var indices = []; - var vertices = []; - var normals = []; - var uvs = []; + } - // generate vertices, normals and uvs + var vc = d1 * d4 - d3 * d2; + if ( vc <= 0 && d1 >= 0 && d3 <= 0 ) { - for ( iy = 0; iy < gridY1; iy ++ ) { + v = d1 / ( d1 - d3 ); + // edge region of AB; barycentric coords (1-v, v, 0) + return target.copy( a ).addScaledVector( vab, v ); - var y = iy * segment_height - height_half; + } - for ( ix = 0; ix < gridX1; ix ++ ) { + vcp.subVectors( p, c ); + var d5 = vab.dot( vcp ); + var d6 = vac.dot( vcp ); + if ( d6 >= 0 && d5 <= d6 ) { - var x = ix * segment_width - width_half; + // vertex region of C; barycentric coords (0, 0, 1) + return target.copy( c ); - vertices.push( x, - y, 0 ); + } - normals.push( 0, 0, 1 ); + var vb = d5 * d2 - d1 * d6; + if ( vb <= 0 && d2 >= 0 && d6 <= 0 ) { - uvs.push( ix / gridX ); - uvs.push( 1 - ( iy / gridY ) ); + w = d2 / ( d2 - d6 ); + // edge region of AC; barycentric coords (1-w, 0, w) + return target.copy( a ).addScaledVector( vac, w ); - } + } - } + var va = d3 * d6 - d5 * d4; + if ( va <= 0 && ( d4 - d3 ) >= 0 && ( d5 - d6 ) >= 0 ) { - // indices + 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 - for ( iy = 0; iy < gridY; iy ++ ) { + } - for ( ix = 0; ix < gridX; ix ++ ) { + // 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 ); - var a = ix + gridX1 * iy; - var b = ix + gridX1 * ( iy + 1 ); - var c = ( ix + 1 ) + gridX1 * ( iy + 1 ); - var d = ( ix + 1 ) + gridX1 * iy; + }; - // faces + }(), - indices.push( a, b, d ); - indices.push( b, c, d ); + equals: function ( triangle ) { - } + return triangle.a.equals( this.a ) && triangle.b.equals( this.b ) && triangle.c.equals( this.c ); } - // 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 ) ); - -} - -PlaneBufferGeometry.prototype = Object.create( BufferGeometry.prototype ); -PlaneBufferGeometry.prototype.constructor = PlaneBufferGeometry; +} ); /** * @author mrdoob / http://mrdoob.com/ @@ -17301,7 +15509,7 @@ PlaneBufferGeometry.prototype.constructor = PlaneBufferGeometry; * * alphaMap: new THREE.Texture( ), * - * envMap: new THREE.TextureCube( [posx, negx, posy, negy, posz, negz] ), + * envMap: new THREE.CubeTexture( [posx, negx, posy, negy, posz, negz] ), * combine: THREE.Multiply, * reflectivity: , * refractionRatio: , @@ -17397,1551 +15605,1462 @@ MeshBasicMaterial.prototype.copy = function ( source ) { }; /** + * @author mrdoob / http://mrdoob.com/ * @author alteredq / http://alteredqualia.com/ - * - * parameters = { - * defines: { "label" : "value" }, - * uniforms: { "parameter1": { value: 1.0 }, "parameter2": { value2: 2 } }, - * - * fragmentShader: , - * vertexShader: , - * - * wireframe: , - * wireframeLinewidth: , - * - * lights: , - * - * skinning: , - * morphTargets: , - * morphNormals: - * } + * @author mikael emtinger / http://gomo.se/ + * @author jonobr1 / http://jonobr1.com/ */ -function ShaderMaterial( parameters ) { - - Material.call( this ); - - this.type = 'ShaderMaterial'; +function Mesh( geometry, material ) { - this.defines = {}; - this.uniforms = {}; + Object3D.call( this ); - 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.type = 'Mesh'; - this.linewidth = 1; + this.geometry = geometry !== undefined ? geometry : new BufferGeometry(); + this.material = material !== undefined ? material : new MeshBasicMaterial( { color: Math.random() * 0xffffff } ); - this.wireframe = false; - this.wireframeLinewidth = 1; + this.drawMode = TrianglesDrawMode; - this.fog = false; // set to use scene fog - this.lights = false; // set to use scene lights - this.clipping = false; // set to use user-defined clipping planes + this.updateMorphTargets(); - this.skinning = false; // set to use skinning attribute streams - this.morphTargets = false; // set to use morph targets - this.morphNormals = false; // set to use morph normals +} - this.extensions = { - derivatives: false, // set to use derivatives - fragDepth: false, // set to use fragment depth values - drawBuffers: false, // set to use draw buffers - shaderTextureLOD: false // set to use shader texture LOD - }; +Mesh.prototype = Object.assign( Object.create( Object3D.prototype ), { - // When rendered geometry doesn't include these attributes but the material does, - // use these default values in WebGL. This avoids errors when buffer data is missing. - this.defaultAttributeValues = { - 'color': [ 1, 1, 1 ], - 'uv': [ 0, 0 ], - 'uv2': [ 0, 0 ] - }; + constructor: Mesh, - this.index0AttributeName = undefined; - this.uniformsNeedUpdate = false; + isMesh: true, - if ( parameters !== undefined ) { + setDrawMode: function ( value ) { - if ( parameters.attributes !== undefined ) { + this.drawMode = value; - console.error( 'THREE.ShaderMaterial: attributes should now be defined in THREE.BufferGeometry instead.' ); + }, - } + copy: function ( source ) { - this.setValues( parameters ); + Object3D.prototype.copy.call( this, source ); - } + this.drawMode = source.drawMode; -} + if ( source.morphTargetInfluences !== undefined ) { -ShaderMaterial.prototype = Object.create( Material.prototype ); -ShaderMaterial.prototype.constructor = ShaderMaterial; + this.morphTargetInfluences = source.morphTargetInfluences.slice(); -ShaderMaterial.prototype.isShaderMaterial = true; + } -ShaderMaterial.prototype.copy = function ( source ) { + if ( source.morphTargetDictionary !== undefined ) { - Material.prototype.copy.call( this, source ); + this.morphTargetDictionary = Object.assign( {}, source.morphTargetDictionary ); - this.fragmentShader = source.fragmentShader; - this.vertexShader = source.vertexShader; + } - this.uniforms = UniformsUtils.clone( source.uniforms ); + return this; - this.defines = source.defines; + }, - this.wireframe = source.wireframe; - this.wireframeLinewidth = source.wireframeLinewidth; + updateMorphTargets: function () { - this.lights = source.lights; - this.clipping = source.clipping; + var geometry = this.geometry; + var m, ml, name; - this.skinning = source.skinning; + if ( geometry.isBufferGeometry ) { - this.morphTargets = source.morphTargets; - this.morphNormals = source.morphNormals; + var morphAttributes = geometry.morphAttributes; + var keys = Object.keys( morphAttributes ); - this.extensions = source.extensions; + if ( keys.length > 0 ) { - return this; + var morphAttribute = morphAttributes[ keys[ 0 ] ]; -}; + if ( morphAttribute !== undefined ) { -ShaderMaterial.prototype.toJSON = function ( meta ) { + this.morphTargetInfluences = []; + this.morphTargetDictionary = {}; - var data = Material.prototype.toJSON.call( this, meta ); + for ( m = 0, ml = morphAttribute.length; m < ml; m ++ ) { - data.uniforms = this.uniforms; - data.vertexShader = this.vertexShader; - data.fragmentShader = this.fragmentShader; + name = morphAttribute[ m ].name || String( m ); - return data; + this.morphTargetInfluences.push( 0 ); + this.morphTargetDictionary[ name ] = m; -}; + } -/** - * @author bhouston / http://clara.io - */ + } -function Ray( origin, direction ) { + } - this.origin = ( origin !== undefined ) ? origin : new Vector3(); - this.direction = ( direction !== undefined ) ? direction : new Vector3(); + } else { -} + var morphTargets = geometry.morphTargets; -Object.assign( Ray.prototype, { + if ( morphTargets !== undefined && morphTargets.length > 0 ) { - set: function ( origin, direction ) { + console.error( 'THREE.Mesh.updateMorphTargets() no longer supports THREE.Geometry. Use THREE.BufferGeometry instead.' ); - this.origin.copy( origin ); - this.direction.copy( direction ); + } - return this; + } }, - clone: function () { + raycast: ( function () { - return new this.constructor().copy( this ); + var inverseMatrix = new Matrix4(); + var ray = new Ray(); + var sphere = new Sphere(); - }, + var vA = new Vector3(); + var vB = new Vector3(); + var vC = new Vector3(); - copy: function ( ray ) { + var tempA = new Vector3(); + var tempB = new Vector3(); + var tempC = new Vector3(); - this.origin.copy( ray.origin ); - this.direction.copy( ray.direction ); + var uvA = new Vector2(); + var uvB = new Vector2(); + var uvC = new Vector2(); - return this; + var intersectionPoint = new Vector3(); + var intersectionPointWorld = new Vector3(); - }, + function checkIntersection( object, material, raycaster, ray, pA, pB, pC, point ) { - at: function ( t, optionalTarget ) { + var intersect; - var result = optionalTarget || new Vector3(); + if ( material.side === BackSide ) { - return result.copy( this.direction ).multiplyScalar( t ).add( this.origin ); + intersect = ray.intersectTriangle( pC, pB, pA, true, point ); - }, + } else { - lookAt: function ( v ) { + intersect = ray.intersectTriangle( pA, pB, pC, material.side !== DoubleSide, point ); - this.direction.copy( v ).sub( this.origin ).normalize(); + } - return this; + if ( intersect === null ) return null; - }, + intersectionPointWorld.copy( point ); + intersectionPointWorld.applyMatrix4( object.matrixWorld ); - recast: function () { + var distance = raycaster.ray.origin.distanceTo( intersectionPointWorld ); - var v1 = new Vector3(); + if ( distance < raycaster.near || distance > raycaster.far ) return null; - return function recast( t ) { + return { + distance: distance, + point: intersectionPointWorld.clone(), + object: object + }; - this.origin.copy( this.at( t, v1 ) ); + } - return this; + function checkBufferGeometryIntersection( object, material, raycaster, ray, position, uv, a, b, c ) { - }; + vA.fromBufferAttribute( position, a ); + vB.fromBufferAttribute( position, b ); + vC.fromBufferAttribute( position, c ); - }(), + var intersection = checkIntersection( object, material, raycaster, ray, vA, vB, vC, intersectionPoint ); - closestPointToPoint: function ( point, optionalTarget ) { + if ( intersection ) { - var result = optionalTarget || new Vector3(); - result.subVectors( point, this.origin ); - var directionDistance = result.dot( this.direction ); + if ( uv ) { - if ( directionDistance < 0 ) { + uvA.fromBufferAttribute( uv, a ); + uvB.fromBufferAttribute( uv, b ); + uvC.fromBufferAttribute( uv, c ); - return result.copy( this.origin ); + intersection.uv = Triangle.getUV( intersectionPoint, vA, vB, vC, uvA, uvB, uvC, new Vector2() ); - } + } - return result.copy( this.direction ).multiplyScalar( directionDistance ).add( this.origin ); + var face = new Face3( a, b, c ); + Triangle.getNormal( vA, vB, vC, face.normal ); - }, + intersection.face = face; - distanceToPoint: function ( point ) { + } - return Math.sqrt( this.distanceSqToPoint( point ) ); + return intersection; - }, + } - distanceSqToPoint: function () { + return function raycast( raycaster, intersects ) { - var v1 = new Vector3(); + var geometry = this.geometry; + var material = this.material; + var matrixWorld = this.matrixWorld; - return function distanceSqToPoint( point ) { + if ( material === undefined ) return; - var directionDistance = v1.subVectors( point, this.origin ).dot( this.direction ); + // Checking boundingSphere distance to ray - // point behind the ray + if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere(); - if ( directionDistance < 0 ) { + sphere.copy( geometry.boundingSphere ); + sphere.applyMatrix4( matrixWorld ); - return this.origin.distanceToSquared( point ); + if ( raycaster.ray.intersectsSphere( sphere ) === false ) return; - } + // - v1.copy( this.direction ).multiplyScalar( directionDistance ).add( this.origin ); + inverseMatrix.getInverse( matrixWorld ); + ray.copy( raycaster.ray ).applyMatrix4( inverseMatrix ); - return v1.distanceToSquared( point ); + // Check boundingBox before continuing - }; + if ( geometry.boundingBox !== null ) { - }(), + if ( ray.intersectsBox( geometry.boundingBox ) === false ) return; - distanceSqToSegment: function () { + } - var segCenter = new Vector3(); - var segDir = new Vector3(); - var diff = new Vector3(); + var intersection; - return function distanceSqToSegment( v0, v1, optionalPointOnRay, optionalPointOnSegment ) { + if ( geometry.isBufferGeometry ) { - // 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 + 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; - segCenter.copy( v0 ).add( v1 ).multiplyScalar( 0.5 ); - segDir.copy( v1 ).sub( v0 ).normalize(); - diff.copy( this.origin ).sub( segCenter ); + if ( index !== null ) { - 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; + // indexed buffer geometry - if ( det > 0 ) { + if ( Array.isArray( material ) ) { - // The ray and segment are not parallel. + for ( i = 0, il = groups.length; i < il; i ++ ) { - s0 = a01 * b1 - b0; - s1 = a01 * b0 - b1; - extDet = segExtent * det; + group = groups[ i ]; + groupMaterial = material[ group.materialIndex ]; - if ( s0 >= 0 ) { + start = Math.max( group.start, drawRange.start ); + end = Math.min( ( group.start + group.count ), ( drawRange.start + drawRange.count ) ); - if ( s1 >= - extDet ) { + for ( j = start, jl = end; j < jl; j += 3 ) { - if ( s1 <= extDet ) { + a = index.getX( j ); + b = index.getX( j + 1 ); + c = index.getX( j + 2 ); - // region 0 - // Minimum at interior points of ray and segment. + intersection = checkBufferGeometryIntersection( this, groupMaterial, raycaster, ray, position, uv, a, b, c ); - var invDet = 1 / det; - s0 *= invDet; - s1 *= invDet; - sqrDist = s0 * ( s0 + a01 * s1 + 2 * b0 ) + s1 * ( a01 * s0 + s1 + 2 * b1 ) + c; + if ( intersection ) { - } else { + intersection.faceIndex = Math.floor( j / 3 ); // triangle number in indexed buffer semantics + intersects.push( intersection ); - // region 1 + } - s1 = segExtent; - s0 = Math.max( 0, - ( a01 * s1 + b0 ) ); - sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; + } } } else { - // region 5 + start = Math.max( 0, drawRange.start ); + end = Math.min( index.count, ( drawRange.start + drawRange.count ) ); - s1 = - segExtent; - s0 = Math.max( 0, - ( a01 * s1 + b0 ) ); - sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; + for ( i = start, il = end; i < il; i += 3 ) { - } + a = index.getX( i ); + b = index.getX( i + 1 ); + c = index.getX( i + 2 ); - } else { + intersection = checkBufferGeometryIntersection( this, material, raycaster, ray, position, uv, a, b, c ); - if ( s1 <= - extDet ) { + if ( intersection ) { - // region 4 + intersection.faceIndex = Math.floor( i / 3 ); // triangle number in indexed buffer semantics + intersects.push( intersection ); - s0 = Math.max( 0, - ( - a01 * segExtent + b0 ) ); - s1 = ( s0 > 0 ) ? - segExtent : Math.min( Math.max( - segExtent, - b1 ), segExtent ); - sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; + } - } else if ( s1 <= extDet ) { + } - // region 3 + } - s0 = 0; - s1 = Math.min( Math.max( - segExtent, - b1 ), segExtent ); - sqrDist = s1 * ( s1 + 2 * b1 ) + c; + } else if ( position !== undefined ) { - } else { + // non-indexed buffer geometry - // region 2 + if ( Array.isArray( material ) ) { - 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; + for ( i = 0, il = groups.length; i < il; i ++ ) { - } + group = groups[ i ]; + groupMaterial = material[ group.materialIndex ]; - } + start = Math.max( group.start, drawRange.start ); + end = Math.min( ( group.start + group.count ), ( drawRange.start + drawRange.count ) ); - } else { + for ( j = start, jl = end; j < jl; j += 3 ) { - // Ray and segment are parallel. + a = j; + b = j + 1; + c = j + 2; - s1 = ( a01 > 0 ) ? - segExtent : segExtent; - s0 = Math.max( 0, - ( a01 * s1 + b0 ) ); - sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; + intersection = checkBufferGeometryIntersection( this, groupMaterial, raycaster, ray, position, uv, a, b, c ); - } + if ( intersection ) { - if ( optionalPointOnRay ) { + intersection.faceIndex = Math.floor( j / 3 ); // triangle number in non-indexed buffer semantics + intersects.push( intersection ); - optionalPointOnRay.copy( this.direction ).multiplyScalar( s0 ).add( this.origin ); + } - } + } - if ( optionalPointOnSegment ) { + } - optionalPointOnSegment.copy( segDir ).multiplyScalar( s1 ).add( segCenter ); + } else { - } + start = Math.max( 0, drawRange.start ); + end = Math.min( position.count, ( drawRange.start + drawRange.count ) ); - return sqrDist; + for ( i = start, il = end; i < il; i += 3 ) { - }; + a = i; + b = i + 1; + c = i + 2; - }(), + intersection = checkBufferGeometryIntersection( this, material, raycaster, ray, position, uv, a, b, c ); - intersectSphere: function () { + if ( intersection ) { - var v1 = new Vector3(); + intersection.faceIndex = Math.floor( i / 3 ); // triangle number in non-indexed buffer semantics + intersects.push( intersection ); - return function intersectSphere( sphere, optionalTarget ) { + } - 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 ( d2 > radius2 ) return null; + } - var thc = Math.sqrt( radius2 - d2 ); + } - // t0 = first intersect point - entrance on front of sphere - var t0 = tca - thc; + } else if ( geometry.isGeometry ) { - // t1 = second intersect point - exit point on back of sphere - var t1 = tca + thc; + var fvA, fvB, fvC; + var isMultiMaterial = Array.isArray( material ); - // test to see if both t0 and t1 are behind the ray - if so, return null - if ( t0 < 0 && t1 < 0 ) return null; + var vertices = geometry.vertices; + var faces = geometry.faces; + var uvs; - // 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, optionalTarget ); + var faceVertexUvs = geometry.faceVertexUvs[ 0 ]; + if ( faceVertexUvs.length > 0 ) uvs = faceVertexUvs; - // else t0 is in front of the ray, so return the first collision point scaled by t0 - return this.at( t0, optionalTarget ); + 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; - intersectsSphere: function ( sphere ) { + fvA = vertices[ face.a ]; + fvB = vertices[ face.b ]; + fvC = vertices[ face.c ]; - return this.distanceToPoint( sphere.center ) <= sphere.radius; + if ( faceMaterial.morphTargets === true ) { - }, + var morphTargets = geometry.morphTargets; + var morphInfluences = this.morphTargetInfluences; - distanceToPlane: function ( plane ) { + vA.set( 0, 0, 0 ); + vB.set( 0, 0, 0 ); + vC.set( 0, 0, 0 ); - var denominator = plane.normal.dot( this.direction ); + for ( var t = 0, tl = morphTargets.length; t < tl; t ++ ) { - if ( denominator === 0 ) { + var influence = morphInfluences[ t ]; - // line is coplanar, return origin - if ( plane.distanceToPoint( this.origin ) === 0 ) { + if ( influence === 0 ) continue; - return 0; + var targets = morphTargets[ t ].vertices; - } + 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 ); - // Null is preferable to undefined since undefined means.... it is undefined + } - return null; + vA.add( fvA ); + vB.add( fvB ); + vC.add( fvC ); - } + fvA = vA; + fvB = vB; + fvC = vC; - var t = - ( this.origin.dot( plane.normal ) + plane.constant ) / denominator; + } - // Return if the ray never intersects the plane + intersection = checkIntersection( this, faceMaterial, raycaster, ray, fvA, fvB, fvC, intersectionPoint ); - return t >= 0 ? t : null; + if ( intersection ) { - }, + if ( uvs && uvs[ f ] ) { - intersectPlane: function ( plane, optionalTarget ) { + var uvs_f = uvs[ f ]; + uvA.copy( uvs_f[ 0 ] ); + uvB.copy( uvs_f[ 1 ] ); + uvC.copy( uvs_f[ 2 ] ); - var t = this.distanceToPlane( plane ); + intersection.uv = Triangle.getUV( intersectionPoint, fvA, fvB, fvC, uvA, uvB, uvC, new Vector2() ); - if ( t === null ) { + } - return null; + intersection.face = face; + intersection.faceIndex = f; + intersects.push( intersection ); - } + } - return this.at( t, optionalTarget ); + } - }, + } - intersectsPlane: function ( plane ) { + }; - // check if the ray lies on the plane first + }() ), - var distToPoint = plane.distanceToPoint( this.origin ); + clone: function () { - if ( distToPoint === 0 ) { + return new this.constructor( this.geometry, this.material ).copy( this ); - return true; + } - } +} ); - var denominator = plane.normal.dot( this.direction ); +/** + * @author mrdoob / http://mrdoob.com/ + */ - if ( denominator * distToPoint < 0 ) { +function WebGLBackground( renderer, state, objects, premultipliedAlpha ) { - return true; + var clearColor = new Color( 0x000000 ); + var clearAlpha = 0; - } + var planeMesh; + var boxMesh; + // Store the current background texture and its `version` + // so we can recompile the material accordingly. + var currentBackground = null; + var currentBackgroundVersion = 0; - // ray origin is behind the plane (and is pointing behind it) + function render( renderList, scene, camera, forceClear ) { - return false; + var background = scene.background; - }, + if ( background === null ) { - intersectBox: function ( box, optionalTarget ) { + setClear( clearColor, clearAlpha ); + currentBackground = null; + currentBackgroundVersion = 0; - var tmin, tmax, tymin, tymax, tzmin, tzmax; + } else if ( background && background.isColor ) { - var invdirx = 1 / this.direction.x, - invdiry = 1 / this.direction.y, - invdirz = 1 / this.direction.z; + setClear( background, 1 ); + forceClear = true; + currentBackground = null; + currentBackgroundVersion = 0; - var origin = this.origin; + } - if ( invdirx >= 0 ) { + if ( renderer.autoClear || forceClear ) { - tmin = ( box.min.x - origin.x ) * invdirx; - tmax = ( box.max.x - origin.x ) * invdirx; + renderer.clear( renderer.autoClearColor, renderer.autoClearDepth, renderer.autoClearStencil ); - } else { + } - tmin = ( box.max.x - origin.x ) * invdirx; - tmax = ( box.min.x - origin.x ) * invdirx; + if ( background && ( background.isCubeTexture || background.isWebGLRenderTargetCube ) ) { - } + if ( boxMesh === undefined ) { - if ( invdiry >= 0 ) { + boxMesh = new Mesh( + new BoxBufferGeometry( 1, 1, 1 ), + new ShaderMaterial( { + type: 'BackgroundCubeMaterial', + uniforms: cloneUniforms( ShaderLib.cube.uniforms ), + vertexShader: ShaderLib.cube.vertexShader, + fragmentShader: ShaderLib.cube.fragmentShader, + side: BackSide, + depthTest: true, + depthWrite: false, + fog: false + } ) + ); - tymin = ( box.min.y - origin.y ) * invdiry; - tymax = ( box.max.y - origin.y ) * invdiry; + boxMesh.geometry.removeAttribute( 'normal' ); + boxMesh.geometry.removeAttribute( 'uv' ); - } else { + boxMesh.onBeforeRender = function ( renderer, scene, camera ) { - tymin = ( box.max.y - origin.y ) * invdiry; - tymax = ( box.min.y - origin.y ) * invdiry; + this.matrixWorld.copyPosition( camera.matrixWorld ); - } + }; - if ( ( tmin > tymax ) || ( tymin > tmax ) ) return null; + // enable code injection for non-built-in material + Object.defineProperty( boxMesh.material, 'map', { - // These lines also handle the case where tmin or tmax is NaN - // (result of 0 * Infinity). x !== x returns true if x is NaN + get: function () { - if ( tymin > tmin || tmin !== tmin ) tmin = tymin; + return this.uniforms.tCube.value; - if ( tymax < tmax || tmax !== tmax ) tmax = tymax; + } - if ( invdirz >= 0 ) { + } ); - tzmin = ( box.min.z - origin.z ) * invdirz; - tzmax = ( box.max.z - origin.z ) * invdirz; + objects.update( boxMesh ); - } else { + } - tzmin = ( box.max.z - origin.z ) * invdirz; - tzmax = ( box.min.z - origin.z ) * invdirz; + var texture = background.isWebGLRenderTargetCube ? background.texture : background; + boxMesh.material.uniforms.tCube.value = texture; + boxMesh.material.uniforms.tFlip.value = ( background.isWebGLRenderTargetCube ) ? 1 : - 1; - } + if ( currentBackground !== background || + currentBackgroundVersion !== texture.version ) { - if ( ( tmin > tzmax ) || ( tzmin > tmax ) ) return null; + boxMesh.material.needsUpdate = true; - if ( tzmin > tmin || tmin !== tmin ) tmin = tzmin; + currentBackground = background; + currentBackgroundVersion = texture.version; - if ( tzmax < tmax || tmax !== tmax ) tmax = tzmax; + } - //return point closest to the ray (positive side) + // push to the pre-sorted opaque render list + renderList.unshift( boxMesh, boxMesh.geometry, boxMesh.material, 0, null ); - if ( tmax < 0 ) return null; - - return this.at( tmin >= 0 ? tmin : tmax, optionalTarget ); - - }, + } else if ( background && background.isTexture ) { - intersectsBox: ( function () { + if ( planeMesh === undefined ) { - var v = new Vector3(); + planeMesh = new Mesh( + new PlaneBufferGeometry( 2, 2 ), + new ShaderMaterial( { + type: 'BackgroundMaterial', + uniforms: cloneUniforms( ShaderLib.background.uniforms ), + vertexShader: ShaderLib.background.vertexShader, + fragmentShader: ShaderLib.background.fragmentShader, + side: FrontSide, + depthTest: false, + depthWrite: false, + fog: false + } ) + ); - return function intersectsBox( box ) { + planeMesh.geometry.removeAttribute( 'normal' ); - return this.intersectBox( box, v ) !== null; + // enable code injection for non-built-in material + Object.defineProperty( planeMesh.material, 'map', { - }; + get: function () { - } )(), + return this.uniforms.t2D.value; - intersectTriangle: function () { + } - // Compute the offset origin, edges, and normal. - var diff = new Vector3(); - var edge1 = new Vector3(); - var edge2 = new Vector3(); - var normal = new Vector3(); + } ); - return function intersectTriangle( a, b, c, backfaceCulling, optionalTarget ) { + objects.update( planeMesh ); - // from http://www.geometrictools.com/GTEngine/Include/Mathematics/GteIntrRay3Triangle3.h + } - edge1.subVectors( b, a ); - edge2.subVectors( c, a ); - normal.crossVectors( edge1, edge2 ); + planeMesh.material.uniforms.t2D.value = background; - // 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 ( background.matrixAutoUpdate === true ) { - if ( DdN > 0 ) { + background.updateMatrix(); - if ( backfaceCulling ) return null; - sign = 1; + } - } else if ( DdN < 0 ) { + planeMesh.material.uniforms.uvTransform.value.copy( background.matrix ); - sign = - 1; - DdN = - DdN; + if ( currentBackground !== background || + currentBackgroundVersion !== background.version ) { - } else { + planeMesh.material.needsUpdate = true; - return null; + currentBackground = background; + currentBackgroundVersion = background.version; } - diff.subVectors( this.origin, a ); - var DdQxE2 = sign * this.direction.dot( edge2.crossVectors( diff, edge2 ) ); - // b1 < 0, no intersection - if ( DdQxE2 < 0 ) { + // push to the pre-sorted opaque render list + renderList.unshift( planeMesh, planeMesh.geometry, planeMesh.material, 0, null ); - return null; + } - } + } - var DdE1xQ = sign * this.direction.dot( edge1.cross( diff ) ); + function setClear( color, alpha ) { - // b2 < 0, no intersection - if ( DdE1xQ < 0 ) { + state.buffers.color.setClear( color.r, color.g, color.b, alpha, premultipliedAlpha ); - return null; + } - } + return { - // b1+b2 > 1, no intersection - if ( DdQxE2 + DdE1xQ > DdN ) { + getClearColor: function () { - return null; + return clearColor; - } + }, + setClearColor: function ( color, alpha ) { - // Line intersects triangle, check if ray does. - var QdN = - sign * diff.dot( normal ); + clearColor.set( color ); + clearAlpha = alpha !== undefined ? alpha : 1; + setClear( clearColor, clearAlpha ); - // t < 0, no intersection - if ( QdN < 0 ) { + }, + getClearAlpha: function () { - return null; + return clearAlpha; - } + }, + setClearAlpha: function ( alpha ) { - // Ray intersects triangle. - return this.at( QdN / DdN, optionalTarget ); + clearAlpha = alpha; + setClear( clearColor, clearAlpha ); - }; + }, + render: render - }(), + }; - applyMatrix4: function ( matrix4 ) { +} - this.origin.applyMatrix4( matrix4 ); - this.direction.transformDirection( matrix4 ); +/** + * @author mrdoob / http://mrdoob.com/ + */ - return this; +function WebGLBufferRenderer( gl, extensions, info, capabilities ) { - }, + var mode; - equals: function ( ray ) { + function setMode( value ) { - return ray.origin.equals( this.origin ) && ray.direction.equals( this.direction ); + mode = value; } -} ); - -/** - * @author bhouston / http://clara.io - */ - -function Line3( start, end ) { - - this.start = ( start !== undefined ) ? start : new Vector3(); - this.end = ( end !== undefined ) ? end : new Vector3(); - -} + function render( start, count ) { -Object.assign( Line3.prototype, { + gl.drawArrays( mode, start, count ); - set: function ( start, end ) { + info.update( count, mode ); - this.start.copy( start ); - this.end.copy( end ); + } - return this; + function renderInstances( geometry, start, count ) { - }, + var extension; - clone: function () { + if ( capabilities.isWebGL2 ) { - return new this.constructor().copy( this ); + extension = gl; - }, + } else { - copy: function ( line ) { + extension = extensions.get( 'ANGLE_instanced_arrays' ); - this.start.copy( line.start ); - this.end.copy( line.end ); + if ( extension === null ) { - return this; + console.error( 'THREE.WebGLBufferRenderer: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.' ); + return; - }, + } - getCenter: function ( optionalTarget ) { + } - var result = optionalTarget || new Vector3(); - return result.addVectors( this.start, this.end ).multiplyScalar( 0.5 ); + extension[ capabilities.isWebGL2 ? 'drawArraysInstanced' : 'drawArraysInstancedANGLE' ]( mode, start, count, geometry.maxInstancedCount ); - }, + info.update( count, mode, geometry.maxInstancedCount ); - delta: function ( optionalTarget ) { + } - var result = optionalTarget || new Vector3(); - return result.subVectors( this.end, this.start ); + // - }, + this.setMode = setMode; + this.render = render; + this.renderInstances = renderInstances; - distanceSq: function () { +} - return this.start.distanceToSquared( this.end ); +/** + * @author mrdoob / http://mrdoob.com/ + */ - }, +function WebGLCapabilities( gl, extensions, parameters ) { - distance: function () { + var maxAnisotropy; - return this.start.distanceTo( this.end ); + function getMaxAnisotropy() { - }, + if ( maxAnisotropy !== undefined ) return maxAnisotropy; - at: function ( t, optionalTarget ) { + var extension = extensions.get( 'EXT_texture_filter_anisotropic' ); - var result = optionalTarget || new Vector3(); + if ( extension !== null ) { - return this.delta( result ).multiplyScalar( t ).add( this.start ); + maxAnisotropy = gl.getParameter( extension.MAX_TEXTURE_MAX_ANISOTROPY_EXT ); - }, + } else { - closestPointToPointParameter: function () { + maxAnisotropy = 0; - var startP = new Vector3(); - var startEnd = new Vector3(); + } - return function closestPointToPointParameter( point, clampToLine ) { + return maxAnisotropy; - startP.subVectors( point, this.start ); - startEnd.subVectors( this.end, this.start ); + } - var startEnd2 = startEnd.dot( startEnd ); - var startEnd_startP = startEnd.dot( startP ); + function getMaxPrecision( precision ) { - var t = startEnd_startP / startEnd2; + if ( precision === 'highp' ) { - if ( clampToLine ) { + if ( gl.getShaderPrecisionFormat( 35633, 36338 ).precision > 0 && + gl.getShaderPrecisionFormat( 35632, 36338 ).precision > 0 ) { - t = _Math.clamp( t, 0, 1 ); + return 'highp'; } - return t; - - }; + precision = 'mediump'; - }(), + } - closestPointToPoint: function ( point, clampToLine, optionalTarget ) { + if ( precision === 'mediump' ) { - var t = this.closestPointToPointParameter( point, clampToLine ); + if ( gl.getShaderPrecisionFormat( 35633, 36337 ).precision > 0 && + gl.getShaderPrecisionFormat( 35632, 36337 ).precision > 0 ) { - var result = optionalTarget || new Vector3(); + return 'mediump'; - return this.delta( result ).multiplyScalar( t ).add( this.start ); + } - }, + } - applyMatrix4: function ( matrix ) { + return 'lowp'; - this.start.applyMatrix4( matrix ); - this.end.applyMatrix4( matrix ); + } - return this; + var isWebGL2 = typeof WebGL2RenderingContext !== 'undefined' && gl instanceof WebGL2RenderingContext; - }, + var precision = parameters.precision !== undefined ? parameters.precision : 'highp'; + var maxPrecision = getMaxPrecision( precision ); - equals: function ( line ) { + if ( maxPrecision !== precision ) { - return line.start.equals( this.start ) && line.end.equals( this.end ); + console.warn( 'THREE.WebGLRenderer:', precision, 'not supported, using', maxPrecision, 'instead.' ); + precision = maxPrecision; } -} ); - -/** - * @author bhouston / http://clara.io - * @author mrdoob / http://mrdoob.com/ - */ - -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(); - -} + var logarithmicDepthBuffer = parameters.logarithmicDepthBuffer === true; -Object.assign( Triangle, { + var maxTextures = gl.getParameter( 34930 ); + var maxVertexTextures = gl.getParameter( 35660 ); + var maxTextureSize = gl.getParameter( 3379 ); + var maxCubemapSize = gl.getParameter( 34076 ); - normal: function () { + var maxAttributes = gl.getParameter( 34921 ); + var maxVertexUniforms = gl.getParameter( 36347 ); + var maxVaryings = gl.getParameter( 36348 ); + var maxFragmentUniforms = gl.getParameter( 36349 ); - var v0 = new Vector3(); + var vertexTextures = maxVertexTextures > 0; + var floatFragmentTextures = isWebGL2 || !! extensions.get( 'OES_texture_float' ); + var floatVertexTextures = vertexTextures && floatFragmentTextures; - return function normal( a, b, c, optionalTarget ) { + return { - var result = optionalTarget || new Vector3(); + isWebGL2: isWebGL2, - result.subVectors( c, b ); - v0.subVectors( a, b ); - result.cross( v0 ); + getMaxAnisotropy: getMaxAnisotropy, + getMaxPrecision: getMaxPrecision, - var resultLengthSq = result.lengthSq(); - if ( resultLengthSq > 0 ) { + precision: precision, + logarithmicDepthBuffer: logarithmicDepthBuffer, - return result.multiplyScalar( 1 / Math.sqrt( resultLengthSq ) ); + maxTextures: maxTextures, + maxVertexTextures: maxVertexTextures, + maxTextureSize: maxTextureSize, + maxCubemapSize: maxCubemapSize, - } + maxAttributes: maxAttributes, + maxVertexUniforms: maxVertexUniforms, + maxVaryings: maxVaryings, + maxFragmentUniforms: maxFragmentUniforms, - return result.set( 0, 0, 0 ); + vertexTextures: vertexTextures, + floatFragmentTextures: floatFragmentTextures, + floatVertexTextures: floatVertexTextures - }; + }; - }(), +} - // static/instance method to calculate barycentric coordinates - // based on: http://www.blackpawn.com/texts/pointinpoly/default.html - barycoordFromPoint: function () { +/** + * @author tschw + */ - var v0 = new Vector3(); - var v1 = new Vector3(); - var v2 = new Vector3(); +function WebGLClipping() { - return function barycoordFromPoint( point, a, b, c, optionalTarget ) { + var scope = this, - v0.subVectors( c, a ); - v1.subVectors( b, a ); - v2.subVectors( point, a ); + globalState = null, + numGlobalPlanes = 0, + localClippingEnabled = false, + renderingShadows = false, - 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 ); + plane = new Plane(), + viewNormalMatrix = new Matrix3(), - var denom = ( dot00 * dot11 - dot01 * dot01 ); + uniform = { value: null, needsUpdate: false }; - var result = optionalTarget || new Vector3(); + this.uniform = uniform; + this.numPlanes = 0; + this.numIntersection = 0; - // collinear or singular triangle - if ( denom === 0 ) { + this.init = function ( planes, enableLocalClipping, camera ) { - // arbitrary location outside of triangle? - // not sure if this is the best idea, maybe should be returning undefined - return result.set( - 2, - 1, - 1 ); + var enabled = + planes.length !== 0 || + enableLocalClipping || + // enable state of previous frame - the clipping code has to + // run another frame in order to reset the state: + numGlobalPlanes !== 0 || + localClippingEnabled; - } + localClippingEnabled = enableLocalClipping; - var invDenom = 1 / denom; - var u = ( dot11 * dot02 - dot01 * dot12 ) * invDenom; - var v = ( dot00 * dot12 - dot01 * dot02 ) * invDenom; + globalState = projectPlanes( planes, camera, 0 ); + numGlobalPlanes = planes.length; - // barycentric coordinates must always sum to 1 - return result.set( 1 - u - v, v, u ); + return enabled; - }; + }; - }(), + this.beginShadows = function () { - containsPoint: function () { + renderingShadows = true; + projectPlanes( null ); - var v1 = new Vector3(); + }; - return function containsPoint( point, a, b, c ) { + this.endShadows = function () { - var result = Triangle.barycoordFromPoint( point, a, b, c, v1 ); + renderingShadows = false; + resetGlobalState(); - return ( result.x >= 0 ) && ( result.y >= 0 ) && ( ( result.x + result.y ) <= 1 ); + }; - }; + this.setState = function ( planes, clipIntersection, clipShadows, camera, cache, fromCache ) { - }() + if ( ! localClippingEnabled || planes === null || planes.length === 0 || renderingShadows && ! clipShadows ) { -} ); + // there's no local clipping -Object.assign( Triangle.prototype, { + if ( renderingShadows ) { - set: function ( a, b, c ) { + // there's no global clipping - this.a.copy( a ); - this.b.copy( b ); - this.c.copy( c ); + projectPlanes( null ); - return this; + } else { - }, + resetGlobalState(); - setFromPointsAndIndices: function ( points, i0, i1, i2 ) { + } - this.a.copy( points[ i0 ] ); - this.b.copy( points[ i1 ] ); - this.c.copy( points[ i2 ] ); + } else { - return this; + var nGlobal = renderingShadows ? 0 : numGlobalPlanes, + lGlobal = nGlobal * 4, - }, + dstArray = cache.clippingState || null; - clone: function () { + uniform.value = dstArray; // ensure unique state - return new this.constructor().copy( this ); + dstArray = projectPlanes( planes, camera, lGlobal, fromCache ); - }, + for ( var i = 0; i !== lGlobal; ++ i ) { - copy: function ( triangle ) { + dstArray[ i ] = globalState[ i ]; - this.a.copy( triangle.a ); - this.b.copy( triangle.b ); - this.c.copy( triangle.c ); + } - return this; + cache.clippingState = dstArray; + this.numIntersection = clipIntersection ? this.numPlanes : 0; + this.numPlanes += nGlobal; - }, + } - area: function () { - var v0 = new Vector3(); - var v1 = new Vector3(); + }; - return function area() { + function resetGlobalState() { - v0.subVectors( this.c, this.b ); - v1.subVectors( this.a, this.b ); + if ( uniform.value !== globalState ) { - return v0.cross( v1 ).length() * 0.5; + uniform.value = globalState; + uniform.needsUpdate = numGlobalPlanes > 0; - }; + } - }(), + scope.numPlanes = numGlobalPlanes; + scope.numIntersection = 0; - midpoint: function ( optionalTarget ) { + } - var result = optionalTarget || new Vector3(); - return result.addVectors( this.a, this.b ).add( this.c ).multiplyScalar( 1 / 3 ); + function projectPlanes( planes, camera, dstOffset, skipTransform ) { - }, + var nPlanes = planes !== null ? planes.length : 0, + dstArray = null; - normal: function ( optionalTarget ) { + if ( nPlanes !== 0 ) { - return Triangle.normal( this.a, this.b, this.c, optionalTarget ); + dstArray = uniform.value; - }, + if ( skipTransform !== true || dstArray === null ) { - plane: function ( optionalTarget ) { + var flatSize = dstOffset + nPlanes * 4, + viewMatrix = camera.matrixWorldInverse; - var result = optionalTarget || new Plane(); + viewNormalMatrix.getNormalMatrix( viewMatrix ); - return result.setFromCoplanarPoints( this.a, this.b, this.c ); + if ( dstArray === null || dstArray.length < flatSize ) { - }, + dstArray = new Float32Array( flatSize ); - barycoordFromPoint: function ( point, optionalTarget ) { + } - return Triangle.barycoordFromPoint( point, this.a, this.b, this.c, optionalTarget ); + for ( var i = 0, i4 = dstOffset; i !== nPlanes; ++ i, i4 += 4 ) { - }, + plane.copy( planes[ i ] ).applyMatrix4( viewMatrix, viewNormalMatrix ); - containsPoint: function ( point ) { + plane.normal.toArray( dstArray, i4 ); + dstArray[ i4 + 3 ] = plane.constant; - return Triangle.containsPoint( point, this.a, this.b, this.c ); + } - }, + } - intersectsBox: function ( box ) { + uniform.value = dstArray; + uniform.needsUpdate = true; - return box.intersectsTriangle( this ); + } - }, + scope.numPlanes = nPlanes; - closestPointToPoint: function () { + return dstArray; - var plane = new Plane(); - var edgeList = [ new Line3(), new Line3(), new Line3() ]; - var projectedPoint = new Vector3(); - var closestPoint = new Vector3(); + } - return function closestPointToPoint( point, optionalTarget ) { +} - var result = optionalTarget || new Vector3(); - var minDistance = Infinity; +/** + * @author mrdoob / http://mrdoob.com/ + */ - // project the point onto the plane of the triangle +function WebGLExtensions( gl ) { - plane.setFromCoplanarPoints( this.a, this.b, this.c ); - plane.projectPoint( point, projectedPoint ); + var extensions = {}; - // check if the projection lies within the triangle + return { - if ( this.containsPoint( projectedPoint ) === true ) { + get: function ( name ) { - // if so, this is the closest point + if ( extensions[ name ] !== undefined ) { - result.copy( projectedPoint ); + return extensions[ name ]; - } else { + } - // if not, the point falls outside the triangle. the result is the closest point to the triangle's edges or vertices + var extension; - edgeList[ 0 ].set( this.a, this.b ); - edgeList[ 1 ].set( this.b, this.c ); - edgeList[ 2 ].set( this.c, this.a ); + switch ( name ) { - for ( var i = 0; i < edgeList.length; i ++ ) { + case 'WEBGL_depth_texture': + extension = gl.getExtension( 'WEBGL_depth_texture' ) || gl.getExtension( 'MOZ_WEBGL_depth_texture' ) || gl.getExtension( 'WEBKIT_WEBGL_depth_texture' ); + break; - edgeList[ i ].closestPointToPoint( projectedPoint, true, closestPoint ); + 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; - var distance = projectedPoint.distanceToSquared( closestPoint ); + 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; - if ( distance < minDistance ) { + case 'WEBGL_compressed_texture_pvrtc': + extension = gl.getExtension( 'WEBGL_compressed_texture_pvrtc' ) || gl.getExtension( 'WEBKIT_WEBGL_compressed_texture_pvrtc' ); + break; - minDistance = distance; + default: + extension = gl.getExtension( name ); - result.copy( closestPoint ); + } - } + if ( extension === null ) { - } + console.warn( 'THREE.WebGLRenderer: ' + name + ' extension not supported.' ); } - return result; - - }; - - }(), + extensions[ name ] = extension; - equals: function ( triangle ) { + return extension; - return triangle.a.equals( this.a ) && triangle.b.equals( this.b ) && triangle.c.equals( this.c ); + } - } + }; -} ); +} /** * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - * @author mikael emtinger / http://gomo.se/ - * @author jonobr1 / http://jonobr1.com/ */ -function Mesh( geometry, material ) { +function WebGLGeometries( gl, attributes, info ) { - Object3D.call( this ); + var geometries = {}; + var wireframeAttributes = {}; - this.type = 'Mesh'; + function onGeometryDispose( event ) { - this.geometry = geometry !== undefined ? geometry : new BufferGeometry(); - this.material = material !== undefined ? material : new MeshBasicMaterial( { color: Math.random() * 0xffffff } ); + var geometry = event.target; + var buffergeometry = geometries[ geometry.id ]; - this.drawMode = TrianglesDrawMode; + if ( buffergeometry.index !== null ) { - this.updateMorphTargets(); + attributes.remove( buffergeometry.index ); -} + } -Mesh.prototype = Object.assign( Object.create( Object3D.prototype ), { + for ( var name in buffergeometry.attributes ) { - constructor: Mesh, + attributes.remove( buffergeometry.attributes[ name ] ); - isMesh: true, + } - setDrawMode: function ( value ) { + geometry.removeEventListener( 'dispose', onGeometryDispose ); - this.drawMode = value; + delete geometries[ geometry.id ]; - }, + var attribute = wireframeAttributes[ buffergeometry.id ]; - copy: function ( source ) { + if ( attribute ) { - Object3D.prototype.copy.call( this, source ); + attributes.remove( attribute ); + delete wireframeAttributes[ buffergeometry.id ]; - this.drawMode = source.drawMode; + } - if ( source.morphTargetInfluences !== undefined ) { + // - this.morphTargetInfluences = source.morphTargetInfluences.slice(); + info.memory.geometries --; - } + } - if ( source.morphTargetDictionary !== undefined ) { + function get( object, geometry ) { - this.morphTargetDictionary = Object.assign( {}, source.morphTargetDictionary ); + var buffergeometry = geometries[ geometry.id ]; - } - - return this; - - }, - - updateMorphTargets: function () { + if ( buffergeometry ) return buffergeometry; - var geometry = this.geometry; - var m, ml, name; + geometry.addEventListener( 'dispose', onGeometryDispose ); if ( geometry.isBufferGeometry ) { - var morphAttributes = geometry.morphAttributes; - var keys = Object.keys( morphAttributes ); - - if ( keys.length > 0 ) { - - var morphAttribute = morphAttributes[ keys[ 0 ] ]; - - if ( morphAttribute !== undefined ) { - - this.morphTargetInfluences = []; - this.morphTargetDictionary = {}; - - for ( m = 0, ml = morphAttribute.length; m < ml; m ++ ) { - - name = morphAttribute[ m ].name || String( m ); + buffergeometry = geometry; - this.morphTargetInfluences.push( 0 ); - this.morphTargetDictionary[ name ] = m; + } else if ( geometry.isGeometry ) { - } + if ( geometry._bufferGeometry === undefined ) { - } + geometry._bufferGeometry = new BufferGeometry().setFromObject( object ); } - } else { - - var morphTargets = geometry.morphTargets; - - if ( morphTargets !== undefined && morphTargets.length > 0 ) { - - this.morphTargetInfluences = []; - this.morphTargetDictionary = {}; - - for ( m = 0, ml = morphTargets.length; m < ml; m ++ ) { - - name = morphTargets[ m ].name || String( m ); - - this.morphTargetInfluences.push( 0 ); - this.morphTargetDictionary[ name ] = m; - - } - - } + buffergeometry = geometry._bufferGeometry; } - }, - - raycast: ( function () { - - var inverseMatrix = new Matrix4(); - var ray = new Ray(); - var sphere = new Sphere(); + geometries[ geometry.id ] = buffergeometry; - var vA = new Vector3(); - var vB = new Vector3(); - var vC = new Vector3(); + info.memory.geometries ++; - var tempA = new Vector3(); - var tempB = new Vector3(); - var tempC = new Vector3(); + return buffergeometry; - var uvA = new Vector2(); - var uvB = new Vector2(); - var uvC = new Vector2(); + } - var barycoord = new Vector3(); + function update( geometry ) { - var intersectionPoint = new Vector3(); - var intersectionPointWorld = new Vector3(); + var index = geometry.index; + var geometryAttributes = geometry.attributes; - function uvIntersection( point, p1, p2, p3, uv1, uv2, uv3 ) { + if ( index !== null ) { - Triangle.barycoordFromPoint( point, p1, p2, p3, barycoord ); + attributes.update( index, 34963 ); - uv1.multiplyScalar( barycoord.x ); - uv2.multiplyScalar( barycoord.y ); - uv3.multiplyScalar( barycoord.z ); + } - uv1.add( uv2 ).add( uv3 ); + for ( var name in geometryAttributes ) { - return uv1.clone(); + attributes.update( geometryAttributes[ name ], 34962 ); } - function checkIntersection( object, material, raycaster, ray, pA, pB, pC, point ) { + // morph targets - var intersect; + var morphAttributes = geometry.morphAttributes; - if ( material.side === BackSide ) { + for ( var name in morphAttributes ) { - intersect = ray.intersectTriangle( pC, pB, pA, true, point ); + var array = morphAttributes[ name ]; - } else { + for ( var i = 0, l = array.length; i < l; i ++ ) { - intersect = ray.intersectTriangle( pA, pB, pC, material.side !== DoubleSide, point ); + attributes.update( array[ i ], 34962 ); } - if ( intersect === null ) return null; - - intersectionPointWorld.copy( point ); - intersectionPointWorld.applyMatrix4( object.matrixWorld ); - - var distance = raycaster.ray.origin.distanceTo( intersectionPointWorld ); - - if ( distance < raycaster.near || distance > raycaster.far ) return null; - - return { - distance: distance, - point: intersectionPointWorld.clone(), - object: object - }; - } - function checkBufferGeometryIntersection( object, raycaster, ray, position, uv, a, b, c ) { - - vA.fromBufferAttribute( position, a ); - vB.fromBufferAttribute( position, b ); - vC.fromBufferAttribute( position, c ); + } - var intersection = checkIntersection( object, object.material, raycaster, ray, vA, vB, vC, intersectionPoint ); + function getWireframeAttribute( geometry ) { - if ( intersection ) { + var attribute = wireframeAttributes[ geometry.id ]; - if ( uv ) { + if ( attribute ) return attribute; - uvA.fromBufferAttribute( uv, a ); - uvB.fromBufferAttribute( uv, b ); - uvC.fromBufferAttribute( uv, c ); + var indices = []; - intersection.uv = uvIntersection( intersectionPoint, vA, vB, vC, uvA, uvB, uvC ); + var geometryIndex = geometry.index; + var geometryAttributes = geometry.attributes; - } + // console.time( 'wireframe' ); - intersection.face = new Face3( a, b, c, Triangle.normal( vA, vB, vC ) ); - intersection.faceIndex = a; + if ( geometryIndex !== null ) { - } + var array = geometryIndex.array; - return intersection; + 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 ]; - return function raycast( raycaster, intersects ) { + indices.push( a, b, b, c, c, a ); - var geometry = this.geometry; - var material = this.material; - var matrixWorld = this.matrixWorld; + } - if ( material === undefined ) return; + } else { - // Checking boundingSphere distance to ray + var array = geometryAttributes.position.array; - if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere(); + for ( var i = 0, l = ( array.length / 3 ) - 1; i < l; i += 3 ) { - sphere.copy( geometry.boundingSphere ); - sphere.applyMatrix4( matrixWorld ); + var a = i + 0; + var b = i + 1; + var c = i + 2; - if ( raycaster.ray.intersectsSphere( sphere ) === false ) return; + indices.push( a, b, b, c, c, a ); - // + } - inverseMatrix.getInverse( matrixWorld ); - ray.copy( raycaster.ray ).applyMatrix4( inverseMatrix ); + } - // Check boundingBox before continuing + // console.timeEnd( 'wireframe' ); - if ( geometry.boundingBox !== null ) { + attribute = new ( arrayMax( indices ) > 65535 ? Uint32BufferAttribute : Uint16BufferAttribute )( indices, 1 ); - if ( ray.intersectsBox( geometry.boundingBox ) === false ) return; + attributes.update( attribute, 34963 ); - } + wireframeAttributes[ geometry.id ] = attribute; - var intersection; + return attribute; - if ( geometry.isBufferGeometry ) { + } - var a, b, c; - var index = geometry.index; - var position = geometry.attributes.position; - var uv = geometry.attributes.uv; - var i, l; + return { - if ( index !== null ) { + get: get, + update: update, - // indexed buffer geometry + getWireframeAttribute: getWireframeAttribute - for ( i = 0, l = index.count; i < l; i += 3 ) { + }; - a = index.getX( i ); - b = index.getX( i + 1 ); - c = index.getX( i + 2 ); +} - intersection = checkBufferGeometryIntersection( this, raycaster, ray, position, uv, a, b, c ); +/** + * @author mrdoob / http://mrdoob.com/ + */ - if ( intersection ) { +function WebGLIndexedBufferRenderer( gl, extensions, info, capabilities ) { - intersection.faceIndex = Math.floor( i / 3 ); // triangle number in indices buffer semantics - intersects.push( intersection ); + var mode; - } + function setMode( value ) { - } + mode = value; - } else if ( position !== undefined ) { + } - // non-indexed buffer geometry + var type, bytesPerElement; - for ( i = 0, l = position.count; i < l; i += 3 ) { + function setIndex( value ) { - a = i; - b = i + 1; - c = i + 2; + type = value.type; + bytesPerElement = value.bytesPerElement; - intersection = checkBufferGeometryIntersection( this, raycaster, ray, position, uv, a, b, c ); + } - if ( intersection ) { + function render( start, count ) { - intersection.index = a; // triangle number in positions buffer semantics - intersects.push( intersection ); + gl.drawElements( mode, count, type, start * bytesPerElement ); - } + info.update( count, mode ); - } + } - } + function renderInstances( geometry, start, count ) { - } else if ( geometry.isGeometry ) { + var extension; - var fvA, fvB, fvC; - var isMultiMaterial = Array.isArray( material ); + if ( capabilities.isWebGL2 ) { - var vertices = geometry.vertices; - var faces = geometry.faces; - var uvs; + extension = gl; - var faceVertexUvs = geometry.faceVertexUvs[ 0 ]; - if ( faceVertexUvs.length > 0 ) uvs = faceVertexUvs; + } else { - for ( var f = 0, fl = faces.length; f < fl; f ++ ) { + var extension = extensions.get( 'ANGLE_instanced_arrays' ); - var face = faces[ f ]; - var faceMaterial = isMultiMaterial ? material[ face.materialIndex ] : material; + if ( extension === null ) { - if ( faceMaterial === undefined ) continue; + console.error( 'THREE.WebGLIndexedBufferRenderer: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.' ); + return; - fvA = vertices[ face.a ]; - fvB = vertices[ face.b ]; - fvC = vertices[ face.c ]; + } - if ( faceMaterial.morphTargets === true ) { + } - var morphTargets = geometry.morphTargets; - var morphInfluences = this.morphTargetInfluences; + extension[ capabilities.isWebGL2 ? 'drawElementsInstanced' : 'drawElementsInstancedANGLE' ]( mode, count, type, start * bytesPerElement, geometry.maxInstancedCount ); - vA.set( 0, 0, 0 ); - vB.set( 0, 0, 0 ); - vC.set( 0, 0, 0 ); + info.update( count, mode, geometry.maxInstancedCount ); - for ( var t = 0, tl = morphTargets.length; t < tl; t ++ ) { + } - var influence = morphInfluences[ t ]; + // - if ( influence === 0 ) continue; + this.setMode = setMode; + this.setIndex = setIndex; + this.render = render; + this.renderInstances = renderInstances; - var targets = morphTargets[ t ].vertices; +} - 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 ); +/** + * @author Mugen87 / https://github.com/Mugen87 + */ - } +function WebGLInfo( gl ) { - vA.add( fvA ); - vB.add( fvB ); - vC.add( fvC ); + var memory = { + geometries: 0, + textures: 0 + }; - fvA = vA; - fvB = vB; - fvC = vC; + var render = { + frame: 0, + calls: 0, + triangles: 0, + points: 0, + lines: 0 + }; - } + function update( count, mode, instanceCount ) { - intersection = checkIntersection( this, faceMaterial, raycaster, ray, fvA, fvB, fvC, intersectionPoint ); + instanceCount = instanceCount || 1; - if ( intersection ) { + render.calls ++; - if ( uvs && uvs[ f ] ) { + switch ( mode ) { - var uvs_f = uvs[ f ]; - uvA.copy( uvs_f[ 0 ] ); - uvB.copy( uvs_f[ 1 ] ); - uvC.copy( uvs_f[ 2 ] ); + case 4: + render.triangles += instanceCount * ( count / 3 ); + break; - intersection.uv = uvIntersection( intersectionPoint, fvA, fvB, fvC, uvA, uvB, uvC ); + case 5: + case 6: + render.triangles += instanceCount * ( count - 2 ); + break; - } + case 1: + render.lines += instanceCount * ( count / 2 ); + break; - intersection.face = face; - intersection.faceIndex = f; - intersects.push( intersection ); + 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; - }; + } - }() ), + } - clone: function () { + function reset() { - return new this.constructor( this.geometry, this.material ).copy( this ); + 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 + }; + +} /** * @author mrdoob / http://mrdoob.com/ */ -function WebGLBackground( renderer, state, geometries, premultipliedAlpha ) { - - var clearColor = new Color( 0x000000 ); - var clearAlpha = 0; +function absNumericalSort( a, b ) { - var planeCamera, planeMesh; - var boxMesh; + return Math.abs( b[ 1 ] ) - Math.abs( a[ 1 ] ); - function render( renderList, scene, camera, forceClear ) { +} - var background = scene.background; +function WebGLMorphtargets( gl ) { - if ( background === null ) { + var influencesList = {}; + var morphInfluences = new Float32Array( 8 ); - setClear( clearColor, clearAlpha ); + function update( object, geometry, material, program ) { - } else if ( background && background.isColor ) { + var objectInfluences = object.morphTargetInfluences; - setClear( background, 1 ); - forceClear = true; + var length = objectInfluences.length; - } + var influences = influencesList[ geometry.id ]; - if ( renderer.autoClear || forceClear ) { + if ( influences === undefined ) { - renderer.clear( renderer.autoClearColor, renderer.autoClearDepth, renderer.autoClearStencil ); + // initialise list - } + influences = []; - if ( background && background.isCubeTexture ) { + for ( var i = 0; i < length; i ++ ) { - if ( boxMesh === undefined ) { + influences[ i ] = [ i, 0 ]; - boxMesh = new Mesh( - new BoxBufferGeometry( 1, 1, 1 ), - new ShaderMaterial( { - uniforms: 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' ); + influencesList[ geometry.id ] = influences; - boxMesh.onBeforeRender = function ( renderer, scene, camera ) { + } - this.matrixWorld.copyPosition( camera.matrixWorld ); + var morphTargets = material.morphTargets && geometry.morphAttributes.position; + var morphNormals = material.morphNormals && geometry.morphAttributes.normal; - }; + // Remove current morphAttributes - geometries.update( boxMesh.geometry ); + for ( var i = 0; i < length; i ++ ) { - } + var influence = influences[ i ]; - boxMesh.material.uniforms.tCube.value = background; + if ( influence[ 1 ] !== 0 ) { - renderList.push( boxMesh, boxMesh.geometry, boxMesh.material, 0, null ); + if ( morphTargets ) geometry.removeAttribute( 'morphTarget' + i ); + if ( morphNormals ) geometry.removeAttribute( 'morphNormal' + i ); - } else if ( background && background.isTexture ) { + } - if ( planeCamera === undefined ) { + } - planeCamera = new OrthographicCamera( - 1, 1, 1, - 1, 0, 1 ); + // Collect influences - planeMesh = new Mesh( - new PlaneBufferGeometry( 2, 2 ), - new MeshBasicMaterial( { depthTest: false, depthWrite: false, fog: false } ) - ); + for ( var i = 0; i < length; i ++ ) { - geometries.update( planeMesh.geometry ); + var influence = influences[ i ]; - } + influence[ 0 ] = i; + influence[ 1 ] = objectInfluences[ i ]; - planeMesh.material.map = background; + } - // TODO Push this to renderList + influences.sort( absNumericalSort ); - renderer.renderBufferDirect( planeCamera, null, planeMesh.geometry, planeMesh.material, planeMesh, null ); + // Add morphAttributes - } + for ( var i = 0; i < 8; i ++ ) { - } + var influence = influences[ i ]; - function setClear( color, alpha ) { + if ( influence ) { - state.buffers.color.setClear( color.r, color.g, color.b, alpha, premultipliedAlpha ); + var index = influence[ 0 ]; + var value = influence[ 1 ]; - } + if ( value ) { - return { + if ( morphTargets ) geometry.addAttribute( 'morphTarget' + i, morphTargets[ index ] ); + if ( morphNormals ) geometry.addAttribute( 'morphNormal' + i, morphNormals[ index ] ); - getClearColor: function () { + morphInfluences[ i ] = value; + continue; - return clearColor; + } - }, - setClearColor: function ( color, alpha ) { + } - clearColor.set( color ); - clearAlpha = alpha !== undefined ? alpha : 1; - setClear( clearColor, clearAlpha ); + morphInfluences[ i ] = 0; - }, - getClearAlpha: function () { + } - return clearAlpha; + program.getUniforms().setValue( gl, 'morphTargetInfluences', morphInfluences ); - }, - setClearAlpha: function ( alpha ) { + } - clearAlpha = alpha; - setClear( clearColor, clearAlpha ); + return { - }, - render: render + update: update }; @@ -18951,729 +17070,1079 @@ function WebGLBackground( renderer, state, geometries, premultipliedAlpha ) { * @author mrdoob / http://mrdoob.com/ */ -function painterSortStable( a, b ) { +function WebGLObjects( geometries, info ) { - if ( a.renderOrder !== b.renderOrder ) { + var updateList = {}; - return a.renderOrder - b.renderOrder; + function update( object ) { - } else if ( a.program && b.program && a.program !== b.program ) { + var frame = info.render.frame; - return a.program.id - b.program.id; + var geometry = object.geometry; + var buffergeometry = geometries.get( object, geometry ); - } else if ( a.material.id !== b.material.id ) { + // Update once per frame - return a.material.id - b.material.id; + if ( updateList[ buffergeometry.id ] !== frame ) { - } else if ( a.z !== b.z ) { + if ( geometry.isGeometry ) { - return a.z - b.z; + buffergeometry.updateFromObject( object ); - } else { + } - return a.id - b.id; + geometries.update( buffergeometry ); - } + updateList[ buffergeometry.id ] = frame; -} + } -function reversePainterSortStable( a, b ) { + return buffergeometry; - if ( a.renderOrder !== b.renderOrder ) { + } - return a.renderOrder - b.renderOrder; + function dispose() { - } if ( a.z !== b.z ) { + updateList = {}; - return b.z - a.z; + } - } else { + return { - return a.id - b.id; + update: update, + dispose: dispose - } + }; } -function WebGLRenderList() { +/** + * @author mrdoob / http://mrdoob.com/ + */ - var renderItems = []; - var renderItemsIndex = 0; +function CubeTexture( images, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding ) { - var opaque = []; - var transparent = []; + images = images !== undefined ? images : []; + mapping = mapping !== undefined ? mapping : CubeReflectionMapping; - function init() { + Texture.call( this, images, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding ); - renderItemsIndex = 0; + this.flipY = false; - opaque.length = 0; - transparent.length = 0; +} - } +CubeTexture.prototype = Object.create( Texture.prototype ); +CubeTexture.prototype.constructor = CubeTexture; - function push( object, geometry, material, z, group ) { +CubeTexture.prototype.isCubeTexture = true; - var renderItem = renderItems[ renderItemsIndex ]; +Object.defineProperty( CubeTexture.prototype, 'images', { - if ( renderItem === undefined ) { + get: function () { - renderItem = { - id: object.id, - object: object, - geometry: geometry, - material: material, - program: material.program, - renderOrder: object.renderOrder, - z: z, - group: group - }; + return this.image; - renderItems[ renderItemsIndex ] = renderItem; + }, - } else { + set: function ( value ) { - 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; + this.image = value; - } + } - ( material.transparent === true ? transparent : opaque ).push( renderItem ); +} ); - renderItemsIndex ++; +/** + * @author Artur Trzesiok + */ - } +function DataTexture3D( data, width, height, depth ) { - function sort() { + // 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 ( opaque.length > 1 ) opaque.sort( painterSortStable ); - if ( transparent.length > 1 ) transparent.sort( reversePainterSortStable ); + Texture.call( this, null ); - } + this.image = { data: data, width: width, height: height, depth: depth }; - return { - opaque: opaque, - transparent: transparent, - - init: init, - push: push, + this.magFilter = NearestFilter; + this.minFilter = NearestFilter; - sort: sort - }; + this.generateMipmaps = false; + this.flipY = false; } -function WebGLRenderLists() { - - var lists = {}; +DataTexture3D.prototype = Object.create( Texture.prototype ); +DataTexture3D.prototype.constructor = DataTexture3D; +DataTexture3D.prototype.isDataTexture3D = true; - function get( scene, camera ) { +/** + * @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 + * + */ - var hash = scene.id + ',' + camera.id; - var list = lists[ hash ]; +var emptyTexture = new Texture(); +var emptyTexture3d = new DataTexture3D(); +var emptyCubeTexture = new CubeTexture(); - if ( list === undefined ) { +// --- Base for inner nodes (including the root) --- - // console.log( 'THREE.WebGLRenderLists:', hash ); +function UniformContainer() { - list = new WebGLRenderList(); - lists[ hash ] = list; + this.seq = []; + this.map = {}; - } +} - return list; +// --- Utilities --- - } +// Array Caches (provide typed arrays for temporary by size) - function dispose() { +var arrayCacheF32 = []; +var arrayCacheI32 = []; - lists = {}; +// Float32Array caches used for uploading Matrix uniforms - } +var mat4array = new Float32Array( 16 ); +var mat3array = new Float32Array( 9 ); +var mat2array = new Float32Array( 4 ); - return { - get: get, - dispose: dispose - }; +// Flattening for arrays of vectors and matrices -} +function flatten( array, nBlocks, blockSize ) { -/** - * @author mrdoob / http://mrdoob.com/ - */ + var firstElem = array[ 0 ]; -function absNumericalSort( a, b ) { + if ( firstElem <= 0 || firstElem > 0 ) return array; + // unoptimized: ! isNaN( firstElem ) + // see http://jacksondunstan.com/articles/983 - return Math.abs( b[ 1 ] ) - Math.abs( a[ 1 ] ); + var n = nBlocks * blockSize, + r = arrayCacheF32[ n ]; -} + if ( r === undefined ) { -function WebGLMorphtargets( gl ) { + r = new Float32Array( n ); + arrayCacheF32[ n ] = r; - var influencesList = {}; - var morphInfluences = new Float32Array( 8 ); + } - function update( object, geometry, material, program ) { + if ( nBlocks !== 0 ) { - var objectInfluences = object.morphTargetInfluences; + firstElem.toArray( r, 0 ); - var length = objectInfluences.length; + for ( var i = 1, offset = 0; i !== nBlocks; ++ i ) { - var influences = influencesList[ geometry.id ]; + offset += blockSize; + array[ i ].toArray( r, offset ); - if ( influences === undefined ) { + } - // initialise list + } - influences = []; + return r; - for ( var i = 0; i < length; i ++ ) { +} - influences[ i ] = [ i, 0 ]; +function arraysEqual( a, b ) { - } + if ( a.length !== b.length ) return false; - influencesList[ geometry.id ] = influences; + for ( var i = 0, l = a.length; i < l; i ++ ) { - } + if ( a[ i ] !== b[ i ] ) return false; - var morphTargets = material.morphTargets && geometry.morphAttributes.position; - var morphNormals = material.morphNormals && geometry.morphAttributes.normal; + } - // Remove current morphAttributes + return true; - for ( var i = 0; i < length; i ++ ) { +} - var influence = influences[ i ]; +function copyArray( a, b ) { - if ( influence[ 1 ] !== 0 ) { + for ( var i = 0, l = b.length; i < l; i ++ ) { - if ( morphTargets ) geometry.removeAttribute( 'morphTarget' + i ); - if ( morphNormals ) geometry.removeAttribute( 'morphNormal' + i ); + a[ i ] = b[ i ]; - } + } - } +} - // Collect influences +// Texture unit allocation - for ( var i = 0; i < length; i ++ ) { +function allocTexUnits( renderer, n ) { - var influence = influences[ i ]; + var r = arrayCacheI32[ n ]; - influence[ 0 ] = i; - influence[ 1 ] = objectInfluences[ i ]; + if ( r === undefined ) { - } + r = new Int32Array( n ); + arrayCacheI32[ n ] = r; - influences.sort( absNumericalSort ); + } - // Add morphAttributes + for ( var i = 0; i !== n; ++ i ) + r[ i ] = renderer.allocTextureUnit(); - for ( var i = 0; i < 8; i ++ ) { + return r; - var influence = influences[ i ]; +} - if ( influence ) { +// --- Setters --- - var index = influence[ 0 ]; - var value = influence[ 1 ]; +// Note: Defining these methods externally, because they come in a bunch +// and this way their names minify. - if ( value ) { +// Single scalar - if ( morphTargets ) geometry.addAttribute( 'morphTarget' + i, morphTargets[ index ] ); - if ( morphNormals ) geometry.addAttribute( 'morphNormal' + i, morphNormals[ index ] ); +function setValue1f( gl, v ) { - morphInfluences[ i ] = value; - continue; + var cache = this.cache; - } + if ( cache[ 0 ] === v ) return; - } + gl.uniform1f( this.addr, v ); - morphInfluences[ i ] = 0; + cache[ 0 ] = v; - } +} - program.getUniforms().setValue( gl, 'morphTargetInfluences', morphInfluences ); +function setValue1i( gl, v ) { - } + var cache = this.cache; - return { + if ( cache[ 0 ] === v ) return; - update: update + gl.uniform1i( this.addr, v ); - }; + cache[ 0 ] = v; } -/** - * @author mrdoob / http://mrdoob.com/ - */ - -function WebGLIndexedBufferRenderer( gl, extensions, infoRender ) { - - var mode; +// Single float vector (from flat array or THREE.VectorN) - function setMode( value ) { +function setValue2fv( gl, v ) { - mode = value; + var cache = this.cache; - } + if ( v.x !== undefined ) { - var type, bytesPerElement; + if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y ) { - function setIndex( value ) { + gl.uniform2f( this.addr, v.x, v.y ); - type = value.type; - bytesPerElement = value.bytesPerElement; + cache[ 0 ] = v.x; + cache[ 1 ] = v.y; - } + } - function render( start, count ) { + } else { - gl.drawElements( mode, count, type, start * bytesPerElement ); + if ( arraysEqual( cache, v ) ) return; - infoRender.calls ++; - infoRender.vertices += count; + gl.uniform2fv( this.addr, v ); - if ( mode === gl.TRIANGLES ) infoRender.faces += count / 3; - else if ( mode === gl.POINTS ) infoRender.points += count; + copyArray( cache, v ); } - function renderInstances( geometry, start, count ) { +} - var extension = extensions.get( 'ANGLE_instanced_arrays' ); +function setValue3fv( gl, v ) { - if ( extension === null ) { + var cache = this.cache; - console.error( 'THREE.WebGLIndexedBufferRenderer: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.' ); - return; + if ( v.x !== undefined ) { - } + if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y || cache[ 2 ] !== v.z ) { - extension.drawElementsInstancedANGLE( mode, count, type, start * bytesPerElement, geometry.maxInstancedCount ); + gl.uniform3f( this.addr, v.x, v.y, v.z ); - infoRender.calls ++; - infoRender.vertices += count * geometry.maxInstancedCount; + cache[ 0 ] = v.x; + cache[ 1 ] = v.y; + cache[ 2 ] = v.z; - if ( mode === gl.TRIANGLES ) infoRender.faces += geometry.maxInstancedCount * count / 3; - else if ( mode === gl.POINTS ) infoRender.points += geometry.maxInstancedCount * count; + } - } + } else if ( v.r !== undefined ) { - // + if ( cache[ 0 ] !== v.r || cache[ 1 ] !== v.g || cache[ 2 ] !== v.b ) { - this.setMode = setMode; - this.setIndex = setIndex; - this.render = render; - this.renderInstances = renderInstances; + gl.uniform3f( this.addr, v.r, v.g, v.b ); -} + cache[ 0 ] = v.r; + cache[ 1 ] = v.g; + cache[ 2 ] = v.b; -/** - * @author mrdoob / http://mrdoob.com/ - */ + } -function WebGLBufferRenderer( gl, extensions, infoRender ) { + } else { - var mode; + if ( arraysEqual( cache, v ) ) return; - function setMode( value ) { + gl.uniform3fv( this.addr, v ); - mode = value; + copyArray( cache, v ); } - function render( start, count ) { +} - gl.drawArrays( mode, start, count ); +function setValue4fv( gl, v ) { - infoRender.calls ++; - infoRender.vertices += count; + var cache = this.cache; - if ( mode === gl.TRIANGLES ) infoRender.faces += count / 3; - else if ( mode === gl.POINTS ) infoRender.points += count; + if ( v.x !== undefined ) { - } + if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y || cache[ 2 ] !== v.z || cache[ 3 ] !== v.w ) { - function renderInstances( geometry, start, count ) { + gl.uniform4f( this.addr, v.x, v.y, v.z, v.w ); - var extension = extensions.get( 'ANGLE_instanced_arrays' ); + cache[ 0 ] = v.x; + cache[ 1 ] = v.y; + cache[ 2 ] = v.z; + cache[ 3 ] = v.w; - if ( extension === null ) { + } - console.error( 'THREE.WebGLBufferRenderer: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.' ); - return; + } else { - } + if ( arraysEqual( cache, v ) ) return; - var position = geometry.attributes.position; + gl.uniform4fv( this.addr, v ); - if ( position.isInterleavedBufferAttribute ) { + copyArray( cache, v ); - count = position.data.count; + } - extension.drawArraysInstancedANGLE( mode, 0, count, geometry.maxInstancedCount ); +} - } else { +// Single matrix (from flat array or MatrixN) - extension.drawArraysInstancedANGLE( mode, start, count, geometry.maxInstancedCount ); +function setValue2fm( gl, v ) { - } + var cache = this.cache; + var elements = v.elements; - infoRender.calls ++; - infoRender.vertices += count * geometry.maxInstancedCount; + if ( elements === undefined ) { - if ( mode === gl.TRIANGLES ) infoRender.faces += geometry.maxInstancedCount * count / 3; - else if ( mode === gl.POINTS ) infoRender.points += geometry.maxInstancedCount * count; + if ( arraysEqual( cache, v ) ) return; - } + gl.uniformMatrix2fv( this.addr, false, v ); - // + copyArray( cache, v ); - this.setMode = setMode; - this.render = render; - this.renderInstances = renderInstances; + } else { -} + if ( arraysEqual( cache, elements ) ) return; -/** - * @author mrdoob / http://mrdoob.com/ - */ + mat2array.set( elements ); -function WebGLGeometries( gl, attributes, infoMemory ) { + gl.uniformMatrix2fv( this.addr, false, mat2array ); - var geometries = {}; - var wireframeAttributes = {}; + copyArray( cache, elements ); - function onGeometryDispose( event ) { + } - var geometry = event.target; - var buffergeometry = geometries[ geometry.id ]; +} - if ( buffergeometry.index !== null ) { +function setValue3fm( gl, v ) { - attributes.remove( buffergeometry.index ); + var cache = this.cache; + var elements = v.elements; - } + if ( elements === undefined ) { - for ( var name in buffergeometry.attributes ) { + if ( arraysEqual( cache, v ) ) return; - attributes.remove( buffergeometry.attributes[ name ] ); + gl.uniformMatrix3fv( this.addr, false, v ); - } + copyArray( cache, v ); - geometry.removeEventListener( 'dispose', onGeometryDispose ); + } else { - delete geometries[ geometry.id ]; + if ( arraysEqual( cache, elements ) ) return; - // TODO Remove duplicate code + mat3array.set( elements ); - var attribute = wireframeAttributes[ geometry.id ]; + gl.uniformMatrix3fv( this.addr, false, mat3array ); - if ( attribute ) { + copyArray( cache, elements ); - attributes.remove( attribute ); - delete wireframeAttributes[ geometry.id ]; + } - } +} - attribute = wireframeAttributes[ buffergeometry.id ]; +function setValue4fm( gl, v ) { - if ( attribute ) { + var cache = this.cache; + var elements = v.elements; - attributes.remove( attribute ); - delete wireframeAttributes[ buffergeometry.id ]; + if ( elements === undefined ) { - } + if ( arraysEqual( cache, v ) ) return; - // + gl.uniformMatrix4fv( this.addr, false, v ); - infoMemory.geometries --; + copyArray( cache, v ); - } + } else { - function get( object, geometry ) { + if ( arraysEqual( cache, elements ) ) return; - var buffergeometry = geometries[ geometry.id ]; + mat4array.set( elements ); - if ( buffergeometry ) return buffergeometry; + gl.uniformMatrix4fv( this.addr, false, mat4array ); - geometry.addEventListener( 'dispose', onGeometryDispose ); + copyArray( cache, elements ); - if ( geometry.isBufferGeometry ) { + } - buffergeometry = geometry; +} - } else if ( geometry.isGeometry ) { +// Single texture (2D / Cube) - if ( geometry._bufferGeometry === undefined ) { +function setValueT1( gl, v, renderer ) { - geometry._bufferGeometry = new BufferGeometry().setFromObject( object ); + var cache = this.cache; + var unit = renderer.allocTextureUnit(); - } + if ( cache[ 0 ] !== unit ) { - buffergeometry = geometry._bufferGeometry; + gl.uniform1i( this.addr, unit ); + cache[ 0 ] = unit; - } + } - geometries[ geometry.id ] = buffergeometry; + renderer.setTexture2D( v || emptyTexture, unit ); - infoMemory.geometries ++; +} - return buffergeometry; +function setValueT3D1( gl, v, renderer ) { - } + var cache = this.cache; + var unit = renderer.allocTextureUnit(); - function update( geometry ) { + if ( cache[ 0 ] !== unit ) { - var index = geometry.index; - var geometryAttributes = geometry.attributes; + gl.uniform1i( this.addr, unit ); + cache[ 0 ] = unit; - if ( index !== null ) { + } - attributes.update( index, gl.ELEMENT_ARRAY_BUFFER ); + renderer.setTexture3D( v || emptyTexture3d, unit ); - } +} - for ( var name in geometryAttributes ) { +function setValueT6( gl, v, renderer ) { - attributes.update( geometryAttributes[ name ], gl.ARRAY_BUFFER ); + var cache = this.cache; + var unit = renderer.allocTextureUnit(); - } + if ( cache[ 0 ] !== unit ) { - // morph targets + gl.uniform1i( this.addr, unit ); + cache[ 0 ] = unit; - var morphAttributes = geometry.morphAttributes; + } - for ( var name in morphAttributes ) { + renderer.setTextureCube( v || emptyCubeTexture, unit ); - var array = morphAttributes[ name ]; +} - for ( var i = 0, l = array.length; i < l; i ++ ) { +// Integer / Boolean vectors or arrays thereof (always flat arrays) - attributes.update( array[ i ], gl.ARRAY_BUFFER ); +function setValue2iv( gl, v ) { - } + var cache = this.cache; - } + if ( arraysEqual( cache, v ) ) return; - } + gl.uniform2iv( this.addr, v ); - function getWireframeAttribute( geometry ) { + copyArray( cache, v ); - var attribute = wireframeAttributes[ geometry.id ]; +} - if ( attribute ) return attribute; +function setValue3iv( gl, v ) { - var indices = []; + var cache = this.cache; - var geometryIndex = geometry.index; - var geometryAttributes = geometry.attributes; + if ( arraysEqual( cache, v ) ) return; - // console.time( 'wireframe' ); + gl.uniform3iv( this.addr, v ); - if ( geometryIndex !== null ) { + copyArray( cache, v ); - var array = geometryIndex.array; +} - for ( var i = 0, l = array.length; i < l; i += 3 ) { +function setValue4iv( gl, v ) { - var a = array[ i + 0 ]; - var b = array[ i + 1 ]; - var c = array[ i + 2 ]; + var cache = this.cache; - indices.push( a, b, b, c, c, a ); + if ( arraysEqual( cache, v ) ) return; - } + gl.uniform4iv( this.addr, v ); - } else { + copyArray( cache, v ); - var array = geometryAttributes.position.array; +} - for ( var i = 0, l = ( array.length / 3 ) - 1; i < l; i += 3 ) { +// Helper to pick the right setter for the singular case - var a = i + 0; - var b = i + 1; - var c = 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 - } + case 0x8b5a: return setValue2fm; // _MAT2 + case 0x8b5b: return setValue3fm; // _MAT3 + case 0x8b5c: return setValue4fm; // _MAT4 - // console.timeEnd( 'wireframe' ); + case 0x8b5e: case 0x8d66: return setValueT1; // SAMPLER_2D, SAMPLER_EXTERNAL_OES + case 0x8B5F: return setValueT3D1; // SAMPLER_3D + case 0x8b60: return setValueT6; // SAMPLER_CUBE - attribute = new ( arrayMax( indices ) > 65535 ? Uint32BufferAttribute : Uint16BufferAttribute )( indices, 1 ); + 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 - attributes.update( attribute, gl.ELEMENT_ARRAY_BUFFER ); + } - wireframeAttributes[ geometry.id ] = attribute; +} - return attribute; +// Array of scalars - } +function setValue1fv( gl, v ) { - return { + var cache = this.cache; - get: get, - update: update, + if ( arraysEqual( cache, v ) ) return; - getWireframeAttribute: getWireframeAttribute + gl.uniform1fv( this.addr, v ); - }; + copyArray( cache, v ); } +function setValue1iv( gl, v ) { -/** - * @author mrdoob / http://mrdoob.com/ - */ + var cache = this.cache; -function WebGLObjects( geometries, infoRender ) { + if ( arraysEqual( cache, v ) ) return; - var updateList = {}; + gl.uniform1iv( this.addr, v ); - function update( object ) { + copyArray( cache, v ); - var frame = infoRender.frame; +} - var geometry = object.geometry; - var buffergeometry = geometries.get( object, geometry ); +// Array of vectors (flat or from THREE classes) - // Update once per frame +function setValueV2a( gl, v ) { - if ( updateList[ buffergeometry.id ] !== frame ) { + var cache = this.cache; + var data = flatten( v, this.size, 2 ); - if ( geometry.isGeometry ) { + if ( arraysEqual( cache, data ) ) return; - buffergeometry.updateFromObject( object ); + gl.uniform2fv( this.addr, data ); - } + this.updateCache( data ); - geometries.update( buffergeometry ); +} - updateList[ buffergeometry.id ] = frame; +function setValueV3a( gl, v ) { - } + var cache = this.cache; + var data = flatten( v, this.size, 3 ); - return buffergeometry; + if ( arraysEqual( cache, data ) ) return; - } + gl.uniform3fv( this.addr, data ); - function dispose() { + this.updateCache( data ); - updateList = {}; +} - } +function setValueV4a( gl, v ) { - return { + var cache = this.cache; + var data = flatten( v, this.size, 4 ); - update: update, - dispose: dispose + if ( arraysEqual( cache, data ) ) return; - }; + gl.uniform4fv( this.addr, data ); -} + this.updateCache( data ); -/** - * @author mrdoob / http://mrdoob.com/ - */ +} -function addLineNumbers( string ) { +// Array of matrices (flat or from THREE clases) - var lines = string.split( '\n' ); +function setValueM2a( gl, v ) { - for ( var i = 0; i < lines.length; i ++ ) { + var cache = this.cache; + var data = flatten( v, this.size, 4 ); - lines[ i ] = ( i + 1 ) + ': ' + lines[ i ]; + if ( arraysEqual( cache, data ) ) return; - } + gl.uniformMatrix2fv( this.addr, false, data ); - return lines.join( '\n' ); + this.updateCache( data ); } -function WebGLShader( gl, type, string ) { +function setValueM3a( gl, v ) { - var shader = gl.createShader( type ); + var cache = this.cache; + var data = flatten( v, this.size, 9 ); - gl.shaderSource( shader, string ); - gl.compileShader( shader ); + if ( arraysEqual( cache, data ) ) return; - if ( gl.getShaderParameter( shader, gl.COMPILE_STATUS ) === false ) { + gl.uniformMatrix3fv( this.addr, false, data ); - console.error( 'THREE.WebGLShader: Shader couldn\'t compile.' ); + this.updateCache( data ); - } +} - if ( gl.getShaderInfoLog( shader ) !== '' ) { +function setValueM4a( gl, v ) { - console.warn( 'THREE.WebGLShader: gl.getShaderInfoLog()', type === gl.VERTEX_SHADER ? 'vertex' : 'fragment', gl.getShaderInfoLog( shader ), addLineNumbers( string ) ); + var cache = this.cache; + var data = flatten( v, this.size, 16 ); - } + if ( arraysEqual( cache, data ) ) return; - // --enable-privileged-webgl-extension - // console.log( type, gl.getExtension( 'WEBGL_debug_shaders' ).getTranslatedShaderSource( shader ) ); + gl.uniformMatrix4fv( this.addr, false, data ); - return shader; + this.updateCache( data ); } -/** - * @author mrdoob / http://mrdoob.com/ - */ +// Array of textures (2D / Cube) -var programIdCount = 0; +function setValueT1a( gl, v, renderer ) { -function getEncodingComponents( encoding ) { + var cache = this.cache; + var n = v.length; - switch ( encoding ) { + var units = allocTexUnits( renderer, n ); - 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 ); + if ( arraysEqual( cache, units ) === false ) { + + gl.uniform1iv( this.addr, units ); + copyArray( cache, units ); } -} + for ( var i = 0; i !== n; ++ i ) { -function getTexelDecodingFunction( functionName, encoding ) { + renderer.setTexture2D( v[ i ] || emptyTexture, units[ i ] ); - var components = getEncodingComponents( encoding ); - return 'vec4 ' + functionName + '( vec4 value ) { return ' + components[ 0 ] + 'ToLinear' + components[ 1 ] + '; }'; + } } -function getTexelEncodingFunction( functionName, encoding ) { +function setValueT6a( gl, v, renderer ) { - var components = getEncodingComponents( encoding ); - return 'vec4 ' + functionName + '( vec4 value ) { return LinearTo' + components[ 0 ] + components[ 1 ] + '; }'; + var cache = this.cache; + var n = v.length; -} + var units = allocTexUnits( renderer, n ); -function getToneMappingFunction( functionName, toneMapping ) { + if ( arraysEqual( cache, units ) === false ) { + + gl.uniform1iv( this.addr, units ); + copyArray( cache, units ); + + } + + for ( var i = 0; i !== n; ++ i ) { + + renderer.setTextureCube( v[ i ] || emptyCubeTexture, units[ i ] ); + + } + +} + +// Helper to pick the right setter for a pure (bottom-level) array + +function getPureArraySetter( type ) { + + switch ( type ) { + + case 0x1406: return 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 + + 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 + + } + +} + +// --- Uniform Classes --- + +function SingleUniform( id, activeInfo, addr ) { + + this.id = id; + this.addr = addr; + this.cache = []; + this.setValue = getSingularSetter( activeInfo.type ); + + // this.path = activeInfo.name; // DEBUG + +} + +function PureArrayUniform( id, activeInfo, addr ) { + + this.id = id; + this.addr = addr; + this.cache = []; + this.size = activeInfo.size; + this.setValue = getPureArraySetter( activeInfo.type ); + + // this.path = activeInfo.name; // DEBUG + +} + +PureArrayUniform.prototype.updateCache = function ( data ) { + + var cache = this.cache; + + if ( data instanceof Float32Array && cache.length !== data.length ) { + + this.cache = new Float32Array( data.length ); + + } + + copyArray( cache, data ); + +}; + +function StructuredUniform( id ) { + + this.id = id; + + UniformContainer.call( this ); // mix-in + +} + +StructuredUniform.prototype.setValue = function ( gl, value, renderer ) { + + var seq = this.seq; + + for ( var i = 0, n = seq.length; i !== n; ++ i ) { + + var u = seq[ i ]; + u.setValue( gl, value[ u.id ], renderer ); + + } + +}; + +// --- Top-level --- + +// 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. + +function addUniform( container, uniformObject ) { + + container.seq.push( uniformObject ); + container.map[ uniformObject.id ] = uniformObject; + +} + +function parseUniform( activeInfo, addr, container ) { + + var path = activeInfo.name, + pathLength = path.length; + + // 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, + + id = match[ 1 ], + idIsIndex = match[ 2 ] === ']', + subscript = match[ 3 ]; + + if ( idIsIndex ) id = id | 0; // convert to integer + + if ( subscript === undefined || subscript === '[' && matchEnd + 2 === pathLength ) { + + // bare name or "pure" bottom-level array "[0]" suffix + + addUniform( container, subscript === undefined ? + new SingleUniform( id, activeInfo, addr ) : + new PureArrayUniform( id, activeInfo, addr ) ); + + break; + + } else { + + // step into inner node / create it in case it doesn't exist + + var map = container.map, next = map[ id ]; + + if ( next === undefined ) { + + next = new StructuredUniform( id ); + addUniform( container, next ); + + } + + container = next; + + } + + } + +} + +// Root Container + +function WebGLUniforms( gl, program, renderer ) { + + UniformContainer.call( this ); + + this.renderer = renderer; + + 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 ); + + parseUniform( info, addr, this ); + + } + +} + +WebGLUniforms.prototype.setValue = function ( gl, name, value ) { + + var u = this.map[ name ]; + + if ( u !== undefined ) u.setValue( gl, value, this.renderer ); + +}; + +WebGLUniforms.prototype.setOptional = function ( gl, object, name ) { + + var v = object[ name ]; + + if ( v !== undefined ) this.setValue( gl, name, v ); + +}; + + +// Static interface + +WebGLUniforms.upload = function ( gl, seq, values, renderer ) { + + for ( var i = 0, n = seq.length; i !== n; ++ i ) { + + var u = seq[ i ], + v = values[ u.id ]; + + if ( v.needsUpdate !== false ) { + + // note: always updating when .needsUpdate is undefined + u.setValue( gl, v.value, renderer ); + + } + + } + +}; + +WebGLUniforms.seqWithValue = function ( seq, values ) { + + var r = []; + + for ( var i = 0, n = seq.length; i !== n; ++ i ) { + + var u = seq[ i ]; + if ( u.id in values ) r.push( u ); + + } + + return r; + +}; + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +function addLineNumbers( string ) { + + var lines = string.split( '\n' ); + + for ( var i = 0; i < lines.length; i ++ ) { + + lines[ i ] = ( i + 1 ) + ': ' + lines[ i ]; + + } + + return lines.join( '\n' ); + +} + +function WebGLShader( gl, type, string ) { + + var shader = gl.createShader( type ); + + gl.shaderSource( shader, string ); + gl.compileShader( shader ); + + if ( gl.getShaderParameter( shader, 35713 ) === false ) { + + console.error( 'THREE.WebGLShader: Shader couldn\'t compile.' ); + + } + + if ( gl.getShaderInfoLog( shader ) !== '' ) { + + console.warn( 'THREE.WebGLShader: gl.getShaderInfoLog()', type === 35633 ? 'vertex' : 'fragment', gl.getShaderInfoLog( shader ), addLineNumbers( string ) ); + + } + + // --enable-privileged-webgl-extension + // console.log( type, gl.getExtension( 'WEBGL_debug_shaders' ).getTranslatedShaderSource( shader ) ); + + return shader; + +} + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +var programIdCount = 0; + +function getEncodingComponents( encoding ) { + + switch ( encoding ) { + + case LinearEncoding: + return [ 'Linear', '( value )' ]; + case sRGBEncoding: + return [ 'sRGB', '( value )' ]; + case RGBEEncoding: + return [ 'RGBE', '( value )' ]; + case RGBM7Encoding: + return [ 'RGBM', '( value, 7.0 )' ]; + case RGBM16Encoding: + return [ 'RGBM', '( value, 16.0 )' ]; + case RGBDEncoding: + return [ 'RGBD', '( value, 256.0 )' ]; + case GammaEncoding: + return [ 'Gamma', '( value, float( GAMMA_FACTOR ) )' ]; + default: + throw new Error( 'unsupported encoding: ' + encoding ); + + } + +} + +function getTexelDecodingFunction( functionName, encoding ) { + + var components = getEncodingComponents( encoding ); + return 'vec4 ' + functionName + '( vec4 value ) { return ' + components[ 0 ] + 'ToLinear' + components[ 1 ] + '; }'; + +} + +function getTexelEncodingFunction( functionName, encoding ) { + + var components = getEncodingComponents( encoding ); + return 'vec4 ' + functionName + '( vec4 value ) { return LinearTo' + components[ 0 ] + components[ 1 ] + '; }'; + +} + +function getToneMappingFunction( functionName, toneMapping ) { var toneMappingName; @@ -19695,6 +18164,10 @@ function getToneMappingFunction( functionName, toneMapping ) { toneMappingName = 'OptimizedCineon'; break; + case ACESFilmicToneMapping: + toneMappingName = 'ACESFilmic'; + break; + default: throw new Error( 'unsupported toneMapping: ' + toneMapping ); @@ -19709,7 +18182,7 @@ function generateExtensions( extensions, parameters, rendererExtensions ) { extensions = extensions || {}; var chunks = [ - ( extensions.derivatives || parameters.envMapCubeUV || parameters.bumpMap || parameters.normalMap || parameters.flatShading ) ? '#extension GL_OES_standard_derivatives : enable' : '', + ( 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' : '' @@ -19741,7 +18214,7 @@ function fetchAttributeLocations( gl, program ) { var attributes = {}; - var n = gl.getProgramParameter( program, gl.ACTIVE_ATTRIBUTES ); + var n = gl.getProgramParameter( program, 35721 ); for ( var i = 0; i < n; i ++ ) { @@ -19785,7 +18258,7 @@ function replaceClippingPlaneNums( string, parameters ) { function parseIncludes( string ) { - var pattern = /^[ \t]*#include +<([\w\d.]+)>/gm; + var pattern = /^[ \t]*#include +<([\w\d./]+)>/gm; function replace( match, include ) { @@ -19827,7 +18300,7 @@ function unrollLoops( string ) { } -function WebGLProgram( renderer, extensions, code, material, shader, parameters ) { +function WebGLProgram( renderer, extensions, code, material, shader, parameters, capabilities ) { var gl = renderer.context; @@ -19910,7 +18383,7 @@ function WebGLProgram( renderer, extensions, code, material, shader, parameters // - var customExtensions = generateExtensions( material.extensions, parameters, extensions ); + var customExtensions = capabilities.isWebGL2 ? '' : generateExtensions( material.extensions, parameters, extensions ); var customDefines = generateDefines( defines ); @@ -19974,6 +18447,7 @@ function WebGLProgram( renderer, extensions, code, material, shader, parameters 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' : '', @@ -19997,7 +18471,7 @@ function WebGLProgram( renderer, extensions, code, material, shader, parameters parameters.sizeAttenuation ? '#define USE_SIZEATTENUATION' : '', parameters.logarithmicDepthBuffer ? '#define USE_LOGDEPTHBUF' : '', - parameters.logarithmicDepthBuffer && extensions.get( 'EXT_frag_depth' ) ? '#define USE_LOGDEPTHBUF_EXT' : '', + parameters.logarithmicDepthBuffer && ( capabilities.isWebGL2 || extensions.get( 'EXT_frag_depth' ) ) ? '#define USE_LOGDEPTHBUF_EXT' : '', 'uniform mat4 modelMatrix;', 'uniform mat4 modelViewMatrix;', @@ -20063,7 +18537,7 @@ function WebGLProgram( renderer, extensions, code, material, shader, parameters customDefines, - parameters.alphaTest ? '#define ALPHATEST ' + parameters.alphaTest : '', + parameters.alphaTest ? '#define ALPHATEST ' + parameters.alphaTest + ( parameters.alphaTest % 1 ? '' : '.0' ) : '', // add '.0' if integer '#define GAMMA_FACTOR ' + gammaFactorDefine, @@ -20071,6 +18545,7 @@ function WebGLProgram( renderer, extensions, code, material, shader, parameters ( parameters.useFog && parameters.fogExp ) ? '#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 : '', @@ -20080,6 +18555,7 @@ function WebGLProgram( renderer, extensions, code, material, shader, parameters 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' : '', @@ -20101,9 +18577,9 @@ function WebGLProgram( renderer, extensions, code, material, shader, parameters parameters.physicallyCorrectLights ? '#define PHYSICALLY_CORRECT_LIGHTS' : '', parameters.logarithmicDepthBuffer ? '#define USE_LOGDEPTHBUF' : '', - parameters.logarithmicDepthBuffer && extensions.get( 'EXT_frag_depth' ) ? '#define USE_LOGDEPTHBUF_EXT' : '', + parameters.logarithmicDepthBuffer && ( capabilities.isWebGL2 || extensions.get( 'EXT_frag_depth' ) ) ? '#define USE_LOGDEPTHBUF_EXT' : '', - parameters.envMap && extensions.get( 'EXT_shader_texture_lod' ) ? '#define TEXTURE_LOD_EXT' : '', + parameters.envMap && ( capabilities.isWebGL2 || extensions.get( 'EXT_shader_texture_lod' ) ) ? '#define TEXTURE_LOD_EXT' : '', 'uniform mat4 viewMatrix;', 'uniform vec3 cameraPosition;', @@ -20114,8 +18590,10 @@ function WebGLProgram( renderer, extensions, code, material, shader, parameters parameters.dithering ? '#define DITHERING' : '', - ( parameters.outputEncoding || parameters.mapEncoding || 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.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 ) : '', @@ -20139,14 +18617,58 @@ function WebGLProgram( renderer, extensions, code, material, shader, parameters vertexShader = unrollLoops( vertexShader ); fragmentShader = unrollLoops( fragmentShader ); + if ( capabilities.isWebGL2 && ! material.isRawShaderMaterial ) { + + var isGLSL3ShaderMaterial = false; + + var versionRegex = /^\s*#version\s+300\s+es\s*\n/; + + if ( material.isShaderMaterial && + vertexShader.match( versionRegex ) !== null && + fragmentShader.match( versionRegex ) !== null ) { + + isGLSL3ShaderMaterial = true; + + vertexShader = vertexShader.replace( versionRegex, '' ); + fragmentShader = fragmentShader.replace( versionRegex, '' ); + + } + + // GLSL 3.0 conversion + prefixVertex = [ + '#version 300 es\n', + '#define attribute in', + '#define varying out', + '#define texture2D texture' + ].join( '\n' ) + '\n' + prefixVertex; + + 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; + + } + var vertexGlsl = prefixVertex + vertexShader; var fragmentGlsl = prefixFragment + fragmentShader; // console.log( '*VERTEX*', vertexGlsl ); // console.log( '*FRAGMENT*', fragmentGlsl ); - var glVertexShader = WebGLShader( gl, gl.VERTEX_SHADER, vertexGlsl ); - var glFragmentShader = WebGLShader( gl, gl.FRAGMENT_SHADER, fragmentGlsl ); + var glVertexShader = WebGLShader( gl, 35633, vertexGlsl ); + var glFragmentShader = WebGLShader( gl, 35632, fragmentGlsl ); gl.attachShader( program, glVertexShader ); gl.attachShader( program, glFragmentShader ); @@ -20176,11 +18698,11 @@ function WebGLProgram( renderer, extensions, code, material, shader, parameters // console.log( '**VERTEX**', gl.getExtension( 'WEBGL_debug_shaders' ).getTranslatedShaderSource( glVertexShader ) ); // console.log( '**FRAGMENT**', gl.getExtension( 'WEBGL_debug_shaders' ).getTranslatedShaderSource( glFragmentShader ) ); - if ( gl.getProgramParameter( program, gl.LINK_STATUS ) === false ) { + if ( gl.getProgramParameter( program, 35714 ) === false ) { runnable = false; - console.error( 'THREE.WebGLProgram: shader error: ', gl.getError(), 'gl.VALIDATE_STATUS', gl.getProgramParameter( program, gl.VALIDATE_STATUS ), 'gl.getProgramInfoLog', programLog, vertexLog, fragmentLog ); + console.error( 'THREE.WebGLProgram: shader error: ', gl.getError(), '35715', gl.getProgramParameter( program, 35715 ), 'gl.getProgramInfoLog', programLog, vertexLog, fragmentLog ); } else if ( programLog !== '' ) { @@ -20292,6 +18814,7 @@ function WebGLProgram( renderer, extensions, code, material, shader, parameters // + this.name = shader.name; this.id = programIdCount ++; this.code = code; this.usedTimes = 1; @@ -20321,15 +18844,17 @@ function WebGLPrograms( renderer, extensions, capabilities ) { MeshToonMaterial: 'phong', MeshStandardMaterial: 'physical', MeshPhysicalMaterial: 'physical', + MeshMatcapMaterial: 'matcap', LineBasicMaterial: 'basic', LineDashedMaterial: 'dashed', PointsMaterial: 'points', - ShadowMaterial: 'shadow' + ShadowMaterial: 'shadow', + SpriteMaterial: 'sprite' }; var parameterNames = [ - "precision", "supportsVertexTextures", "map", "mapEncoding", "envMap", "envMapMode", "envMapEncoding", - "lightMap", "aoMap", "emissiveMap", "emissiveMapEncoding", "bumpMap", "normalMap", "displacementMap", "specularMap", + "precision", "supportsVertexTextures", "map", "mapEncoding", "matcap", "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", @@ -20440,6 +18965,8 @@ function WebGLPrograms( renderer, extensions, capabilities ) { 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 ), @@ -20450,6 +18977,7 @@ function WebGLPrograms( renderer, extensions, capabilities ) { 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, @@ -20547,6 +19075,8 @@ function WebGLPrograms( renderer, extensions, capabilities ) { array.push( renderer.gammaOutput ); + array.push( renderer.gammaFactor ); + return array.join(); }; @@ -20573,7 +19103,7 @@ function WebGLPrograms( renderer, extensions, capabilities ) { if ( program === undefined ) { - program = new WebGLProgram( renderer, extensions, code, material, shader, parameters ); + program = new WebGLProgram( renderer, extensions, code, material, shader, parameters, capabilities ); programs.push( program ); } @@ -20604,875 +19134,1251 @@ function WebGLPrograms( renderer, extensions, capabilities ) { } /** - * @author mrdoob / http://mrdoob.com/ + * @author fordacious / fordacious.github.io */ -function WebGLTextures( _gl, extensions, state, properties, capabilities, utils, infoMemory, infoRender ) { +function WebGLProperties() { - var _isWebGL2 = ( typeof WebGL2RenderingContext !== 'undefined' && _gl instanceof WebGL2RenderingContext ); - var _videoTextures = {}; - var _canvas; + var properties = new WeakMap(); - // + function get( object ) { - function clampToMaxSize( image, maxSize ) { + var map = properties.get( object ); - if ( image.width > maxSize || image.height > maxSize ) { + if ( map === undefined ) { - // Warning: Scaling through the canvas will only work with images that use - // premultiplied alpha. + map = {}; + properties.set( object, map ); - var scale = maxSize / Math.max( image.width, image.height ); + } - 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 ); + return map; - var context = canvas.getContext( '2d' ); - context.drawImage( image, 0, 0, image.width, image.height, 0, 0, canvas.width, canvas.height ); + } + + function remove( object ) { - console.warn( 'THREE.WebGLRenderer: image is too big (' + image.width + 'x' + image.height + '). Resized to ' + canvas.width + 'x' + canvas.height, image ); + properties.delete( object ); - return canvas; + } - } + function update( object, key, value ) { - return image; + properties.get( object )[ key ] = value; } - function isPowerOfTwo( image ) { + function dispose() { - return _Math.isPowerOfTwo( image.width ) && _Math.isPowerOfTwo( image.height ); + properties = new WeakMap(); } - function makePowerOfTwo( image ) { - - if ( image instanceof HTMLImageElement || image instanceof HTMLCanvasElement || image instanceof ImageBitmap ) { + return { + get: get, + remove: remove, + update: update, + dispose: dispose + }; - if ( _canvas === undefined ) _canvas = document.createElementNS( 'http://www.w3.org/1999/xhtml', 'canvas' ); +} - _canvas.width = _Math.floorPowerOfTwo( image.width ); - _canvas.height = _Math.floorPowerOfTwo( image.height ); +/** + * @author mrdoob / http://mrdoob.com/ + */ - var context = _canvas.getContext( '2d' ); - context.drawImage( image, 0, 0, _canvas.width, _canvas.height ); +function painterSortStable( a, b ) { - console.warn( 'THREE.WebGLRenderer: image is not power of two (' + image.width + 'x' + image.height + '). Resized to ' + _canvas.width + 'x' + _canvas.height, image ); + if ( a.renderOrder !== b.renderOrder ) { - return _canvas; + return a.renderOrder - b.renderOrder; - } + } else if ( a.program && b.program && a.program !== b.program ) { - return image; + return a.program.id - b.program.id; - } + } else if ( a.material.id !== b.material.id ) { - function textureNeedsPowerOfTwo( texture ) { + return a.material.id - b.material.id; - return ( texture.wrapS !== ClampToEdgeWrapping || texture.wrapT !== ClampToEdgeWrapping ) || - ( texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter ); + } else if ( a.z !== b.z ) { - } + return a.z - b.z; - function textureNeedsGenerateMipmaps( texture, isPowerOfTwo ) { + } else { - return texture.generateMipmaps && isPowerOfTwo && - texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter; + return a.id - b.id; } - // Fallback filters for non-power-of-2 textures +} - function filterFallback( f ) { +function reversePainterSortStable( a, b ) { - if ( f === NearestFilter || f === NearestMipMapNearestFilter || f === NearestMipMapLinearFilter ) { + if ( a.renderOrder !== b.renderOrder ) { - return _gl.NEAREST; + return a.renderOrder - b.renderOrder; - } + } if ( a.z !== b.z ) { - return _gl.LINEAR; + return b.z - a.z; - } + } else { - // + return a.id - b.id; - function onTextureDispose( event ) { + } - var texture = event.target; +} - texture.removeEventListener( 'dispose', onTextureDispose ); - deallocateTexture( texture ); +function WebGLRenderList() { - if ( texture.isVideoTexture ) { + var renderItems = []; + var renderItemsIndex = 0; - delete _videoTextures[ texture.id ]; + var opaque = []; + var transparent = []; - } + function init() { + + renderItemsIndex = 0; - infoMemory.textures --; + opaque.length = 0; + transparent.length = 0; } - function onRenderTargetDispose( event ) { + function getNextRenderItem( object, geometry, material, z, group ) { - var renderTarget = event.target; + var renderItem = renderItems[ renderItemsIndex ]; - renderTarget.removeEventListener( 'dispose', onRenderTargetDispose ); + if ( renderItem === undefined ) { - deallocateRenderTarget( renderTarget ); + renderItem = { + id: object.id, + object: object, + geometry: geometry, + material: material, + program: material.program, + renderOrder: object.renderOrder, + z: z, + group: group + }; - infoMemory.textures --; + renderItems[ renderItemsIndex ] = renderItem; - } + } 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 deallocateTexture( texture ) { + } - var textureProperties = properties.get( texture ); + renderItemsIndex ++; - if ( texture.image && textureProperties.__image__webglTextureCube ) { + return renderItem; - // cube texture + } - _gl.deleteTexture( textureProperties.__image__webglTextureCube ); + function push( object, geometry, material, z, group ) { - } else { + var renderItem = getNextRenderItem( object, geometry, material, z, group ); - // 2D texture + ( material.transparent === true ? transparent : opaque ).push( renderItem ); - if ( textureProperties.__webglInit === undefined ) return; + } - _gl.deleteTexture( textureProperties.__webglTexture ); + function unshift( object, geometry, material, z, group ) { - } + var renderItem = getNextRenderItem( object, geometry, material, z, group ); - // remove all webgl properties - properties.remove( texture ); + ( material.transparent === true ? transparent : opaque ).unshift( renderItem ); } - function deallocateRenderTarget( renderTarget ) { - - var renderTargetProperties = properties.get( renderTarget ); - var textureProperties = properties.get( renderTarget.texture ); + function sort() { - if ( ! renderTarget ) return; + if ( opaque.length > 1 ) opaque.sort( painterSortStable ); + if ( transparent.length > 1 ) transparent.sort( reversePainterSortStable ); - if ( textureProperties.__webglTexture !== undefined ) { + } - _gl.deleteTexture( textureProperties.__webglTexture ); + return { + opaque: opaque, + transparent: transparent, - } + init: init, + push: push, + unshift: unshift, - if ( renderTarget.depthTexture ) { + sort: sort + }; - renderTarget.depthTexture.dispose(); +} - } +function WebGLRenderLists() { - if ( renderTarget.isWebGLRenderTargetCube ) { + var lists = {}; - for ( var i = 0; i < 6; i ++ ) { + function get( scene, camera ) { - _gl.deleteFramebuffer( renderTargetProperties.__webglFramebuffer[ i ] ); - if ( renderTargetProperties.__webglDepthbuffer ) _gl.deleteRenderbuffer( renderTargetProperties.__webglDepthbuffer[ i ] ); + var cameras = lists[ scene.id ]; + var list; + if ( cameras === undefined ) { - } + list = new WebGLRenderList(); + lists[ scene.id ] = {}; + lists[ scene.id ][ camera.id ] = list; } else { - _gl.deleteFramebuffer( renderTargetProperties.__webglFramebuffer ); - if ( renderTargetProperties.__webglDepthbuffer ) _gl.deleteRenderbuffer( renderTargetProperties.__webglDepthbuffer ); + list = cameras[ camera.id ]; + if ( list === undefined ) { + + list = new WebGLRenderList(); + cameras[ camera.id ] = list; + + } } - properties.remove( renderTarget.texture ); - properties.remove( renderTarget ); + return list; } - // + function dispose() { + lists = {}; + } - function setTexture2D( texture, slot ) { + return { + get: get, + dispose: dispose + }; - var textureProperties = properties.get( texture ); +} - if ( texture.isVideoTexture ) updateVideoTexture( texture ); +/** + * @author mrdoob / http://mrdoob.com/ + */ - if ( texture.version > 0 && textureProperties.__version !== texture.version ) { +function UniformsCache() { - var image = texture.image; + var lights = {}; - if ( image === undefined ) { + return { - console.warn( 'THREE.WebGLRenderer: Texture marked for update but image is undefined', texture ); + get: function ( light ) { - } else if ( image.complete === false ) { + if ( lights[ light.id ] !== undefined ) { - console.warn( 'THREE.WebGLRenderer: Texture marked for update but image is incomplete', texture ); + return lights[ light.id ]; - } else { + } - uploadTexture( textureProperties, texture, slot ); - return; + var uniforms; - } + switch ( light.type ) { - } + case 'DirectionalLight': + uniforms = { + direction: new Vector3(), + color: new Color(), - state.activeTexture( _gl.TEXTURE0 + slot ); - state.bindTexture( _gl.TEXTURE_2D, textureProperties.__webglTexture ); + shadow: false, + shadowBias: 0, + shadowRadius: 1, + shadowMapSize: new Vector2() + }; + break; - } + case 'SpotLight': + uniforms = { + position: new Vector3(), + direction: new Vector3(), + color: new Color(), + distance: 0, + coneCos: 0, + penumbraCos: 0, + decay: 0, - function setTextureCube( texture, slot ) { + shadow: false, + shadowBias: 0, + shadowRadius: 1, + shadowMapSize: new Vector2() + }; + break; - var textureProperties = properties.get( texture ); + case 'PointLight': + uniforms = { + position: new Vector3(), + color: new Color(), + distance: 0, + decay: 0, - if ( texture.image.length === 6 ) { + shadow: false, + shadowBias: 0, + shadowRadius: 1, + shadowMapSize: new Vector2(), + shadowCameraNear: 1, + shadowCameraFar: 1000 + }; + break; - if ( texture.version > 0 && textureProperties.__version !== texture.version ) { + case 'HemisphereLight': + uniforms = { + direction: new Vector3(), + skyColor: new Color(), + groundColor: new Color() + }; + break; - if ( ! textureProperties.__image__webglTextureCube ) { + case 'RectAreaLight': + uniforms = { + color: new Color(), + position: new Vector3(), + halfWidth: new Vector3(), + halfHeight: new Vector3() + // TODO (abelnation): set RectAreaLight shadow uniforms + }; + break; - texture.addEventListener( 'dispose', onTextureDispose ); + } - textureProperties.__image__webglTextureCube = _gl.createTexture(); + lights[ light.id ] = uniforms; - infoMemory.textures ++; + return uniforms; - } + } - state.activeTexture( _gl.TEXTURE0 + slot ); - state.bindTexture( _gl.TEXTURE_CUBE_MAP, textureProperties.__image__webglTextureCube ); + }; - _gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, texture.flipY ); +} - var isCompressed = ( texture && texture.isCompressedTexture ); - var isDataTexture = ( texture.image[ 0 ] && texture.image[ 0 ].isDataTexture ); +var count = 0; - var cubeImage = []; +function WebGLLights() { - for ( var i = 0; i < 6; i ++ ) { + var cache = new UniformsCache(); - if ( ! isCompressed && ! isDataTexture ) { + var state = { - cubeImage[ i ] = clampToMaxSize( texture.image[ i ], capabilities.maxCubemapSize ); + id: count ++, - } else { + hash: { + stateID: - 1, + directionalLength: - 1, + pointLength: - 1, + spotLength: - 1, + rectAreaLength: - 1, + hemiLength: - 1, + shadowsLength: - 1 + }, - cubeImage[ i ] = isDataTexture ? texture.image[ i ].image : texture.image[ i ]; + ambient: [ 0, 0, 0 ], + directional: [], + directionalShadowMap: [], + directionalShadowMatrix: [], + spot: [], + spotShadowMap: [], + spotShadowMatrix: [], + rectArea: [], + point: [], + pointShadowMap: [], + pointShadowMatrix: [], + hemi: [] - } + }; - } + var vector3 = new Vector3(); + var matrix4 = new Matrix4(); + var matrix42 = new Matrix4(); - var image = cubeImage[ 0 ], - isPowerOfTwoImage = isPowerOfTwo( image ), - glFormat = utils.convert( texture.format ), - glType = utils.convert( texture.type ); + function setup( lights, shadows, camera ) { - setTextureParameters( _gl.TEXTURE_CUBE_MAP, texture, isPowerOfTwoImage ); + var r = 0, g = 0, b = 0; - for ( var i = 0; i < 6; i ++ ) { + var directionalLength = 0; + var pointLength = 0; + var spotLength = 0; + var rectAreaLength = 0; + var hemiLength = 0; - if ( ! isCompressed ) { + var viewMatrix = camera.matrixWorldInverse; - if ( isDataTexture ) { + for ( var i = 0, l = lights.length; i < l; i ++ ) { - state.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glFormat, cubeImage[ i ].width, cubeImage[ i ].height, 0, glFormat, glType, cubeImage[ i ].data ); + var light = lights[ i ]; - } else { + var color = light.color; + var intensity = light.intensity; + var distance = light.distance; - state.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glFormat, glFormat, glType, cubeImage[ i ] ); + var shadowMap = ( light.shadow && light.shadow.map ) ? light.shadow.map.texture : null; - } + if ( light.isAmbientLight ) { - } else { + r += color.r * intensity; + g += color.g * intensity; + b += color.b * intensity; - var mipmap, mipmaps = cubeImage[ i ].mipmaps; + } else if ( light.isDirectionalLight ) { - for ( var j = 0, jl = mipmaps.length; j < jl; j ++ ) { + var uniforms = cache.get( light ); - mipmap = mipmaps[ j ]; + 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 ( texture.format !== RGBAFormat && texture.format !== RGBFormat ) { + uniforms.shadow = light.castShadow; - if ( state.getCompressedTextureFormats().indexOf( glFormat ) > - 1 ) { + if ( light.castShadow ) { - state.compressedTexImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glFormat, mipmap.width, mipmap.height, 0, mipmap.data ); + var shadow = light.shadow; - } else { + uniforms.shadowBias = shadow.bias; + uniforms.shadowRadius = shadow.radius; + uniforms.shadowMapSize = shadow.mapSize; - console.warn( 'THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .setTextureCube()' ); + } - } + state.directionalShadowMap[ directionalLength ] = shadowMap; + state.directionalShadowMatrix[ directionalLength ] = light.shadow.matrix; + state.directional[ directionalLength ] = uniforms; - } else { + directionalLength ++; - state.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data ); + } else if ( light.isSpotLight ) { - } + var uniforms = cache.get( light ); - } + uniforms.position.setFromMatrixPosition( light.matrixWorld ); + uniforms.position.applyMatrix4( viewMatrix ); - } + uniforms.color.copy( color ).multiplyScalar( intensity ); + uniforms.distance = distance; - } + uniforms.direction.setFromMatrixPosition( light.matrixWorld ); + vector3.setFromMatrixPosition( light.target.matrixWorld ); + uniforms.direction.sub( vector3 ); + uniforms.direction.transformDirection( viewMatrix ); - if ( textureNeedsGenerateMipmaps( texture, isPowerOfTwoImage ) ) { + 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 ) { + + var shadow = light.shadow; - _gl.generateMipmap( _gl.TEXTURE_CUBE_MAP ); + uniforms.shadowBias = shadow.bias; + uniforms.shadowRadius = shadow.radius; + uniforms.shadowMapSize = shadow.mapSize; } - textureProperties.__version = texture.version; + state.spotShadowMap[ spotLength ] = shadowMap; + state.spotShadowMatrix[ spotLength ] = light.shadow.matrix; + state.spot[ spotLength ] = uniforms; - if ( texture.onUpdate ) texture.onUpdate( texture ); + spotLength ++; - } else { + } else if ( light.isRectAreaLight ) { - state.activeTexture( _gl.TEXTURE0 + slot ); - state.bindTexture( _gl.TEXTURE_CUBE_MAP, textureProperties.__image__webglTextureCube ); + 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 ) ); - } + // (b) intensity is the brightness of the light + uniforms.color.copy( color ).multiplyScalar( intensity ); - } + uniforms.position.setFromMatrixPosition( light.matrixWorld ); + uniforms.position.applyMatrix4( viewMatrix ); - function setTextureCubeDynamic( texture, slot ) { + // extract local rotation of light to derive width/height half vectors + matrix42.identity(); + matrix4.copy( light.matrixWorld ); + matrix4.premultiply( viewMatrix ); + matrix42.extractRotation( matrix4 ); - state.activeTexture( _gl.TEXTURE0 + slot ); - state.bindTexture( _gl.TEXTURE_CUBE_MAP, properties.get( texture ).__webglTexture ); + uniforms.halfWidth.set( light.width * 0.5, 0.0, 0.0 ); + uniforms.halfHeight.set( 0.0, light.height * 0.5, 0.0 ); - } + uniforms.halfWidth.applyMatrix4( matrix42 ); + uniforms.halfHeight.applyMatrix4( matrix42 ); - function setTextureParameters( textureType, texture, isPowerOfTwoImage ) { + // TODO (abelnation): RectAreaLight distance? + // uniforms.distance = distance; - var extension; + state.rectArea[ rectAreaLength ] = uniforms; - if ( isPowerOfTwoImage ) { + rectAreaLength ++; - _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_S, utils.convert( texture.wrapS ) ); - _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_T, utils.convert( texture.wrapT ) ); + } else if ( light.isPointLight ) { - _gl.texParameteri( textureType, _gl.TEXTURE_MAG_FILTER, utils.convert( texture.magFilter ) ); - _gl.texParameteri( textureType, _gl.TEXTURE_MIN_FILTER, utils.convert( texture.minFilter ) ); + var uniforms = cache.get( light ); - } else { + uniforms.position.setFromMatrixPosition( light.matrixWorld ); + uniforms.position.applyMatrix4( viewMatrix ); - _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_S, _gl.CLAMP_TO_EDGE ); - _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_T, _gl.CLAMP_TO_EDGE ); + uniforms.color.copy( light.color ).multiplyScalar( light.intensity ); + uniforms.distance = light.distance; + uniforms.decay = light.decay; - if ( texture.wrapS !== ClampToEdgeWrapping || texture.wrapT !== ClampToEdgeWrapping ) { + uniforms.shadow = light.castShadow; - console.warn( 'THREE.WebGLRenderer: Texture is not power of two. Texture.wrapS and Texture.wrapT should be set to THREE.ClampToEdgeWrapping.', texture ); + if ( light.castShadow ) { - } + var shadow = light.shadow; - _gl.texParameteri( textureType, _gl.TEXTURE_MAG_FILTER, filterFallback( texture.magFilter ) ); - _gl.texParameteri( textureType, _gl.TEXTURE_MIN_FILTER, filterFallback( texture.minFilter ) ); + uniforms.shadowBias = shadow.bias; + uniforms.shadowRadius = shadow.radius; + uniforms.shadowMapSize = shadow.mapSize; + uniforms.shadowCameraNear = shadow.camera.near; + uniforms.shadowCameraFar = shadow.camera.far; - if ( texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter ) { + } - console.warn( 'THREE.WebGLRenderer: Texture is not power of two. Texture.minFilter should be set to THREE.NearestFilter or THREE.LinearFilter.', texture ); + state.pointShadowMap[ pointLength ] = shadowMap; + state.pointShadowMatrix[ pointLength ] = light.shadow.matrix; + state.point[ pointLength ] = uniforms; - } + pointLength ++; - } + } else if ( light.isHemisphereLight ) { - extension = extensions.get( 'EXT_texture_filter_anisotropic' ); + var uniforms = cache.get( light ); - if ( extension ) { + uniforms.direction.setFromMatrixPosition( light.matrixWorld ); + uniforms.direction.transformDirection( viewMatrix ); + uniforms.direction.normalize(); - if ( texture.type === FloatType && extensions.get( 'OES_texture_float_linear' ) === null ) return; - if ( texture.type === HalfFloatType && extensions.get( 'OES_texture_half_float_linear' ) === null ) return; + uniforms.skyColor.copy( light.color ).multiplyScalar( intensity ); + uniforms.groundColor.copy( light.groundColor ).multiplyScalar( intensity ); - if ( texture.anisotropy > 1 || properties.get( texture ).__currentAnisotropy ) { + state.hemi[ hemiLength ] = uniforms; - _gl.texParameterf( textureType, extension.TEXTURE_MAX_ANISOTROPY_EXT, Math.min( texture.anisotropy, capabilities.getMaxAnisotropy() ) ); - properties.get( texture ).__currentAnisotropy = texture.anisotropy; + hemiLength ++; } } - } + state.ambient[ 0 ] = r; + state.ambient[ 1 ] = g; + state.ambient[ 2 ] = b; - function uploadTexture( textureProperties, texture, slot ) { + state.directional.length = directionalLength; + state.spot.length = spotLength; + state.rectArea.length = rectAreaLength; + state.point.length = pointLength; + state.hemi.length = hemiLength; - if ( textureProperties.__webglInit === undefined ) { + 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; - textureProperties.__webglInit = true; + } - texture.addEventListener( 'dispose', onTextureDispose ); + return { + setup: setup, + state: state + }; - textureProperties.__webglTexture = _gl.createTexture(); +} - infoMemory.textures ++; +/** + * @author Mugen87 / https://github.com/Mugen87 + */ - } +function WebGLRenderState() { - state.activeTexture( _gl.TEXTURE0 + slot ); - state.bindTexture( _gl.TEXTURE_2D, textureProperties.__webglTexture ); + var lights = new WebGLLights(); - _gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, texture.flipY ); - _gl.pixelStorei( _gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultiplyAlpha ); - _gl.pixelStorei( _gl.UNPACK_ALIGNMENT, texture.unpackAlignment ); + var lightsArray = []; + var shadowsArray = []; - var image = clampToMaxSize( texture.image, capabilities.maxTextureSize ); - - if ( textureNeedsPowerOfTwo( texture ) && isPowerOfTwo( image ) === false ) { - - image = makePowerOfTwo( image ); - - } + function init() { - var isPowerOfTwoImage = isPowerOfTwo( image ), - glFormat = utils.convert( texture.format ), - glType = utils.convert( texture.type ); + lightsArray.length = 0; + shadowsArray.length = 0; - setTextureParameters( _gl.TEXTURE_2D, texture, isPowerOfTwoImage ); + } - var mipmap, mipmaps = texture.mipmaps; + function pushLight( light ) { - if ( texture.isDepthTexture ) { + lightsArray.push( light ); - // populate depth texture with dummy data + } - var internalFormat = _gl.DEPTH_COMPONENT; + function pushShadow( shadowLight ) { - if ( texture.type === FloatType ) { + shadowsArray.push( shadowLight ); - if ( ! _isWebGL2 ) throw new Error( 'Float Depth Texture only supported in WebGL2.0' ); - internalFormat = _gl.DEPTH_COMPONENT32F; + } - } else if ( _isWebGL2 ) { + function setupLights( camera ) { - // WebGL 2.0 requires signed internalformat for glTexImage2D - internalFormat = _gl.DEPTH_COMPONENT16; + lights.setup( lightsArray, shadowsArray, camera ); - } + } - if ( texture.format === DepthFormat && internalFormat === _gl.DEPTH_COMPONENT ) { + var state = { + lightsArray: lightsArray, + shadowsArray: shadowsArray, - // 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 ) { + lights: lights + }; - console.warn( 'THREE.WebGLRenderer: Use UnsignedShortType or UnsignedIntType for DepthFormat DepthTexture.' ); + return { + init: init, + state: state, + setupLights: setupLights, - texture.type = UnsignedShortType; - glType = utils.convert( texture.type ); + pushLight: pushLight, + pushShadow: pushShadow + }; - } +} - } +function WebGLRenderStates() { - // Depth stencil textures need the DEPTH_STENCIL internal format - // (https://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/) - if ( texture.format === DepthStencilFormat ) { + var renderStates = {}; - internalFormat = _gl.DEPTH_STENCIL; + function get( scene, camera ) { - // 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 ) { + var renderState; - console.warn( 'THREE.WebGLRenderer: Use UnsignedInt248Type for DepthStencilFormat DepthTexture.' ); + if ( renderStates[ scene.id ] === undefined ) { - texture.type = UnsignedInt248Type; - glType = utils.convert( texture.type ); + renderState = new WebGLRenderState(); + renderStates[ scene.id ] = {}; + renderStates[ scene.id ][ camera.id ] = renderState; - } + } else { - } + if ( renderStates[ scene.id ][ camera.id ] === undefined ) { - state.texImage2D( _gl.TEXTURE_2D, 0, internalFormat, image.width, image.height, 0, glFormat, glType, null ); + renderState = new WebGLRenderState(); + renderStates[ scene.id ][ camera.id ] = renderState; - } else if ( texture.isDataTexture ) { + } else { - // 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 + renderState = renderStates[ scene.id ][ camera.id ]; - if ( mipmaps.length > 0 && isPowerOfTwoImage ) { + } - for ( var i = 0, il = mipmaps.length; i < il; i ++ ) { + } - mipmap = mipmaps[ i ]; - state.texImage2D( _gl.TEXTURE_2D, i, glFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data ); + return renderState; - } + } - texture.generateMipmaps = false; + function dispose() { - } else { + renderStates = {}; - state.texImage2D( _gl.TEXTURE_2D, 0, glFormat, image.width, image.height, 0, glFormat, glType, image.data ); + } - } + return { + get: get, + dispose: dispose + }; - } else if ( texture.isCompressedTexture ) { +} - for ( var i = 0, il = mipmaps.length; i < il; i ++ ) { +/** + * @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: + * } + */ - mipmap = mipmaps[ i ]; +function MeshDepthMaterial( parameters ) { - if ( texture.format !== RGBAFormat && texture.format !== RGBFormat ) { + Material.call( this ); - if ( state.getCompressedTextureFormats().indexOf( glFormat ) > - 1 ) { + this.type = 'MeshDepthMaterial'; - state.compressedTexImage2D( _gl.TEXTURE_2D, i, glFormat, mipmap.width, mipmap.height, 0, mipmap.data ); + this.depthPacking = BasicDepthPacking; - } else { + this.skinning = false; + this.morphTargets = false; - console.warn( 'THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .uploadTexture()' ); + this.map = null; - } + this.alphaMap = null; - } else { + this.displacementMap = null; + this.displacementScale = 1; + this.displacementBias = 0; - state.texImage2D( _gl.TEXTURE_2D, i, glFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data ); + this.wireframe = false; + this.wireframeLinewidth = 1; - } + this.fog = false; + this.lights = false; - } + this.setValues( parameters ); - } else { +} - // regular Texture (image, video, canvas) +MeshDepthMaterial.prototype = Object.create( Material.prototype ); +MeshDepthMaterial.prototype.constructor = MeshDepthMaterial; - // 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 +MeshDepthMaterial.prototype.isMeshDepthMaterial = true; - if ( mipmaps.length > 0 && isPowerOfTwoImage ) { +MeshDepthMaterial.prototype.copy = function ( source ) { - for ( var i = 0, il = mipmaps.length; i < il; i ++ ) { + Material.prototype.copy.call( this, source ); - mipmap = mipmaps[ i ]; - state.texImage2D( _gl.TEXTURE_2D, i, glFormat, glFormat, glType, mipmap ); + this.depthPacking = source.depthPacking; - } + this.skinning = source.skinning; + this.morphTargets = source.morphTargets; - texture.generateMipmaps = false; + this.map = source.map; - } else { + this.alphaMap = source.alphaMap; - state.texImage2D( _gl.TEXTURE_2D, 0, glFormat, glFormat, glType, image ); + this.displacementMap = source.displacementMap; + this.displacementScale = source.displacementScale; + this.displacementBias = source.displacementBias; - } + this.wireframe = source.wireframe; + this.wireframeLinewidth = source.wireframeLinewidth; - } + return this; - if ( textureNeedsGenerateMipmaps( texture, isPowerOfTwoImage ) ) _gl.generateMipmap( _gl.TEXTURE_2D ); +}; - textureProperties.__version = texture.version; +/** + * @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: + * + * } + */ - if ( texture.onUpdate ) texture.onUpdate( texture ); +function MeshDistanceMaterial( parameters ) { - } + Material.call( this ); - // Render targets + this.type = 'MeshDistanceMaterial'; - // Setup storage for target texture and bind it to correct framebuffer - function setupFrameBufferTexture( framebuffer, renderTarget, attachment, textureTarget ) { + this.referencePosition = new Vector3(); + this.nearDistance = 1; + this.farDistance = 1000; - var glFormat = utils.convert( renderTarget.texture.format ); - var glType = utils.convert( renderTarget.texture.type ); - state.texImage2D( textureTarget, 0, glFormat, renderTarget.width, renderTarget.height, 0, glFormat, glType, null ); - _gl.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer ); - _gl.framebufferTexture2D( _gl.FRAMEBUFFER, attachment, textureTarget, properties.get( renderTarget.texture ).__webglTexture, 0 ); - _gl.bindFramebuffer( _gl.FRAMEBUFFER, null ); + this.skinning = false; + this.morphTargets = false; - } + this.map = null; - // Setup storage for internal depth/stencil buffers and bind to correct framebuffer - function setupRenderBufferStorage( renderbuffer, renderTarget ) { + this.alphaMap = null; - _gl.bindRenderbuffer( _gl.RENDERBUFFER, renderbuffer ); + this.displacementMap = null; + this.displacementScale = 1; + this.displacementBias = 0; - if ( renderTarget.depthBuffer && ! renderTarget.stencilBuffer ) { + this.fog = false; + this.lights = false; - _gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.DEPTH_COMPONENT16, renderTarget.width, renderTarget.height ); - _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer ); + this.setValues( parameters ); - } else if ( renderTarget.depthBuffer && renderTarget.stencilBuffer ) { +} - _gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.DEPTH_STENCIL, renderTarget.width, renderTarget.height ); - _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer ); +MeshDistanceMaterial.prototype = Object.create( Material.prototype ); +MeshDistanceMaterial.prototype.constructor = MeshDistanceMaterial; - } else { +MeshDistanceMaterial.prototype.isMeshDistanceMaterial = true; - // FIXME: We don't support !depth !stencil - _gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.RGBA4, renderTarget.width, renderTarget.height ); +MeshDistanceMaterial.prototype.copy = function ( source ) { - } + Material.prototype.copy.call( this, source ); - _gl.bindRenderbuffer( _gl.RENDERBUFFER, null ); + this.referencePosition.copy( source.referencePosition ); + this.nearDistance = source.nearDistance; + this.farDistance = source.farDistance; - } + this.skinning = source.skinning; + this.morphTargets = source.morphTargets; - // Setup resources for a Depth Texture for a FBO (needs an extension) - function setupDepthTexture( framebuffer, renderTarget ) { + this.map = source.map; - var isCube = ( renderTarget && renderTarget.isWebGLRenderTargetCube ); - if ( isCube ) throw new Error( 'Depth Texture with cube render targets is not supported' ); + this.alphaMap = source.alphaMap; - _gl.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer ); + this.displacementMap = source.displacementMap; + this.displacementScale = source.displacementScale; + this.displacementBias = source.displacementBias; - if ( ! ( renderTarget.depthTexture && renderTarget.depthTexture.isDepthTexture ) ) { + return this; - throw new Error( 'renderTarget.depthTexture must be an instance of THREE.DepthTexture' ); +}; - } +/** + * @author alteredq / http://alteredqualia.com/ + * @author mrdoob / http://mrdoob.com/ + */ - // 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 ) { +function WebGLShadowMap( _renderer, _objects, maxTextureSize ) { - renderTarget.depthTexture.image.width = renderTarget.width; - renderTarget.depthTexture.image.height = renderTarget.height; - renderTarget.depthTexture.needsUpdate = true; + var _frustum = new Frustum(), + _projScreenMatrix = new Matrix4(), - } + _shadowMapSize = new Vector2(), + _maxShadowMapSize = new Vector2( maxTextureSize, maxTextureSize ), - setTexture2D( renderTarget.depthTexture, 0 ); + _lookTarget = new Vector3(), + _lightPositionWorld = new Vector3(), - var webglDepthTexture = properties.get( renderTarget.depthTexture ).__webglTexture; + _MorphingFlag = 1, + _SkinningFlag = 2, - if ( renderTarget.depthTexture.format === DepthFormat ) { + _NumberOfMaterialVariants = ( _MorphingFlag | _SkinningFlag ) + 1, - _gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.TEXTURE_2D, webglDepthTexture, 0 ); + _depthMaterials = new Array( _NumberOfMaterialVariants ), + _distanceMaterials = new Array( _NumberOfMaterialVariants ), - } else if ( renderTarget.depthTexture.format === DepthStencilFormat ) { + _materialCache = {}; - _gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.TEXTURE_2D, webglDepthTexture, 0 ); + var shadowSide = { 0: BackSide, 1: FrontSide, 2: DoubleSide }; - } else { + 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 ) + ]; - throw new Error( 'Unknown depthTexture format' ); + 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 cube2DViewPorts = [ + new Vector4(), new Vector4(), new Vector4(), + new Vector4(), new Vector4(), new Vector4() + ]; - } + // init - // Setup GL resources for a non-texture depth buffer - function setupDepthRenderbuffer( renderTarget ) { + for ( var i = 0; i !== _NumberOfMaterialVariants; ++ i ) { - var renderTargetProperties = properties.get( renderTarget ); + var useMorphing = ( i & _MorphingFlag ) !== 0; + var useSkinning = ( i & _SkinningFlag ) !== 0; - var isCube = ( renderTarget.isWebGLRenderTargetCube === true ); + var depthMaterial = new MeshDepthMaterial( { - if ( renderTarget.depthTexture ) { + depthPacking: RGBADepthPacking, - if ( isCube ) throw new Error( 'target.depthTexture not supported in Cube render targets' ); + morphTargets: useMorphing, + skinning: useSkinning - setupDepthTexture( renderTargetProperties.__webglFramebuffer, renderTarget ); + } ); - } else { + _depthMaterials[ i ] = depthMaterial; - if ( isCube ) { + // - renderTargetProperties.__webglDepthbuffer = []; + var distanceMaterial = new MeshDistanceMaterial( { - for ( var i = 0; i < 6; i ++ ) { + morphTargets: useMorphing, + skinning: useSkinning - _gl.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglFramebuffer[ i ] ); - renderTargetProperties.__webglDepthbuffer[ i ] = _gl.createRenderbuffer(); - setupRenderBufferStorage( renderTargetProperties.__webglDepthbuffer[ i ], renderTarget ); + } ); - } + _distanceMaterials[ i ] = distanceMaterial; - } else { + } - _gl.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglFramebuffer ); - renderTargetProperties.__webglDepthbuffer = _gl.createRenderbuffer(); - setupRenderBufferStorage( renderTargetProperties.__webglDepthbuffer, renderTarget ); + // - } + var scope = this; - } + this.enabled = false; - _gl.bindFramebuffer( _gl.FRAMEBUFFER, null ); + this.autoUpdate = true; + this.needsUpdate = false; - } + this.type = PCFShadowMap; - // Set up GL resources for the render target - function setupRenderTarget( renderTarget ) { + this.render = function ( lights, scene, camera ) { - var renderTargetProperties = properties.get( renderTarget ); - var textureProperties = properties.get( renderTarget.texture ); + if ( scope.enabled === false ) return; + if ( scope.autoUpdate === false && scope.needsUpdate === false ) return; - renderTarget.addEventListener( 'dispose', onRenderTargetDispose ); + if ( lights.length === 0 ) return; - textureProperties.__webglTexture = _gl.createTexture(); + // TODO Clean up (needed in case of contextlost) + var _gl = _renderer.context; + var _state = _renderer.state; - infoMemory.textures ++; + // 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 isCube = ( renderTarget.isWebGLRenderTargetCube === true ); - var isTargetPowerOfTwo = isPowerOfTwo( renderTarget ); + // render depth map - // Setup framebuffer + var faceCount; - if ( isCube ) { + for ( var i = 0, il = lights.length; i < il; i ++ ) { - renderTargetProperties.__webglFramebuffer = []; + var light = lights[ i ]; + var shadow = light.shadow; + var isPointLight = light && light.isPointLight; - for ( var i = 0; i < 6; i ++ ) { + if ( shadow === undefined ) { - renderTargetProperties.__webglFramebuffer[ i ] = _gl.createFramebuffer(); + console.warn( 'THREE.WebGLShadowMap:', light, 'has no shadow.' ); + continue; } - } else { - - renderTargetProperties.__webglFramebuffer = _gl.createFramebuffer(); + var shadowCamera = shadow.camera; - } + _shadowMapSize.copy( shadow.mapSize ); + _shadowMapSize.min( _maxShadowMapSize ); - // Setup color buffer + if ( isPointLight ) { - if ( isCube ) { + var vpWidth = _shadowMapSize.x; + var vpHeight = _shadowMapSize.y; - state.bindTexture( _gl.TEXTURE_CUBE_MAP, textureProperties.__webglTexture ); - setTextureParameters( _gl.TEXTURE_CUBE_MAP, renderTarget.texture, isTargetPowerOfTwo ); + // 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 - for ( var i = 0; i < 6; i ++ ) { + // 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 ); - setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer[ i ], renderTarget, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i ); + _shadowMapSize.x *= 4.0; + _shadowMapSize.y *= 2.0; } - if ( textureNeedsGenerateMipmaps( renderTarget.texture, isTargetPowerOfTwo ) ) _gl.generateMipmap( _gl.TEXTURE_CUBE_MAP ); - state.bindTexture( _gl.TEXTURE_CUBE_MAP, null ); + if ( shadow.map === null ) { - } else { + var pars = { minFilter: NearestFilter, magFilter: NearestFilter, format: RGBAFormat }; - state.bindTexture( _gl.TEXTURE_2D, textureProperties.__webglTexture ); - setTextureParameters( _gl.TEXTURE_2D, renderTarget.texture, isTargetPowerOfTwo ); - setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer, renderTarget, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_2D ); + shadow.map = new WebGLRenderTarget( _shadowMapSize.x, _shadowMapSize.y, pars ); + shadow.map.texture.name = light.name + ".shadowMap"; - if ( textureNeedsGenerateMipmaps( renderTarget.texture, isTargetPowerOfTwo ) ) _gl.generateMipmap( _gl.TEXTURE_2D ); - state.bindTexture( _gl.TEXTURE_2D, null ); + shadowCamera.updateProjectionMatrix(); - } + } - // Setup depth and stencil buffers + if ( shadow.isSpotLightShadow ) { - if ( renderTarget.depthBuffer ) { + shadow.update( light ); - setupDepthRenderbuffer( renderTarget ); + } - } + var shadowMap = shadow.map; + var shadowMatrix = shadow.matrix; - } + _lightPositionWorld.setFromMatrixPosition( light.matrixWorld ); + shadowCamera.position.copy( _lightPositionWorld ); - function updateRenderTargetMipmap( renderTarget ) { + if ( isPointLight ) { - var texture = renderTarget.texture; - var isTargetPowerOfTwo = isPowerOfTwo( renderTarget ); + faceCount = 6; - if ( textureNeedsGenerateMipmaps( texture, isTargetPowerOfTwo ) ) { + // for point lights we set the shadow matrix to be a translation-only matrix + // equal to inverse of the light's position - var target = renderTarget.isWebGLRenderTargetCube ? _gl.TEXTURE_CUBE_MAP : _gl.TEXTURE_2D; - var webglTexture = properties.get( texture ).__webglTexture; + shadowMatrix.makeTranslation( - _lightPositionWorld.x, - _lightPositionWorld.y, - _lightPositionWorld.z ); - state.bindTexture( target, webglTexture ); - _gl.generateMipmap( target ); - state.bindTexture( target, null ); + } else { - } + faceCount = 1; - } + _lookTarget.setFromMatrixPosition( light.target.matrixWorld ); + shadowCamera.lookAt( _lookTarget ); + shadowCamera.updateMatrixWorld(); - function updateVideoTexture( texture ) { + // compute shadow matrix - var id = texture.id; - var frame = infoRender.frame; + 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 + ); - // Check the last frame we updated the VideoTexture + shadowMatrix.multiply( shadowCamera.projectionMatrix ); + shadowMatrix.multiply( shadowCamera.matrixWorldInverse ); - if ( _videoTextures[ id ] !== frame ) { + } - _videoTextures[ id ] = frame; - texture.update(); + _renderer.setRenderTarget( shadowMap ); + _renderer.clear(); - } + // render shadow map for each cube face (if omni-directional) or + // run a single pass if not - } + for ( var face = 0; face < faceCount; face ++ ) { - this.setTexture2D = setTexture2D; - this.setTextureCube = setTextureCube; - this.setTextureCubeDynamic = setTextureCubeDynamic; - this.setupRenderTarget = setupRenderTarget; - this.updateRenderTargetMipmap = updateRenderTargetMipmap; + if ( isPointLight ) { -} + _lookTarget.copy( shadowCamera.position ); + _lookTarget.add( cubeDirections[ face ] ); + shadowCamera.up.copy( cubeUps[ face ] ); + shadowCamera.lookAt( _lookTarget ); + shadowCamera.updateMatrixWorld(); -/** - * @author fordacious / fordacious.github.io - */ + var vpDimensions = cube2DViewPorts[ face ]; + _state.viewport( vpDimensions ); -function WebGLProperties() { + } - var properties = {}; + // update camera matrices and frustum - function get( object ) { + _projScreenMatrix.multiplyMatrices( shadowCamera.projectionMatrix, shadowCamera.matrixWorldInverse ); + _frustum.setFromMatrix( _projScreenMatrix ); - var uuid = object.uuid; - var map = properties[ uuid ]; + // set object matrices & frustum culling - if ( map === undefined ) { + renderObject( scene, camera, shadowCamera, isPointLight ); - map = {}; - properties[ uuid ] = map; + } } - return map; - - } + scope.needsUpdate = false; - function remove( object ) { + }; - delete properties[ object.uuid ]; + function getDepthMaterial( object, material, isPointLight, lightPositionWorld, shadowCameraNear, shadowCameraFar ) { - } + var geometry = object.geometry; - function update( object, key, value ) { + var result = null; - var uuid = object.uuid; - var map = properties[ uuid ]; + var materialVariants = _depthMaterials; + var customMaterial = object.customDepthMaterial; - map[ key ] = value; + if ( isPointLight ) { - } + materialVariants = _distanceMaterials; + customMaterial = object.customDistanceMaterial; - function dispose() { + } + + if ( ! customMaterial ) { + + var useMorphing = false; + + if ( material.morphTargets ) { + + if ( geometry && geometry.isBufferGeometry ) { + + useMorphing = geometry.morphAttributes && geometry.morphAttributes.position && geometry.morphAttributes.position.length > 0; + + } else if ( geometry && geometry.isGeometry ) { + + useMorphing = geometry.morphTargets && geometry.morphTargets.length > 0; + + } + + } + + if ( object.isSkinnedMesh && material.skinning === false ) { + + console.warn( 'THREE.WebGLShadowMap: THREE.SkinnedMesh with material.skinning set to false:', object ); + + } + + var useSkinning = object.isSkinnedMesh && material.skinning; + + var variantIndex = 0; + + if ( useMorphing ) variantIndex |= _MorphingFlag; + if ( useSkinning ) variantIndex |= _SkinningFlag; + + result = materialVariants[ variantIndex ]; + + } else { + + result = customMaterial; + + } + + if ( _renderer.localClippingEnabled && + material.clipShadows === true && + material.clippingPlanes.length !== 0 ) { + + // in this case we need a unique material instance reflecting the + // appropriate state + + var keyA = result.uuid, keyB = material.uuid; + + var materialsForVariant = _materialCache[ keyA ]; + + if ( materialsForVariant === undefined ) { + + materialsForVariant = {}; + _materialCache[ keyA ] = materialsForVariant; + + } + + var cachedMaterial = materialsForVariant[ keyB ]; + + if ( cachedMaterial === undefined ) { + + cachedMaterial = result.clone(); + materialsForVariant[ keyB ] = cachedMaterial; + + } + + result = cachedMaterial; + + } + + result.visible = material.visible; + result.wireframe = material.wireframe; + + result.side = ( material.shadowSide != null ) ? material.shadowSide : shadowSide[ material.side ]; + + result.clipShadows = material.clipShadows; + result.clippingPlanes = material.clippingPlanes; + result.clipIntersection = material.clipIntersection; + + result.wireframeLinewidth = material.wireframeLinewidth; + result.linewidth = material.linewidth; + + if ( isPointLight && result.isMeshDistanceMaterial ) { + + result.referencePosition.copy( lightPositionWorld ); + result.nearDistance = shadowCameraNear; + result.farDistance = shadowCameraFar; - properties = {}; + } + + return result; } - return { - get: get, - remove: remove, - update: update, - dispose: dispose - }; + function renderObject( object, camera, shadowCamera, isPointLight ) { + + if ( object.visible === false ) return; + + var visible = object.layers.test( camera.layers ); + + if ( visible && ( object.isMesh || object.isLine || object.isPoints ) ) { + + if ( object.castShadow && ( ! object.frustumCulled || _frustum.intersectsObject( object ) ) ) { + + object.modelViewMatrix.multiplyMatrices( shadowCamera.matrixWorldInverse, object.matrixWorld ); + + var geometry = _objects.update( object ); + var material = object.material; + + if ( Array.isArray( material ) ) { + + var groups = geometry.groups; + + for ( var k = 0, kl = groups.length; k < kl; k ++ ) { + + var group = groups[ k ]; + var groupMaterial = material[ group.materialIndex ]; + + if ( groupMaterial && groupMaterial.visible ) { + + var depthMaterial = getDepthMaterial( object, groupMaterial, isPointLight, _lightPositionWorld, shadowCamera.near, shadowCamera.far ); + _renderer.renderBufferDirect( shadowCamera, null, geometry, depthMaterial, object, group ); + + } + + } + + } else if ( material.visible ) { + + var depthMaterial = getDepthMaterial( object, material, isPointLight, _lightPositionWorld, shadowCamera.near, shadowCamera.far ); + _renderer.renderBufferDirect( shadowCamera, null, geometry, depthMaterial, object, null ); + + } + + } + + } + + var children = object.children; + + for ( var i = 0, l = children.length; i < l; i ++ ) { + + renderObject( children[ i ], camera, shadowCamera, isPointLight ); + + } + + } } @@ -21480,7 +20386,7 @@ function WebGLProperties() { * @author mrdoob / http://mrdoob.com/ */ -function WebGLState( gl, extensions, utils ) { +function WebGLState( gl, extensions, utils, capabilities ) { function ColorBuffer() { @@ -21555,11 +20461,11 @@ function WebGLState( gl, extensions, utils ) { if ( depthTest ) { - enable( gl.DEPTH_TEST ); + enable( 2929 ); } else { - disable( gl.DEPTH_TEST ); + disable( 2929 ); } @@ -21586,53 +20492,53 @@ function WebGLState( gl, extensions, utils ) { case NeverDepth: - gl.depthFunc( gl.NEVER ); + gl.depthFunc( 512 ); break; case AlwaysDepth: - gl.depthFunc( gl.ALWAYS ); + gl.depthFunc( 519 ); break; case LessDepth: - gl.depthFunc( gl.LESS ); + gl.depthFunc( 513 ); break; case LessEqualDepth: - gl.depthFunc( gl.LEQUAL ); + gl.depthFunc( 515 ); break; case EqualDepth: - gl.depthFunc( gl.EQUAL ); + gl.depthFunc( 514 ); break; case GreaterEqualDepth: - gl.depthFunc( gl.GEQUAL ); + gl.depthFunc( 518 ); break; case GreaterDepth: - gl.depthFunc( gl.GREATER ); + gl.depthFunc( 516 ); break; case NotEqualDepth: - gl.depthFunc( gl.NOTEQUAL ); + gl.depthFunc( 517 ); break; default: - gl.depthFunc( gl.LEQUAL ); + gl.depthFunc( 515 ); } } else { - gl.depthFunc( gl.LEQUAL ); + gl.depthFunc( 515 ); } @@ -21692,11 +20598,11 @@ function WebGLState( gl, extensions, utils ) { if ( stencilTest ) { - enable( gl.STENCIL_TEST ); + enable( 2960 ); } else { - disable( gl.STENCIL_TEST ); + disable( 2960 ); } @@ -21787,17 +20693,18 @@ function WebGLState( gl, extensions, utils ) { var depthBuffer = new DepthBuffer(); var stencilBuffer = new StencilBuffer(); - var maxVertexAttributes = gl.getParameter( gl.MAX_VERTEX_ATTRIBS ); + var maxVertexAttributes = gl.getParameter( 34921 ); var newAttributes = new Uint8Array( maxVertexAttributes ); var enabledAttributes = new Uint8Array( maxVertexAttributes ); var attributeDivisors = new Uint8Array( maxVertexAttributes ); - var capabilities = {}; + var enabledCapabilities = {}; var compressedTextureFormats = null; var currentProgram = null; + var currentBlendingEnabled = null; var currentBlending = null; var currentBlendEquation = null; var currentBlendSrc = null; @@ -21815,21 +20722,21 @@ function WebGLState( gl, extensions, utils ) { var currentPolygonOffsetFactor = null; var currentPolygonOffsetUnits = null; - var maxTextures = gl.getParameter( gl.MAX_COMBINED_TEXTURE_IMAGE_UNITS ); + var maxTextures = gl.getParameter( 35661 ); var lineWidthAvailable = false; var version = 0; - var glVersion = gl.getParameter( gl.VERSION ); + var glVersion = gl.getParameter( 7938 ); if ( glVersion.indexOf( 'WebGL' ) !== - 1 ) { - version = parseFloat( /^WebGL\ ([0-9])/.exec( glVersion )[ 1 ] ); - lineWidthAvailable = ( version >= 1.0 ); + 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 ); + version = parseFloat( /^OpenGL\ ES\ ([0-9])/.exec( glVersion )[ 1 ] ); + lineWidthAvailable = ( version >= 2.0 ); } @@ -21845,12 +20752,12 @@ function WebGLState( gl, extensions, utils ) { var texture = gl.createTexture(); gl.bindTexture( type, texture ); - gl.texParameteri( type, gl.TEXTURE_MIN_FILTER, gl.NEAREST ); - gl.texParameteri( type, gl.TEXTURE_MAG_FILTER, gl.NEAREST ); + gl.texParameteri( type, 10241, 9728 ); + gl.texParameteri( type, 10240, 9728 ); for ( var i = 0; i < count; i ++ ) { - gl.texImage2D( target + i, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, data ); + gl.texImage2D( target + i, 0, 6408, 1, 1, 0, 6408, 5121, data ); } @@ -21859,8 +20766,8 @@ function WebGLState( gl, extensions, utils ) { } var emptyTextures = {}; - emptyTextures[ gl.TEXTURE_2D ] = createTexture( gl.TEXTURE_2D, gl.TEXTURE_2D, 1 ); - emptyTextures[ gl.TEXTURE_CUBE_MAP ] = createTexture( gl.TEXTURE_CUBE_MAP, gl.TEXTURE_CUBE_MAP_POSITIVE_X, 6 ); + emptyTextures[ 3553 ] = createTexture( 3553, 3553, 1 ); + emptyTextures[ 34067 ] = createTexture( 34067, 34069, 6 ); // init @@ -21868,15 +20775,14 @@ function WebGLState( gl, extensions, utils ) { depthBuffer.setClear( 1 ); stencilBuffer.setClear( 0 ); - enable( gl.DEPTH_TEST ); + enable( 2929 ); depthBuffer.setFunc( LessEqualDepth ); setFlipSided( false ); setCullFace( CullFaceBack ); - enable( gl.CULL_FACE ); + enable( 2884 ); - enable( gl.BLEND ); - setBlending( NormalBlending ); + setBlending( NoBlending ); // @@ -21892,23 +20798,7 @@ function WebGLState( gl, extensions, utils ) { function enableAttribute( attribute ) { - newAttributes[ attribute ] = 1; - - if ( enabledAttributes[ attribute ] === 0 ) { - - gl.enableVertexAttribArray( attribute ); - enabledAttributes[ attribute ] = 1; - - } - - if ( attributeDivisors[ attribute ] !== 0 ) { - - var extension = extensions.get( 'ANGLE_instanced_arrays' ); - - extension.vertexAttribDivisorANGLE( attribute, 0 ); - attributeDivisors[ attribute ] = 0; - - } + enableAttributeAndDivisor( attribute, 0 ); } @@ -21925,9 +20815,9 @@ function WebGLState( gl, extensions, utils ) { if ( attributeDivisors[ attribute ] !== meshPerAttribute ) { - var extension = extensions.get( 'ANGLE_instanced_arrays' ); + var extension = capabilities.isWebGL2 ? gl : extensions.get( 'ANGLE_instanced_arrays' ); - extension.vertexAttribDivisorANGLE( attribute, meshPerAttribute ); + extension[ capabilities.isWebGL2 ? 'vertexAttribDivisor' : 'vertexAttribDivisorANGLE' ]( attribute, meshPerAttribute ); attributeDivisors[ attribute ] = meshPerAttribute; } @@ -21951,10 +20841,10 @@ function WebGLState( gl, extensions, utils ) { function enable( id ) { - if ( capabilities[ id ] !== true ) { + if ( enabledCapabilities[ id ] !== true ) { gl.enable( id ); - capabilities[ id ] = true; + enabledCapabilities[ id ] = true; } @@ -21962,10 +20852,10 @@ function WebGLState( gl, extensions, utils ) { function disable( id ) { - if ( capabilities[ id ] !== false ) { + if ( enabledCapabilities[ id ] !== false ) { gl.disable( id ); - capabilities[ id ] = false; + enabledCapabilities[ id ] = false; } @@ -21982,7 +20872,7 @@ function WebGLState( gl, extensions, utils ) { extensions.get( 'WEBGL_compressed_texture_etc1' ) || extensions.get( 'WEBGL_compressed_texture_astc' ) ) { - var formats = gl.getParameter( gl.COMPRESSED_TEXTURE_FORMATS ); + var formats = gl.getParameter( 34467 ); for ( var i = 0; i < formats.length; i ++ ) { @@ -22016,139 +20906,152 @@ function WebGLState( gl, extensions, utils ) { function setBlending( blending, blendEquation, blendSrc, blendDst, blendEquationAlpha, blendSrcAlpha, blendDstAlpha, premultipliedAlpha ) { - if ( blending !== NoBlending ) { + if ( blending === NoBlending ) { - enable( gl.BLEND ); + if ( currentBlendingEnabled ) { - } else { + disable( 3042 ); + currentBlendingEnabled = false; + + } - disable( gl.BLEND ); + return; } - if ( blending !== CustomBlending ) { + if ( ! currentBlendingEnabled ) { - if ( blending !== currentBlending || premultipliedAlpha !== currentPremultipledAlpha ) { + enable( 3042 ); + currentBlendingEnabled = true; - switch ( blending ) { + } - case AdditiveBlending: + if ( blending !== CustomBlending ) { - if ( premultipliedAlpha ) { + if ( blending !== currentBlending || premultipliedAlpha !== currentPremultipledAlpha ) { - gl.blendEquationSeparate( gl.FUNC_ADD, gl.FUNC_ADD ); - gl.blendFuncSeparate( gl.ONE, gl.ONE, gl.ONE, gl.ONE ); + if ( currentBlendEquation !== AddEquation || currentBlendEquationAlpha !== AddEquation ) { - } else { + gl.blendEquation( 32774 ); - gl.blendEquation( gl.FUNC_ADD ); - gl.blendFunc( gl.SRC_ALPHA, gl.ONE ); + currentBlendEquation = AddEquation; + currentBlendEquationAlpha = AddEquation; - } - break; + } - case SubtractiveBlending: + if ( premultipliedAlpha ) { - if ( premultipliedAlpha ) { + switch ( blending ) { - gl.blendEquationSeparate( gl.FUNC_ADD, gl.FUNC_ADD ); - gl.blendFuncSeparate( gl.ZERO, gl.ZERO, gl.ONE_MINUS_SRC_COLOR, gl.ONE_MINUS_SRC_ALPHA ); + case NormalBlending: + gl.blendFuncSeparate( 1, 771, 1, 771 ); + break; - } else { + case AdditiveBlending: + gl.blendFunc( 1, 1 ); + break; - gl.blendEquation( gl.FUNC_ADD ); - gl.blendFunc( gl.ZERO, gl.ONE_MINUS_SRC_COLOR ); + case SubtractiveBlending: + gl.blendFuncSeparate( 0, 0, 769, 771 ); + break; - } - break; + case MultiplyBlending: + gl.blendFuncSeparate( 0, 768, 0, 770 ); + break; - case MultiplyBlending: + default: + console.error( 'THREE.WebGLState: Invalid blending: ', blending ); + break; - if ( premultipliedAlpha ) { + } - gl.blendEquationSeparate( gl.FUNC_ADD, gl.FUNC_ADD ); - gl.blendFuncSeparate( gl.ZERO, gl.SRC_COLOR, gl.ZERO, gl.SRC_ALPHA ); + } else { - } else { + switch ( blending ) { - gl.blendEquation( gl.FUNC_ADD ); - gl.blendFunc( gl.ZERO, gl.SRC_COLOR ); + case NormalBlending: + gl.blendFuncSeparate( 770, 771, 1, 771 ); + break; - } - break; + case AdditiveBlending: + gl.blendFunc( 770, 1 ); + break; - default: + case SubtractiveBlending: + gl.blendFunc( 0, 769 ); + break; - if ( premultipliedAlpha ) { + case MultiplyBlending: + gl.blendFunc( 0, 768 ); + break; - gl.blendEquationSeparate( gl.FUNC_ADD, gl.FUNC_ADD ); - gl.blendFuncSeparate( gl.ONE, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA ); + default: + console.error( 'THREE.WebGLState: Invalid blending: ', blending ); + break; - } else { + } - gl.blendEquationSeparate( gl.FUNC_ADD, gl.FUNC_ADD ); - gl.blendFuncSeparate( gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA ); + } - } + currentBlendSrc = null; + currentBlendDst = null; + currentBlendSrcAlpha = null; + currentBlendDstAlpha = null; - } + currentBlending = blending; + currentPremultipledAlpha = premultipliedAlpha; } - currentBlendEquation = null; - currentBlendSrc = null; - currentBlendDst = null; - currentBlendEquationAlpha = null; - currentBlendSrcAlpha = null; - currentBlendDstAlpha = null; + return; - } else { + } - blendEquationAlpha = blendEquationAlpha || blendEquation; - blendSrcAlpha = blendSrcAlpha || blendSrc; - blendDstAlpha = blendDstAlpha || blendDst; + // custom blending - if ( blendEquation !== currentBlendEquation || blendEquationAlpha !== currentBlendEquationAlpha ) { + blendEquationAlpha = blendEquationAlpha || blendEquation; + blendSrcAlpha = blendSrcAlpha || blendSrc; + blendDstAlpha = blendDstAlpha || blendDst; - gl.blendEquationSeparate( utils.convert( blendEquation ), utils.convert( blendEquationAlpha ) ); + if ( blendEquation !== currentBlendEquation || blendEquationAlpha !== currentBlendEquationAlpha ) { - currentBlendEquation = blendEquation; - currentBlendEquationAlpha = blendEquationAlpha; + gl.blendEquationSeparate( utils.convert( blendEquation ), utils.convert( blendEquationAlpha ) ); - } + currentBlendEquation = blendEquation; + currentBlendEquationAlpha = blendEquationAlpha; - if ( blendSrc !== currentBlendSrc || blendDst !== currentBlendDst || blendSrcAlpha !== currentBlendSrcAlpha || blendDstAlpha !== currentBlendDstAlpha ) { + } - gl.blendFuncSeparate( utils.convert( blendSrc ), utils.convert( blendDst ), utils.convert( blendSrcAlpha ), utils.convert( blendDstAlpha ) ); + if ( blendSrc !== currentBlendSrc || blendDst !== currentBlendDst || blendSrcAlpha !== currentBlendSrcAlpha || blendDstAlpha !== currentBlendDstAlpha ) { - currentBlendSrc = blendSrc; - currentBlendDst = blendDst; - currentBlendSrcAlpha = blendSrcAlpha; - currentBlendDstAlpha = blendDstAlpha; + gl.blendFuncSeparate( utils.convert( blendSrc ), utils.convert( blendDst ), utils.convert( blendSrcAlpha ), utils.convert( blendDstAlpha ) ); - } + currentBlendSrc = blendSrc; + currentBlendDst = blendDst; + currentBlendSrcAlpha = blendSrcAlpha; + currentBlendDstAlpha = blendDstAlpha; } currentBlending = blending; - currentPremultipledAlpha = premultipliedAlpha; + currentPremultipledAlpha = null; } function setMaterial( material, frontFaceCW ) { material.side === DoubleSide - ? disable( gl.CULL_FACE ) - : enable( gl.CULL_FACE ); + ? disable( 2884 ) + : enable( 2884 ); var flipSided = ( material.side === BackSide ); if ( frontFaceCW ) flipSided = ! flipSided; setFlipSided( flipSided ); - material.transparent === true - ? setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst, material.blendEquationAlpha, material.blendSrcAlpha, material.blendDstAlpha, material.premultipliedAlpha ) - : setBlending( NoBlending ); + ( material.blending === NormalBlending && material.transparent === false ) + ? setBlending( NoBlending ) + : setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst, material.blendEquationAlpha, material.blendSrcAlpha, material.blendDstAlpha, material.premultipliedAlpha ); depthBuffer.setFunc( material.depthFunc ); depthBuffer.setTest( material.depthTest ); @@ -22167,11 +21070,11 @@ function WebGLState( gl, extensions, utils ) { if ( flipSided ) { - gl.frontFace( gl.CW ); + gl.frontFace( 2304 ); } else { - gl.frontFace( gl.CCW ); + gl.frontFace( 2305 ); } @@ -22185,21 +21088,21 @@ function WebGLState( gl, extensions, utils ) { if ( cullFace !== CullFaceNone ) { - enable( gl.CULL_FACE ); + enable( 2884 ); if ( cullFace !== currentCullFace ) { if ( cullFace === CullFaceBack ) { - gl.cullFace( gl.BACK ); + gl.cullFace( 1029 ); } else if ( cullFace === CullFaceFront ) { - gl.cullFace( gl.FRONT ); + gl.cullFace( 1028 ); } else { - gl.cullFace( gl.FRONT_AND_BACK ); + gl.cullFace( 1032 ); } @@ -22207,7 +21110,7 @@ function WebGLState( gl, extensions, utils ) { } else { - disable( gl.CULL_FACE ); + disable( 2884 ); } @@ -22231,7 +21134,7 @@ function WebGLState( gl, extensions, utils ) { if ( polygonOffset ) { - enable( gl.POLYGON_OFFSET_FILL ); + enable( 32823 ); if ( currentPolygonOffsetFactor !== factor || currentPolygonOffsetUnits !== units ) { @@ -22244,7 +21147,7 @@ function WebGLState( gl, extensions, utils ) { } else { - disable( gl.POLYGON_OFFSET_FILL ); + disable( 32823 ); } @@ -22254,11 +21157,11 @@ function WebGLState( gl, extensions, utils ) { if ( scissorTest ) { - enable( gl.SCISSOR_TEST ); + enable( 3089 ); } else { - disable( gl.SCISSOR_TEST ); + disable( 3089 ); } @@ -22268,7 +21171,7 @@ function WebGLState( gl, extensions, utils ) { function activeTexture( webglSlot ) { - if ( webglSlot === undefined ) webglSlot = gl.TEXTURE0 + maxTextures - 1; + if ( webglSlot === undefined ) webglSlot = 33984 + maxTextures - 1; if ( currentTextureSlot !== webglSlot ) { @@ -22335,6 +21238,20 @@ function WebGLState( gl, extensions, utils ) { } + function texImage3D() { + + try { + + gl.texImage3D.apply( gl, arguments ); + + } catch ( error ) { + + console.error( 'THREE.WebGLState:', error ); + + } + + } + // function scissor( scissor ) { @@ -22374,7 +21291,7 @@ function WebGLState( gl, extensions, utils ) { } - capabilities = {}; + enabledCapabilities = {}; compressedTextureFormats = null; @@ -22427,6 +21344,7 @@ function WebGLState( gl, extensions, utils ) { bindTexture: bindTexture, compressedTexImage2D: compressedTexImage2D, texImage2D: texImage2D, + texImage3D: texImage3D, scissor: scissor, viewport: viewport, @@ -22441,8015 +21359,7688 @@ function WebGLState( gl, extensions, utils ) { * @author mrdoob / http://mrdoob.com/ */ -function WebGLCapabilities( gl, extensions, parameters ) { +function WebGLTextures( _gl, extensions, state, properties, capabilities, utils, info ) { - var maxAnisotropy; + var _videoTextures = {}; + var _canvas; - function getMaxAnisotropy() { + // - if ( maxAnisotropy !== undefined ) return maxAnisotropy; + function clampToMaxSize( image, maxSize ) { - var extension = extensions.get( 'EXT_texture_filter_anisotropic' ); + if ( image.width > maxSize || image.height > maxSize ) { - if ( extension !== null ) { + if ( 'data' in image ) { - maxAnisotropy = gl.getParameter( extension.MAX_TEXTURE_MAX_ANISOTROPY_EXT ); + console.warn( 'THREE.WebGLRenderer: image in DataTexture is too big (' + image.width + 'x' + image.height + ').' ); + return; - } else { + } - maxAnisotropy = 0; + // Warning: Scaling through the canvas will only work with images that use + // premultiplied alpha. + + var scale = maxSize / Math.max( image.width, image.height ); + + 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 ); + + 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 ); + + return canvas; } - return maxAnisotropy; + return image; } - function getMaxPrecision( precision ) { - - if ( precision === 'highp' ) { + function isPowerOfTwo( image ) { - if ( gl.getShaderPrecisionFormat( gl.VERTEX_SHADER, gl.HIGH_FLOAT ).precision > 0 && - gl.getShaderPrecisionFormat( gl.FRAGMENT_SHADER, gl.HIGH_FLOAT ).precision > 0 ) { + return _Math.isPowerOfTwo( image.width ) && _Math.isPowerOfTwo( image.height ); - return 'highp'; + } - } + function makePowerOfTwo( image ) { - precision = 'mediump'; + if ( image instanceof HTMLImageElement || image instanceof HTMLCanvasElement || image instanceof ImageBitmap ) { - } + if ( _canvas === undefined ) _canvas = document.createElementNS( 'http://www.w3.org/1999/xhtml', 'canvas' ); - if ( precision === 'mediump' ) { + _canvas.width = _Math.floorPowerOfTwo( image.width ); + _canvas.height = _Math.floorPowerOfTwo( image.height ); - if ( gl.getShaderPrecisionFormat( gl.VERTEX_SHADER, gl.MEDIUM_FLOAT ).precision > 0 && - gl.getShaderPrecisionFormat( gl.FRAGMENT_SHADER, gl.MEDIUM_FLOAT ).precision > 0 ) { + var context = _canvas.getContext( '2d' ); + context.drawImage( image, 0, 0, _canvas.width, _canvas.height ); - return 'mediump'; + console.warn( 'THREE.WebGLRenderer: image is not power of two (' + image.width + 'x' + image.height + '). Resized to ' + _canvas.width + 'x' + _canvas.height ); - } + return _canvas; } - return 'lowp'; + return image; } - var precision = parameters.precision !== undefined ? parameters.precision : 'highp'; - var maxPrecision = getMaxPrecision( precision ); + function textureNeedsPowerOfTwo( texture ) { - if ( maxPrecision !== precision ) { + if ( capabilities.isWebGL2 ) return false; - console.warn( 'THREE.WebGLRenderer:', precision, 'not supported, using', maxPrecision, 'instead.' ); - precision = maxPrecision; + return ( texture.wrapS !== ClampToEdgeWrapping || texture.wrapT !== ClampToEdgeWrapping ) || + ( texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter ); } - var logarithmicDepthBuffer = parameters.logarithmicDepthBuffer === true; + function textureNeedsGenerateMipmaps( texture, isPowerOfTwo ) { - var maxTextures = gl.getParameter( gl.MAX_TEXTURE_IMAGE_UNITS ); - var maxVertexTextures = gl.getParameter( gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS ); - var maxTextureSize = gl.getParameter( gl.MAX_TEXTURE_SIZE ); - var maxCubemapSize = gl.getParameter( gl.MAX_CUBE_MAP_TEXTURE_SIZE ); + return texture.generateMipmaps && isPowerOfTwo && + texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter; - var maxAttributes = gl.getParameter( gl.MAX_VERTEX_ATTRIBS ); - var maxVertexUniforms = gl.getParameter( gl.MAX_VERTEX_UNIFORM_VECTORS ); - var maxVaryings = gl.getParameter( gl.MAX_VARYING_VECTORS ); - var maxFragmentUniforms = gl.getParameter( gl.MAX_FRAGMENT_UNIFORM_VECTORS ); + } - var vertexTextures = maxVertexTextures > 0; - var floatFragmentTextures = !! extensions.get( 'OES_texture_float' ); - var floatVertexTextures = vertexTextures && floatFragmentTextures; + function generateMipmap( target, texture, width, height ) { - return { + _gl.generateMipmap( target ); - getMaxAnisotropy: getMaxAnisotropy, - getMaxPrecision: getMaxPrecision, + var textureProperties = properties.get( texture ); - precision: precision, - logarithmicDepthBuffer: logarithmicDepthBuffer, + // 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; - maxTextures: maxTextures, - maxVertexTextures: maxVertexTextures, - maxTextureSize: maxTextureSize, - maxCubemapSize: maxCubemapSize, + } - maxAttributes: maxAttributes, - maxVertexUniforms: maxVertexUniforms, - maxVaryings: maxVaryings, - maxFragmentUniforms: maxFragmentUniforms, + function getInternalFormat( glFormat, glType ) { - vertexTextures: vertexTextures, - floatFragmentTextures: floatFragmentTextures, - floatVertexTextures: floatVertexTextures + if ( ! capabilities.isWebGL2 ) return glFormat; - }; + if ( glFormat === 6403 ) { -} + if ( glType === 5126 ) return 33326; + if ( glType === 5131 ) return 33325; + if ( glType === 5121 ) return 33321; -/** - * @author mrdoob / http://mrdoob.com/ - * @author greggman / http://games.greggman.com/ - * @author zz85 / http://www.lab4games.net/zz85/blog - * @author tschw - */ + } -function PerspectiveCamera( fov, aspect, near, far ) { + if ( glFormat === 6407 ) { - Camera.call( this ); + if ( glType === 5126 ) return 34837; + if ( glType === 5131 ) return 34843; + if ( glType === 5121 ) return 32849; - this.type = 'PerspectiveCamera'; + } - this.fov = fov !== undefined ? fov : 50; - this.zoom = 1; + if ( glFormat === 6408 ) { - this.near = near !== undefined ? near : 0.1; - this.far = far !== undefined ? far : 2000; - this.focus = 10; + if ( glType === 5126 ) return 34836; + if ( glType === 5131 ) return 34842; + if ( glType === 5121 ) return 32856; - this.aspect = aspect !== undefined ? aspect : 1; - this.view = null; + } - this.filmGauge = 35; // width of the film (default in millimeters) - this.filmOffset = 0; // horizontal film offset (same unit as gauge) + return glFormat; - this.updateProjectionMatrix(); + } -} + // Fallback filters for non-power-of-2 textures -PerspectiveCamera.prototype = Object.assign( Object.create( Camera.prototype ), { + function filterFallback( f ) { - constructor: PerspectiveCamera, + if ( f === NearestFilter || f === NearestMipMapNearestFilter || f === NearestMipMapLinearFilter ) { - isPerspectiveCamera: true, + return 9728; - copy: function ( source, recursive ) { + } - Camera.prototype.copy.call( this, source, recursive ); + return 9729; - this.fov = source.fov; - this.zoom = source.zoom; + } - this.near = source.near; - this.far = source.far; - this.focus = source.focus; + // - this.aspect = source.aspect; - this.view = source.view === null ? null : Object.assign( {}, source.view ); + function onTextureDispose( event ) { - this.filmGauge = source.filmGauge; - this.filmOffset = source.filmOffset; + var texture = event.target; - return this; + texture.removeEventListener( 'dispose', onTextureDispose ); - }, + deallocateTexture( texture ); - /** - * 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 ) { + if ( texture.isVideoTexture ) { - // see http://www.bobatkins.com/photography/technical/field_of_view.html - var vExtentSlope = 0.5 * this.getFilmHeight() / focalLength; + delete _videoTextures[ texture.id ]; - this.fov = _Math.RAD2DEG * 2 * Math.atan( vExtentSlope ); - this.updateProjectionMatrix(); + } - }, + info.memory.textures --; - /** - * Calculates the focal length from the current .fov and .filmGauge. - */ - getFocalLength: function () { + } - var vExtentSlope = Math.tan( _Math.DEG2RAD * 0.5 * this.fov ); + function onRenderTargetDispose( event ) { - return 0.5 * this.getFilmHeight() / vExtentSlope; + var renderTarget = event.target; - }, + renderTarget.removeEventListener( 'dispose', onRenderTargetDispose ); - getEffectiveFOV: function () { + deallocateRenderTarget( renderTarget ); - return _Math.RAD2DEG * 2 * Math.atan( - Math.tan( _Math.DEG2RAD * 0.5 * this.fov ) / this.zoom ); + info.memory.textures --; - }, + } - getFilmWidth: function () { + // - // film not completely covered in portrait format (aspect < 1) - return this.filmGauge * Math.min( this.aspect, 1 ); + function deallocateTexture( texture ) { - }, + var textureProperties = properties.get( texture ); - getFilmHeight: function () { + if ( texture.image && textureProperties.__image__webglTextureCube ) { - // film not completely covered in landscape format (aspect > 1) - return this.filmGauge / Math.max( this.aspect, 1 ); + // cube texture - }, + _gl.deleteTexture( textureProperties.__image__webglTextureCube ); - /** - * 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 ) { + } else { - this.aspect = fullWidth / fullHeight; + // 2D texture - if ( this.view === null ) { + if ( textureProperties.__webglInit === undefined ) return; - this.view = { - enabled: true, - fullWidth: 1, - fullHeight: 1, - offsetX: 0, - offsetY: 0, - width: 1, - height: 1 - }; + _gl.deleteTexture( textureProperties.__webglTexture ); } - 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; + // remove all webgl properties + properties.remove( texture ); - this.updateProjectionMatrix(); + } - }, + function deallocateRenderTarget( renderTarget ) { - clearViewOffset: function () { + var renderTargetProperties = properties.get( renderTarget ); + var textureProperties = properties.get( renderTarget.texture ); - if ( this.view !== null ) { + if ( ! renderTarget ) return; - this.view.enabled = false; + if ( textureProperties.__webglTexture !== undefined ) { + + _gl.deleteTexture( textureProperties.__webglTexture ); } - this.updateProjectionMatrix(); + if ( renderTarget.depthTexture ) { - }, + renderTarget.depthTexture.dispose(); - updateProjectionMatrix: function () { + } - 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; + if ( renderTarget.isWebGLRenderTargetCube ) { - if ( this.view !== null && this.view.enabled ) { + for ( var i = 0; i < 6; i ++ ) { - var fullWidth = view.fullWidth, - fullHeight = view.fullHeight; + _gl.deleteFramebuffer( renderTargetProperties.__webglFramebuffer[ i ] ); + if ( renderTargetProperties.__webglDepthbuffer ) _gl.deleteRenderbuffer( renderTargetProperties.__webglDepthbuffer[ i ] ); - 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(); + } - this.projectionMatrix.makePerspective( left, left + width, top, top - height, near, this.far ); + } else { - }, + _gl.deleteFramebuffer( renderTargetProperties.__webglFramebuffer ); + if ( renderTargetProperties.__webglDepthbuffer ) _gl.deleteRenderbuffer( renderTargetProperties.__webglDepthbuffer ); - toJSON: function ( meta ) { + } - var data = Object3D.prototype.toJSON.call( this, meta ); + properties.remove( renderTarget.texture ); + properties.remove( renderTarget ); - data.object.fov = this.fov; - data.object.zoom = this.zoom; + } - data.object.near = this.near; - data.object.far = this.far; - data.object.focus = this.focus; + // - data.object.aspect = this.aspect; - if ( this.view !== null ) data.object.view = Object.assign( {}, this.view ); - data.object.filmGauge = this.filmGauge; - data.object.filmOffset = this.filmOffset; + function setTexture2D( texture, slot ) { - return data; + var textureProperties = properties.get( texture ); - } + if ( texture.isVideoTexture ) updateVideoTexture( texture ); -} ); + if ( texture.version > 0 && textureProperties.__version !== texture.version ) { -/** - * @author mrdoob / http://mrdoob.com/ - */ + var image = texture.image; -function ArrayCamera( array ) { + if ( image === undefined ) { - PerspectiveCamera.call( this ); + console.warn( 'THREE.WebGLRenderer: Texture marked for update but image is undefined' ); - this.cameras = array || []; + } else if ( image.complete === false ) { -} + console.warn( 'THREE.WebGLRenderer: Texture marked for update but image is incomplete' ); -ArrayCamera.prototype = Object.assign( Object.create( PerspectiveCamera.prototype ), { + } else { - constructor: ArrayCamera, + uploadTexture( textureProperties, texture, slot ); + return; - isArrayCamera: true + } -} ); + } -/** - * @author mrdoob / http://mrdoob.com/ - */ + state.activeTexture( 33984 + slot ); + state.bindTexture( 3553, textureProperties.__webglTexture ); -function WebVRManager( renderer ) { + } - var scope = this; + function setTexture3D( texture, slot ) { - var device = null; - var frameData = null; + var textureProperties = properties.get( texture ); - var poseTarget = null; + if ( texture.version > 0 && textureProperties.__version !== texture.version ) { - var standingMatrix = new Matrix4(); - var standingMatrixInverse = new Matrix4(); + uploadTexture( textureProperties, texture, slot ); + return; - if ( typeof window !== 'undefined' && 'VRFrameData' in window ) { + } - frameData = new window.VRFrameData(); + state.activeTexture( 33984 + slot ); + state.bindTexture( 32879, textureProperties.__webglTexture ); } - var matrixWorldInverse = new Matrix4(); - - 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 ); - - // - var currentSize, currentPixelRatio; + function setTextureCube( texture, slot ) { - function onVRDisplayPresentChange() { + var textureProperties = properties.get( texture ); - if ( device !== null && device.isPresenting ) { + if ( texture.image.length === 6 ) { - var eyeParameters = device.getEyeParameters( 'left' ); - var renderWidth = eyeParameters.renderWidth; - var renderHeight = eyeParameters.renderHeight; + if ( texture.version > 0 && textureProperties.__version !== texture.version ) { - currentPixelRatio = renderer.getPixelRatio(); - currentSize = renderer.getSize(); + if ( ! textureProperties.__image__webglTextureCube ) { - renderer.setDrawingBufferSize( renderWidth * 2, renderHeight, 1 ); + texture.addEventListener( 'dispose', onTextureDispose ); - } else if ( scope.enabled ) { + textureProperties.__image__webglTextureCube = _gl.createTexture(); - renderer.setDrawingBufferSize( currentSize.width, currentSize.height, currentPixelRatio ); + info.memory.textures ++; - } + } - } + state.activeTexture( 33984 + slot ); + state.bindTexture( 34067, textureProperties.__image__webglTextureCube ); - if ( typeof window !== 'undefined' ) { + _gl.pixelStorei( 37440, texture.flipY ); - window.addEventListener( 'vrdisplaypresentchange', onVRDisplayPresentChange, false ); + var isCompressed = ( texture && texture.isCompressedTexture ); + var isDataTexture = ( texture.image[ 0 ] && texture.image[ 0 ].isDataTexture ); - } + var cubeImage = []; - // + for ( var i = 0; i < 6; i ++ ) { - this.enabled = false; - this.userHeight = 1.6; + if ( ! isCompressed && ! isDataTexture ) { - this.getDevice = function () { + cubeImage[ i ] = clampToMaxSize( texture.image[ i ], capabilities.maxCubemapSize ); - return device; + } else { - }; + cubeImage[ i ] = isDataTexture ? texture.image[ i ].image : texture.image[ i ]; - this.setDevice = function ( value ) { + } - if ( value !== undefined ) device = value; + } - }; + var image = cubeImage[ 0 ], + isPowerOfTwoImage = isPowerOfTwo( image ), + glFormat = utils.convert( texture.format ), + glType = utils.convert( texture.type ), + glInternalFormat = getInternalFormat( glFormat, glType ); - this.setPoseTarget = function ( object ) { + setTextureParameters( 34067, texture, isPowerOfTwoImage ); - if ( object !== undefined ) poseTarget = object; + for ( var i = 0; i < 6; i ++ ) { - }; + if ( ! isCompressed ) { - this.getCamera = function ( camera ) { + if ( isDataTexture ) { - if ( device === null ) return camera; + state.texImage2D( 34069 + i, 0, glInternalFormat, cubeImage[ i ].width, cubeImage[ i ].height, 0, glFormat, glType, cubeImage[ i ].data ); - device.depthNear = camera.near; - device.depthFar = camera.far; + } else { - device.getFrameData( frameData ); + state.texImage2D( 34069 + i, 0, glInternalFormat, glFormat, glType, cubeImage[ i ] ); - // + } - var pose = frameData.pose; - var poseObject = poseTarget !== null ? poseTarget : camera; + } else { - if ( pose.position !== null ) { + var mipmap, mipmaps = cubeImage[ i ].mipmaps; - poseObject.position.fromArray( pose.position ); + for ( var j = 0, jl = mipmaps.length; j < jl; j ++ ) { - } else { + mipmap = mipmaps[ j ]; - poseObject.position.set( 0, 0, 0 ); + if ( texture.format !== RGBAFormat && texture.format !== RGBFormat ) { - } + if ( state.getCompressedTextureFormats().indexOf( glFormat ) > - 1 ) { - if ( pose.orientation !== null ) { + state.compressedTexImage2D( 34069 + i, j, glInternalFormat, mipmap.width, mipmap.height, 0, mipmap.data ); - poseObject.quaternion.fromArray( pose.orientation ); + } else { - } + console.warn( 'THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .setTextureCube()' ); - var stageParameters = device.stageParameters; + } - if ( stageParameters ) { + } else { - standingMatrix.fromArray( stageParameters.sittingToStandingTransform ); + state.texImage2D( 34069 + i, j, glInternalFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data ); - } else { + } - standingMatrix.makeTranslation( 0, scope.userHeight, 0 ); + } - } + } - poseObject.position.applyMatrix4( standingMatrix ); - poseObject.updateMatrixWorld(); + } - if ( device.isPresenting === false ) return camera; + if ( ! isCompressed ) { - // + textureProperties.__maxMipLevel = 0; - cameraL.near = camera.near; - cameraR.near = camera.near; + } else { - cameraL.far = camera.far; - cameraR.far = camera.far; + textureProperties.__maxMipLevel = mipmaps.length - 1; - cameraVR.matrixWorld.copy( camera.matrixWorld ); - cameraVR.matrixWorldInverse.copy( camera.matrixWorldInverse ); + } - cameraL.matrixWorldInverse.fromArray( frameData.leftViewMatrix ); - cameraR.matrixWorldInverse.fromArray( frameData.rightViewMatrix ); + if ( textureNeedsGenerateMipmaps( texture, isPowerOfTwoImage ) ) { - // TODO (mrdoob) Double check this code + // We assume images for cube map have the same size. + generateMipmap( 34067, texture, image.width, image.height ); - standingMatrixInverse.getInverse( standingMatrix ); + } - cameraL.matrixWorldInverse.multiply( standingMatrixInverse ); - cameraR.matrixWorldInverse.multiply( standingMatrixInverse ); + textureProperties.__version = texture.version; - var parent = poseObject.parent; + if ( texture.onUpdate ) texture.onUpdate( texture ); - if ( parent !== null ) { + } else { - matrixWorldInverse.getInverse( parent.matrixWorld ); + state.activeTexture( 33984 + slot ); + state.bindTexture( 34067, textureProperties.__image__webglTextureCube ); - cameraL.matrixWorldInverse.multiply( matrixWorldInverse ); - cameraR.matrixWorldInverse.multiply( matrixWorldInverse ); + } } - // envMap and Mirror needs camera.matrixWorld - - cameraL.matrixWorld.getInverse( cameraL.matrixWorldInverse ); - cameraR.matrixWorld.getInverse( cameraR.matrixWorldInverse ); + } - cameraL.projectionMatrix.fromArray( frameData.leftProjectionMatrix ); - cameraR.projectionMatrix.fromArray( frameData.rightProjectionMatrix ); + function setTextureCubeDynamic( texture, slot ) { - // HACK (mrdoob) - // https://github.com/w3c/webvr/issues/203 + state.activeTexture( 33984 + slot ); + state.bindTexture( 34067, properties.get( texture ).__webglTexture ); - cameraVR.projectionMatrix.copy( cameraL.projectionMatrix ); + } - // + function setTextureParameters( textureType, texture, isPowerOfTwoImage ) { - var layers = device.getLayers(); + var extension; - if ( layers.length ) { + if ( isPowerOfTwoImage ) { - var layer = layers[ 0 ]; + _gl.texParameteri( textureType, 10242, utils.convert( texture.wrapS ) ); + _gl.texParameteri( textureType, 10243, utils.convert( texture.wrapT ) ); - if ( layer.leftBounds !== null && layer.leftBounds.length === 4 ) { + _gl.texParameteri( textureType, 10240, utils.convert( texture.magFilter ) ); + _gl.texParameteri( textureType, 10241, utils.convert( texture.minFilter ) ); - cameraL.bounds.fromArray( layer.leftBounds ); + } else { - } + _gl.texParameteri( textureType, 10242, 33071 ); + _gl.texParameteri( textureType, 10243, 33071 ); - if ( layer.rightBounds !== null && layer.rightBounds.length === 4 ) { + if ( texture.wrapS !== ClampToEdgeWrapping || texture.wrapT !== ClampToEdgeWrapping ) { - cameraR.bounds.fromArray( layer.rightBounds ); + console.warn( 'THREE.WebGLRenderer: Texture is not power of two. Texture.wrapS and Texture.wrapT should be set to THREE.ClampToEdgeWrapping.' ); } - } - - return cameraVR; + _gl.texParameteri( textureType, 10240, filterFallback( texture.magFilter ) ); + _gl.texParameteri( textureType, 10241, filterFallback( texture.minFilter ) ); - }; + if ( texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter ) { - this.getStandingMatrix = function () { + console.warn( 'THREE.WebGLRenderer: Texture is not power of two. Texture.minFilter should be set to THREE.NearestFilter or THREE.LinearFilter.' ); - return standingMatrix; + } - }; + } - this.submitFrame = function () { + extension = extensions.get( 'EXT_texture_filter_anisotropic' ); - if ( device && device.isPresenting ) device.submitFrame(); + if ( extension ) { - }; + 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; - this.dispose = function () { + if ( texture.anisotropy > 1 || properties.get( texture ).__currentAnisotropy ) { - if ( typeof window !== 'undefined' ) { + _gl.texParameterf( textureType, extension.TEXTURE_MAX_ANISOTROPY_EXT, Math.min( texture.anisotropy, capabilities.getMaxAnisotropy() ) ); + properties.get( texture ).__currentAnisotropy = texture.anisotropy; - window.removeEventListener( 'vrdisplaypresentchange', onVRDisplayPresentChange ); + } } - }; - -} + } -/** - * @author mrdoob / http://mrdoob.com/ - */ + function uploadTexture( textureProperties, texture, slot ) { -function WebGLExtensions( gl ) { + var textureType; - var extensions = {}; + if ( texture.isDataTexture3D ) { - return { + textureType = 32879; - get: function ( name ) { + } else { - if ( extensions[ name ] !== undefined ) { + textureType = 3553; - return extensions[ name ]; + } - } - var extension; + if ( textureProperties.__webglInit === undefined ) { - switch ( name ) { + textureProperties.__webglInit = true; - case 'WEBGL_depth_texture': - extension = gl.getExtension( 'WEBGL_depth_texture' ) || gl.getExtension( 'MOZ_WEBGL_depth_texture' ) || gl.getExtension( 'WEBKIT_WEBGL_depth_texture' ); - break; + texture.addEventListener( 'dispose', onTextureDispose ); - 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; + textureProperties.__webglTexture = _gl.createTexture(); - 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; + info.memory.textures ++; - case 'WEBGL_compressed_texture_pvrtc': - extension = gl.getExtension( 'WEBGL_compressed_texture_pvrtc' ) || gl.getExtension( 'WEBKIT_WEBGL_compressed_texture_pvrtc' ); - break; + } + state.activeTexture( 33984 + slot ); - case 'WEBGL_compressed_texture_etc1': - extension = gl.getExtension( 'WEBGL_compressed_texture_etc1' ); - break; - default: - extension = gl.getExtension( name ); + state.bindTexture( textureType, textureProperties.__webglTexture ); - } - if ( extension === null ) { - console.warn( 'THREE.WebGLRenderer: ' + name + ' extension not supported.' ); + _gl.pixelStorei( 37440, texture.flipY ); + _gl.pixelStorei( 37441, texture.premultiplyAlpha ); + _gl.pixelStorei( 3317, texture.unpackAlignment ); - } + var image = clampToMaxSize( texture.image, capabilities.maxTextureSize ); - extensions[ name ] = extension; + if ( textureNeedsPowerOfTwo( texture ) && isPowerOfTwo( image ) === false ) { - return extension; + image = makePowerOfTwo( image ); } - }; + var isPowerOfTwoImage = isPowerOfTwo( image ), + glFormat = utils.convert( texture.format ), + glType = utils.convert( texture.type ), + glInternalFormat = getInternalFormat( glFormat, glType ); -} + setTextureParameters( textureType, texture, isPowerOfTwoImage ); -/** - * @author tschw - */ + var mipmap, mipmaps = texture.mipmaps; -function WebGLClipping() { + if ( texture.isDepthTexture ) { - var scope = this, + // populate depth texture with dummy data - globalState = null, - numGlobalPlanes = 0, - localClippingEnabled = false, - renderingShadows = false, + glInternalFormat = 6402; - plane = new Plane(), - viewNormalMatrix = new Matrix3(), + if ( texture.type === FloatType ) { - uniform = { value: null, needsUpdate: false }; + if ( ! capabilities.isWebGL2 ) throw new Error( 'Float Depth Texture only supported in WebGL2.0' ); + glInternalFormat = 36012; - this.uniform = uniform; - this.numPlanes = 0; - this.numIntersection = 0; + } else if ( capabilities.isWebGL2 ) { - this.init = function ( planes, enableLocalClipping, camera ) { + // WebGL 2.0 requires signed internalformat for glTexImage2D + glInternalFormat = 33189; - 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; + } - localClippingEnabled = enableLocalClipping; + if ( texture.format === DepthFormat && glInternalFormat === 6402 ) { - globalState = projectPlanes( planes, camera, 0 ); - numGlobalPlanes = planes.length; + // 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 ) { - return enabled; + console.warn( 'THREE.WebGLRenderer: Use UnsignedShortType or UnsignedIntType for DepthFormat DepthTexture.' ); - }; + texture.type = UnsignedShortType; + glType = utils.convert( texture.type ); - this.beginShadows = function () { + } - renderingShadows = true; - projectPlanes( null ); + } - }; + // Depth stencil textures need the DEPTH_STENCIL internal format + // (https://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/) + if ( texture.format === DepthStencilFormat ) { - this.endShadows = function () { + glInternalFormat = 34041; - renderingShadows = false; - resetGlobalState(); + // The error INVALID_OPERATION is generated by texImage2D if format and internalformat are + // DEPTH_STENCIL and type is not UNSIGNED_INT_24_8_WEBGL. + // (https://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/) + if ( texture.type !== UnsignedInt248Type ) { - }; + console.warn( 'THREE.WebGLRenderer: Use UnsignedInt248Type for DepthStencilFormat DepthTexture.' ); - this.setState = function ( planes, clipIntersection, clipShadows, camera, cache, fromCache ) { + texture.type = UnsignedInt248Type; + glType = utils.convert( texture.type ); - if ( ! localClippingEnabled || planes === null || planes.length === 0 || renderingShadows && ! clipShadows ) { + } - // there's no local clipping + } - if ( renderingShadows ) { + state.texImage2D( 3553, 0, glInternalFormat, image.width, image.height, 0, glFormat, glType, null ); - // there's no global clipping + } else if ( texture.isDataTexture ) { - projectPlanes( 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 - } else { + if ( mipmaps.length > 0 && isPowerOfTwoImage ) { - resetGlobalState(); + for ( var i = 0, il = mipmaps.length; i < il; i ++ ) { - } + mipmap = mipmaps[ i ]; + state.texImage2D( 3553, i, glInternalFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data ); - } else { + } - var nGlobal = renderingShadows ? 0 : numGlobalPlanes, - lGlobal = nGlobal * 4, + texture.generateMipmaps = false; + textureProperties.__maxMipLevel = mipmaps.length - 1; - dstArray = cache.clippingState || null; + } else { - uniform.value = dstArray; // ensure unique state + state.texImage2D( 3553, 0, glInternalFormat, image.width, image.height, 0, glFormat, glType, image.data ); + textureProperties.__maxMipLevel = 0; - dstArray = projectPlanes( planes, camera, lGlobal, fromCache ); + } - for ( var i = 0; i !== lGlobal; ++ i ) { + } else if ( texture.isCompressedTexture ) { - dstArray[ i ] = globalState[ i ]; + for ( var i = 0, il = mipmaps.length; i < il; i ++ ) { - } + mipmap = mipmaps[ i ]; - cache.clippingState = dstArray; - this.numIntersection = clipIntersection ? this.numPlanes : 0; - this.numPlanes += nGlobal; + 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 { - function resetGlobalState() { + console.warn( 'THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .uploadTexture()' ); - if ( uniform.value !== globalState ) { + } - uniform.value = globalState; - uniform.needsUpdate = numGlobalPlanes > 0; + } else { - } + state.texImage2D( 3553, i, glInternalFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data ); - scope.numPlanes = numGlobalPlanes; - scope.numIntersection = 0; + } - } + } - function projectPlanes( planes, camera, dstOffset, skipTransform ) { + textureProperties.__maxMipLevel = mipmaps.length - 1; - var nPlanes = planes !== null ? planes.length : 0, - dstArray = null; + } else if ( texture.isDataTexture3D ) { - if ( nPlanes !== 0 ) { + state.texImage3D( 32879, 0, glInternalFormat, image.width, image.height, image.depth, 0, glFormat, glType, image.data ); + textureProperties.__maxMipLevel = 0; - dstArray = uniform.value; + } else { - if ( skipTransform !== true || dstArray === null ) { + // regular Texture (image, video, canvas) - var flatSize = dstOffset + nPlanes * 4, - viewMatrix = camera.matrixWorldInverse; + // 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 - viewNormalMatrix.getNormalMatrix( viewMatrix ); + if ( mipmaps.length > 0 && isPowerOfTwoImage ) { - if ( dstArray === null || dstArray.length < flatSize ) { + for ( var i = 0, il = mipmaps.length; i < il; i ++ ) { - dstArray = new Float32Array( flatSize ); + mipmap = mipmaps[ i ]; + state.texImage2D( 3553, i, glInternalFormat, glFormat, glType, mipmap ); } - for ( var i = 0, i4 = dstOffset; i !== nPlanes; ++ i, i4 += 4 ) { - - plane.copy( planes[ i ] ).applyMatrix4( viewMatrix, viewNormalMatrix ); + texture.generateMipmaps = false; + textureProperties.__maxMipLevel = mipmaps.length - 1; - plane.normal.toArray( dstArray, i4 ); - dstArray[ i4 + 3 ] = plane.constant; + } else { - } + state.texImage2D( 3553, 0, glInternalFormat, glFormat, glType, image ); + textureProperties.__maxMipLevel = 0; } - uniform.value = dstArray; - uniform.needsUpdate = true; + } + + if ( textureNeedsGenerateMipmaps( texture, isPowerOfTwoImage ) ) { + + generateMipmap( 3553, texture, image.width, image.height ); } - scope.numPlanes = nPlanes; + textureProperties.__version = texture.version; - return dstArray; + if ( texture.onUpdate ) texture.onUpdate( texture ); } -} - -/** - * @author thespite / http://www.twitter.com/thespite - */ + // Render targets -function WebGLUtils( gl, extensions ) { + // Setup storage for target texture and bind it to correct framebuffer + function setupFrameBufferTexture( framebuffer, renderTarget, attachment, textureTarget ) { - function convert( p ) { + 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 ); - var extension; + } - if ( p === RepeatWrapping ) return gl.REPEAT; - if ( p === ClampToEdgeWrapping ) return gl.CLAMP_TO_EDGE; - if ( p === MirroredRepeatWrapping ) return gl.MIRRORED_REPEAT; + // Setup storage for internal depth/stencil buffers and bind to correct framebuffer + function setupRenderBufferStorage( renderbuffer, renderTarget ) { - if ( p === NearestFilter ) return gl.NEAREST; - if ( p === NearestMipMapNearestFilter ) return gl.NEAREST_MIPMAP_NEAREST; - if ( p === NearestMipMapLinearFilter ) return gl.NEAREST_MIPMAP_LINEAR; + _gl.bindRenderbuffer( 36161, renderbuffer ); - if ( p === LinearFilter ) return gl.LINEAR; - if ( p === LinearMipMapNearestFilter ) return gl.LINEAR_MIPMAP_NEAREST; - if ( p === LinearMipMapLinearFilter ) return gl.LINEAR_MIPMAP_LINEAR; + if ( renderTarget.depthBuffer && ! renderTarget.stencilBuffer ) { - if ( p === UnsignedByteType ) return gl.UNSIGNED_BYTE; - if ( p === UnsignedShort4444Type ) return gl.UNSIGNED_SHORT_4_4_4_4; - if ( p === UnsignedShort5551Type ) return gl.UNSIGNED_SHORT_5_5_5_1; - if ( p === UnsignedShort565Type ) return gl.UNSIGNED_SHORT_5_6_5; + _gl.renderbufferStorage( 36161, 33189, renderTarget.width, renderTarget.height ); + _gl.framebufferRenderbuffer( 36160, 36096, 36161, renderbuffer ); - if ( p === ByteType ) return gl.BYTE; - if ( p === ShortType ) return gl.SHORT; - if ( p === UnsignedShortType ) return gl.UNSIGNED_SHORT; - if ( p === IntType ) return gl.INT; - if ( p === UnsignedIntType ) return gl.UNSIGNED_INT; - if ( p === FloatType ) return gl.FLOAT; + } else if ( renderTarget.depthBuffer && renderTarget.stencilBuffer ) { - if ( p === HalfFloatType ) { + _gl.renderbufferStorage( 36161, 34041, renderTarget.width, renderTarget.height ); + _gl.framebufferRenderbuffer( 36160, 33306, 36161, renderbuffer ); - extension = extensions.get( 'OES_texture_half_float' ); + } else { - if ( extension !== null ) return extension.HALF_FLOAT_OES; + // FIXME: We don't support !depth !stencil + _gl.renderbufferStorage( 36161, 32854, renderTarget.width, renderTarget.height ); } - if ( p === AlphaFormat ) return gl.ALPHA; - if ( p === RGBFormat ) return gl.RGB; - if ( p === RGBAFormat ) return gl.RGBA; - if ( p === LuminanceFormat ) return gl.LUMINANCE; - if ( p === LuminanceAlphaFormat ) return gl.LUMINANCE_ALPHA; - if ( p === DepthFormat ) return gl.DEPTH_COMPONENT; - if ( p === DepthStencilFormat ) return gl.DEPTH_STENCIL; + _gl.bindRenderbuffer( 36161, null ); - if ( p === AddEquation ) return gl.FUNC_ADD; - if ( p === SubtractEquation ) return gl.FUNC_SUBTRACT; - if ( p === ReverseSubtractEquation ) return gl.FUNC_REVERSE_SUBTRACT; + } - if ( p === ZeroFactor ) return gl.ZERO; - if ( p === OneFactor ) return gl.ONE; - if ( p === SrcColorFactor ) return gl.SRC_COLOR; - if ( p === OneMinusSrcColorFactor ) return gl.ONE_MINUS_SRC_COLOR; - if ( p === SrcAlphaFactor ) return gl.SRC_ALPHA; - if ( p === OneMinusSrcAlphaFactor ) return gl.ONE_MINUS_SRC_ALPHA; - if ( p === DstAlphaFactor ) return gl.DST_ALPHA; - if ( p === OneMinusDstAlphaFactor ) return gl.ONE_MINUS_DST_ALPHA; + // Setup resources for a Depth Texture for a FBO (needs an extension) + function setupDepthTexture( framebuffer, renderTarget ) { - if ( p === DstColorFactor ) return gl.DST_COLOR; - if ( p === OneMinusDstColorFactor ) return gl.ONE_MINUS_DST_COLOR; - if ( p === SrcAlphaSaturateFactor ) return gl.SRC_ALPHA_SATURATE; + var isCube = ( renderTarget && renderTarget.isWebGLRenderTargetCube ); + if ( isCube ) throw new Error( 'Depth Texture with cube render targets is not supported' ); - if ( p === RGB_S3TC_DXT1_Format || p === RGBA_S3TC_DXT1_Format || - p === RGBA_S3TC_DXT3_Format || p === RGBA_S3TC_DXT5_Format ) { + _gl.bindFramebuffer( 36160, framebuffer ); - extension = extensions.get( 'WEBGL_compressed_texture_s3tc' ); + if ( ! ( renderTarget.depthTexture && renderTarget.depthTexture.isDepthTexture ) ) { - if ( extension !== null ) { + throw new Error( 'renderTarget.depthTexture must be an instance of THREE.DepthTexture' ); - 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; + } - } + // 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; - if ( p === RGB_PVRTC_4BPPV1_Format || p === RGB_PVRTC_2BPPV1_Format || - p === RGBA_PVRTC_4BPPV1_Format || p === RGBA_PVRTC_2BPPV1_Format ) { + } - extension = extensions.get( 'WEBGL_compressed_texture_pvrtc' ); + setTexture2D( renderTarget.depthTexture, 0 ); - if ( extension !== null ) { + var webglDepthTexture = properties.get( renderTarget.depthTexture ).__webglTexture; - 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; + if ( renderTarget.depthTexture.format === DepthFormat ) { - } + _gl.framebufferTexture2D( 36160, 36096, 3553, webglDepthTexture, 0 ); - } + } else if ( renderTarget.depthTexture.format === DepthStencilFormat ) { - if ( p === RGB_ETC1_Format ) { + _gl.framebufferTexture2D( 36160, 33306, 3553, webglDepthTexture, 0 ); - extension = extensions.get( 'WEBGL_compressed_texture_etc1' ); + } else { - if ( extension !== null ) return extension.COMPRESSED_RGB_ETC1_WEBGL; + throw new Error( 'Unknown depthTexture format' ); } - 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' ); + // Setup GL resources for a non-texture depth buffer + function setupDepthRenderbuffer( renderTarget ) { - if ( extension !== null ) { + var renderTargetProperties = properties.get( renderTarget ); - return p; + var isCube = ( renderTarget.isWebGLRenderTargetCube === true ); - } + if ( renderTarget.depthTexture ) { - } + if ( isCube ) throw new Error( 'target.depthTexture not supported in Cube render targets' ); - if ( p === MinEquation || p === MaxEquation ) { + setupDepthTexture( renderTargetProperties.__webglFramebuffer, renderTarget ); - extension = extensions.get( 'EXT_blend_minmax' ); + } else { - if ( extension !== null ) { + if ( isCube ) { - if ( p === MinEquation ) return extension.MIN_EXT; - if ( p === MaxEquation ) return extension.MAX_EXT; + renderTargetProperties.__webglDepthbuffer = []; - } + for ( var i = 0; i < 6; i ++ ) { - } + _gl.bindFramebuffer( 36160, renderTargetProperties.__webglFramebuffer[ i ] ); + renderTargetProperties.__webglDepthbuffer[ i ] = _gl.createRenderbuffer(); + setupRenderBufferStorage( renderTargetProperties.__webglDepthbuffer[ i ], renderTarget ); - if ( p === UnsignedInt248Type ) { + } - extension = extensions.get( 'WEBGL_depth_texture' ); + } else { - if ( extension !== null ) return extension.UNSIGNED_INT_24_8_WEBGL; + _gl.bindFramebuffer( 36160, renderTargetProperties.__webglFramebuffer ); + renderTargetProperties.__webglDepthbuffer = _gl.createRenderbuffer(); + setupRenderBufferStorage( renderTargetProperties.__webglDepthbuffer, renderTarget ); + + } } - return 0; + _gl.bindFramebuffer( 36160, null ); } - return { convert: convert }; + // Set up GL resources for the render target + function setupRenderTarget( renderTarget ) { -} + var renderTargetProperties = properties.get( renderTarget ); + var textureProperties = properties.get( renderTarget.texture ); -/** - * @author mrdoob / http://mrdoob.com/ - */ + renderTarget.addEventListener( 'dispose', onRenderTargetDispose ); -function UniformsCache() { + textureProperties.__webglTexture = _gl.createTexture(); - var lights = {}; + info.memory.textures ++; - return { + var isCube = ( renderTarget.isWebGLRenderTargetCube === true ); + var isTargetPowerOfTwo = isPowerOfTwo( renderTarget ); - get: function ( light ) { + // Setup framebuffer - if ( lights[ light.id ] !== undefined ) { + if ( isCube ) { - return lights[ light.id ]; + renderTargetProperties.__webglFramebuffer = []; + + for ( var i = 0; i < 6; i ++ ) { + + renderTargetProperties.__webglFramebuffer[ i ] = _gl.createFramebuffer(); } - var uniforms; + } else { - switch ( light.type ) { + renderTargetProperties.__webglFramebuffer = _gl.createFramebuffer(); - case 'DirectionalLight': - uniforms = { - direction: new Vector3(), - color: new Color(), + } - shadow: false, - shadowBias: 0, - shadowRadius: 1, - shadowMapSize: new Vector2() - }; - break; + // Setup color buffer - case 'SpotLight': - uniforms = { - position: new Vector3(), - direction: new Vector3(), - color: new Color(), - distance: 0, - coneCos: 0, - penumbraCos: 0, - decay: 0, + if ( isCube ) { - shadow: false, - shadowBias: 0, - shadowRadius: 1, - shadowMapSize: new Vector2() - }; - break; + state.bindTexture( 34067, textureProperties.__webglTexture ); + setTextureParameters( 34067, renderTarget.texture, isTargetPowerOfTwo ); - case 'PointLight': - uniforms = { - position: new Vector3(), - color: new Color(), - distance: 0, - decay: 0, + for ( var i = 0; i < 6; i ++ ) { - shadow: false, - shadowBias: 0, - shadowRadius: 1, - shadowMapSize: new Vector2(), - shadowCameraNear: 1, - shadowCameraFar: 1000 - }; - break; + setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer[ i ], renderTarget, 36064, 34069 + i ); - 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; + if ( textureNeedsGenerateMipmaps( renderTarget.texture, isTargetPowerOfTwo ) ) { + + generateMipmap( 34067, renderTarget.texture, renderTarget.width, renderTarget.height ); } - lights[ light.id ] = uniforms; + state.bindTexture( 34067, null ); - return uniforms; + } else { - } + state.bindTexture( 3553, textureProperties.__webglTexture ); + setTextureParameters( 3553, renderTarget.texture, isTargetPowerOfTwo ); + setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer, renderTarget, 36064, 3553 ); - }; + if ( textureNeedsGenerateMipmaps( renderTarget.texture, isTargetPowerOfTwo ) ) { -} + generateMipmap( 3553, renderTarget.texture, renderTarget.width, renderTarget.height ); -var count = 0; + } -function WebGLLights() { + state.bindTexture( 3553, null ); - var cache = new UniformsCache(); + } - var state = { + // Setup depth and stencil buffers - id: count ++, + if ( renderTarget.depthBuffer ) { - hash: '', + setupDepthRenderbuffer( renderTarget ); - ambient: [ 0, 0, 0 ], - directional: [], - directionalShadowMap: [], - directionalShadowMatrix: [], - spot: [], - spotShadowMap: [], - spotShadowMatrix: [], - rectArea: [], - point: [], - pointShadowMap: [], - pointShadowMatrix: [], - hemi: [] + } - }; + } - var vector3 = new Vector3(); - var matrix4 = new Matrix4(); - var matrix42 = new Matrix4(); + function updateRenderTargetMipmap( renderTarget ) { - function setup( lights, shadows, camera ) { + var texture = renderTarget.texture; + var isTargetPowerOfTwo = isPowerOfTwo( renderTarget ); - var r = 0, g = 0, b = 0; + if ( textureNeedsGenerateMipmaps( texture, isTargetPowerOfTwo ) ) { - var directionalLength = 0; - var pointLength = 0; - var spotLength = 0; - var rectAreaLength = 0; - var hemiLength = 0; + var target = renderTarget.isWebGLRenderTargetCube ? 34067 : 3553; + var webglTexture = properties.get( texture ).__webglTexture; - var viewMatrix = camera.matrixWorldInverse; + state.bindTexture( target, webglTexture ); + generateMipmap( target, texture, renderTarget.width, renderTarget.height ); + state.bindTexture( target, null ); - 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; + function updateVideoTexture( texture ) { - var shadowMap = ( light.shadow && light.shadow.map ) ? light.shadow.map.texture : null; + var id = texture.id; + var frame = info.render.frame; - if ( light.isAmbientLight ) { + // Check the last frame we updated the VideoTexture - r += color.r * intensity; - g += color.g * intensity; - b += color.b * intensity; + if ( _videoTextures[ id ] !== frame ) { - } else if ( light.isDirectionalLight ) { + _videoTextures[ id ] = frame; + texture.update(); - var uniforms = cache.get( light ); + } - 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 ); + } - uniforms.shadow = light.castShadow; + this.setTexture2D = setTexture2D; + this.setTexture3D = setTexture3D; + this.setTextureCube = setTextureCube; + this.setTextureCubeDynamic = setTextureCubeDynamic; + this.setupRenderTarget = setupRenderTarget; + this.updateRenderTargetMipmap = updateRenderTargetMipmap; - if ( light.castShadow ) { +} - var shadow = light.shadow; +/** + * @author thespite / http://www.twitter.com/thespite + */ - uniforms.shadowBias = shadow.bias; - uniforms.shadowRadius = shadow.radius; - uniforms.shadowMapSize = shadow.mapSize; +function WebGLUtils( gl, extensions, capabilities ) { - } + function convert( p ) { - state.directionalShadowMap[ directionalLength ] = shadowMap; - state.directionalShadowMatrix[ directionalLength ] = light.shadow.matrix; - state.directional[ directionalLength ] = uniforms; + var extension; - directionalLength ++; + if ( p === RepeatWrapping ) return 10497; + if ( p === ClampToEdgeWrapping ) return 33071; + if ( p === MirroredRepeatWrapping ) return 33648; - } else if ( light.isSpotLight ) { + if ( p === NearestFilter ) return 9728; + if ( p === NearestMipMapNearestFilter ) return 9984; + if ( p === NearestMipMapLinearFilter ) return 9986; - var uniforms = cache.get( light ); + if ( p === LinearFilter ) return 9729; + if ( p === LinearMipMapNearestFilter ) return 9985; + if ( p === LinearMipMapLinearFilter ) return 9987; - uniforms.position.setFromMatrixPosition( light.matrixWorld ); - uniforms.position.applyMatrix4( viewMatrix ); + if ( p === UnsignedByteType ) return 5121; + if ( p === UnsignedShort4444Type ) return 32819; + if ( p === UnsignedShort5551Type ) return 32820; + if ( p === UnsignedShort565Type ) return 33635; - uniforms.color.copy( color ).multiplyScalar( intensity ); - uniforms.distance = distance; + 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; - uniforms.direction.setFromMatrixPosition( light.matrixWorld ); - vector3.setFromMatrixPosition( light.target.matrixWorld ); - uniforms.direction.sub( vector3 ); - uniforms.direction.transformDirection( viewMatrix ); + if ( p === HalfFloatType ) { - uniforms.coneCos = Math.cos( light.angle ); - uniforms.penumbraCos = Math.cos( light.angle * ( 1 - light.penumbra ) ); - uniforms.decay = ( light.distance === 0 ) ? 0.0 : light.decay; + if ( capabilities.isWebGL2 ) return 5131; - uniforms.shadow = light.castShadow; + extension = extensions.get( 'OES_texture_half_float' ); - if ( light.castShadow ) { + if ( extension !== null ) return extension.HALF_FLOAT_OES; - var shadow = light.shadow; + } - uniforms.shadowBias = shadow.bias; - uniforms.shadowRadius = shadow.radius; - uniforms.shadowMapSize = shadow.mapSize; + 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; - } + if ( p === AddEquation ) return 32774; + if ( p === SubtractEquation ) return 32778; + if ( p === ReverseSubtractEquation ) return 32779; - state.spotShadowMap[ spotLength ] = shadowMap; - state.spotShadowMatrix[ spotLength ] = light.shadow.matrix; - state.spot[ spotLength ] = uniforms; + 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; - spotLength ++; + if ( p === DstColorFactor ) return 774; + if ( p === OneMinusDstColorFactor ) return 775; + if ( p === SrcAlphaSaturateFactor ) return 776; - } else if ( light.isRectAreaLight ) { + if ( p === RGB_S3TC_DXT1_Format || p === RGBA_S3TC_DXT1_Format || + p === RGBA_S3TC_DXT3_Format || p === RGBA_S3TC_DXT5_Format ) { - var uniforms = cache.get( light ); + extension = extensions.get( 'WEBGL_compressed_texture_s3tc' ); - // (a) intensity is the total visible light emitted - //uniforms.color.copy( color ).multiplyScalar( intensity / ( light.width * light.height * Math.PI ) ); + if ( extension !== null ) { - // (b) intensity is the brightness of the light - uniforms.color.copy( color ).multiplyScalar( intensity ); + 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; - uniforms.position.setFromMatrixPosition( light.matrixWorld ); - uniforms.position.applyMatrix4( viewMatrix ); + } - // extract local rotation of light to derive width/height half vectors - matrix42.identity(); - matrix4.copy( light.matrixWorld ); - matrix4.premultiply( viewMatrix ); - matrix42.extractRotation( matrix4 ); + } - uniforms.halfWidth.set( light.width * 0.5, 0.0, 0.0 ); - uniforms.halfHeight.set( 0.0, light.height * 0.5, 0.0 ); + if ( p === RGB_PVRTC_4BPPV1_Format || p === RGB_PVRTC_2BPPV1_Format || + p === RGBA_PVRTC_4BPPV1_Format || p === RGBA_PVRTC_2BPPV1_Format ) { - uniforms.halfWidth.applyMatrix4( matrix42 ); - uniforms.halfHeight.applyMatrix4( matrix42 ); + extension = extensions.get( 'WEBGL_compressed_texture_pvrtc' ); - // TODO (abelnation): RectAreaLight distance? - // uniforms.distance = distance; + if ( extension !== null ) { - state.rectArea[ rectAreaLength ] = uniforms; + 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; - rectAreaLength ++; + } - } else if ( light.isPointLight ) { + } - var uniforms = cache.get( light ); + if ( p === RGB_ETC1_Format ) { - uniforms.position.setFromMatrixPosition( light.matrixWorld ); - uniforms.position.applyMatrix4( viewMatrix ); + extension = extensions.get( 'WEBGL_compressed_texture_etc1' ); - uniforms.color.copy( light.color ).multiplyScalar( light.intensity ); - uniforms.distance = light.distance; - uniforms.decay = ( light.distance === 0 ) ? 0.0 : light.decay; + if ( extension !== null ) return extension.COMPRESSED_RGB_ETC1_WEBGL; - uniforms.shadow = light.castShadow; + } - if ( light.castShadow ) { + 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 ) { - var shadow = light.shadow; + extension = extensions.get( 'WEBGL_compressed_texture_astc' ); - uniforms.shadowBias = shadow.bias; - uniforms.shadowRadius = shadow.radius; - uniforms.shadowMapSize = shadow.mapSize; - uniforms.shadowCameraNear = shadow.camera.near; - uniforms.shadowCameraFar = shadow.camera.far; + if ( extension !== null ) { - } + return p; - state.pointShadowMap[ pointLength ] = shadowMap; - state.pointShadowMatrix[ pointLength ] = light.shadow.matrix; - state.point[ pointLength ] = uniforms; + } - pointLength ++; + } - } else if ( light.isHemisphereLight ) { + if ( p === MinEquation || p === MaxEquation ) { - var uniforms = cache.get( light ); + if ( capabilities.isWebGL2 ) { - uniforms.direction.setFromMatrixPosition( light.matrixWorld ); - uniforms.direction.transformDirection( viewMatrix ); - uniforms.direction.normalize(); + if ( p === MinEquation ) return 32775; + if ( p === MaxEquation ) return 32776; - uniforms.skyColor.copy( light.color ).multiplyScalar( intensity ); - uniforms.groundColor.copy( light.groundColor ).multiplyScalar( intensity ); + } - state.hemi[ hemiLength ] = uniforms; + extension = extensions.get( 'EXT_blend_minmax' ); - hemiLength ++; + if ( extension !== null ) { + + if ( p === MinEquation ) return extension.MIN_EXT; + if ( p === MaxEquation ) return extension.MAX_EXT; } } - state.ambient[ 0 ] = r; - state.ambient[ 1 ] = g; - state.ambient[ 2 ] = b; + if ( p === UnsignedInt248Type ) { - state.directional.length = directionalLength; - state.spot.length = spotLength; - state.rectArea.length = rectAreaLength; - state.point.length = pointLength; - state.hemi.length = hemiLength; + if ( capabilities.isWebGL2 ) return 34042; + + extension = extensions.get( 'WEBGL_depth_texture' ); + + if ( extension !== null ) return extension.UNSIGNED_INT_24_8_WEBGL; + + } - state.hash = state.id + ',' + directionalLength + ',' + pointLength + ',' + spotLength + ',' + rectAreaLength + ',' + hemiLength + ',' + shadows.length; + return 0; } - return { - setup: setup, - state: state - }; + return { convert: convert }; } /** - * @author Mugen87 / https://github.com/Mugen87 + * @author mrdoob / http://mrdoob.com/ */ -function WebGLRenderState() { +function Group() { - var lights = new WebGLLights(); + Object3D.call( this ); - var lightsArray = []; - var shadowsArray = []; - var spritesArray = []; + this.type = 'Group'; - function init() { +} - lightsArray.length = 0; - shadowsArray.length = 0; - spritesArray.length = 0; +Group.prototype = Object.assign( Object.create( Object3D.prototype ), { - } + constructor: Group, - function pushLight( light ) { + isGroup: true - lightsArray.push( light ); +} ); - } +/** + * @author mrdoob / http://mrdoob.com/ + * @author mikael emtinger / http://gomo.se/ + * @author WestLangley / http://github.com/WestLangley +*/ - function pushShadow( shadowLight ) { +function Camera() { - shadowsArray.push( shadowLight ); + Object3D.call( this ); - } + this.type = 'Camera'; - function pushSprite( shadowLight ) { + this.matrixWorldInverse = new Matrix4(); - spritesArray.push( shadowLight ); + this.projectionMatrix = new Matrix4(); + this.projectionMatrixInverse = new Matrix4(); - } +} - function setupLights( camera ) { +Camera.prototype = Object.assign( Object.create( Object3D.prototype ), { - lights.setup( lightsArray, shadowsArray, camera ); + constructor: Camera, - } + isCamera: true, - var state = { - lightsArray: lightsArray, - shadowsArray: shadowsArray, - spritesArray: spritesArray, + copy: function ( source, recursive ) { - lights: lights - }; + Object3D.prototype.copy.call( this, source, recursive ); - return { - init: init, - state: state, - setupLights: setupLights, + this.matrixWorldInverse.copy( source.matrixWorldInverse ); - pushLight: pushLight, - pushShadow: pushShadow, - pushSprite: pushSprite - }; + this.projectionMatrix.copy( source.projectionMatrix ); + this.projectionMatrixInverse.copy( source.projectionMatrixInverse ); -} + return this; -function WebGLRenderStates() { + }, - var renderStates = {}; + getWorldDirection: function ( target ) { - function get( scene, camera ) { + if ( target === undefined ) { - var hash = scene.id + ',' + camera.id; + console.warn( 'THREE.Camera: .getWorldDirection() target is now required' ); + target = new Vector3(); - var renderState = renderStates[ hash ]; + } - if ( renderState === undefined ) { + this.updateMatrixWorld( true ); - renderState = new WebGLRenderState(); - renderStates[ hash ] = renderState; + var e = this.matrixWorld.elements; - } + return target.set( - e[ 8 ], - e[ 9 ], - e[ 10 ] ).normalize(); - return renderState; + }, - } + updateMatrixWorld: function ( force ) { - function dispose() { + Object3D.prototype.updateMatrixWorld.call( this, force ); - renderStates = {}; + this.matrixWorldInverse.getInverse( this.matrixWorld ); - } + }, - return { - get: get, - dispose: dispose - }; + clone: function () { -} + return new this.constructor().copy( this ); + + } + +} ); /** - * @author supereggbert / http://www.paulbrunt.co.uk/ * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - * @author szimek / https://github.com/szimek/ + * @author greggman / http://games.greggman.com/ + * @author zz85 / http://www.lab4games.net/zz85/blog * @author tschw */ -function WebGLRenderer( parameters ) { +function PerspectiveCamera( fov, aspect, near, far ) { - console.log( 'THREE.WebGLRenderer', REVISION ); + Camera.call( this ); - parameters = parameters || {}; + this.type = 'PerspectiveCamera'; - var _canvas = parameters.canvas !== undefined ? parameters.canvas : document.createElementNS( 'http://www.w3.org/1999/xhtml', 'canvas' ), - _context = parameters.context !== undefined ? parameters.context : null, + this.fov = fov !== undefined ? fov : 50; + this.zoom = 1; - _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'; + this.near = near !== undefined ? near : 0.1; + this.far = far !== undefined ? far : 2000; + this.focus = 10; - var currentRenderList = null; - var currentRenderState = null; + this.aspect = aspect !== undefined ? aspect : 1; + this.view = null; - // public properties + this.filmGauge = 35; // width of the film (default in millimeters) + this.filmOffset = 0; // horizontal film offset (same unit as gauge) - this.domElement = _canvas; - this.context = null; + this.updateProjectionMatrix(); - // clearing +} - this.autoClear = true; - this.autoClearColor = true; - this.autoClearDepth = true; - this.autoClearStencil = true; +PerspectiveCamera.prototype = Object.assign( Object.create( Camera.prototype ), { - // scene graph + constructor: PerspectiveCamera, - this.sortObjects = true; + isPerspectiveCamera: true, - // user-defined clipping + copy: function ( source, recursive ) { - this.clippingPlanes = []; - this.localClippingEnabled = false; + Camera.prototype.copy.call( this, source, recursive ); - // physically based shading + this.fov = source.fov; + this.zoom = source.zoom; - this.gammaFactor = 2.0; // for backwards compatibility - this.gammaInput = false; - this.gammaOutput = false; + this.near = source.near; + this.far = source.far; + this.focus = source.focus; - // physical lights + this.aspect = source.aspect; + this.view = source.view === null ? null : Object.assign( {}, source.view ); - this.physicallyCorrectLights = false; + this.filmGauge = source.filmGauge; + this.filmOffset = source.filmOffset; - // tone mapping - - this.toneMapping = LinearToneMapping; - this.toneMappingExposure = 1.0; - this.toneMappingWhitePoint = 1.0; - - // morphs - - this.maxMorphTargets = 8; - this.maxMorphNormals = 4; - - // internal properties - - var _this = this, + return this; - _isContextLost = false, + }, - // internal state cache + /** + * 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 ) { - _currentRenderTarget = null, - _currentFramebuffer = null, - _currentMaterialId = - 1, - _currentGeometryProgram = '', + // see http://www.bobatkins.com/photography/technical/field_of_view.html + var vExtentSlope = 0.5 * this.getFilmHeight() / focalLength; - _currentCamera = null, - _currentArrayCamera = null, + this.fov = _Math.RAD2DEG * 2 * Math.atan( vExtentSlope ); + this.updateProjectionMatrix(); - _currentViewport = new Vector4(), - _currentScissor = new Vector4(), - _currentScissorTest = null, + }, - // + /** + * Calculates the focal length from the current .fov and .filmGauge. + */ + getFocalLength: function () { - _usedTextureUnits = 0, + var vExtentSlope = Math.tan( _Math.DEG2RAD * 0.5 * this.fov ); - // + return 0.5 * this.getFilmHeight() / vExtentSlope; - _width = _canvas.width, - _height = _canvas.height, + }, - _pixelRatio = 1, + getEffectiveFOV: function () { - _viewport = new Vector4( 0, 0, _width, _height ), - _scissor = new Vector4( 0, 0, _width, _height ), - _scissorTest = false, + return _Math.RAD2DEG * 2 * Math.atan( + Math.tan( _Math.DEG2RAD * 0.5 * this.fov ) / this.zoom ); - // frustum + }, - _frustum = new Frustum(), + getFilmWidth: function () { - // clipping + // film not completely covered in portrait format (aspect < 1) + return this.filmGauge * Math.min( this.aspect, 1 ); - _clipping = new WebGLClipping(), - _clippingEnabled = false, - _localClippingEnabled = false, + }, - // camera matrices cache + getFilmHeight: function () { - _projScreenMatrix = new Matrix4(), + // film not completely covered in landscape format (aspect > 1) + return this.filmGauge / Math.max( this.aspect, 1 ); - _vector3 = new Vector3(), + }, - // info + /** + * 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 ) { - _infoMemory = { - geometries: 0, - textures: 0 - }, + this.aspect = fullWidth / fullHeight; - _infoRender = { + if ( this.view === null ) { - frame: 0, - calls: 0, - vertices: 0, - faces: 0, - points: 0 + this.view = { + enabled: true, + fullWidth: 1, + fullHeight: 1, + offsetX: 0, + offsetY: 0, + width: 1, + height: 1 + }; - }; + } - this.info = { + 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; - render: _infoRender, - memory: _infoMemory, - programs: null, - autoReset: true, - reset: resetInfo + this.updateProjectionMatrix(); - }; + }, - function resetInfo() { + clearViewOffset: function () { - _infoRender.frame ++; - _infoRender.calls = 0; - _infoRender.vertices = 0; - _infoRender.faces = 0; - _infoRender.points = 0; + if ( this.view !== null ) { - } + this.view.enabled = false; - function getTargetPixelRatio() { + } - return _currentRenderTarget === null ? _pixelRatio : 1; + this.updateProjectionMatrix(); - } + }, - // initialize + updateProjectionMatrix: function () { - var _gl; + 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; - try { + if ( this.view !== null && this.view.enabled ) { - var contextAttributes = { - alpha: _alpha, - depth: _depth, - stencil: _stencil, - antialias: _antialias, - premultipliedAlpha: _premultipliedAlpha, - preserveDrawingBuffer: _preserveDrawingBuffer, - powerPreference: _powerPreference - }; + var fullWidth = view.fullWidth, + fullHeight = view.fullHeight; - // event listeners must be registered before WebGL context is created, see #12753 + left += view.offsetX * width / fullWidth; + top -= view.offsetY * height / fullHeight; + width *= view.width / fullWidth; + height *= view.height / fullHeight; - _canvas.addEventListener( 'webglcontextlost', onContextLost, false ); - _canvas.addEventListener( 'webglcontextrestored', onContextRestore, false ); + } - _gl = _context || _canvas.getContext( 'webgl', contextAttributes ) || _canvas.getContext( 'experimental-webgl', contextAttributes ); + var skew = this.filmOffset; + if ( skew !== 0 ) left += near * skew / this.getFilmWidth(); - if ( _gl === null ) { + this.projectionMatrix.makePerspective( left, left + width, top, top - height, near, this.far ); - if ( _canvas.getContext( 'webgl' ) !== null ) { + this.projectionMatrixInverse.getInverse( this.projectionMatrix ); - throw new Error( 'Error creating WebGL context with your selected attributes.' ); + }, - } else { + toJSON: function ( meta ) { - throw new Error( 'Error creating WebGL context.' ); + var data = Object3D.prototype.toJSON.call( this, meta ); - } + data.object.fov = this.fov; + data.object.zoom = this.zoom; - } + data.object.near = this.near; + data.object.far = this.far; + data.object.focus = this.focus; - // Some experimental-webgl implementations do not have getShaderPrecisionFormat + data.object.aspect = this.aspect; - if ( _gl.getShaderPrecisionFormat === undefined ) { + if ( this.view !== null ) data.object.view = Object.assign( {}, this.view ); - _gl.getShaderPrecisionFormat = function () { + data.object.filmGauge = this.filmGauge; + data.object.filmOffset = this.filmOffset; - return { 'rangeMin': 1, 'rangeMax': 1, 'precision': 1 }; + return data; - }; + } - } +} ); - } catch ( error ) { +/** + * @author mrdoob / http://mrdoob.com/ + */ - console.error( 'THREE.WebGLRenderer: ' + error.message ); +function ArrayCamera( array ) { - } + PerspectiveCamera.call( this ); - var extensions, capabilities, state; - var properties, textures, attributes, geometries, objects; - var programCache, renderLists, renderStates; + this.cameras = array || []; - var background, morphtargets, bufferRenderer, indexedBufferRenderer; - var spriteRenderer; +} - var utils; +ArrayCamera.prototype = Object.assign( Object.create( PerspectiveCamera.prototype ), { - function initGLContext() { + constructor: ArrayCamera, - extensions = new WebGLExtensions( _gl ); - extensions.get( 'WEBGL_depth_texture' ); - extensions.get( 'OES_texture_float' ); - extensions.get( 'OES_texture_float_linear' ); - extensions.get( 'OES_texture_half_float' ); - extensions.get( 'OES_texture_half_float_linear' ); - extensions.get( 'OES_standard_derivatives' ); - extensions.get( 'OES_element_index_uint' ); - extensions.get( 'ANGLE_instanced_arrays' ); + isArrayCamera: true - utils = new WebGLUtils( _gl, extensions ); +} ); - capabilities = new WebGLCapabilities( _gl, extensions, parameters ); +/** + * @author jsantell / https://www.jsantell.com/ + * @author mrdoob / http://mrdoob.com/ + */ - state = new WebGLState( _gl, extensions, utils ); - state.scissor( _currentScissor.copy( _scissor ).multiplyScalar( _pixelRatio ) ); - state.viewport( _currentViewport.copy( _viewport ).multiplyScalar( _pixelRatio ) ); +var cameraLPos = new Vector3(); +var cameraRPos = new Vector3(); - properties = new WebGLProperties(); - textures = new WebGLTextures( _gl, extensions, state, properties, capabilities, utils, _infoMemory, _infoRender ); - attributes = new WebGLAttributes( _gl ); - geometries = new WebGLGeometries( _gl, attributes, _infoMemory ); - objects = new WebGLObjects( geometries, _infoRender ); - morphtargets = new WebGLMorphtargets( _gl ); - programCache = new WebGLPrograms( _this, extensions, capabilities ); - renderLists = new WebGLRenderLists(); - renderStates = new WebGLRenderStates(); +/** + * 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 ) { - background = new WebGLBackground( _this, state, geometries, _premultipliedAlpha ); + cameraLPos.setFromMatrixPosition( cameraL.matrixWorld ); + cameraRPos.setFromMatrixPosition( cameraR.matrixWorld ); - bufferRenderer = new WebGLBufferRenderer( _gl, extensions, _infoRender ); - indexedBufferRenderer = new WebGLIndexedBufferRenderer( _gl, extensions, _infoRender ); + var ipd = cameraLPos.distanceTo( cameraRPos ); - spriteRenderer = new WebGLSpriteRenderer( _this, _gl, state, textures, capabilities ); + var projL = cameraL.projectionMatrix.elements; + var projR = cameraR.projectionMatrix.elements; - _this.info.programs = programCache.programs; + // 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 ]; - _this.context = _gl; - _this.capabilities = capabilities; - _this.extensions = extensions; - _this.properties = properties; - _this.renderLists = renderLists; - _this.state = state; + 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; - initGLContext(); + // 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 ); - // vr + // 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; - var vr = new WebVRManager( _this ); + camera.projectionMatrix.makePerspective( left2, right2, top2, bottom2, near2, far2 ); - this.vr = vr; +} - // shadow map +/** + * @author mrdoob / http://mrdoob.com/ + */ - var shadowMap = new WebGLShadowMap( _this, objects, capabilities.maxTextureSize ); +function WebVRManager( renderer ) { - this.shadowMap = shadowMap; + var scope = this; - // API + var device = null; + var frameData = null; - this.getContext = function () { + var poseTarget = null; - return _gl; + var controllers = []; + var standingMatrix = new Matrix4(); + var standingMatrixInverse = new Matrix4(); - }; + var framebufferScaleFactor = 1.0; - this.getContextAttributes = function () { + var frameOfReferenceType = 'stage'; - return _gl.getContextAttributes(); + if ( typeof window !== 'undefined' && 'VRFrameData' in window ) { - }; + frameData = new window.VRFrameData(); + window.addEventListener( 'vrdisplaypresentchange', onVRDisplayPresentChange, false ); - this.forceContextLoss = function () { + } - var extension = extensions.get( 'WEBGL_lose_context' ); - if ( extension ) extension.loseContext(); + 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 ); - this.forceContextRestore = function () { + var cameraR = new PerspectiveCamera(); + cameraR.bounds = new Vector4( 0.5, 0.0, 0.5, 1.0 ); + cameraR.layers.enable( 2 ); - var extension = extensions.get( 'WEBGL_lose_context' ); - if ( extension ) extension.restoreContext(); + var cameraVR = new ArrayCamera( [ cameraL, cameraR ] ); + cameraVR.layers.enable( 1 ); + cameraVR.layers.enable( 2 ); - }; + // - this.getPixelRatio = function () { + function isPresenting() { - return _pixelRatio; + return device !== null && device.isPresenting === true; - }; + } - this.setPixelRatio = function ( value ) { + var currentSize, currentPixelRatio; - if ( value === undefined ) return; + function onVRDisplayPresentChange() { - _pixelRatio = value; + if ( isPresenting() ) { - this.setSize( _width, _height, false ); + var eyeParameters = device.getEyeParameters( 'left' ); + var renderWidth = eyeParameters.renderWidth * framebufferScaleFactor; + var renderHeight = eyeParameters.renderHeight * framebufferScaleFactor; - }; + currentPixelRatio = renderer.getPixelRatio(); + currentSize = renderer.getSize(); - this.getSize = function () { + renderer.setDrawingBufferSize( renderWidth * 2, renderHeight, 1 ); - return { - width: _width, - height: _height - }; + animation.start(); - }; + } else { - this.setSize = function ( width, height, updateStyle ) { + if ( scope.enabled ) { - var device = vr.getDevice(); + renderer.setDrawingBufferSize( currentSize.width, currentSize.height, currentPixelRatio ); - if ( device && device.isPresenting ) { + } - console.warn( 'THREE.WebGLRenderer: Can\'t change size while VR device is presenting.' ); - return; + animation.stop(); } - _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'; + var triggers = []; - } + function findGamepad( id ) { - this.setViewport( 0, 0, width, height ); + var gamepads = navigator.getGamepads && navigator.getGamepads(); - }; + for ( var i = 0, j = 0, l = gamepads.length; i < l; i ++ ) { - this.getDrawingBufferSize = function () { + var gamepad = gamepads[ i ]; - return { - width: _width * _pixelRatio, - height: _height * _pixelRatio - }; + 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' ) ) ) { - }; + if ( j === id ) return gamepad; - this.setDrawingBufferSize = function ( width, height, pixelRatio ) { + j ++; - _width = width; - _height = height; + } - _pixelRatio = pixelRatio; + } - _canvas.width = width * pixelRatio; - _canvas.height = height * pixelRatio; + } - this.setViewport( 0, 0, width, height ); + function updateControllers() { - }; + for ( var i = 0; i < controllers.length; i ++ ) { - this.getCurrentViewport = function () { + var controller = controllers[ i ]; - return _currentViewport; + var gamepad = findGamepad( i ); - }; + if ( gamepad !== undefined && gamepad.pose !== undefined ) { - this.setViewport = function ( x, y, width, height ) { + if ( gamepad.pose === null ) return; - _viewport.set( x, _height - y - height, width, height ); - state.viewport( _currentViewport.copy( _viewport ).multiplyScalar( _pixelRatio ) ); + // Pose - }; + var pose = gamepad.pose; - this.setScissor = function ( x, y, width, height ) { + if ( pose.hasPosition === false ) controller.position.set( 0.2, - 0.6, - 0.05 ); - _scissor.set( x, _height - y - height, width, height ); - state.scissor( _currentScissor.copy( _scissor ).multiplyScalar( _pixelRatio ) ); + 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; - }; + // Trigger - this.setScissorTest = function ( boolean ) { + var buttonId = gamepad.id === 'Daydream Controller' ? 0 : 1; - state.setScissorTest( _scissorTest = boolean ); + if ( triggers[ i ] !== gamepad.buttons[ buttonId ].pressed ) { - }; + triggers[ i ] = gamepad.buttons[ buttonId ].pressed; - // Clearing + if ( triggers[ i ] === true ) { - this.getClearColor = function () { + controller.dispatchEvent( { type: 'selectstart' } ); - return background.getClearColor(); + } else { - }; + controller.dispatchEvent( { type: 'selectend' } ); + controller.dispatchEvent( { type: 'select' } ); - this.setClearColor = function () { + } - background.setClearColor.apply( background, arguments ); + } - }; + } else { - this.getClearAlpha = function () { + controller.visible = false; - return background.getClearAlpha(); + } - }; + } - this.setClearAlpha = function () { + } - background.setClearAlpha.apply( background, arguments ); + // - }; + this.enabled = false; - this.clear = function ( color, depth, stencil ) { + this.getController = function ( id ) { - var bits = 0; + var controller = controllers[ id ]; - if ( color === undefined || color ) bits |= _gl.COLOR_BUFFER_BIT; - if ( depth === undefined || depth ) bits |= _gl.DEPTH_BUFFER_BIT; - if ( stencil === undefined || stencil ) bits |= _gl.STENCIL_BUFFER_BIT; + if ( controller === undefined ) { - _gl.clear( bits ); + controller = new Group(); + controller.matrixAutoUpdate = false; + controller.visible = false; - }; + controllers[ id ] = controller; - this.clearColor = function () { + } - this.clear( true, false, false ); + return controller; }; - this.clearDepth = function () { + this.getDevice = function () { - this.clear( false, true, false ); + return device; }; - this.clearStencil = function () { - - this.clear( false, false, true ); - - }; + this.setDevice = function ( value ) { - this.clearTarget = function ( renderTarget, color, depth, stencil ) { + if ( value !== undefined ) device = value; - this.setRenderTarget( renderTarget ); - this.clear( color, depth, stencil ); + animation.setContext( value ); }; - // - - this.dispose = function () { + this.setFramebufferScaleFactor = function ( value ) { - _canvas.removeEventListener( 'webglcontextlost', onContextLost, false ); - _canvas.removeEventListener( 'webglcontextrestored', onContextRestore, false ); + framebufferScaleFactor = value; - renderLists.dispose(); - renderStates.dispose(); - properties.dispose(); - objects.dispose(); + }; - vr.dispose(); + this.setFrameOfReferenceType = function ( value ) { - stopAnimation(); + frameOfReferenceType = value; }; - // Events + this.setPoseTarget = function ( object ) { - function onContextLost( event ) { + if ( object !== undefined ) poseTarget = object; - event.preventDefault(); + }; - console.log( 'THREE.WebGLRenderer: Context Lost.' ); + this.getCamera = function ( camera ) { - _isContextLost = true; + var userHeight = frameOfReferenceType === 'stage' ? 1.6 : 0; - } + if ( device === null ) { - function onContextRestore( /* event */ ) { + camera.position.set( 0, userHeight, 0 ); + return camera; - console.log( 'THREE.WebGLRenderer: Context Restored.' ); + } - _isContextLost = false; + device.depthNear = camera.near; + device.depthFar = camera.far; - initGLContext(); + device.getFrameData( frameData ); - } + // - function onMaterialDispose( event ) { + if ( frameOfReferenceType === 'stage' ) { - var material = event.target; + var stageParameters = device.stageParameters; - material.removeEventListener( 'dispose', onMaterialDispose ); + if ( stageParameters ) { - deallocateMaterial( material ); + standingMatrix.fromArray( stageParameters.sittingToStandingTransform ); - } + } else { - // Buffer deallocation + standingMatrix.makeTranslation( 0, userHeight, 0 ); - function deallocateMaterial( material ) { + } - releaseMaterialProgramReference( material ); + } - properties.remove( material ); - } + var pose = frameData.pose; + var poseObject = poseTarget !== null ? poseTarget : camera; + // 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 ); - function releaseMaterialProgramReference( material ) { + if ( pose.orientation !== null ) { - var programInfo = properties.get( material ).program; + tempQuaternion.fromArray( pose.orientation ); + poseObject.quaternion.multiply( tempQuaternion ); - material.program = undefined; + } - if ( programInfo !== undefined ) { + if ( pose.position !== null ) { - programCache.releaseProgram( programInfo ); + tempQuaternion.setFromRotationMatrix( standingMatrix ); + tempPosition.fromArray( pose.position ); + tempPosition.applyQuaternion( tempQuaternion ); + poseObject.position.add( tempPosition ); } - } + poseObject.updateMatrixWorld(); - // Buffer rendering + if ( device.isPresenting === false ) return camera; - function renderObjectImmediate( object, program, material ) { + // - object.render( function ( object ) { + cameraL.near = camera.near; + cameraR.near = camera.near; - _this.renderBufferImmediate( object, program, material ); + cameraL.far = camera.far; + cameraR.far = camera.far; - } ); + cameraL.matrixWorldInverse.fromArray( frameData.leftViewMatrix ); + cameraR.matrixWorldInverse.fromArray( frameData.rightViewMatrix ); - } + // TODO (mrdoob) Double check this code - this.renderBufferImmediate = function ( object, program, material ) { + standingMatrixInverse.getInverse( standingMatrix ); - state.initAttributes(); + if ( frameOfReferenceType === 'stage' ) { - var buffers = properties.get( object ); + cameraL.matrixWorldInverse.multiply( standingMatrixInverse ); + cameraR.matrixWorldInverse.multiply( standingMatrixInverse ); - 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(); + } - var programAttributes = program.getAttributes(); + var parent = poseObject.parent; - if ( object.hasPositions ) { + if ( parent !== null ) { - _gl.bindBuffer( _gl.ARRAY_BUFFER, buffers.position ); - _gl.bufferData( _gl.ARRAY_BUFFER, object.positionArray, _gl.DYNAMIC_DRAW ); + matrixWorldInverse.getInverse( parent.matrixWorld ); - state.enableAttribute( programAttributes.position ); - _gl.vertexAttribPointer( programAttributes.position, 3, _gl.FLOAT, false, 0, 0 ); + cameraL.matrixWorldInverse.multiply( matrixWorldInverse ); + cameraR.matrixWorldInverse.multiply( matrixWorldInverse ); } - if ( object.hasNormals ) { + // envMap and Mirror needs camera.matrixWorld - _gl.bindBuffer( _gl.ARRAY_BUFFER, buffers.normal ); + cameraL.matrixWorld.getInverse( cameraL.matrixWorldInverse ); + cameraR.matrixWorld.getInverse( cameraR.matrixWorldInverse ); - if ( ! material.isMeshPhongMaterial && - ! material.isMeshStandardMaterial && - ! material.isMeshNormalMaterial && - material.flatShading === true ) { + cameraL.projectionMatrix.fromArray( frameData.leftProjectionMatrix ); + cameraR.projectionMatrix.fromArray( frameData.rightProjectionMatrix ); - for ( var i = 0, l = object.count * 3; i < l; i += 9 ) { + setProjectionFromUnion( cameraVR, cameraL, cameraR ); - var array = object.normalArray; + // - var nx = ( array[ i + 0 ] + array[ i + 3 ] + array[ i + 6 ] ) / 3; - var ny = ( array[ i + 1 ] + array[ i + 4 ] + array[ i + 7 ] ) / 3; - var nz = ( array[ i + 2 ] + array[ i + 5 ] + array[ i + 8 ] ) / 3; + var layers = device.getLayers(); - array[ i + 0 ] = nx; - array[ i + 1 ] = ny; - array[ i + 2 ] = nz; + if ( layers.length ) { - array[ i + 3 ] = nx; - array[ i + 4 ] = ny; - array[ i + 5 ] = nz; + var layer = layers[ 0 ]; - array[ i + 6 ] = nx; - array[ i + 7 ] = ny; - array[ i + 8 ] = nz; + if ( layer.leftBounds !== null && layer.leftBounds.length === 4 ) { - } + cameraL.bounds.fromArray( layer.leftBounds ); } - _gl.bufferData( _gl.ARRAY_BUFFER, object.normalArray, _gl.DYNAMIC_DRAW ); + if ( layer.rightBounds !== null && layer.rightBounds.length === 4 ) { - state.enableAttribute( programAttributes.normal ); + cameraR.bounds.fromArray( layer.rightBounds ); - _gl.vertexAttribPointer( programAttributes.normal, 3, _gl.FLOAT, false, 0, 0 ); + } } - if ( object.hasUvs && material.map ) { + updateControllers(); - _gl.bindBuffer( _gl.ARRAY_BUFFER, buffers.uv ); - _gl.bufferData( _gl.ARRAY_BUFFER, object.uvArray, _gl.DYNAMIC_DRAW ); + return cameraVR; - state.enableAttribute( programAttributes.uv ); - - _gl.vertexAttribPointer( programAttributes.uv, 2, _gl.FLOAT, false, 0, 0 ); - - } + }; - if ( object.hasColors && material.vertexColors !== NoColors ) { + this.getStandingMatrix = function () { - _gl.bindBuffer( _gl.ARRAY_BUFFER, buffers.color ); - _gl.bufferData( _gl.ARRAY_BUFFER, object.colorArray, _gl.DYNAMIC_DRAW ); + return standingMatrix; - state.enableAttribute( programAttributes.color ); + }; - _gl.vertexAttribPointer( programAttributes.color, 3, _gl.FLOAT, false, 0, 0 ); + this.isPresenting = isPresenting; - } + // Animation Loop - state.disableUnusedAttributes(); + var animation = new WebGLAnimation(); - _gl.drawArrays( _gl.TRIANGLES, 0, object.count ); + this.setAnimationLoop = function ( callback ) { - object.count = 0; + animation.setAnimationLoop( callback ); }; - this.renderBufferDirect = function ( camera, fog, geometry, material, object, group ) { - - var frontFaceCW = ( object.isMesh && object.matrixWorld.determinant() < 0 ); + this.submitFrame = function () { - state.setMaterial( material, frontFaceCW ); + if ( isPresenting() ) device.submitFrame(); - var program = setProgram( camera, fog, material, object ); - var geometryProgram = geometry.id + '_' + program.id + '_' + ( material.wireframe === true ); + }; - var updateBuffers = false; + this.dispose = function () { - if ( geometryProgram !== _currentGeometryProgram ) { + if ( typeof window !== 'undefined' ) { - _currentGeometryProgram = geometryProgram; - updateBuffers = true; + window.removeEventListener( 'vrdisplaypresentchange', onVRDisplayPresentChange ); } - if ( object.morphTargetInfluences ) { - - morphtargets.update( object, geometry, material, program ); - - updateBuffers = true; + }; - } +} - // +/** + * @author mrdoob / http://mrdoob.com/ + */ - var index = geometry.index; - var position = geometry.attributes.position; - var rangeFactor = 1; +function WebXRManager( renderer ) { - if ( material.wireframe === true ) { + var gl = renderer.context; - index = geometries.getWireframeAttribute( geometry ); - rangeFactor = 2; + var device = null; + var session = null; - } + var framebufferScaleFactor = 1.0; - var attribute; - var renderer = bufferRenderer; + var frameOfReference = null; + var frameOfReferenceType = 'stage'; - if ( index !== null ) { + var pose = null; - attribute = attributes.get( index ); + var controllers = []; + var inputSources = []; - renderer = indexedBufferRenderer; - renderer.setIndex( attribute ); + function isPresenting() { - } + return session !== null && frameOfReference !== null; - if ( updateBuffers ) { + } - setupVertexAttributes( material, program, geometry ); + // - if ( index !== null ) { + var cameraL = new PerspectiveCamera(); + cameraL.layers.enable( 1 ); + cameraL.viewport = new Vector4(); - _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, attribute.buffer ); + 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 ); - } + // - // + this.enabled = false; - var dataCount = Infinity; + this.getController = function ( id ) { - if ( index !== null ) { + var controller = controllers[ id ]; - dataCount = index.count; + if ( controller === undefined ) { - } else if ( position !== undefined ) { + controller = new Group(); + controller.matrixAutoUpdate = false; + controller.visible = false; - dataCount = position.count; + controllers[ id ] = controller; } - var rangeStart = geometry.drawRange.start * rangeFactor; - var rangeCount = geometry.drawRange.count * rangeFactor; + return controller; - 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; + this.getDevice = function () { - var drawCount = Math.max( 0, drawEnd - drawStart + 1 ); + return device; - if ( drawCount === 0 ) return; + }; - // + this.setDevice = function ( value ) { - if ( object.isMesh ) { + if ( value !== undefined ) device = value; + if ( value instanceof XRDevice ) gl.setCompatibleXRDevice( value ); - if ( material.wireframe === true ) { + }; - state.setLineWidth( material.wireframeLinewidth * getTargetPixelRatio() ); - renderer.setMode( _gl.LINES ); + // - } else { + function onSessionEvent( event ) { - switch ( object.drawMode ) { + var controller = controllers[ inputSources.indexOf( event.inputSource ) ]; + if ( controller ) controller.dispatchEvent( { type: event.type } ); - case TrianglesDrawMode: - renderer.setMode( _gl.TRIANGLES ); - break; + } - case TriangleStripDrawMode: - renderer.setMode( _gl.TRIANGLE_STRIP ); - break; + function onSessionEnd() { - case TriangleFanDrawMode: - renderer.setMode( _gl.TRIANGLE_FAN ); - break; + renderer.setFramebuffer( null ); + animation.stop(); - } + } - } + this.setFramebufferScaleFactor = function ( value ) { + framebufferScaleFactor = value; - } else if ( object.isLine ) { + }; - var lineWidth = material.linewidth; + this.setFrameOfReferenceType = function ( value ) { - if ( lineWidth === undefined ) lineWidth = 1; // Not using Line*Material + frameOfReferenceType = value; - state.setLineWidth( lineWidth * getTargetPixelRatio() ); + }; - if ( object.isLineSegments ) { + this.setSession = function ( value ) { - renderer.setMode( _gl.LINES ); + session = value; - } else if ( object.isLineLoop ) { + if ( session !== null ) { - renderer.setMode( _gl.LINE_LOOP ); + session.addEventListener( 'select', onSessionEvent ); + session.addEventListener( 'selectstart', onSessionEvent ); + session.addEventListener( 'selectend', onSessionEvent ); + session.addEventListener( 'end', onSessionEnd ); - } else { + session.baseLayer = new XRWebGLLayer( session, gl, { framebufferScaleFactor: framebufferScaleFactor } ); + session.requestFrameOfReference( frameOfReferenceType ).then( function ( value ) { - renderer.setMode( _gl.LINE_STRIP ); + frameOfReference = value; - } + renderer.setFramebuffer( session.baseLayer.framebuffer ); - } else if ( object.isPoints ) { + animation.setContext( session ); + animation.start(); - renderer.setMode( _gl.POINTS ); + } ); - } + // - if ( geometry && geometry.isInstancedBufferGeometry ) { + inputSources = session.getInputSources(); - if ( geometry.maxInstancedCount > 0 ) { + session.addEventListener( 'inputsourceschange', function () { - renderer.renderInstances( geometry, drawStart, drawCount ); + inputSources = session.getInputSources(); + console.log( inputSources ); - } + for ( var i = 0; i < controllers.length; i ++ ) { - } else { + var controller = controllers[ i ]; + controller.userData.inputSource = inputSources[ i ]; - renderer.render( drawStart, drawCount ); + } + + } ); } }; - function setupVertexAttributes( material, program, geometry, startIndex ) { + function updateCamera( camera, parent ) { - if ( geometry && geometry.isInstancedBufferGeometry ) { + if ( parent === null ) { - if ( extensions.get( 'ANGLE_instanced_arrays' ) === null ) { + camera.matrixWorld.copy( camera.matrix ); - console.error( 'THREE.WebGLRenderer.setupVertexAttributes: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.' ); - return; + } else { - } + camera.matrixWorld.multiplyMatrices( parent.matrixWorld, camera.matrix ); } - if ( startIndex === undefined ) startIndex = 0; + camera.matrixWorldInverse.getInverse( camera.matrixWorld ); - state.initAttributes(); + } - var geometryAttributes = geometry.attributes; + this.getCamera = function ( camera ) { - var programAttributes = program.getAttributes(); + if ( isPresenting() ) { - var materialDefaultAttributeValues = material.defaultAttributeValues; + var parent = camera.parent; + var cameras = cameraVR.cameras; - for ( var name in programAttributes ) { + updateCamera( cameraVR, parent ); - var programAttribute = programAttributes[ name ]; + for ( var i = 0; i < cameras.length; i ++ ) { - if ( programAttribute >= 0 ) { + updateCamera( cameras[ i ], parent ); - var geometryAttribute = geometryAttributes[ name ]; + } - if ( geometryAttribute !== undefined ) { + // update camera and its children - var normalized = geometryAttribute.normalized; - var size = geometryAttribute.itemSize; + camera.matrixWorld.copy( cameraVR.matrixWorld ); - var attribute = attributes.get( geometryAttribute ); + var children = camera.children; - // TODO Attribute may not be available on context restore + for ( var i = 0, l = children.length; i < l; i ++ ) { - if ( attribute === undefined ) continue; + children[ i ].updateMatrixWorld( true ); - var buffer = attribute.buffer; - var type = attribute.type; - var bytesPerElement = attribute.bytesPerElement; + } - if ( geometryAttribute.isInterleavedBufferAttribute ) { + setProjectionFromUnion( cameraVR, cameraL, cameraR ); - var data = geometryAttribute.data; - var stride = data.stride; - var offset = geometryAttribute.offset; + return cameraVR; - if ( data && data.isInstancedInterleavedBuffer ) { + } - state.enableAttributeAndDivisor( programAttribute, data.meshPerAttribute ); + return camera; - if ( geometry.maxInstancedCount === undefined ) { + }; - geometry.maxInstancedCount = data.meshPerAttribute * data.count; + this.isPresenting = isPresenting; - } + // Animation Loop - } else { + var onAnimationFrameCallback = null; - state.enableAttribute( programAttribute ); + function onAnimationFrame( time, frame ) { - } + pose = frame.getDevicePose( frameOfReference ); - _gl.bindBuffer( _gl.ARRAY_BUFFER, buffer ); - _gl.vertexAttribPointer( programAttribute, size, type, normalized, stride * bytesPerElement, ( startIndex * stride + offset ) * bytesPerElement ); + if ( pose !== null ) { - } else { + var layer = session.baseLayer; + var views = frame.views; - if ( geometryAttribute.isInstancedBufferAttribute ) { + for ( var i = 0; i < views.length; i ++ ) { - state.enableAttributeAndDivisor( programAttribute, geometryAttribute.meshPerAttribute ); + var view = views[ i ]; + var viewport = layer.getViewport( view ); + var viewMatrix = pose.getViewMatrix( view ); - if ( geometry.maxInstancedCount === undefined ) { + 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 ); - geometry.maxInstancedCount = geometryAttribute.meshPerAttribute * geometryAttribute.count; + if ( i === 0 ) { - } + cameraVR.matrix.copy( camera.matrix ); - } else { + } - state.enableAttribute( programAttribute ); + } - } + } - _gl.bindBuffer( _gl.ARRAY_BUFFER, buffer ); - _gl.vertexAttribPointer( programAttribute, size, type, normalized, 0, startIndex * size * bytesPerElement ); + // - } + for ( var i = 0; i < controllers.length; i ++ ) { - } else if ( materialDefaultAttributeValues !== undefined ) { + var controller = controllers[ i ]; - var value = materialDefaultAttributeValues[ name ]; + var inputSource = inputSources[ i ]; - if ( value !== undefined ) { + if ( inputSource ) { - switch ( value.length ) { + var inputPose = frame.getInputPose( inputSource, frameOfReference ); - case 2: - _gl.vertexAttrib2fv( programAttribute, value ); - break; + if ( inputPose !== null ) { - case 3: - _gl.vertexAttrib3fv( programAttribute, value ); - break; + if ( 'targetRay' in inputPose ) { - case 4: - _gl.vertexAttrib4fv( programAttribute, value ); - break; + controller.matrix.elements = inputPose.targetRay.transformMatrix; - default: - _gl.vertexAttrib1fv( programAttribute, value ); + } else if ( 'pointerMatrix' in inputPose ) { - } + // DEPRECATED + + controller.matrix.elements = inputPose.pointerMatrix; } + controller.matrix.decompose( controller.position, controller.rotation, controller.scale ); + controller.visible = true; + + continue; + } } + controller.visible = false; + } - state.disableUnusedAttributes(); + if ( onAnimationFrameCallback ) onAnimationFrameCallback( time ); } - // Compile - - this.compile = function ( scene, camera ) { + var animation = new WebGLAnimation(); + animation.setAnimationLoop( onAnimationFrame ); - currentRenderState = renderStates.get( scene, camera ); - currentRenderState.init(); + this.setAnimationLoop = function ( callback ) { - scene.traverse( function ( object ) { + onAnimationFrameCallback = callback; - if ( object.isLight ) { + }; - currentRenderState.pushLight( object ); + this.dispose = function () {}; - if ( object.castShadow ) { + // DEPRECATED - currentRenderState.pushShadow( object ); + this.getStandingMatrix = function () { - } + console.warn( 'THREE.WebXRManager: getStandingMatrix() is no longer needed.' ); + return new THREE.Matrix4(); - } + }; - } ); + this.submitFrame = function () {}; - currentRenderState.setupLights( camera ); +} - scene.traverse( function ( object ) { +/** + * @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 ( object.material ) { +function WebGLRenderer( parameters ) { - if ( Array.isArray( object.material ) ) { + console.log( 'THREE.WebGLRenderer', REVISION ); - for ( var i = 0; i < object.material.length; i ++ ) { + parameters = parameters || {}; - initMaterial( object.material[ i ], scene.fog, object ); + 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'; - } else { + var currentRenderList = null; + var currentRenderState = null; - initMaterial( object.material, scene.fog, object ); + // public properties - } + this.domElement = _canvas; + this.context = null; - } + // clearing - } ); + this.autoClear = true; + this.autoClearColor = true; + this.autoClearDepth = true; + this.autoClearStencil = true; - }; + // scene graph - // Animation Loop + this.sortObjects = true; - var isAnimating = false; - var onAnimationFrame = null; + // user-defined clipping - function startAnimation() { + this.clippingPlanes = []; + this.localClippingEnabled = false; - if ( isAnimating ) return; + // physically based shading - requestAnimationLoopFrame(); + this.gammaFactor = 2.0; // for backwards compatibility + this.gammaInput = false; + this.gammaOutput = false; - isAnimating = true; + // physical lights - } + this.physicallyCorrectLights = false; - function stopAnimation() { + // tone mapping - isAnimating = false; + this.toneMapping = LinearToneMapping; + this.toneMappingExposure = 1.0; + this.toneMappingWhitePoint = 1.0; - } + // morphs - function requestAnimationLoopFrame() { + this.maxMorphTargets = 8; + this.maxMorphNormals = 4; - var device = vr.getDevice(); + // internal properties - if ( device && device.isPresenting ) { + var _this = this, - device.requestAnimationFrame( animationLoop ); + _isContextLost = false, - } else { + // internal state cache - window.requestAnimationFrame( animationLoop ); + _framebuffer = null, - } + _currentRenderTarget = null, + _currentFramebuffer = null, + _currentMaterialId = - 1, - } + // geometry and program caching - function animationLoop( time ) { + _currentGeometryProgram = { + geometry: null, + program: null, + wireframe: false + }, - if ( isAnimating === false ) return; + _currentCamera = null, + _currentArrayCamera = null, - onAnimationFrame( time ); + _currentViewport = new Vector4(), + _currentScissor = new Vector4(), + _currentScissorTest = null, - requestAnimationLoopFrame(); + // - } + _usedTextureUnits = 0, - this.animate = function ( callback ) { + // - onAnimationFrame = callback; - onAnimationFrame !== null ? startAnimation() : stopAnimation(); + _width = _canvas.width, + _height = _canvas.height, - }; + _pixelRatio = 1, - // Rendering + _viewport = new Vector4( 0, 0, _width, _height ), + _scissor = new Vector4( 0, 0, _width, _height ), + _scissorTest = false, - this.render = function ( scene, camera, renderTarget, forceClear ) { + // frustum - if ( ! ( camera && camera.isCamera ) ) { + _frustum = new Frustum(), - console.error( 'THREE.WebGLRenderer.render: camera is not an instance of THREE.Camera.' ); - return; + // clipping - } + _clipping = new WebGLClipping(), + _clippingEnabled = false, + _localClippingEnabled = false, - if ( _isContextLost ) return; + // camera matrices cache - // reset caching for this frame + _projScreenMatrix = new Matrix4(), - _currentGeometryProgram = ''; - _currentMaterialId = - 1; - _currentCamera = null; + _vector3 = new Vector3(); - // update scene graph + function getTargetPixelRatio() { - if ( scene.autoUpdate === true ) scene.updateMatrixWorld(); + return _currentRenderTarget === null ? _pixelRatio : 1; - // update camera matrices and frustum + } - if ( camera.parent === null ) camera.updateMatrixWorld(); + // initialize - if ( vr.enabled ) { + var _gl; - camera = vr.getCamera( camera ); + try { - } + var contextAttributes = { + alpha: _alpha, + depth: _depth, + stencil: _stencil, + antialias: _antialias, + premultipliedAlpha: _premultipliedAlpha, + preserveDrawingBuffer: _preserveDrawingBuffer, + powerPreference: _powerPreference + }; - // + // event listeners must be registered before WebGL context is created, see #12753 - currentRenderState = renderStates.get( scene, camera ); - currentRenderState.init(); + _canvas.addEventListener( 'webglcontextlost', onContextLost, false ); + _canvas.addEventListener( 'webglcontextrestored', onContextRestore, false ); - scene.onBeforeRender( _this, scene, camera, renderTarget ); + _gl = _context || _canvas.getContext( 'webgl', contextAttributes ) || _canvas.getContext( 'experimental-webgl', contextAttributes ); - _projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse ); - _frustum.setFromMatrix( _projScreenMatrix ); + if ( _gl === null ) { - _localClippingEnabled = this.localClippingEnabled; - _clippingEnabled = _clipping.init( this.clippingPlanes, _localClippingEnabled, camera ); + if ( _canvas.getContext( 'webgl' ) !== null ) { - currentRenderList = renderLists.get( scene, camera ); - currentRenderList.init(); + throw new Error( 'Error creating WebGL context with your selected attributes.' ); - projectObject( scene, camera, _this.sortObjects ); + } else { - if ( _this.sortObjects === true ) { + throw new Error( 'Error creating WebGL context.' ); - currentRenderList.sort(); + } } - // - - if ( _clippingEnabled ) _clipping.beginShadows(); + // Some experimental-webgl implementations do not have getShaderPrecisionFormat - var shadowsArray = currentRenderState.state.shadowsArray; + if ( _gl.getShaderPrecisionFormat === undefined ) { - shadowMap.render( shadowsArray, scene, camera ); + _gl.getShaderPrecisionFormat = function () { - currentRenderState.setupLights( camera ); + return { 'rangeMin': 1, 'rangeMax': 1, 'precision': 1 }; - if ( _clippingEnabled ) _clipping.endShadows(); + }; - // + } - if ( this.info.autoReset ) this.info.reset(); + } catch ( error ) { - if ( renderTarget === undefined ) { + console.error( 'THREE.WebGLRenderer: ' + error.message ); - renderTarget = null; + } - } + var extensions, capabilities, state, info; + var properties, textures, attributes, geometries, objects; + var programCache, renderLists, renderStates; - this.setRenderTarget( renderTarget ); + var background, morphtargets, bufferRenderer, indexedBufferRenderer; - // + var utils; - background.render( currentRenderList, scene, camera, forceClear ); + function initGLContext() { - // render scene + extensions = new WebGLExtensions( _gl ); - var opaqueObjects = currentRenderList.opaque; - var transparentObjects = currentRenderList.transparent; + capabilities = new WebGLCapabilities( _gl, extensions, parameters ); - if ( scene.overrideMaterial ) { + if ( ! capabilities.isWebGL2 ) { - var overrideMaterial = scene.overrideMaterial; + 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 ( opaqueObjects.length ) renderObjects( opaqueObjects, scene, camera, overrideMaterial ); - if ( transparentObjects.length ) renderObjects( transparentObjects, scene, camera, overrideMaterial ); + } - } else { + extensions.get( 'OES_texture_float_linear' ); - // opaque pass (front-to-back order) + utils = new WebGLUtils( _gl, extensions, capabilities ); - if ( opaqueObjects.length ) renderObjects( opaqueObjects, scene, camera ); + state = new WebGLState( _gl, extensions, utils, capabilities ); + state.scissor( _currentScissor.copy( _scissor ).multiplyScalar( _pixelRatio ) ); + state.viewport( _currentViewport.copy( _viewport ).multiplyScalar( _pixelRatio ) ); - // transparent pass (back-to-front order) + 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 ( transparentObjects.length ) renderObjects( transparentObjects, scene, camera ); + background = new WebGLBackground( _this, state, objects, _premultipliedAlpha ); - } + bufferRenderer = new WebGLBufferRenderer( _gl, extensions, info, capabilities ); + indexedBufferRenderer = new WebGLIndexedBufferRenderer( _gl, extensions, info, capabilities ); - // custom renderers + info.programs = programCache.programs; - var spritesArray = currentRenderState.state.spritesArray; + _this.context = _gl; + _this.capabilities = capabilities; + _this.extensions = extensions; + _this.properties = properties; + _this.renderLists = renderLists; + _this.state = state; + _this.info = info; - spriteRenderer.render( spritesArray, scene, camera ); + } - // Generate mipmap if we're using any kind of mipmap filtering + initGLContext(); - if ( renderTarget ) { + // vr - textures.updateRenderTargetMipmap( renderTarget ); + var vr = null; - } + if ( typeof navigator !== 'undefined' ) { - // Ensure depth buffer writing is enabled so it can be cleared on next render + vr = ( 'xr' in navigator ) ? new WebXRManager( _this ) : new WebVRManager( _this ); - state.buffers.depth.setTest( true ); - state.buffers.depth.setMask( true ); - state.buffers.color.setMask( true ); + } - state.setPolygonOffset( false ); + this.vr = vr; - scene.onAfterRender( _this, scene, camera ); + // shadow map - if ( vr.enabled ) { + var shadowMap = new WebGLShadowMap( _this, objects, capabilities.maxTextureSize ); - vr.submitFrame(); + this.shadowMap = shadowMap; - } + // API - // _gl.finish(); + this.getContext = function () { - currentRenderList = null; - currentRenderState = null; + return _gl; }; - /* - // TODO Duplicated code (Frustum) + this.getContextAttributes = function () { - var _sphere = new Sphere(); + return _gl.getContextAttributes(); - function isObjectViewable( object ) { + }; - var geometry = object.geometry; + this.forceContextLoss = function () { - if ( geometry.boundingSphere === null ) - geometry.computeBoundingSphere(); + var extension = extensions.get( 'WEBGL_lose_context' ); + if ( extension ) extension.loseContext(); - _sphere.copy( geometry.boundingSphere ). - applyMatrix4( object.matrixWorld ); + }; - return isSphereViewable( _sphere ); + this.forceContextRestore = function () { - } + var extension = extensions.get( 'WEBGL_lose_context' ); + if ( extension ) extension.restoreContext(); - function isSpriteViewable( sprite ) { + }; - _sphere.center.set( 0, 0, 0 ); - _sphere.radius = 0.7071067811865476; - _sphere.applyMatrix4( sprite.matrixWorld ); + this.getPixelRatio = function () { - return isSphereViewable( _sphere ); + return _pixelRatio; - } + }; - function isSphereViewable( sphere ) { + this.setPixelRatio = function ( value ) { - if ( ! _frustum.intersectsSphere( sphere ) ) return false; + if ( value === undefined ) return; - var numPlanes = _clipping.numPlanes; + _pixelRatio = value; - if ( numPlanes === 0 ) return true; + this.setSize( _width, _height, false ); - var planes = _this.clippingPlanes, + }; - center = sphere.center, - negRad = - sphere.radius, - i = 0; + this.getSize = function () { - do { + return { + width: _width, + height: _height + }; - // out when deeper than radius in the negative halfspace - if ( planes[ i ].distanceToPoint( center ) < negRad ) return false; + }; - } while ( ++ i !== numPlanes ); + this.setSize = function ( width, height, updateStyle ) { - return true; + if ( vr.isPresenting() ) { - } - */ + console.warn( 'THREE.WebGLRenderer: Can\'t change size while VR device is presenting.' ); + return; - function projectObject( object, camera, sortObjects ) { + } - if ( object.visible === false ) return; + _width = width; + _height = height; - var visible = object.layers.test( camera.layers ); + _canvas.width = width * _pixelRatio; + _canvas.height = height * _pixelRatio; - if ( visible ) { + if ( updateStyle !== false ) { - if ( object.isLight ) { - - currentRenderState.pushLight( object ); - - if ( object.castShadow ) { - - currentRenderState.pushShadow( object ); - - } - - } else if ( object.isSprite ) { - - if ( ! object.frustumCulled || _frustum.intersectsSprite( object ) ) { - - currentRenderState.pushSprite( object ); - - } + _canvas.style.width = width + 'px'; + _canvas.style.height = height + 'px'; - } else if ( object.isImmediateRenderObject ) { + } - if ( sortObjects ) { + this.setViewport( 0, 0, width, height ); - _vector3.setFromMatrixPosition( object.matrixWorld ) - .applyMatrix4( _projScreenMatrix ); + }; - } + this.getDrawingBufferSize = function () { - currentRenderList.push( object, null, object.material, _vector3.z, null ); + return { + width: _width * _pixelRatio, + height: _height * _pixelRatio + }; - } else if ( object.isMesh || object.isLine || object.isPoints ) { + }; - if ( object.isSkinnedMesh ) { + this.setDrawingBufferSize = function ( width, height, pixelRatio ) { - object.skeleton.update(); + _width = width; + _height = height; - } + _pixelRatio = pixelRatio; - if ( ! object.frustumCulled || _frustum.intersectsObject( object ) ) { + _canvas.width = width * pixelRatio; + _canvas.height = height * pixelRatio; - if ( sortObjects ) { + this.setViewport( 0, 0, width, height ); - _vector3.setFromMatrixPosition( object.matrixWorld ) - .applyMatrix4( _projScreenMatrix ); + }; - } + this.getCurrentViewport = function () { - var geometry = objects.update( object ); - var material = object.material; + return _currentViewport; - if ( Array.isArray( material ) ) { + }; - var groups = geometry.groups; + this.setViewport = function ( x, y, width, height ) { - for ( var i = 0, l = groups.length; i < l; i ++ ) { + _viewport.set( x, _height - y - height, width, height ); + state.viewport( _currentViewport.copy( _viewport ).multiplyScalar( _pixelRatio ) ); - var group = groups[ i ]; - var groupMaterial = material[ group.materialIndex ]; + }; - if ( groupMaterial && groupMaterial.visible ) { + this.setScissor = function ( x, y, width, height ) { - currentRenderList.push( object, geometry, groupMaterial, _vector3.z, group ); + _scissor.set( x, _height - y - height, width, height ); + state.scissor( _currentScissor.copy( _scissor ).multiplyScalar( _pixelRatio ) ); - } + }; - } + this.setScissorTest = function ( boolean ) { - } else if ( material.visible ) { + state.setScissorTest( _scissorTest = boolean ); - currentRenderList.push( object, geometry, material, _vector3.z, null ); + }; - } + // Clearing - } + this.getClearColor = function () { - } + return background.getClearColor(); - } + }; - var children = object.children; + this.setClearColor = function () { - for ( var i = 0, l = children.length; i < l; i ++ ) { + background.setClearColor.apply( background, arguments ); - projectObject( children[ i ], camera, sortObjects ); + }; - } + this.getClearAlpha = function () { - } + return background.getClearAlpha(); - function renderObjects( renderList, scene, camera, overrideMaterial ) { + }; - for ( var i = 0, l = renderList.length; i < l; i ++ ) { + this.setClearAlpha = function () { - var renderItem = renderList[ i ]; + background.setClearAlpha.apply( background, arguments ); - var object = renderItem.object; - var geometry = renderItem.geometry; - var material = overrideMaterial === undefined ? renderItem.material : overrideMaterial; - var group = renderItem.group; + }; - if ( camera.isArrayCamera ) { + this.clear = function ( color, depth, stencil ) { - _currentArrayCamera = camera; + var bits = 0; - var cameras = camera.cameras; + if ( color === undefined || color ) bits |= 16384; + if ( depth === undefined || depth ) bits |= 256; + if ( stencil === undefined || stencil ) bits |= 1024; - for ( var j = 0, jl = cameras.length; j < jl; j ++ ) { + _gl.clear( bits ); - var camera2 = cameras[ j ]; + }; - if ( object.layers.test( camera2.layers ) ) { + this.clearColor = function () { - var bounds = camera2.bounds; + this.clear( true, false, false ); - var x = bounds.x * _width; - var y = bounds.y * _height; - var width = bounds.z * _width; - var height = bounds.w * _height; + }; - state.viewport( _currentViewport.set( x, y, width, height ).multiplyScalar( _pixelRatio ) ); + this.clearDepth = function () { - renderObject( object, scene, camera2, geometry, material, group ); + this.clear( false, true, false ); - } + }; - } + this.clearStencil = function () { - } else { + this.clear( false, false, true ); - _currentArrayCamera = null; + }; - renderObject( object, scene, camera, geometry, material, group ); + // - } + this.dispose = function () { - } + _canvas.removeEventListener( 'webglcontextlost', onContextLost, false ); + _canvas.removeEventListener( 'webglcontextrestored', onContextRestore, false ); - } + renderLists.dispose(); + renderStates.dispose(); + properties.dispose(); + objects.dispose(); - function renderObject( object, scene, camera, geometry, material, group ) { + vr.dispose(); - object.onBeforeRender( _this, scene, camera, geometry, material, group ); - currentRenderState = renderStates.get( scene, _currentArrayCamera || camera ); + animation.stop(); - object.modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld ); - object.normalMatrix.getNormalMatrix( object.modelViewMatrix ); + }; - if ( object.isImmediateRenderObject ) { + // Events - var frontFaceCW = ( object.isMesh && object.matrixWorld.determinant() < 0 ); + function onContextLost( event ) { - state.setMaterial( material, frontFaceCW ); + event.preventDefault(); - var program = setProgram( camera, scene.fog, material, object ); + console.log( 'THREE.WebGLRenderer: Context Lost.' ); - _currentGeometryProgram = ''; + _isContextLost = true; - renderObjectImmediate( object, program, material ); + } - } else { + function onContextRestore( /* event */ ) { - _this.renderBufferDirect( camera, scene.fog, geometry, material, object, group ); + console.log( 'THREE.WebGLRenderer: Context Restored.' ); - } + _isContextLost = false; - object.onAfterRender( _this, scene, camera, geometry, material, group ); - currentRenderState = renderStates.get( scene, _currentArrayCamera || camera ); + initGLContext(); } - function initMaterial( material, fog, object ) { + function onMaterialDispose( event ) { - var materialProperties = properties.get( material ); + var material = event.target; - var lights = currentRenderState.state.lights; - var shadowsArray = currentRenderState.state.shadowsArray; + material.removeEventListener( 'dispose', onMaterialDispose ); - var parameters = programCache.getParameters( - material, lights.state, shadowsArray, fog, _clipping.numPlanes, _clipping.numIntersection, object ); + deallocateMaterial( material ); - var code = programCache.getProgramCode( material, parameters ); + } - var program = materialProperties.program; - var programChange = true; + // Buffer deallocation - if ( program === undefined ) { + function deallocateMaterial( material ) { - // new material - material.addEventListener( 'dispose', onMaterialDispose ); + releaseMaterialProgramReference( material ); - } else if ( program.code !== code ) { + properties.remove( material ); - // changed glsl or parameters - releaseMaterialProgramReference( material ); + } - } else if ( materialProperties.lightsHash !== lights.state.hash ) { - properties.update( material, 'lightsHash', lights.state.hash ); - programChange = false; + function releaseMaterialProgramReference( material ) { - } else if ( parameters.shaderID !== undefined ) { + var programInfo = properties.get( material ).program; - // same glsl and uniform list - return; + material.program = undefined; - } else { + if ( programInfo !== undefined ) { - // only rebuild uniform list - programChange = false; + programCache.releaseProgram( programInfo ); } - if ( programChange ) { + } - if ( parameters.shaderID ) { + // Buffer rendering - var shader = ShaderLib[ parameters.shaderID ]; + function renderObjectImmediate( object, program ) { - materialProperties.shader = { - name: material.type, - uniforms: UniformsUtils.clone( shader.uniforms ), - vertexShader: shader.vertexShader, - fragmentShader: shader.fragmentShader - }; + object.render( function ( object ) { - } else { + _this.renderBufferImmediate( object, program ); - materialProperties.shader = { - name: material.type, - uniforms: material.uniforms, - vertexShader: material.vertexShader, - fragmentShader: material.fragmentShader - }; + } ); - } + } - material.onBeforeCompile( materialProperties.shader ); + this.renderBufferImmediate = function ( object, program ) { - program = programCache.acquireProgram( material, materialProperties.shader, parameters, code ); + state.initAttributes(); - materialProperties.program = program; - material.program = program; + 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(); var programAttributes = program.getAttributes(); - if ( material.morphTargets ) { + if ( object.hasPositions ) { - material.numSupportedMorphTargets = 0; + _gl.bindBuffer( 34962, buffers.position ); + _gl.bufferData( 34962, object.positionArray, 35048 ); - for ( var i = 0; i < _this.maxMorphTargets; i ++ ) { + state.enableAttribute( programAttributes.position ); + _gl.vertexAttribPointer( programAttributes.position, 3, 5126, false, 0, 0 ); - if ( programAttributes[ 'morphTarget' + i ] >= 0 ) { + } - material.numSupportedMorphTargets ++; + if ( object.hasNormals ) { - } + _gl.bindBuffer( 34962, buffers.normal ); + _gl.bufferData( 34962, object.normalArray, 35048 ); - } + state.enableAttribute( programAttributes.normal ); + _gl.vertexAttribPointer( programAttributes.normal, 3, 5126, false, 0, 0 ); } - if ( material.morphNormals ) { + if ( object.hasUvs ) { - material.numSupportedMorphNormals = 0; + _gl.bindBuffer( 34962, buffers.uv ); + _gl.bufferData( 34962, object.uvArray, 35048 ); - for ( var i = 0; i < _this.maxMorphNormals; i ++ ) { + state.enableAttribute( programAttributes.uv ); + _gl.vertexAttribPointer( programAttributes.uv, 2, 5126, false, 0, 0 ); - if ( programAttributes[ 'morphNormal' + i ] >= 0 ) { + } - material.numSupportedMorphNormals ++; + if ( object.hasColors ) { - } + _gl.bindBuffer( 34962, buffers.color ); + _gl.bufferData( 34962, object.colorArray, 35048 ); - } + state.enableAttribute( programAttributes.color ); + _gl.vertexAttribPointer( programAttributes.color, 3, 5126, false, 0, 0 ); } - var uniforms = materialProperties.shader.uniforms; + state.disableUnusedAttributes(); - if ( ! material.isShaderMaterial && - ! material.isRawShaderMaterial || - material.clipping === true ) { + _gl.drawArrays( 4, 0, object.count ); - materialProperties.numClippingPlanes = _clipping.numPlanes; - materialProperties.numIntersection = _clipping.numIntersection; - uniforms.clippingPlanes = _clipping.uniform; + object.count = 0; - } + }; - materialProperties.fog = fog; + this.renderBufferDirect = function ( camera, fog, geometry, material, object, group ) { - // store the light setup it was created for + var frontFaceCW = ( object.isMesh && object.normalMatrix.determinant() < 0 ); - materialProperties.lightsHash = lights.state.hash; + state.setMaterial( material, frontFaceCW ); - if ( material.lights ) { + var program = setProgram( camera, fog, material, object ); - // wire up the material to this renderer's lighting state + var updateBuffers = false; - 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; + if ( _currentGeometryProgram.geometry !== geometry.id || + _currentGeometryProgram.program !== program.id || + _currentGeometryProgram.wireframe !== ( material.wireframe === true ) ) { - 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 + _currentGeometryProgram.geometry = geometry.id; + _currentGeometryProgram.program = program.id; + _currentGeometryProgram.wireframe = material.wireframe === true; + updateBuffers = true; } - var progUniforms = materialProperties.program.getUniforms(), - uniformsList = - WebGLUniforms.seqWithValue( progUniforms.seq, uniforms ); - - materialProperties.uniformsList = uniformsList; - - } - - function setProgram( camera, fog, material, object ) { + if ( object.morphTargetInfluences ) { - _usedTextureUnits = 0; + morphtargets.update( object, geometry, material, program ); - var materialProperties = properties.get( material ); - var lights = currentRenderState.state.lights; + updateBuffers = true; - if ( _clippingEnabled ) { + } - if ( _localClippingEnabled || camera !== _currentCamera ) { + // - var useCache = - camera === _currentCamera && - material.id === _currentMaterialId; + var index = geometry.index; + var position = geometry.attributes.position; + var rangeFactor = 1; - // 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 ); + if ( material.wireframe === true ) { - } + index = geometries.getWireframeAttribute( geometry ); + rangeFactor = 2; } - if ( material.needsUpdate === false ) { + var attribute; + var renderer = bufferRenderer; - if ( materialProperties.program === undefined ) { + if ( index !== null ) { - material.needsUpdate = true; + attribute = attributes.get( index ); - } else if ( material.fog && materialProperties.fog !== fog ) { + renderer = indexedBufferRenderer; + renderer.setIndex( attribute ); - material.needsUpdate = true; + } - } else if ( material.lights && materialProperties.lightsHash !== lights.state.hash ) { + if ( updateBuffers ) { - material.needsUpdate = true; + setupVertexAttributes( material, program, geometry ); - } else if ( materialProperties.numClippingPlanes !== undefined && - ( materialProperties.numClippingPlanes !== _clipping.numPlanes || - materialProperties.numIntersection !== _clipping.numIntersection ) ) { + if ( index !== null ) { - material.needsUpdate = true; + _gl.bindBuffer( 34963, attribute.buffer ); } } - if ( material.needsUpdate ) { - - initMaterial( material, fog, object ); - material.needsUpdate = false; + // - } + var dataCount = Infinity; - var refreshProgram = false; - var refreshMaterial = false; - var refreshLights = false; + if ( index !== null ) { - var program = materialProperties.program, - p_uniforms = program.getUniforms(), - m_uniforms = materialProperties.shader.uniforms; + dataCount = index.count; - if ( state.useProgram( program.program ) ) { + } else if ( position !== undefined ) { - refreshProgram = true; - refreshMaterial = true; - refreshLights = true; + dataCount = position.count; } - if ( material.id !== _currentMaterialId ) { + var rangeStart = geometry.drawRange.start * rangeFactor; + var rangeCount = geometry.drawRange.count * rangeFactor; - _currentMaterialId = material.id; + var groupStart = group !== null ? group.start * rangeFactor : 0; + var groupCount = group !== null ? group.count * rangeFactor : Infinity; - refreshMaterial = true; + var drawStart = Math.max( rangeStart, groupStart ); + var drawEnd = Math.min( dataCount, rangeStart + rangeCount, groupStart + groupCount ) - 1; - } + var drawCount = Math.max( 0, drawEnd - drawStart + 1 ); - if ( refreshProgram || camera !== _currentCamera ) { + if ( drawCount === 0 ) return; - p_uniforms.setValue( _gl, 'projectionMatrix', camera.projectionMatrix ); + // - if ( capabilities.logarithmicDepthBuffer ) { + if ( object.isMesh ) { - p_uniforms.setValue( _gl, 'logDepthBufFC', - 2.0 / ( Math.log( camera.far + 1.0 ) / Math.LN2 ) ); + if ( material.wireframe === true ) { - } + state.setLineWidth( material.wireframeLinewidth * getTargetPixelRatio() ); + renderer.setMode( 1 ); - // Avoid unneeded uniform updates per ArrayCamera's sub-camera + } else { - if ( _currentCamera !== ( _currentArrayCamera || camera ) ) { + switch ( object.drawMode ) { - _currentCamera = ( _currentArrayCamera || camera ); + case TrianglesDrawMode: + renderer.setMode( 4 ); + break; - // 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: + case TriangleStripDrawMode: + renderer.setMode( 5 ); + break; - refreshMaterial = true; // set to true on material change - refreshLights = true; // remains set until update done + case TriangleFanDrawMode: + renderer.setMode( 6 ); + break; - } + } - // load material specific uniforms - // (shader material also gets them for the sake of genericity) + } - if ( material.isShaderMaterial || - material.isMeshPhongMaterial || - material.isMeshStandardMaterial || - material.envMap ) { - var uCamPos = p_uniforms.map.cameraPosition; + } else if ( object.isLine ) { - if ( uCamPos !== undefined ) { + var lineWidth = material.linewidth; - uCamPos.setValue( _gl, - _vector3.setFromMatrixPosition( camera.matrixWorld ) ); + if ( lineWidth === undefined ) lineWidth = 1; // Not using Line*Material - } + state.setLineWidth( lineWidth * getTargetPixelRatio() ); - } + if ( object.isLineSegments ) { - if ( material.isMeshPhongMaterial || - material.isMeshLambertMaterial || - material.isMeshBasicMaterial || - material.isMeshStandardMaterial || - material.isShaderMaterial || - material.skinning ) { + renderer.setMode( 1 ); - p_uniforms.setValue( _gl, 'viewMatrix', camera.matrixWorldInverse ); + } else if ( object.isLineLoop ) { - } + renderer.setMode( 2 ); - } + } else { - // 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 + renderer.setMode( 3 ); - if ( material.skinning ) { + } - p_uniforms.setOptional( _gl, object, 'bindMatrix' ); - p_uniforms.setOptional( _gl, object, 'bindMatrixInverse' ); + } else if ( object.isPoints ) { - var skeleton = object.skeleton; + renderer.setMode( 0 ); - if ( skeleton ) { + } else if ( object.isSprite ) { - var bones = skeleton.bones; + renderer.setMode( 4 ); - if ( capabilities.floatVertexTextures ) { + } - if ( skeleton.boneTexture === undefined ) { + if ( geometry && geometry.isInstancedBufferGeometry ) { - // 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.maxInstancedCount > 0 ) { + renderer.renderInstances( geometry, drawStart, drawCount ); - var size = Math.sqrt( bones.length * 4 ); // 4 pixels needed for 1 matrix - size = _Math.ceilPowerOfTwo( size ); - size = Math.max( size, 4 ); + } - var boneMatrices = new Float32Array( size * size * 4 ); // 4 floats per RGBA pixel - boneMatrices.set( skeleton.boneMatrices ); // copy current values + } else { - var boneTexture = new DataTexture( boneMatrices, size, size, RGBAFormat, FloatType ); - boneTexture.needsUpdate = true; + renderer.render( drawStart, drawCount ); - skeleton.boneMatrices = boneMatrices; - skeleton.boneTexture = boneTexture; - skeleton.boneTextureSize = size; + } - } + }; - p_uniforms.setValue( _gl, 'boneTexture', skeleton.boneTexture ); - p_uniforms.setValue( _gl, 'boneTextureSize', skeleton.boneTextureSize ); + function setupVertexAttributes( material, program, geometry ) { - } else { + if ( geometry && geometry.isInstancedBufferGeometry & ! capabilities.isWebGL2 ) { - p_uniforms.setOptional( _gl, skeleton, 'boneMatrices' ); + 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; } } - if ( refreshMaterial ) { - - p_uniforms.setValue( _gl, 'toneMappingExposure', _this.toneMappingExposure ); - p_uniforms.setValue( _gl, 'toneMappingWhitePoint', _this.toneMappingWhitePoint ); + state.initAttributes(); - if ( material.lights ) { + var geometryAttributes = geometry.attributes; - // the current material requires lighting info + var programAttributes = program.getAttributes(); - // 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 materialDefaultAttributeValues = material.defaultAttributeValues; - markUniformsLightsNeedsUpdate( m_uniforms, refreshLights ); + for ( var name in programAttributes ) { - } + var programAttribute = programAttributes[ name ]; - // refresh uniforms common to several materials + if ( programAttribute >= 0 ) { - if ( fog && material.fog ) { + var geometryAttribute = geometryAttributes[ name ]; - refreshUniformsFog( m_uniforms, fog ); + if ( geometryAttribute !== undefined ) { - } + var normalized = geometryAttribute.normalized; + var size = geometryAttribute.itemSize; - if ( material.isMeshBasicMaterial ) { + var attribute = attributes.get( geometryAttribute ); - refreshUniformsCommon( m_uniforms, material ); + // TODO Attribute may not be available on context restore - } else if ( material.isMeshLambertMaterial ) { + if ( attribute === undefined ) continue; - refreshUniformsCommon( m_uniforms, material ); - refreshUniformsLambert( m_uniforms, material ); - - } else if ( material.isMeshPhongMaterial ) { - - refreshUniformsCommon( m_uniforms, material ); + var buffer = attribute.buffer; + var type = attribute.type; + var bytesPerElement = attribute.bytesPerElement; - if ( material.isMeshToonMaterial ) { + if ( geometryAttribute.isInterleavedBufferAttribute ) { - refreshUniformsToon( m_uniforms, material ); + var data = geometryAttribute.data; + var stride = data.stride; + var offset = geometryAttribute.offset; - } else { + if ( data && data.isInstancedInterleavedBuffer ) { - refreshUniformsPhong( m_uniforms, material ); + state.enableAttributeAndDivisor( programAttribute, data.meshPerAttribute ); - } + if ( geometry.maxInstancedCount === undefined ) { - } else if ( material.isMeshStandardMaterial ) { + geometry.maxInstancedCount = data.meshPerAttribute * data.count; - refreshUniformsCommon( m_uniforms, material ); + } - if ( material.isMeshPhysicalMaterial ) { + } else { - refreshUniformsPhysical( m_uniforms, material ); + state.enableAttribute( programAttribute ); - } else { + } - refreshUniformsStandard( m_uniforms, material ); + _gl.bindBuffer( 34962, buffer ); + _gl.vertexAttribPointer( programAttribute, size, type, normalized, stride * bytesPerElement, offset * bytesPerElement ); - } + } else { - } else if ( material.isMeshDepthMaterial ) { + if ( geometryAttribute.isInstancedBufferAttribute ) { - refreshUniformsCommon( m_uniforms, material ); - refreshUniformsDepth( m_uniforms, material ); + state.enableAttributeAndDivisor( programAttribute, geometryAttribute.meshPerAttribute ); - } else if ( material.isMeshDistanceMaterial ) { + if ( geometry.maxInstancedCount === undefined ) { - refreshUniformsCommon( m_uniforms, material ); - refreshUniformsDistance( m_uniforms, material ); + geometry.maxInstancedCount = geometryAttribute.meshPerAttribute * geometryAttribute.count; - } else if ( material.isMeshNormalMaterial ) { + } - refreshUniformsCommon( m_uniforms, material ); - refreshUniformsNormal( m_uniforms, material ); + } else { - } else if ( material.isLineBasicMaterial ) { + state.enableAttribute( programAttribute ); - refreshUniformsLine( m_uniforms, material ); + } - if ( material.isLineDashedMaterial ) { + _gl.bindBuffer( 34962, buffer ); + _gl.vertexAttribPointer( programAttribute, size, type, normalized, 0, 0 ); - refreshUniformsDash( m_uniforms, material ); + } - } + } else if ( materialDefaultAttributeValues !== undefined ) { - } else if ( material.isPointsMaterial ) { + var value = materialDefaultAttributeValues[ name ]; - refreshUniformsPoints( m_uniforms, material ); + if ( value !== undefined ) { - } else if ( material.isShadowMaterial ) { + switch ( value.length ) { - m_uniforms.color.value = material.color; - m_uniforms.opacity.value = material.opacity; + case 2: + _gl.vertexAttrib2fv( programAttribute, value ); + break; - } + case 3: + _gl.vertexAttrib3fv( programAttribute, value ); + break; - // RectAreaLight Texture - // TODO (mrdoob): Find a nicer implementation + case 4: + _gl.vertexAttrib4fv( programAttribute, value ); + break; - 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; + default: + _gl.vertexAttrib1fv( programAttribute, value ); - WebGLUniforms.upload( _gl, materialProperties.uniformsList, m_uniforms, _this ); + } - } + } - if ( material.isShaderMaterial && material.uniformsNeedUpdate === true ) { + } - WebGLUniforms.upload( _gl, materialProperties.uniformsList, m_uniforms, _this ); - material.uniformsNeedUpdate = false; + } } - // 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; + state.disableUnusedAttributes(); } - // Uniforms (refresh uniforms objects) + // Compile - function refreshUniformsCommon( uniforms, material ) { + this.compile = function ( scene, camera ) { - uniforms.opacity.value = material.opacity; + currentRenderState = renderStates.get( scene, camera ); + currentRenderState.init(); - if ( material.color ) { + scene.traverse( function ( object ) { - uniforms.diffuse.value = material.color; + if ( object.isLight ) { - } + currentRenderState.pushLight( object ); - if ( material.emissive ) { + if ( object.castShadow ) { - uniforms.emissive.value.copy( material.emissive ).multiplyScalar( material.emissiveIntensity ); + currentRenderState.pushShadow( object ); - } + } - if ( material.map ) { + } - uniforms.map.value = material.map; + } ); - } + currentRenderState.setupLights( camera ); - if ( material.alphaMap ) { + scene.traverse( function ( object ) { - uniforms.alphaMap.value = material.alphaMap; + if ( object.material ) { - } + if ( Array.isArray( object.material ) ) { - if ( material.specularMap ) { + for ( var i = 0; i < object.material.length; i ++ ) { - uniforms.specularMap.value = material.specularMap; + initMaterial( object.material[ i ], scene.fog, object ); - } + } - if ( material.envMap ) { + } else { - uniforms.envMap.value = material.envMap; + initMaterial( object.material, scene.fog, object ); - // 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; + } - } + } ); - if ( material.lightMap ) { + }; - uniforms.lightMap.value = material.lightMap; - uniforms.lightMapIntensity.value = material.lightMapIntensity; + // Animation Loop - } + var onAnimationFrameCallback = null; - if ( material.aoMap ) { + function onAnimationFrame( time ) { - uniforms.aoMap.value = material.aoMap; - uniforms.aoMapIntensity.value = material.aoMapIntensity; + if ( vr.isPresenting() ) return; + if ( onAnimationFrameCallback ) onAnimationFrameCallback( time ); - } + } - // uv repeat and offset setting priorities - // 1. color map - // 2. specular map - // 3. normal map - // 4. bump map - // 5. alpha map - // 6. emissive map + var animation = new WebGLAnimation(); + animation.setAnimationLoop( onAnimationFrame ); - var uvScaleMap; + if ( typeof window !== 'undefined' ) animation.setContext( window ); - if ( material.map ) { + this.setAnimationLoop = function ( callback ) { - uvScaleMap = material.map; + onAnimationFrameCallback = callback; + vr.setAnimationLoop( callback ); - } else if ( material.specularMap ) { + animation.start(); - uvScaleMap = material.specularMap; + }; - } else if ( material.displacementMap ) { + // Rendering - uvScaleMap = material.displacementMap; + this.render = function ( scene, camera, renderTarget, forceClear ) { - } else if ( material.normalMap ) { + if ( ! ( camera && camera.isCamera ) ) { - uvScaleMap = material.normalMap; + console.error( 'THREE.WebGLRenderer.render: camera is not an instance of THREE.Camera.' ); + return; - } else if ( material.bumpMap ) { + } - uvScaleMap = material.bumpMap; + if ( _isContextLost ) return; - } else if ( material.roughnessMap ) { + // reset caching for this frame - uvScaleMap = material.roughnessMap; + _currentGeometryProgram.geometry = null; + _currentGeometryProgram.program = null; + _currentGeometryProgram.wireframe = false; + _currentMaterialId = - 1; + _currentCamera = null; - } else if ( material.metalnessMap ) { + // update scene graph - uvScaleMap = material.metalnessMap; + if ( scene.autoUpdate === true ) scene.updateMatrixWorld(); - } else if ( material.alphaMap ) { + // update camera matrices and frustum - uvScaleMap = material.alphaMap; + if ( camera.parent === null ) camera.updateMatrixWorld(); - } else if ( material.emissiveMap ) { + if ( vr.enabled ) { - uvScaleMap = material.emissiveMap; + camera = vr.getCamera( camera ); } - if ( uvScaleMap !== undefined ) { + // - // backwards compatibility - if ( uvScaleMap.isWebGLRenderTarget ) { + currentRenderState = renderStates.get( scene, camera ); + currentRenderState.init(); - uvScaleMap = uvScaleMap.texture; + scene.onBeforeRender( _this, scene, camera, renderTarget ); - } + _projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse ); + _frustum.setFromMatrix( _projScreenMatrix ); - if ( uvScaleMap.matrixAutoUpdate === true ) { + _localClippingEnabled = this.localClippingEnabled; + _clippingEnabled = _clipping.init( this.clippingPlanes, _localClippingEnabled, camera ); - var offset = uvScaleMap.offset; - var repeat = uvScaleMap.repeat; - var rotation = uvScaleMap.rotation; - var center = uvScaleMap.center; + currentRenderList = renderLists.get( scene, camera ); + currentRenderList.init(); - uvScaleMap.matrix.setUvTransform( offset.x, offset.y, repeat.x, repeat.y, rotation, center.x, center.y ); + projectObject( scene, camera, _this.sortObjects ); - } + if ( _this.sortObjects === true ) { - uniforms.uvTransform.value.copy( uvScaleMap.matrix ); + currentRenderList.sort(); } - } + // - function refreshUniformsLine( uniforms, material ) { + if ( _clippingEnabled ) _clipping.beginShadows(); - uniforms.diffuse.value = material.color; - uniforms.opacity.value = material.opacity; + var shadowsArray = currentRenderState.state.shadowsArray; - } + shadowMap.render( shadowsArray, scene, camera ); - function refreshUniformsDash( uniforms, material ) { + currentRenderState.setupLights( camera ); - uniforms.dashSize.value = material.dashSize; - uniforms.totalSize.value = material.dashSize + material.gapSize; - uniforms.scale.value = material.scale; + if ( _clippingEnabled ) _clipping.endShadows(); - } + // - function refreshUniformsPoints( uniforms, material ) { + if ( this.info.autoReset ) this.info.reset(); - uniforms.diffuse.value = material.color; - uniforms.opacity.value = material.opacity; - uniforms.size.value = material.size * _pixelRatio; - uniforms.scale.value = _height * 0.5; + if ( renderTarget === undefined ) { - uniforms.map.value = material.map; + renderTarget = null; - if ( material.map !== null ) { + } - if ( material.map.matrixAutoUpdate === true ) { + this.setRenderTarget( renderTarget ); - var offset = material.map.offset; - var repeat = material.map.repeat; - var rotation = material.map.rotation; - var center = material.map.center; + // - material.map.matrix.setUvTransform( offset.x, offset.y, repeat.x, repeat.y, rotation, center.x, center.y ); + background.render( currentRenderList, scene, camera, forceClear ); - } + // render scene - uniforms.uvTransform.value.copy( material.map.matrix ); + var opaqueObjects = currentRenderList.opaque; + var transparentObjects = currentRenderList.transparent; - } + if ( scene.overrideMaterial ) { - } + var overrideMaterial = scene.overrideMaterial; - function refreshUniformsFog( uniforms, fog ) { + if ( opaqueObjects.length ) renderObjects( opaqueObjects, scene, camera, overrideMaterial ); + if ( transparentObjects.length ) renderObjects( transparentObjects, scene, camera, overrideMaterial ); - uniforms.fogColor.value = fog.color; + } else { - if ( fog.isFog ) { + // opaque pass (front-to-back order) - uniforms.fogNear.value = fog.near; - uniforms.fogFar.value = fog.far; + if ( opaqueObjects.length ) renderObjects( opaqueObjects, scene, camera ); - } else if ( fog.isFogExp2 ) { + // transparent pass (back-to-front order) - uniforms.fogDensity.value = fog.density; + if ( transparentObjects.length ) renderObjects( transparentObjects, scene, camera ); } - } - - function refreshUniformsLambert( uniforms, material ) { + // Generate mipmap if we're using any kind of mipmap filtering - if ( material.emissiveMap ) { + if ( renderTarget ) { - uniforms.emissiveMap.value = material.emissiveMap; + textures.updateRenderTargetMipmap( renderTarget ); } - } + // Ensure depth buffer writing is enabled so it can be cleared on next render - function refreshUniformsPhong( uniforms, material ) { + state.buffers.depth.setTest( true ); + state.buffers.depth.setMask( true ); + state.buffers.color.setMask( true ); - uniforms.specular.value = material.specular; - uniforms.shininess.value = Math.max( material.shininess, 1e-4 ); // to prevent pow( 0.0, 0.0 ) + state.setPolygonOffset( false ); - if ( material.emissiveMap ) { + scene.onAfterRender( _this, scene, camera ); - uniforms.emissiveMap.value = material.emissiveMap; + if ( vr.enabled ) { + + vr.submitFrame(); } - if ( material.bumpMap ) { + // _gl.finish(); - uniforms.bumpMap.value = material.bumpMap; - uniforms.bumpScale.value = material.bumpScale; + currentRenderList = null; + currentRenderState = null; - } + }; - if ( material.normalMap ) { + function projectObject( object, camera, sortObjects ) { - uniforms.normalMap.value = material.normalMap; - uniforms.normalScale.value.copy( material.normalScale ); + if ( object.visible === false ) return; - } + var visible = object.layers.test( camera.layers ); - if ( material.displacementMap ) { + if ( visible ) { - uniforms.displacementMap.value = material.displacementMap; - uniforms.displacementScale.value = material.displacementScale; - uniforms.displacementBias.value = material.displacementBias; + if ( object.isLight ) { - } + currentRenderState.pushLight( object ); - } + if ( object.castShadow ) { - function refreshUniformsToon( uniforms, material ) { + currentRenderState.pushShadow( object ); - refreshUniformsPhong( uniforms, material ); + } - if ( material.gradientMap ) { + } else if ( object.isSprite ) { - uniforms.gradientMap.value = material.gradientMap; + if ( ! object.frustumCulled || _frustum.intersectsSprite( object ) ) { - } + if ( sortObjects ) { - } + _vector3.setFromMatrixPosition( object.matrixWorld ) + .applyMatrix4( _projScreenMatrix ); - function refreshUniformsStandard( uniforms, material ) { + } - uniforms.roughness.value = material.roughness; - uniforms.metalness.value = material.metalness; + var geometry = objects.update( object ); + var material = object.material; - if ( material.roughnessMap ) { + currentRenderList.push( object, geometry, material, _vector3.z, null ); - uniforms.roughnessMap.value = material.roughnessMap; + } - } + } else if ( object.isImmediateRenderObject ) { - if ( material.metalnessMap ) { + if ( sortObjects ) { - uniforms.metalnessMap.value = material.metalnessMap; + _vector3.setFromMatrixPosition( object.matrixWorld ) + .applyMatrix4( _projScreenMatrix ); - } + } - if ( material.emissiveMap ) { + currentRenderList.push( object, null, object.material, _vector3.z, null ); - uniforms.emissiveMap.value = material.emissiveMap; + } else if ( object.isMesh || object.isLine || object.isPoints ) { - } + if ( object.isSkinnedMesh ) { - if ( material.bumpMap ) { + object.skeleton.update(); - uniforms.bumpMap.value = material.bumpMap; - uniforms.bumpScale.value = material.bumpScale; + } - } + if ( ! object.frustumCulled || _frustum.intersectsObject( object ) ) { - if ( material.normalMap ) { + if ( sortObjects ) { - uniforms.normalMap.value = material.normalMap; - uniforms.normalScale.value.copy( material.normalScale ); + _vector3.setFromMatrixPosition( object.matrixWorld ) + .applyMatrix4( _projScreenMatrix ); - } + } - if ( material.displacementMap ) { + var geometry = objects.update( object ); + var material = object.material; - uniforms.displacementMap.value = material.displacementMap; - uniforms.displacementScale.value = material.displacementScale; - uniforms.displacementBias.value = material.displacementBias; + if ( Array.isArray( material ) ) { - } + var groups = geometry.groups; - if ( material.envMap ) { + for ( var i = 0, l = groups.length; i < l; i ++ ) { - //uniforms.envMap.value = material.envMap; // part of uniforms common - uniforms.envMapIntensity.value = material.envMapIntensity; + var group = groups[ i ]; + var groupMaterial = material[ group.materialIndex ]; - } + if ( groupMaterial && groupMaterial.visible ) { - } + currentRenderList.push( object, geometry, groupMaterial, _vector3.z, group ); - function refreshUniformsPhysical( uniforms, material ) { + } - uniforms.clearCoat.value = material.clearCoat; - uniforms.clearCoatRoughness.value = material.clearCoatRoughness; + } - refreshUniformsStandard( uniforms, material ); + } else if ( material.visible ) { - } + currentRenderList.push( object, geometry, material, _vector3.z, null ); - function refreshUniformsDepth( uniforms, material ) { + } - if ( material.displacementMap ) { + } - uniforms.displacementMap.value = material.displacementMap; - uniforms.displacementScale.value = material.displacementScale; - uniforms.displacementBias.value = material.displacementBias; + } } - } - - function refreshUniformsDistance( uniforms, material ) { + var children = object.children; - if ( material.displacementMap ) { + for ( var i = 0, l = children.length; i < l; i ++ ) { - uniforms.displacementMap.value = material.displacementMap; - uniforms.displacementScale.value = material.displacementScale; - uniforms.displacementBias.value = material.displacementBias; + projectObject( children[ i ], camera, sortObjects ); } - uniforms.referencePosition.value.copy( material.referencePosition ); - uniforms.nearDistance.value = material.nearDistance; - uniforms.farDistance.value = material.farDistance; - } - function refreshUniformsNormal( uniforms, material ) { + function renderObjects( renderList, scene, camera, overrideMaterial ) { - if ( material.bumpMap ) { + for ( var i = 0, l = renderList.length; i < l; i ++ ) { - uniforms.bumpMap.value = material.bumpMap; - uniforms.bumpScale.value = material.bumpScale; + var renderItem = renderList[ i ]; - } + var object = renderItem.object; + var geometry = renderItem.geometry; + var material = overrideMaterial === undefined ? renderItem.material : overrideMaterial; + var group = renderItem.group; - if ( material.normalMap ) { + if ( camera.isArrayCamera ) { - uniforms.normalMap.value = material.normalMap; - uniforms.normalScale.value.copy( material.normalScale ); + _currentArrayCamera = camera; - } + var cameras = camera.cameras; - if ( material.displacementMap ) { + for ( var j = 0, jl = cameras.length; j < jl; j ++ ) { - uniforms.displacementMap.value = material.displacementMap; - uniforms.displacementScale.value = material.displacementScale; - uniforms.displacementBias.value = material.displacementBias; + var camera2 = cameras[ j ]; - } + if ( object.layers.test( camera2.layers ) ) { - } + if ( 'viewport' in camera2 ) { // XR - // If uniforms are marked as clean, they don't need to be loaded to the GPU. + state.viewport( _currentViewport.copy( camera2.viewport ) ); - function markUniformsLightsNeedsUpdate( uniforms, value ) { + } else { - uniforms.ambientLightColor.needsUpdate = value; + var bounds = camera2.bounds; - uniforms.directionalLights.needsUpdate = value; - uniforms.pointLights.needsUpdate = value; - uniforms.spotLights.needsUpdate = value; - uniforms.rectAreaLights.needsUpdate = value; - uniforms.hemisphereLights.needsUpdate = value; + var x = bounds.x * _width; + var y = bounds.y * _height; + var width = bounds.z * _width; + var height = bounds.w * _height; - } + state.viewport( _currentViewport.set( x, y, width, height ).multiplyScalar( _pixelRatio ) ); - // Textures + } - function allocTextureUnit() { + currentRenderState.setupLights( camera2 ); - var textureUnit = _usedTextureUnits; + renderObject( object, scene, camera2, geometry, material, group ); - if ( textureUnit >= capabilities.maxTextures ) { + } - console.warn( 'THREE.WebGLRenderer: Trying to use ' + textureUnit + ' texture units while this GPU supports only ' + capabilities.maxTextures ); + } - } + } else { - _usedTextureUnits += 1; + _currentArrayCamera = null; - return textureUnit; + renderObject( object, scene, camera, geometry, material, group ); - } + } - this.allocTextureUnit = allocTextureUnit; + } - // this.setTexture2D = setTexture2D; - this.setTexture2D = ( function () { + } - var warned = false; + function renderObject( object, scene, camera, geometry, material, group ) { - // backwards compatibility: peel texture.texture - return function setTexture2D( texture, slot ) { + object.onBeforeRender( _this, scene, camera, geometry, material, group ); + currentRenderState = renderStates.get( scene, _currentArrayCamera || camera ); - if ( texture && texture.isWebGLRenderTarget ) { + object.modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld ); + object.normalMatrix.getNormalMatrix( object.modelViewMatrix ); - if ( ! warned ) { + if ( object.isImmediateRenderObject ) { - console.warn( "THREE.WebGLRenderer.setTexture2D: don't use render targets as textures. Use their .texture property instead." ); - warned = true; + state.setMaterial( material ); - } + var program = setProgram( camera, scene.fog, material, object ); - texture = texture.texture; + _currentGeometryProgram.geometry = null; + _currentGeometryProgram.program = null; + _currentGeometryProgram.wireframe = false; - } + renderObjectImmediate( object, program ); - textures.setTexture2D( texture, slot ); + } else { - }; + _this.renderBufferDirect( camera, scene.fog, geometry, material, object, group ); - }() ); - - this.setTexture = ( function () { - - var warned = false; - - return function setTexture( texture, slot ) { + } - if ( ! warned ) { + object.onAfterRender( _this, scene, camera, geometry, material, group ); + currentRenderState = renderStates.get( scene, _currentArrayCamera || camera ); - console.warn( "THREE.WebGLRenderer: .setTexture is deprecated, use setTexture2D instead." ); - warned = true; + } - } + function initMaterial( material, fog, object ) { - textures.setTexture2D( texture, slot ); + var materialProperties = properties.get( material ); - }; + var lights = currentRenderState.state.lights; + var shadowsArray = currentRenderState.state.shadowsArray; - }() ); + var lightsHash = materialProperties.lightsHash; + var lightsStateHash = lights.state.hash; - this.setTextureCube = ( function () { + var parameters = programCache.getParameters( + material, lights.state, shadowsArray, fog, _clipping.numPlanes, _clipping.numIntersection, object ); - var warned = false; + var code = programCache.getProgramCode( material, parameters ); - return function setTextureCube( texture, slot ) { + var program = materialProperties.program; + var programChange = true; - // backwards compatibility: peel texture.texture - if ( texture && texture.isWebGLRenderTargetCube ) { + if ( program === undefined ) { - if ( ! warned ) { + // new material + material.addEventListener( 'dispose', onMaterialDispose ); - console.warn( "THREE.WebGLRenderer.setTextureCube: don't use cube render targets as textures. Use their .texture property instead." ); - warned = true; + } else if ( program.code !== code ) { - } + // changed glsl or parameters + releaseMaterialProgramReference( material ); - texture = texture.texture; + } 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; - // 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 ) ) { + } else if ( parameters.shaderID !== undefined ) { - // CompressedTexture can have Array in image :/ + // same glsl and uniform list + return; - // this function alone should take care of cube textures - textures.setTextureCube( texture, slot ); + } else { - } else { + // only rebuild uniform list + programChange = false; - // assumed: texture property of THREE.WebGLRenderTargetCube + } - textures.setTextureCubeDynamic( texture, slot ); + if ( programChange ) { - } + if ( parameters.shaderID ) { - }; + var shader = ShaderLib[ parameters.shaderID ]; - }() ); + materialProperties.shader = { + name: material.type, + uniforms: cloneUniforms( shader.uniforms ), + vertexShader: shader.vertexShader, + fragmentShader: shader.fragmentShader + }; - this.getRenderTarget = function () { + } else { - return _currentRenderTarget; + materialProperties.shader = { + name: material.type, + uniforms: material.uniforms, + vertexShader: material.vertexShader, + fragmentShader: material.fragmentShader + }; - }; + } - this.setRenderTarget = function ( renderTarget ) { + material.onBeforeCompile( materialProperties.shader, _this ); - _currentRenderTarget = renderTarget; + // Computing code again as onBeforeCompile may have changed the shaders + code = programCache.getProgramCode( material, parameters ); - if ( renderTarget && properties.get( renderTarget ).__webglFramebuffer === undefined ) { + program = programCache.acquireProgram( material, materialProperties.shader, parameters, code ); - textures.setupRenderTarget( renderTarget ); + materialProperties.program = program; + material.program = program; } - var framebuffer = null; - var isCube = false; + var programAttributes = program.getAttributes(); - if ( renderTarget ) { + if ( material.morphTargets ) { - var __webglFramebuffer = properties.get( renderTarget ).__webglFramebuffer; + material.numSupportedMorphTargets = 0; - if ( renderTarget.isWebGLRenderTargetCube ) { + for ( var i = 0; i < _this.maxMorphTargets; i ++ ) { - framebuffer = __webglFramebuffer[ renderTarget.activeCubeFace ]; - isCube = true; + if ( programAttributes[ 'morphTarget' + i ] >= 0 ) { - } else { + material.numSupportedMorphTargets ++; - framebuffer = __webglFramebuffer; + } } - _currentViewport.copy( renderTarget.viewport ); - _currentScissor.copy( renderTarget.scissor ); - _currentScissorTest = renderTarget.scissorTest; + } - } else { + if ( material.morphNormals ) { - _currentViewport.copy( _viewport ).multiplyScalar( _pixelRatio ); - _currentScissor.copy( _scissor ).multiplyScalar( _pixelRatio ); - _currentScissorTest = _scissorTest; + material.numSupportedMorphNormals = 0; - } + for ( var i = 0; i < _this.maxMorphNormals; i ++ ) { - if ( _currentFramebuffer !== framebuffer ) { + if ( programAttributes[ 'morphNormal' + i ] >= 0 ) { - _gl.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer ); - _currentFramebuffer = framebuffer; + material.numSupportedMorphNormals ++; + + } + + } } - state.viewport( _currentViewport ); - state.scissor( _currentScissor ); - state.setScissorTest( _currentScissorTest ); + var uniforms = materialProperties.shader.uniforms; - if ( isCube ) { + if ( ! material.isShaderMaterial && + ! material.isRawShaderMaterial || + material.clipping === true ) { - var textureProperties = properties.get( renderTarget.texture ); - _gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_CUBE_MAP_POSITIVE_X + renderTarget.activeCubeFace, textureProperties.__webglTexture, renderTarget.activeMipMapLevel ); + materialProperties.numClippingPlanes = _clipping.numPlanes; + materialProperties.numIntersection = _clipping.numIntersection; + uniforms.clippingPlanes = _clipping.uniform; } - }; - - this.readRenderTargetPixels = function ( renderTarget, x, y, width, height, buffer ) { + materialProperties.fog = fog; - if ( ! ( renderTarget && renderTarget.isWebGLRenderTarget ) ) { + // store the light setup it was created for + if ( lightsHash === undefined ) { - console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.' ); - return; + materialProperties.lightsHash = lightsHash = {}; } - var framebuffer = properties.get( renderTarget ).__webglFramebuffer; + 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 ( framebuffer ) { + if ( material.lights ) { - var restore = false; + // wire up the material to this renderer's lighting state - if ( framebuffer !== _currentFramebuffer ) { + 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; - _gl.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer ); + 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 - restore = true; + } - } + var progUniforms = materialProperties.program.getUniforms(), + uniformsList = + WebGLUniforms.seqWithValue( progUniforms.seq, uniforms ); - try { + materialProperties.uniformsList = uniformsList; - var texture = renderTarget.texture; - var textureFormat = texture.format; - var textureType = texture.type; + } - if ( textureFormat !== RGBAFormat && utils.convert( textureFormat ) !== _gl.getParameter( _gl.IMPLEMENTATION_COLOR_READ_FORMAT ) ) { + function setProgram( camera, fog, material, object ) { - console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in RGBA or implementation defined format.' ); - return; + _usedTextureUnits = 0; - } + var materialProperties = properties.get( material ); + var lights = currentRenderState.state.lights; - if ( textureType !== UnsignedByteType && utils.convert( textureType ) !== _gl.getParameter( _gl.IMPLEMENTATION_COLOR_READ_TYPE ) && // IE11, Edge and Chrome Mac < 52 (#9513) - ! ( textureType === FloatType && ( extensions.get( 'OES_texture_float' ) || extensions.get( 'WEBGL_color_buffer_float' ) ) ) && // Chrome Mac >= 52 and Firefox - ! ( textureType === HalfFloatType && extensions.get( 'EXT_color_buffer_half_float' ) ) ) { + var lightsHash = materialProperties.lightsHash; + var lightsStateHash = lights.state.hash; - console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in UnsignedByteType or implementation defined type.' ); - return; + if ( _clippingEnabled ) { - } + if ( _localClippingEnabled || camera !== _currentCamera ) { - if ( _gl.checkFramebufferStatus( _gl.FRAMEBUFFER ) === _gl.FRAMEBUFFER_COMPLETE ) { + var useCache = + camera === _currentCamera && + material.id === _currentMaterialId; - // the following if statement ensures valid read requests (no out-of-bounds pixels, see #8604) + // 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 ); - 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 ); + } - } + if ( material.needsUpdate === false ) { - } else { + if ( materialProperties.program === undefined ) { - console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: readPixels from renderTarget failed. Framebuffer not complete.' ); + material.needsUpdate = true; - } + } else if ( material.fog && materialProperties.fog !== fog ) { - } finally { + material.needsUpdate = true; - if ( restore ) { + } 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 ) ) { - _gl.bindFramebuffer( _gl.FRAMEBUFFER, _currentFramebuffer ); + material.needsUpdate = true; - } + } else if ( materialProperties.numClippingPlanes !== undefined && + ( materialProperties.numClippingPlanes !== _clipping.numPlanes || + materialProperties.numIntersection !== _clipping.numIntersection ) ) { + + material.needsUpdate = true; } } - }; + if ( material.needsUpdate ) { - this.copyFramebufferToTexture = function ( position, texture, level ) { + initMaterial( material, fog, object ); + material.needsUpdate = false; - var width = texture.image.width; - var height = texture.image.height; - var internalFormat = utils.convert( texture.format ); + } - this.setTexture2D( texture, 0 ); + var refreshProgram = false; + var refreshMaterial = false; + var refreshLights = false; - _gl.copyTexImage2D( _gl.TEXTURE_2D, level || 0, internalFormat, position.x, position.y, width, height, 0 ); + var program = materialProperties.program, + p_uniforms = program.getUniforms(), + m_uniforms = materialProperties.shader.uniforms; - }; + if ( state.useProgram( program.program ) ) { -} + refreshProgram = true; + refreshMaterial = true; + refreshLights = true; -/** - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - */ + } -function FogExp2( color, density ) { + if ( material.id !== _currentMaterialId ) { - this.name = ''; + _currentMaterialId = material.id; - this.color = new Color( color ); - this.density = ( density !== undefined ) ? density : 0.00025; + refreshMaterial = true; -} + } -FogExp2.prototype.isFogExp2 = true; + if ( refreshProgram || _currentCamera !== camera ) { -FogExp2.prototype.clone = function () { + p_uniforms.setValue( _gl, 'projectionMatrix', camera.projectionMatrix ); - return new FogExp2( this.color.getHex(), this.density ); + if ( capabilities.logarithmicDepthBuffer ) { -}; + p_uniforms.setValue( _gl, 'logDepthBufFC', + 2.0 / ( Math.log( camera.far + 1.0 ) / Math.LN2 ) ); -FogExp2.prototype.toJSON = function ( /* meta */ ) { + } - return { - type: 'FogExp2', - color: this.color.getHex(), - density: this.density - }; + if ( _currentCamera !== camera ) { -}; + _currentCamera = camera; -/** - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - */ + // 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: -function Fog( color, near, far ) { + refreshMaterial = true; // set to true on material change + refreshLights = true; // remains set until update done - this.name = ''; + } - this.color = new Color( color ); + // load material specific uniforms + // (shader material also gets them for the sake of genericity) - this.near = ( near !== undefined ) ? near : 1; - this.far = ( far !== undefined ) ? far : 1000; + if ( material.isShaderMaterial || + material.isMeshPhongMaterial || + material.isMeshStandardMaterial || + material.envMap ) { -} + var uCamPos = p_uniforms.map.cameraPosition; -Fog.prototype.isFog = true; + if ( uCamPos !== undefined ) { -Fog.prototype.clone = function () { + uCamPos.setValue( _gl, + _vector3.setFromMatrixPosition( camera.matrixWorld ) ); - return new Fog( this.color.getHex(), this.near, this.far ); + } -}; + } -Fog.prototype.toJSON = function ( /* meta */ ) { + if ( material.isMeshPhongMaterial || + material.isMeshLambertMaterial || + material.isMeshBasicMaterial || + material.isMeshStandardMaterial || + material.isShaderMaterial || + material.skinning ) { - return { - type: 'Fog', - color: this.color.getHex(), - near: this.near, - far: this.far - }; + p_uniforms.setValue( _gl, 'viewMatrix', camera.matrixWorldInverse ); -}; + } -/** - * @author mrdoob / http://mrdoob.com/ - */ + } -function Scene() { + // 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 - Object3D.call( this ); + if ( material.skinning ) { - this.type = 'Scene'; + p_uniforms.setOptional( _gl, object, 'bindMatrix' ); + p_uniforms.setOptional( _gl, object, 'bindMatrixInverse' ); - this.background = null; - this.fog = null; - this.overrideMaterial = null; + var skeleton = object.skeleton; - this.autoUpdate = true; // checked by the renderer + if ( skeleton ) { -} + var bones = skeleton.bones; -Scene.prototype = Object.assign( Object.create( Object3D.prototype ), { + if ( capabilities.floatVertexTextures ) { - constructor: Scene, + if ( skeleton.boneTexture === undefined ) { - copy: function ( source, recursive ) { + // 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) - Object3D.prototype.copy.call( this, source, recursive ); - 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(); + var size = Math.sqrt( bones.length * 4 ); // 4 pixels needed for 1 matrix + size = _Math.ceilPowerOfTwo( size ); + size = Math.max( size, 4 ); - this.autoUpdate = source.autoUpdate; - this.matrixAutoUpdate = source.matrixAutoUpdate; + var boneMatrices = new Float32Array( size * size * 4 ); // 4 floats per RGBA pixel + boneMatrices.set( skeleton.boneMatrices ); // copy current values - return this; + var boneTexture = new DataTexture( boneMatrices, size, size, RGBAFormat, FloatType ); + boneTexture.needsUpdate = true; - }, + skeleton.boneMatrices = boneMatrices; + skeleton.boneTexture = boneTexture; + skeleton.boneTextureSize = size; - toJSON: function ( meta ) { + } - var data = Object3D.prototype.toJSON.call( this, meta ); + p_uniforms.setValue( _gl, 'boneTexture', skeleton.boneTexture ); + p_uniforms.setValue( _gl, 'boneTextureSize', skeleton.boneTextureSize ); - if ( this.background !== null ) data.object.background = this.background.toJSON( meta ); - if ( this.fog !== null ) data.object.fog = this.fog.toJSON(); + } else { - return data; + p_uniforms.setOptional( _gl, skeleton, 'boneMatrices' ); - } + } -} ); + } -/** - * @author alteredq / http://alteredqualia.com/ - * - * parameters = { - * color: , - * opacity: , - * map: new THREE.Texture( ), - * - * uvOffset: new THREE.Vector2(), - * uvScale: new THREE.Vector2() - * } - */ + } -function SpriteMaterial( parameters ) { + if ( refreshMaterial ) { - Material.call( this ); + p_uniforms.setValue( _gl, 'toneMappingExposure', _this.toneMappingExposure ); + p_uniforms.setValue( _gl, 'toneMappingWhitePoint', _this.toneMappingWhitePoint ); - this.type = 'SpriteMaterial'; + if ( material.lights ) { - this.color = new Color( 0xffffff ); - this.map = null; + // the current material requires lighting info - this.rotation = 0; + // 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 - this.fog = false; - this.lights = false; + markUniformsLightsNeedsUpdate( m_uniforms, refreshLights ); - this.setValues( parameters ); + } -} + // refresh uniforms common to several materials -SpriteMaterial.prototype = Object.create( Material.prototype ); -SpriteMaterial.prototype.constructor = SpriteMaterial; -SpriteMaterial.prototype.isSpriteMaterial = true; + if ( fog && material.fog ) { -SpriteMaterial.prototype.copy = function ( source ) { + refreshUniformsFog( m_uniforms, fog ); - Material.prototype.copy.call( this, source ); + } - this.color.copy( source.color ); - this.map = source.map; + if ( material.isMeshBasicMaterial ) { - this.rotation = source.rotation; + refreshUniformsCommon( m_uniforms, material ); - return this; + } else if ( material.isMeshLambertMaterial ) { -}; + refreshUniformsCommon( m_uniforms, material ); + refreshUniformsLambert( m_uniforms, material ); -/** - * @author mikael emtinger / http://gomo.se/ - * @author alteredq / http://alteredqualia.com/ - */ + } else if ( material.isMeshPhongMaterial ) { -function Sprite( material ) { + refreshUniformsCommon( m_uniforms, material ); - Object3D.call( this ); + if ( material.isMeshToonMaterial ) { - this.type = 'Sprite'; + refreshUniformsToon( m_uniforms, material ); - this.material = ( material !== undefined ) ? material : new SpriteMaterial(); + } else { - this.center = new Vector2( 0.5, 0.5 ); + refreshUniformsPhong( m_uniforms, material ); -} + } -Sprite.prototype = Object.assign( Object.create( Object3D.prototype ), { + } else if ( material.isMeshStandardMaterial ) { - constructor: Sprite, + refreshUniformsCommon( m_uniforms, material ); - isSprite: true, + if ( material.isMeshPhysicalMaterial ) { - raycast: ( function () { + refreshUniformsPhysical( m_uniforms, material ); - var intersectPoint = new Vector3(); - var worldPosition = new Vector3(); - var worldScale = new Vector3(); + } else { - return function raycast( raycaster, intersects ) { + refreshUniformsStandard( m_uniforms, material ); - worldPosition.setFromMatrixPosition( this.matrixWorld ); - raycaster.ray.closestPointToPoint( worldPosition, intersectPoint ); + } - worldScale.setFromMatrixScale( this.matrixWorld ); - var guessSizeSq = worldScale.x * worldScale.y / 4; + } else if ( material.isMeshMatcapMaterial ) { - if ( worldPosition.distanceToSquared( intersectPoint ) > guessSizeSq ) return; + refreshUniformsCommon( m_uniforms, material ); - var distance = raycaster.ray.origin.distanceTo( intersectPoint ); + refreshUniformsMatcap( m_uniforms, material ); - if ( distance < raycaster.near || distance > raycaster.far ) return; + } else if ( material.isMeshDepthMaterial ) { - intersects.push( { + refreshUniformsCommon( m_uniforms, material ); + refreshUniformsDepth( m_uniforms, material ); - distance: distance, - point: intersectPoint.clone(), - face: null, - object: this + } else if ( material.isMeshDistanceMaterial ) { - } ); + refreshUniformsCommon( m_uniforms, material ); + refreshUniformsDistance( m_uniforms, material ); - }; + } else if ( material.isMeshNormalMaterial ) { - }() ), + refreshUniformsCommon( m_uniforms, material ); + refreshUniformsNormal( m_uniforms, material ); - clone: function () { + } else if ( material.isLineBasicMaterial ) { - return new this.constructor( this.material ).copy( this ); + refreshUniformsLine( m_uniforms, material ); - }, + if ( material.isLineDashedMaterial ) { - copy: function ( source ) { + refreshUniformsDash( m_uniforms, material ); - Object3D.prototype.copy.call( this, source ); + } - if ( source.center !== undefined ) this.center.copy( source.center ); + } else if ( material.isPointsMaterial ) { - return this; + refreshUniformsPoints( m_uniforms, material ); - } + } else if ( material.isSpriteMaterial ) { + refreshUniformsSprites( m_uniforms, material ); -} ); + } else if ( material.isShadowMaterial ) { -/** - * @author mikael emtinger / http://gomo.se/ - * @author alteredq / http://alteredqualia.com/ - * @author mrdoob / http://mrdoob.com/ - */ + m_uniforms.color.value = material.color; + m_uniforms.opacity.value = material.opacity; -function LOD() { + } - Object3D.call( this ); - - this.type = 'LOD'; - - Object.defineProperties( this, { - levels: { - enumerable: true, - value: [] - } - } ); - -} + // RectAreaLight Texture + // TODO (mrdoob): Find a nicer implementation -LOD.prototype = Object.assign( Object.create( Object3D.prototype ), { + 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; - constructor: LOD, + WebGLUniforms.upload( _gl, materialProperties.uniformsList, m_uniforms, _this ); - copy: function ( source ) { + } - Object3D.prototype.copy.call( this, source, false ); + if ( material.isShaderMaterial && material.uniformsNeedUpdate === true ) { - var levels = source.levels; + WebGLUniforms.upload( _gl, materialProperties.uniformsList, m_uniforms, _this ); + material.uniformsNeedUpdate = false; - for ( var i = 0, l = levels.length; i < l; i ++ ) { + } - var level = levels[ i ]; + if ( material.isSpriteMaterial ) { - this.addLevel( level.object.clone(), level.distance ); + p_uniforms.setValue( _gl, 'center', object.center ); } - return this; - - }, + // common matrices - addLevel: function ( object, distance ) { + p_uniforms.setValue( _gl, 'modelViewMatrix', object.modelViewMatrix ); + p_uniforms.setValue( _gl, 'normalMatrix', object.normalMatrix ); + p_uniforms.setValue( _gl, 'modelMatrix', object.matrixWorld ); - if ( distance === undefined ) distance = 0; + return program; - distance = Math.abs( distance ); + } - var levels = this.levels; + // Uniforms (refresh uniforms objects) - for ( var l = 0; l < levels.length; l ++ ) { + function refreshUniformsCommon( uniforms, material ) { - if ( distance < levels[ l ].distance ) { + uniforms.opacity.value = material.opacity; - break; + if ( material.color ) { - } + uniforms.diffuse.value = material.color; } - levels.splice( l, 0, { distance: distance, object: object } ); - - this.add( object ); + if ( material.emissive ) { - }, + uniforms.emissive.value.copy( material.emissive ).multiplyScalar( material.emissiveIntensity ); - getObjectForDistance: function ( distance ) { + } - var levels = this.levels; + if ( material.map ) { - for ( var i = 1, l = levels.length; i < l; i ++ ) { + uniforms.map.value = material.map; - if ( distance < levels[ i ].distance ) { + } - break; + if ( material.alphaMap ) { - } + uniforms.alphaMap.value = material.alphaMap; } - return levels[ i - 1 ].object; + if ( material.specularMap ) { - }, + uniforms.specularMap.value = material.specularMap; - raycast: ( function () { + } - var matrixPosition = new Vector3(); + if ( material.envMap ) { - return function raycast( raycaster, intersects ) { + uniforms.envMap.value = material.envMap; - matrixPosition.setFromMatrixPosition( this.matrixWorld ); + // 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.isCubeTexture ? - 1 : 1; - var distance = raycaster.ray.origin.distanceTo( matrixPosition ); + uniforms.reflectivity.value = material.reflectivity; + uniforms.refractionRatio.value = material.refractionRatio; - this.getObjectForDistance( distance ).raycast( raycaster, intersects ); + uniforms.maxMipLevel.value = properties.get( material.envMap ).__maxMipLevel; - }; + } - }() ), + if ( material.lightMap ) { - update: function () { + uniforms.lightMap.value = material.lightMap; + uniforms.lightMapIntensity.value = material.lightMapIntensity; - var v1 = new Vector3(); - var v2 = new Vector3(); + } - return function update( camera ) { + if ( material.aoMap ) { - var levels = this.levels; + uniforms.aoMap.value = material.aoMap; + uniforms.aoMapIntensity.value = material.aoMapIntensity; - if ( levels.length > 1 ) { + } - v1.setFromMatrixPosition( camera.matrixWorld ); - v2.setFromMatrixPosition( this.matrixWorld ); + // uv repeat and offset setting priorities + // 1. color map + // 2. specular map + // 3. normal map + // 4. bump map + // 5. alpha map + // 6. emissive map - var distance = v1.distanceTo( v2 ); + var uvScaleMap; - levels[ 0 ].object.visible = true; + if ( material.map ) { - for ( var i = 1, l = levels.length; i < l; i ++ ) { + uvScaleMap = material.map; - if ( distance >= levels[ i ].distance ) { + } else if ( material.specularMap ) { - levels[ i - 1 ].object.visible = false; - levels[ i ].object.visible = true; + uvScaleMap = material.specularMap; - } else { + } else if ( material.displacementMap ) { - break; + uvScaleMap = material.displacementMap; - } + } else if ( material.normalMap ) { - } + uvScaleMap = material.normalMap; - for ( ; i < l; i ++ ) { + } else if ( material.bumpMap ) { - levels[ i ].object.visible = false; + uvScaleMap = material.bumpMap; - } + } else if ( material.roughnessMap ) { - } + uvScaleMap = material.roughnessMap; - }; + } else if ( material.metalnessMap ) { - }(), + uvScaleMap = material.metalnessMap; - toJSON: function ( meta ) { + } else if ( material.alphaMap ) { - var data = Object3D.prototype.toJSON.call( this, meta ); + uvScaleMap = material.alphaMap; - data.object.levels = []; + } else if ( material.emissiveMap ) { - var levels = this.levels; + uvScaleMap = material.emissiveMap; - for ( var i = 0, l = levels.length; i < l; i ++ ) { + } - var level = levels[ i ]; + if ( uvScaleMap !== undefined ) { - data.object.levels.push( { - object: level.object.uuid, - distance: level.distance - } ); + // backwards compatibility + if ( uvScaleMap.isWebGLRenderTarget ) { - } + uvScaleMap = uvScaleMap.texture; - return data; + } - } + if ( uvScaleMap.matrixAutoUpdate === true ) { -} ); + uvScaleMap.updateMatrix(); -/** - * @author mikael emtinger / http://gomo.se/ - * @author alteredq / http://alteredqualia.com/ - * @author michael guerrero / http://realitymeltdown.com - * @author ikerr / http://verold.com - */ + } -function Skeleton( bones, boneInverses ) { + uniforms.uvTransform.value.copy( uvScaleMap.matrix ); - // copy the bone array + } - bones = bones || []; + } - this.bones = bones.slice( 0 ); - this.boneMatrices = new Float32Array( this.bones.length * 16 ); + function refreshUniformsLine( uniforms, material ) { - // use the supplied bone inverses or calculate the inverses + uniforms.diffuse.value = material.color; + uniforms.opacity.value = material.opacity; - if ( boneInverses === undefined ) { + } - this.calculateInverses(); + function refreshUniformsDash( uniforms, material ) { - } else { + uniforms.dashSize.value = material.dashSize; + uniforms.totalSize.value = material.dashSize + material.gapSize; + uniforms.scale.value = material.scale; - if ( this.bones.length === boneInverses.length ) { + } - this.boneInverses = boneInverses.slice( 0 ); + function refreshUniformsPoints( uniforms, material ) { - } else { + uniforms.diffuse.value = material.color; + uniforms.opacity.value = material.opacity; + uniforms.size.value = material.size * _pixelRatio; + uniforms.scale.value = _height * 0.5; - console.warn( 'THREE.Skeleton boneInverses is the wrong length.' ); + uniforms.map.value = material.map; - this.boneInverses = []; + if ( material.map !== null ) { - for ( var i = 0, il = this.bones.length; i < il; i ++ ) { + if ( material.map.matrixAutoUpdate === true ) { - this.boneInverses.push( new Matrix4() ); + material.map.updateMatrix(); } + uniforms.uvTransform.value.copy( material.map.matrix ); + } } -} - -Object.assign( Skeleton.prototype, { - - calculateInverses: function () { - - this.boneInverses = []; + function refreshUniformsSprites( uniforms, material ) { - for ( var i = 0, il = this.bones.length; i < il; i ++ ) { + uniforms.diffuse.value = material.color; + uniforms.opacity.value = material.opacity; + uniforms.rotation.value = material.rotation; + uniforms.map.value = material.map; - var inverse = new Matrix4(); + if ( material.map !== null ) { - if ( this.bones[ i ] ) { + if ( material.map.matrixAutoUpdate === true ) { - inverse.getInverse( this.bones[ i ].matrixWorld ); + material.map.updateMatrix(); } - this.boneInverses.push( inverse ); + uniforms.uvTransform.value.copy( material.map.matrix ); } - }, + } - pose: function () { + function refreshUniformsFog( uniforms, fog ) { - var bone, i, il; + uniforms.fogColor.value = fog.color; - // recover the bind-time world matrices + if ( fog.isFog ) { - for ( i = 0, il = this.bones.length; i < il; i ++ ) { + uniforms.fogNear.value = fog.near; + uniforms.fogFar.value = fog.far; - bone = this.bones[ i ]; + } else if ( fog.isFogExp2 ) { - if ( bone ) { + uniforms.fogDensity.value = fog.density; - bone.matrixWorld.getInverse( this.boneInverses[ i ] ); + } - } + } - } + function refreshUniformsLambert( uniforms, material ) { - // compute the local matrices, positions, rotations and scales + if ( material.emissiveMap ) { - for ( i = 0, il = this.bones.length; i < il; i ++ ) { + uniforms.emissiveMap.value = material.emissiveMap; - bone = this.bones[ i ]; + } - if ( bone ) { + } - if ( bone.parent && bone.parent.isBone ) { + function refreshUniformsPhong( uniforms, material ) { - bone.matrix.getInverse( bone.parent.matrixWorld ); - bone.matrix.multiply( bone.matrixWorld ); + uniforms.specular.value = material.specular; + uniforms.shininess.value = Math.max( material.shininess, 1e-4 ); // to prevent pow( 0.0, 0.0 ) - } else { + if ( material.emissiveMap ) { - bone.matrix.copy( bone.matrixWorld ); + uniforms.emissiveMap.value = material.emissiveMap; - } + } - bone.matrix.decompose( bone.position, bone.quaternion, bone.scale ); + if ( material.bumpMap ) { - } + uniforms.bumpMap.value = material.bumpMap; + uniforms.bumpScale.value = material.bumpScale; + if ( material.side === BackSide ) uniforms.bumpScale.value *= - 1; } - }, + if ( material.normalMap ) { - update: ( function () { + uniforms.normalMap.value = material.normalMap; + uniforms.normalScale.value.copy( material.normalScale ); + if ( material.side === BackSide ) uniforms.normalScale.value.negate(); - var offsetMatrix = new Matrix4(); - var identityMatrix = new Matrix4(); + } - return function update() { + if ( material.displacementMap ) { - var bones = this.bones; - var boneInverses = this.boneInverses; - var boneMatrices = this.boneMatrices; - var boneTexture = this.boneTexture; + uniforms.displacementMap.value = material.displacementMap; + uniforms.displacementScale.value = material.displacementScale; + uniforms.displacementBias.value = material.displacementBias; - // flatten bone matrices to array + } - for ( var i = 0, il = bones.length; i < il; i ++ ) { + } - // compute the offset between the current and the original transform + function refreshUniformsToon( uniforms, material ) { - var matrix = bones[ i ] ? bones[ i ].matrixWorld : identityMatrix; + refreshUniformsPhong( uniforms, material ); - offsetMatrix.multiplyMatrices( matrix, boneInverses[ i ] ); - offsetMatrix.toArray( boneMatrices, i * 16 ); + if ( material.gradientMap ) { - } + uniforms.gradientMap.value = material.gradientMap; - if ( boneTexture !== undefined ) { + } - boneTexture.needsUpdate = true; + } - } + function refreshUniformsStandard( uniforms, material ) { - }; + uniforms.roughness.value = material.roughness; + uniforms.metalness.value = material.metalness; - } )(), + if ( material.roughnessMap ) { - clone: function () { + uniforms.roughnessMap.value = material.roughnessMap; - return new Skeleton( this.bones, this.boneInverses ); + } - }, + if ( material.metalnessMap ) { - getBoneByName: function ( name ) { + uniforms.metalnessMap.value = material.metalnessMap; - for ( var i = 0, il = this.bones.length; i < il; i ++ ) { + } - var bone = this.bones[ i ]; + if ( material.emissiveMap ) { - if ( bone.name === name ) { + uniforms.emissiveMap.value = material.emissiveMap; - return bone; + } - } + if ( material.bumpMap ) { + + uniforms.bumpMap.value = material.bumpMap; + uniforms.bumpScale.value = material.bumpScale; + if ( material.side === BackSide ) uniforms.bumpScale.value *= - 1; } - return undefined; + if ( material.normalMap ) { - } + uniforms.normalMap.value = material.normalMap; + uniforms.normalScale.value.copy( material.normalScale ); + if ( material.side === BackSide ) uniforms.normalScale.value.negate(); -} ); + } -/** - * @author mikael emtinger / http://gomo.se/ - * @author alteredq / http://alteredqualia.com/ - * @author ikerr / http://verold.com - */ + if ( material.displacementMap ) { -function Bone() { + uniforms.displacementMap.value = material.displacementMap; + uniforms.displacementScale.value = material.displacementScale; + uniforms.displacementBias.value = material.displacementBias; - Object3D.call( this ); + } - this.type = 'Bone'; + if ( material.envMap ) { -} + //uniforms.envMap.value = material.envMap; // part of uniforms common + uniforms.envMapIntensity.value = material.envMapIntensity; -Bone.prototype = Object.assign( Object.create( Object3D.prototype ), { + } - constructor: Bone, + } - isBone: true + function refreshUniformsPhysical( uniforms, material ) { -} ); + refreshUniformsStandard( uniforms, material ); -/** - * @author mikael emtinger / http://gomo.se/ - * @author alteredq / http://alteredqualia.com/ - * @author ikerr / http://verold.com - */ + uniforms.reflectivity.value = material.reflectivity; // also part of uniforms common -function SkinnedMesh( geometry, material ) { + uniforms.clearCoat.value = material.clearCoat; + uniforms.clearCoatRoughness.value = material.clearCoatRoughness; - Mesh.call( this, geometry, material ); + } - this.type = 'SkinnedMesh'; + function refreshUniformsMatcap( uniforms, material ) { - this.bindMode = 'attached'; - this.bindMatrix = new Matrix4(); - this.bindMatrixInverse = new Matrix4(); + if ( material.matcap ) { - var bones = this.initBones(); - var skeleton = new Skeleton( bones ); + uniforms.matcap.value = material.matcap; - this.bind( skeleton, this.matrixWorld ); + } - this.normalizeSkinWeights(); + if ( material.bumpMap ) { -} + uniforms.bumpMap.value = material.bumpMap; + uniforms.bumpScale.value = material.bumpScale; + if ( material.side === BackSide ) uniforms.bumpScale.value *= - 1; -SkinnedMesh.prototype = Object.assign( Object.create( Mesh.prototype ), { + } - constructor: SkinnedMesh, + if ( material.normalMap ) { - isSkinnedMesh: true, + uniforms.normalMap.value = material.normalMap; + uniforms.normalScale.value.copy( material.normalScale ); + if ( material.side === BackSide ) uniforms.normalScale.value.negate(); - initBones: function () { + } - var bones = [], bone, gbone; - var i, il; + if ( material.displacementMap ) { - if ( this.geometry && this.geometry.bones !== undefined ) { + uniforms.displacementMap.value = material.displacementMap; + uniforms.displacementScale.value = material.displacementScale; + uniforms.displacementBias.value = material.displacementBias; - // first, create array of 'Bone' objects from geometry data + } - for ( i = 0, il = this.geometry.bones.length; i < il; i ++ ) { + } - gbone = this.geometry.bones[ i ]; + function refreshUniformsDepth( uniforms, material ) { - // create new 'Bone' object + if ( material.displacementMap ) { - bone = new Bone(); - bones.push( bone ); + uniforms.displacementMap.value = material.displacementMap; + uniforms.displacementScale.value = material.displacementScale; + uniforms.displacementBias.value = material.displacementBias; - // 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 ); + } - } + function refreshUniformsDistance( uniforms, material ) { - // second, create bone hierarchy + if ( material.displacementMap ) { - for ( i = 0, il = this.geometry.bones.length; i < il; i ++ ) { + uniforms.displacementMap.value = material.displacementMap; + uniforms.displacementScale.value = material.displacementScale; + uniforms.displacementBias.value = material.displacementBias; - gbone = this.geometry.bones[ i ]; + } - if ( ( gbone.parent !== - 1 ) && ( gbone.parent !== null ) && ( bones[ gbone.parent ] !== undefined ) ) { + uniforms.referencePosition.value.copy( material.referencePosition ); + uniforms.nearDistance.value = material.nearDistance; + uniforms.farDistance.value = material.farDistance; - // subsequent bones in the hierarchy + } - bones[ gbone.parent ].add( bones[ i ] ); + function refreshUniformsNormal( uniforms, material ) { - } else { + if ( material.bumpMap ) { - // topmost bone, immediate child of the skinned mesh + uniforms.bumpMap.value = material.bumpMap; + uniforms.bumpScale.value = material.bumpScale; + if ( material.side === BackSide ) uniforms.bumpScale.value *= - 1; - this.add( bones[ i ] ); + } - } + if ( material.normalMap ) { - } + uniforms.normalMap.value = material.normalMap; + uniforms.normalScale.value.copy( material.normalScale ); + if ( material.side === BackSide ) uniforms.normalScale.value.negate(); } - // 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.displacementMap ) { - return bones; + uniforms.displacementMap.value = material.displacementMap; + uniforms.displacementScale.value = material.displacementScale; + uniforms.displacementBias.value = material.displacementBias; - }, + } - bind: function ( skeleton, bindMatrix ) { + } - this.skeleton = skeleton; + // If uniforms are marked as clean, they don't need to be loaded to the GPU. - if ( bindMatrix === undefined ) { + function markUniformsLightsNeedsUpdate( uniforms, value ) { - this.updateMatrixWorld( true ); + uniforms.ambientLightColor.needsUpdate = value; - this.skeleton.calculateInverses(); + uniforms.directionalLights.needsUpdate = value; + uniforms.pointLights.needsUpdate = value; + uniforms.spotLights.needsUpdate = value; + uniforms.rectAreaLights.needsUpdate = value; + uniforms.hemisphereLights.needsUpdate = value; - bindMatrix = this.matrixWorld; + } - } + // Textures - this.bindMatrix.copy( bindMatrix ); - this.bindMatrixInverse.getInverse( bindMatrix ); + function allocTextureUnit() { - }, + var textureUnit = _usedTextureUnits; - pose: function () { + if ( textureUnit >= capabilities.maxTextures ) { - this.skeleton.pose(); + console.warn( 'THREE.WebGLRenderer: Trying to use ' + textureUnit + ' texture units while this GPU supports only ' + capabilities.maxTextures ); - }, + } - normalizeSkinWeights: function () { + _usedTextureUnits += 1; - var scale, i; + return textureUnit; - if ( this.geometry && this.geometry.isGeometry ) { + } - for ( i = 0; i < this.geometry.skinWeights.length; i ++ ) { + this.allocTextureUnit = allocTextureUnit; - var sw = this.geometry.skinWeights[ i ]; + // this.setTexture2D = setTexture2D; + this.setTexture2D = ( function () { - scale = 1.0 / sw.manhattanLength(); + var warned = false; - if ( scale !== Infinity ) { + // backwards compatibility: peel texture.texture + return function setTexture2D( texture, slot ) { - sw.multiplyScalar( scale ); + if ( texture && texture.isWebGLRenderTarget ) { - } else { + if ( ! warned ) { - sw.set( 1, 0, 0, 0 ); // do something reasonable + console.warn( "THREE.WebGLRenderer.setTexture2D: don't use render targets as textures. Use their .texture property instead." ); + warned = true; } + texture = texture.texture; + } - } else if ( this.geometry && this.geometry.isBufferGeometry ) { + textures.setTexture2D( texture, slot ); + + }; - var vec = new Vector4(); + }() ); - var skinWeight = this.geometry.attributes.skinWeight; + this.setTexture3D = ( function () { - for ( i = 0; i < skinWeight.count; i ++ ) { + // backwards compatibility: peel texture.texture + return function setTexture3D( texture, slot ) { - vec.x = skinWeight.getX( i ); - vec.y = skinWeight.getY( i ); - vec.z = skinWeight.getZ( i ); - vec.w = skinWeight.getW( i ); + textures.setTexture3D( texture, slot ); - scale = 1.0 / vec.manhattanLength(); + }; - if ( scale !== Infinity ) { + }() ); - vec.multiplyScalar( scale ); + this.setTexture = ( function () { - } else { + var warned = false; - vec.set( 1, 0, 0, 0 ); // do something reasonable + return function setTexture( texture, slot ) { - } + if ( ! warned ) { - skinWeight.setXYZW( i, vec.x, vec.y, vec.z, vec.w ); + console.warn( "THREE.WebGLRenderer: .setTexture is deprecated, use setTexture2D instead." ); + warned = true; } - } + textures.setTexture2D( texture, slot ); - }, + }; - updateMatrixWorld: function ( force ) { + }() ); - Mesh.prototype.updateMatrixWorld.call( this, force ); - - if ( this.bindMode === 'attached' ) { - - this.bindMatrixInverse.getInverse( this.matrixWorld ); - - } else if ( this.bindMode === 'detached' ) { - - this.bindMatrixInverse.getInverse( this.bindMatrix ); + this.setTextureCube = ( function () { - } else { + var warned = false; - console.warn( 'THREE.SkinnedMesh: Unrecognized bindMode: ' + this.bindMode ); + return function setTextureCube( texture, slot ) { - } + // backwards compatibility: peel texture.texture + if ( texture && texture.isWebGLRenderTargetCube ) { - }, + if ( ! warned ) { - clone: function () { + console.warn( "THREE.WebGLRenderer.setTextureCube: don't use cube render targets as textures. Use their .texture property instead." ); + warned = true; - return new this.constructor( this.geometry, this.material ).copy( this ); + } - } + texture = texture.texture; -} ); + } -/** - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - * - * parameters = { - * color: , - * opacity: , - * - * linewidth: , - * linecap: "round", - * linejoin: "round" - * } - */ + // 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 LineBasicMaterial( parameters ) { + // CompressedTexture can have Array in image :/ - Material.call( this ); + // this function alone should take care of cube textures + textures.setTextureCube( texture, slot ); - this.type = 'LineBasicMaterial'; + } else { - this.color = new Color( 0xffffff ); + // assumed: texture property of THREE.WebGLRenderTargetCube - this.linewidth = 1; - this.linecap = 'round'; - this.linejoin = 'round'; + textures.setTextureCubeDynamic( texture, slot ); - this.lights = false; + } - this.setValues( parameters ); + }; -} + }() ); -LineBasicMaterial.prototype = Object.create( Material.prototype ); -LineBasicMaterial.prototype.constructor = LineBasicMaterial; + // -LineBasicMaterial.prototype.isLineBasicMaterial = true; + this.setFramebuffer = function ( value ) { -LineBasicMaterial.prototype.copy = function ( source ) { + _framebuffer = value; - Material.prototype.copy.call( this, source ); + }; - this.color.copy( source.color ); + this.getRenderTarget = function () { - this.linewidth = source.linewidth; - this.linecap = source.linecap; - this.linejoin = source.linejoin; + return _currentRenderTarget; - return this; + }; -}; + this.setRenderTarget = function ( renderTarget ) { -/** - * @author mrdoob / http://mrdoob.com/ - */ + _currentRenderTarget = renderTarget; -function Line( geometry, material, mode ) { + if ( renderTarget && properties.get( renderTarget ).__webglFramebuffer === undefined ) { - if ( mode === 1 ) { + textures.setupRenderTarget( renderTarget ); - console.warn( 'THREE.Line: parameter THREE.LinePieces no longer supported. Created THREE.LineSegments instead.' ); - return new LineSegments( geometry, material ); + } - } + var framebuffer = _framebuffer; + var isCube = false; - Object3D.call( this ); + if ( renderTarget ) { - this.type = 'Line'; + var __webglFramebuffer = properties.get( renderTarget ).__webglFramebuffer; - this.geometry = geometry !== undefined ? geometry : new BufferGeometry(); - this.material = material !== undefined ? material : new LineBasicMaterial( { color: Math.random() * 0xffffff } ); + if ( renderTarget.isWebGLRenderTargetCube ) { -} + framebuffer = __webglFramebuffer[ renderTarget.activeCubeFace ]; + isCube = true; -Line.prototype = Object.assign( Object.create( Object3D.prototype ), { + } else { - constructor: Line, + framebuffer = __webglFramebuffer; - isLine: true, + } - computeLineDistances: ( function () { + _currentViewport.copy( renderTarget.viewport ); + _currentScissor.copy( renderTarget.scissor ); + _currentScissorTest = renderTarget.scissorTest; - var start = new Vector3(); - var end = new Vector3(); + } else { - return function computeLineDistances() { + _currentViewport.copy( _viewport ).multiplyScalar( _pixelRatio ); + _currentScissor.copy( _scissor ).multiplyScalar( _pixelRatio ); + _currentScissorTest = _scissorTest; - var geometry = this.geometry; + } - if ( geometry.isBufferGeometry ) { + if ( _currentFramebuffer !== framebuffer ) { - // we assume non-indexed geometry + _gl.bindFramebuffer( 36160, framebuffer ); + _currentFramebuffer = framebuffer; - if ( geometry.index === null ) { + } - var positionAttribute = geometry.attributes.position; - var lineDistances = [ 0 ]; + state.viewport( _currentViewport ); + state.scissor( _currentScissor ); + state.setScissorTest( _currentScissorTest ); - for ( var i = 1, l = positionAttribute.count; i < l; i ++ ) { + if ( isCube ) { - start.fromBufferAttribute( positionAttribute, i - 1 ); - end.fromBufferAttribute( positionAttribute, i ); + var textureProperties = properties.get( renderTarget.texture ); + _gl.framebufferTexture2D( 36160, 36064, 34069 + renderTarget.activeCubeFace, textureProperties.__webglTexture, renderTarget.activeMipMapLevel ); - lineDistances[ i ] = lineDistances[ i - 1 ]; - lineDistances[ i ] += start.distanceTo( end ); + } - } + }; - geometry.addAttribute( 'lineDistance', new THREE.Float32BufferAttribute( lineDistances, 1 ) ); + this.readRenderTargetPixels = function ( renderTarget, x, y, width, height, buffer ) { - } else { + if ( ! ( renderTarget && renderTarget.isWebGLRenderTarget ) ) { - console.warn( 'THREE.Line.computeLineDistances(): Computation only possible with non-indexed BufferGeometry.' ); + console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.' ); + return; - } + } - } else if ( geometry.isGeometry ) { + var framebuffer = properties.get( renderTarget ).__webglFramebuffer; - var vertices = geometry.vertices; - var lineDistances = geometry.lineDistances; + if ( framebuffer ) { - lineDistances[ 0 ] = 0; + var restore = false; - for ( var i = 1, l = vertices.length; i < l; i ++ ) { + if ( framebuffer !== _currentFramebuffer ) { - lineDistances[ i ] = lineDistances[ i - 1 ]; - lineDistances[ i ] += vertices[ i - 1 ].distanceTo( vertices[ i ] ); + _gl.bindFramebuffer( 36160, framebuffer ); - } + restore = true; } - return this; + try { - }; + var texture = renderTarget.texture; + var textureFormat = texture.format; + var textureType = texture.type; - }() ), + if ( textureFormat !== RGBAFormat && utils.convert( textureFormat ) !== _gl.getParameter( 35739 ) ) { - raycast: ( function () { + console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in RGBA or implementation defined format.' ); + return; - var inverseMatrix = new Matrix4(); - var ray = new Ray(); - var sphere = new Sphere(); + } - return function raycast( raycaster, intersects ) { + 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 precision = raycaster.linePrecision; - var precisionSq = precision * precision; + console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in UnsignedByteType or implementation defined type.' ); + return; - var geometry = this.geometry; - var matrixWorld = this.matrixWorld; + } - // Checking boundingSphere distance to ray + if ( _gl.checkFramebufferStatus( 36160 ) === 36053 ) { - if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere(); + // the following if statement ensures valid read requests (no out-of-bounds pixels, see #8604) - sphere.copy( geometry.boundingSphere ); - sphere.applyMatrix4( matrixWorld ); + if ( ( x >= 0 && x <= ( renderTarget.width - width ) ) && ( y >= 0 && y <= ( renderTarget.height - height ) ) ) { - if ( raycaster.ray.intersectsSphere( sphere ) === false ) return; + _gl.readPixels( x, y, width, height, utils.convert( textureFormat ), utils.convert( textureType ), buffer ); - // + } - inverseMatrix.getInverse( matrixWorld ); - ray.copy( raycaster.ray ).applyMatrix4( inverseMatrix ); + } else { - var vStart = new Vector3(); - var vEnd = new Vector3(); - var interSegment = new Vector3(); - var interRay = new Vector3(); - var step = ( this && this.isLineSegments ) ? 2 : 1; + console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: readPixels from renderTarget failed. Framebuffer not complete.' ); - if ( geometry.isBufferGeometry ) { + } - var index = geometry.index; - var attributes = geometry.attributes; - var positions = attributes.position.array; + } finally { - if ( index !== null ) { + if ( restore ) { - var indices = index.array; + _gl.bindFramebuffer( 36160, _currentFramebuffer ); - for ( var i = 0, l = indices.length - 1; i < l; i += step ) { + } - var a = indices[ i ]; - var b = indices[ i + 1 ]; + } - vStart.fromArray( positions, a * 3 ); - vEnd.fromArray( positions, b * 3 ); + } - var distSq = ray.distanceSqToSegment( vStart, vEnd, interRay, interSegment ); + }; - if ( distSq > precisionSq ) continue; + this.copyFramebufferToTexture = function ( position, texture, level ) { - interRay.applyMatrix4( this.matrixWorld ); //Move back to world space for distance calculation + var width = texture.image.width; + var height = texture.image.height; + var glFormat = utils.convert( texture.format ); - var distance = raycaster.ray.origin.distanceTo( interRay ); + this.setTexture2D( texture, 0 ); - if ( distance < raycaster.near || distance > raycaster.far ) continue; + _gl.copyTexImage2D( 3553, level || 0, glFormat, position.x, position.y, width, height, 0 ); - intersects.push( { + }; - distance: distance, - // What do we want? intersection point on the ray or on the segment?? - // point: raycaster.ray.at( distance ), - point: interSegment.clone().applyMatrix4( this.matrixWorld ), - index: i, - face: null, - faceIndex: null, - object: this + this.copyTextureToTexture = function ( position, srcTexture, dstTexture, level ) { - } ); + var width = srcTexture.image.width; + var height = srcTexture.image.height; + var glFormat = utils.convert( dstTexture.format ); + var glType = utils.convert( dstTexture.type ); - } + this.setTexture2D( dstTexture, 0 ); - } else { + if ( srcTexture.isDataTexture ) { - for ( var i = 0, l = positions.length / 3 - 1; i < l; i += step ) { + _gl.texSubImage2D( 3553, level || 0, position.x, position.y, width, height, glFormat, glType, srcTexture.image.data ); - vStart.fromArray( positions, 3 * i ); - vEnd.fromArray( positions, 3 * i + 3 ); + } else { - var distSq = ray.distanceSqToSegment( vStart, vEnd, interRay, interSegment ); + _gl.texSubImage2D( 3553, level || 0, position.x, position.y, glFormat, glType, srcTexture.image ); - if ( distSq > precisionSq ) continue; + } - interRay.applyMatrix4( this.matrixWorld ); //Move back to world space for distance calculation + }; - var distance = raycaster.ray.origin.distanceTo( interRay ); +} - if ( distance < raycaster.near || distance > raycaster.far ) continue; +/** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + */ - intersects.push( { +function FogExp2( color, density ) { - 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 + this.name = ''; - } ); + this.color = new Color( color ); + this.density = ( density !== undefined ) ? density : 0.00025; - } +} - } +FogExp2.prototype.isFogExp2 = true; - } else if ( geometry.isGeometry ) { +FogExp2.prototype.clone = function () { - var vertices = geometry.vertices; - var nbVertices = vertices.length; + return new FogExp2( this.color, this.density ); - for ( var i = 0; i < nbVertices - 1; i += step ) { +}; - var distSq = ray.distanceSqToSegment( vertices[ i ], vertices[ i + 1 ], interRay, interSegment ); +FogExp2.prototype.toJSON = function ( /* meta */ ) { - if ( distSq > precisionSq ) continue; + return { + type: 'FogExp2', + color: this.color.getHex(), + density: this.density + }; - interRay.applyMatrix4( this.matrixWorld ); //Move back to world space for distance calculation +}; - var distance = raycaster.ray.origin.distanceTo( interRay ); +/** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + */ - if ( distance < raycaster.near || distance > raycaster.far ) continue; +function Fog( color, near, far ) { - intersects.push( { + this.name = ''; - 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 + this.color = new Color( color ); - } ); + this.near = ( near !== undefined ) ? near : 1; + this.far = ( far !== undefined ) ? far : 1000; - } +} - } +Fog.prototype.isFog = true; - }; +Fog.prototype.clone = function () { - }() ), + return new Fog( this.color, this.near, this.far ); - clone: function () { +}; - return new this.constructor( this.geometry, this.material ).copy( this ); +Fog.prototype.toJSON = function ( /* meta */ ) { - } + return { + type: 'Fog', + color: this.color.getHex(), + near: this.near, + far: this.far + }; -} ); +}; /** * @author mrdoob / http://mrdoob.com/ */ -function LineSegments( geometry, material ) { - - Line.call( this, geometry, material ); - - this.type = 'LineSegments'; - -} +function Scene() { -LineSegments.prototype = Object.assign( Object.create( Line.prototype ), { + Object3D.call( this ); - constructor: LineSegments, + this.type = 'Scene'; - isLineSegments: true, + this.background = null; + this.fog = null; + this.overrideMaterial = null; - computeLineDistances: ( function () { + this.autoUpdate = true; // checked by the renderer - var start = new Vector3(); - var end = new Vector3(); +} - return function computeLineDistances() { +Scene.prototype = Object.assign( Object.create( Object3D.prototype ), { - var geometry = this.geometry; + constructor: Scene, - if ( geometry.isBufferGeometry ) { + copy: function ( source, recursive ) { - // we assume non-indexed geometry + Object3D.prototype.copy.call( this, source, recursive ); - if ( geometry.index === null ) { + 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(); - var positionAttribute = geometry.attributes.position; - var lineDistances = []; + this.autoUpdate = source.autoUpdate; + this.matrixAutoUpdate = source.matrixAutoUpdate; - for ( var i = 0, l = positionAttribute.count; i < l; i += 2 ) { + return this; - start.fromBufferAttribute( positionAttribute, i ); - end.fromBufferAttribute( positionAttribute, i + 1 ); + }, - lineDistances[ i ] = ( i === 0 ) ? 0 : lineDistances[ i - 1 ]; - lineDistances[ i + 1 ] = lineDistances[ i ] + start.distanceTo( end ); + toJSON: function ( meta ) { - } + var data = Object3D.prototype.toJSON.call( this, meta ); - geometry.addAttribute( 'lineDistance', new THREE.Float32BufferAttribute( lineDistances, 1 ) ); + if ( this.background !== null ) data.object.background = this.background.toJSON( meta ); + if ( this.fog !== null ) data.object.fog = this.fog.toJSON(); - } else { + return data; - console.warn( 'THREE.LineSegments.computeLineDistances(): Computation only possible with non-indexed BufferGeometry.' ); + } - } +} ); - } else if ( geometry.isGeometry ) { +/** + * @author benaadams / https://twitter.com/ben_a_adams + */ - var vertices = geometry.vertices; - var lineDistances = geometry.lineDistances; +function InterleavedBuffer( array, stride ) { - for ( var i = 0, l = vertices.length; i < l; i += 2 ) { + this.array = array; + this.stride = stride; + this.count = array !== undefined ? array.length / stride : 0; - start.copy( vertices[ i ] ); - end.copy( vertices[ i + 1 ] ); + this.dynamic = false; + this.updateRange = { offset: 0, count: - 1 }; - lineDistances[ i ] = ( i === 0 ) ? 0 : lineDistances[ i - 1 ]; - lineDistances[ i + 1 ] = lineDistances[ i ] + start.distanceTo( end ); + this.version = 0; - } +} - } +Object.defineProperty( InterleavedBuffer.prototype, 'needsUpdate', { - return this; + set: function ( value ) { - }; + if ( value === true ) this.version ++; - }() ) + } } ); -/** - * @author mgreter / http://github.com/mgreter - */ +Object.assign( InterleavedBuffer.prototype, { -function LineLoop( geometry, material ) { + isInterleavedBuffer: true, - Line.call( this, geometry, material ); + onUploadCallback: function () {}, - this.type = 'LineLoop'; + setArray: function ( array ) { -} + if ( Array.isArray( array ) ) { -LineLoop.prototype = Object.assign( Object.create( Line.prototype ), { + throw new TypeError( 'THREE.BufferAttribute: array should be a Typed Array.' ); - constructor: LineLoop, + } - isLineLoop: true, + this.count = array !== undefined ? array.length / this.stride : 0; + this.array = array; -} ); + return this; -/** - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - * - * parameters = { - * color: , - * opacity: , - * map: new THREE.Texture( ), - * - * size: , - * sizeAttenuation: - * } - */ + }, -function PointsMaterial( parameters ) { + setDynamic: function ( value ) { - Material.call( this ); + this.dynamic = value; - this.type = 'PointsMaterial'; + return this; - this.color = new Color( 0xffffff ); + }, - this.map = null; + copy: function ( source ) { - this.size = 1; - this.sizeAttenuation = true; + this.array = new source.array.constructor( source.array ); + this.count = source.count; + this.stride = source.stride; + this.dynamic = source.dynamic; - this.lights = false; + return this; - this.setValues( parameters ); + }, -} + copyAt: function ( index1, attribute, index2 ) { -PointsMaterial.prototype = Object.create( Material.prototype ); -PointsMaterial.prototype.constructor = PointsMaterial; + index1 *= this.stride; + index2 *= attribute.stride; -PointsMaterial.prototype.isPointsMaterial = true; + for ( var i = 0, l = this.stride; i < l; i ++ ) { -PointsMaterial.prototype.copy = function ( source ) { + this.array[ index1 + i ] = attribute.array[ index2 + i ]; - Material.prototype.copy.call( this, source ); + } - this.color.copy( source.color ); + return this; - this.map = source.map; + }, - this.size = source.size; - this.sizeAttenuation = source.sizeAttenuation; + set: function ( value, offset ) { - return this; + if ( offset === undefined ) offset = 0; -}; + this.array.set( value, offset ); -/** - * @author alteredq / http://alteredqualia.com/ - */ + return this; -function Points( geometry, material ) { + }, - Object3D.call( this ); + clone: function () { - this.type = 'Points'; + return new this.constructor().copy( this ); - this.geometry = geometry !== undefined ? geometry : new BufferGeometry(); - this.material = material !== undefined ? material : new PointsMaterial( { color: Math.random() * 0xffffff } ); + }, -} + onUpload: function ( callback ) { -Points.prototype = Object.assign( Object.create( Object3D.prototype ), { + this.onUploadCallback = callback; - constructor: Points, + return this; - isPoints: true, + } - raycast: ( function () { +} ); - var inverseMatrix = new Matrix4(); - var ray = new Ray(); - var sphere = new Sphere(); +/** + * @author benaadams / https://twitter.com/ben_a_adams + */ - return function raycast( raycaster, intersects ) { +function InterleavedBufferAttribute( interleavedBuffer, itemSize, offset, normalized ) { - var object = this; - var geometry = this.geometry; - var matrixWorld = this.matrixWorld; - var threshold = raycaster.params.Points.threshold; + this.data = interleavedBuffer; + this.itemSize = itemSize; + this.offset = offset; - // Checking boundingSphere distance to ray + this.normalized = normalized === true; - if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere(); +} - sphere.copy( geometry.boundingSphere ); - sphere.applyMatrix4( matrixWorld ); - sphere.radius += threshold; +Object.defineProperties( InterleavedBufferAttribute.prototype, { - if ( raycaster.ray.intersectsSphere( sphere ) === false ) return; + count: { - // + get: function () { - inverseMatrix.getInverse( matrixWorld ); - ray.copy( raycaster.ray ).applyMatrix4( inverseMatrix ); + return this.data.count; - var localThreshold = threshold / ( ( this.scale.x + this.scale.y + this.scale.z ) / 3 ); - var localThresholdSq = localThreshold * localThreshold; - var position = new Vector3(); + } - function testPoint( point, index ) { + }, - var rayPointDistanceSq = ray.distanceSqToPoint( point ); + array: { - if ( rayPointDistanceSq < localThresholdSq ) { + get: function () { - var intersectPoint = ray.closestPointToPoint( point ); - intersectPoint.applyMatrix4( matrixWorld ); + return this.data.array; - var distance = raycaster.ray.origin.distanceTo( intersectPoint ); + } - if ( distance < raycaster.near || distance > raycaster.far ) return; + } - intersects.push( { +} ); - distance: distance, - distanceToRay: Math.sqrt( rayPointDistanceSq ), - point: intersectPoint.clone(), - index: index, - face: null, - object: object +Object.assign( InterleavedBufferAttribute.prototype, { - } ); + isInterleavedBufferAttribute: true, - } + setX: function ( index, x ) { - } + this.data.array[ index * this.data.stride + this.offset ] = x; - if ( geometry.isBufferGeometry ) { + return this; - var index = geometry.index; - var attributes = geometry.attributes; - var positions = attributes.position.array; + }, - if ( index !== null ) { + setY: function ( index, y ) { - var indices = index.array; + this.data.array[ index * this.data.stride + this.offset + 1 ] = y; - for ( var i = 0, il = indices.length; i < il; i ++ ) { + return this; - var a = indices[ i ]; + }, - position.fromArray( positions, a * 3 ); + setZ: function ( index, z ) { - testPoint( position, a ); + this.data.array[ index * this.data.stride + this.offset + 2 ] = z; - } + return this; - } else { + }, - for ( var i = 0, l = positions.length / 3; i < l; i ++ ) { + setW: function ( index, w ) { - position.fromArray( positions, i * 3 ); + this.data.array[ index * this.data.stride + this.offset + 3 ] = w; - testPoint( position, i ); + return this; - } + }, - } + getX: function ( index ) { - } else { + return this.data.array[ index * this.data.stride + this.offset ]; - var vertices = geometry.vertices; + }, - for ( var i = 0, l = vertices.length; i < l; i ++ ) { + getY: function ( index ) { - testPoint( vertices[ i ], i ); + 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 ]; - }() ), + }, - clone: function () { + getW: function ( index ) { - return new this.constructor( this.geometry, this.material ).copy( this ); + return this.data.array[ index * this.data.stride + this.offset + 3 ]; - } + }, -} ); + setXY: function ( index, x, y ) { -/** - * @author mrdoob / http://mrdoob.com/ - */ + index = index * this.data.stride + this.offset; -function Group() { + this.data.array[ index + 0 ] = x; + this.data.array[ index + 1 ] = y; - Object3D.call( this ); + return this; - this.type = 'Group'; + }, -} + setXYZ: function ( index, x, y, z ) { -Group.prototype = Object.assign( Object.create( Object3D.prototype ), { + index = index * this.data.stride + this.offset; - constructor: Group, + this.data.array[ index + 0 ] = x; + this.data.array[ index + 1 ] = y; + this.data.array[ index + 2 ] = z; - isGroup: true + return this; + + }, + + setXYZW: function ( index, x, y, z, w ) { + + index = index * this.data.stride + this.offset; + + this.data.array[ index + 0 ] = x; + this.data.array[ index + 1 ] = y; + this.data.array[ index + 2 ] = z; + this.data.array[ index + 3 ] = w; + + return this; + + } } ); /** - * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + * + * parameters = { + * color: , + * map: new THREE.Texture( ), + * rotation: , + * sizeAttenuation: + * } */ -function VideoTexture( video, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ) { +function SpriteMaterial( parameters ) { - Texture.call( this, video, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ); + Material.call( this ); - this.generateMipmaps = false; + this.type = 'SpriteMaterial'; -} + this.color = new Color( 0xffffff ); + this.map = null; -VideoTexture.prototype = Object.assign( Object.create( Texture.prototype ), { + this.rotation = 0; - constructor: VideoTexture, + this.sizeAttenuation = true; - isVideoTexture: true, + this.lights = false; + this.transparent = true; - update: function () { + this.setValues( parameters ); - var video = this.image; +} - if ( video.readyState >= video.HAVE_CURRENT_DATA ) { +SpriteMaterial.prototype = Object.create( Material.prototype ); +SpriteMaterial.prototype.constructor = SpriteMaterial; +SpriteMaterial.prototype.isSpriteMaterial = true; - this.needsUpdate = true; +SpriteMaterial.prototype.copy = function ( source ) { - } + Material.prototype.copy.call( this, source ); - } + this.color.copy( source.color ); + this.map = source.map; -} ); + this.rotation = source.rotation; + + this.sizeAttenuation = source.sizeAttenuation; + + return this; + +}; /** + * @author mikael emtinger / http://gomo.se/ * @author alteredq / http://alteredqualia.com/ */ -function CompressedTexture( mipmaps, width, height, format, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy, encoding ) { - - Texture.call( this, null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding ); +var geometry; - this.image = { width: width, height: height }; - this.mipmaps = mipmaps; +function Sprite( material ) { - // no flipping for cube textures - // (also flipping doesn't work for compressed textures ) + Object3D.call( this ); - this.flipY = false; + this.type = 'Sprite'; - // can't generate mipmaps for compressed textures - // mips must be embedded in DDS files + if ( geometry === undefined ) { - this.generateMipmaps = false; + geometry = new BufferGeometry(); -} + 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 + ] ); -CompressedTexture.prototype = Object.create( Texture.prototype ); -CompressedTexture.prototype.constructor = CompressedTexture; + var interleavedBuffer = new InterleavedBuffer( float32Array, 5 ); -CompressedTexture.prototype.isCompressedTexture = true; + 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 ) ); -/** - * @author Matt DesLauriers / @mattdesl - * @author atix / arthursilber.de - */ + } -function DepthTexture( width, height, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy, format ) { + this.geometry = geometry; + this.material = ( material !== undefined ) ? material : new SpriteMaterial(); - format = format !== undefined ? format : DepthFormat; + this.center = new Vector2( 0.5, 0.5 ); - if ( format !== DepthFormat && format !== DepthStencilFormat ) { +} - throw new Error( 'DepthTexture format must be either THREE.DepthFormat or THREE.DepthStencilFormat' ); +Sprite.prototype = Object.assign( Object.create( Object3D.prototype ), { - } + constructor: Sprite, - if ( type === undefined && format === DepthFormat ) type = UnsignedShortType; - if ( type === undefined && format === DepthStencilFormat ) type = UnsignedInt248Type; + isSprite: true, - Texture.call( this, null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ); + raycast: ( function () { - this.image = { width: width, height: height }; + var intersectPoint = new Vector3(); + var worldScale = new Vector3(); + var mvPosition = new Vector3(); - this.magFilter = magFilter !== undefined ? magFilter : NearestFilter; - this.minFilter = minFilter !== undefined ? minFilter : NearestFilter; + var alignedPosition = new Vector2(); + var rotatedPosition = new Vector2(); + var viewWorldMatrix = new Matrix4(); - this.flipY = false; - this.generateMipmaps = false; + var vA = new Vector3(); + var vB = new Vector3(); + var vC = new Vector3(); -} + var uvA = new Vector2(); + var uvB = new Vector2(); + var uvC = new Vector2(); -DepthTexture.prototype = Object.create( Texture.prototype ); -DepthTexture.prototype.constructor = DepthTexture; -DepthTexture.prototype.isDepthTexture = true; + function transformVertex( vertexPosition, mvPosition, center, scale, sin, cos ) { -/** - * @author mrdoob / http://mrdoob.com/ - * @author Mugen87 / https://github.com/Mugen87 - */ + // compute position in camera space + alignedPosition.subVectors( vertexPosition, center ).addScalar( 0.5 ).multiply( scale ); -function WireframeGeometry( geometry ) { + // to check if rotation is not zero + if ( sin !== undefined ) { - BufferGeometry.call( this ); + rotatedPosition.x = ( cos * alignedPosition.x ) - ( sin * alignedPosition.y ); + rotatedPosition.y = ( sin * alignedPosition.x ) + ( cos * alignedPosition.y ); - this.type = 'WireframeGeometry'; + } else { - // buffer + rotatedPosition.copy( alignedPosition ); - var vertices = []; + } - // helper variables - var i, j, l, o, ol; - var edge = [ 0, 0 ], edges = {}, e, edge1, edge2; - var key, keys = [ 'a', 'b', 'c' ]; - var vertex; + vertexPosition.copy( mvPosition ); + vertexPosition.x += rotatedPosition.x; + vertexPosition.y += rotatedPosition.y; - // different logic for Geometry and BufferGeometry + // transform to world space + vertexPosition.applyMatrix4( viewWorldMatrix ); - if ( geometry && geometry.isGeometry ) { + } - // create a data structure that contains all edges without duplicates + return function raycast( raycaster, intersects ) { - var faces = geometry.faces; + worldScale.setFromMatrixScale( this.matrixWorld ); + viewWorldMatrix.getInverse( this.modelViewMatrix ).premultiply( this.matrixWorld ); + mvPosition.setFromMatrixPosition( this.modelViewMatrix ); - for ( i = 0, l = faces.length; i < l; i ++ ) { + var rotation = this.material.rotation; + var sin, cos; + if ( rotation !== 0 ) { - var face = faces[ i ]; + cos = Math.cos( rotation ); + sin = Math.sin( rotation ); - for ( j = 0; j < 3; j ++ ) { + } - 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 ); + var center = this.center; - key = edge[ 0 ] + ',' + edge[ 1 ]; + 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 ); - if ( edges[ key ] === undefined ) { + uvA.set( 0, 0 ); + uvB.set( 1, 0 ); + uvC.set( 1, 1 ); - edges[ key ] = { index1: edge[ 0 ], index2: edge[ 1 ] }; + // check first triangle + var intersect = raycaster.ray.intersectTriangle( vA, vB, vC, false, intersectPoint ); - } + if ( intersect === null ) { - } + // check second triangle + transformVertex( vB.set( - 0.5, 0.5, 0 ), mvPosition, center, worldScale, sin, cos ); + uvB.set( 0, 1 ); - } + intersect = raycaster.ray.intersectTriangle( vA, vC, vB, false, intersectPoint ); + if ( intersect === null ) { - // generate vertices + return; - for ( key in edges ) { + } - e = edges[ key ]; + } - vertex = geometry.vertices[ e.index1 ]; - vertices.push( vertex.x, vertex.y, vertex.z ); + var distance = raycaster.ray.origin.distanceTo( intersectPoint ); - vertex = geometry.vertices[ e.index2 ]; - vertices.push( vertex.x, vertex.y, vertex.z ); + if ( distance < raycaster.near || distance > raycaster.far ) return; - } + intersects.push( { - } else if ( geometry && geometry.isBufferGeometry ) { + distance: distance, + point: intersectPoint.clone(), + uv: Triangle.getUV( intersectPoint, vA, vB, vC, uvA, uvB, uvC, new Vector2() ), + face: null, + object: this - var position, indices, groups; - var group, start, count; - var index1, index2; + } ); - vertex = new Vector3(); + }; - if ( geometry.index !== null ) { + }() ), - // indexed BufferGeometry + clone: function () { - position = geometry.attributes.position; - indices = geometry.index; - groups = geometry.groups; + return new this.constructor( this.material ).copy( this ); - if ( groups.length === 0 ) { + }, - groups = [ { start: 0, count: indices.count, materialIndex: 0 } ]; + copy: function ( source ) { - } + Object3D.prototype.copy.call( this, source ); - // create a data structure that contains all eges without duplicates + if ( source.center !== undefined ) this.center.copy( source.center ); - for ( o = 0, ol = groups.length; o < ol; ++ o ) { + return this; - group = groups[ o ]; + } - start = group.start; - count = group.count; - for ( i = start, l = ( start + count ); i < l; i += 3 ) { +} ); - for ( j = 0; j < 3; j ++ ) { +/** + * @author mikael emtinger / http://gomo.se/ + * @author alteredq / http://alteredqualia.com/ + * @author mrdoob / http://mrdoob.com/ + */ - 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 ); +function LOD() { - key = edge[ 0 ] + ',' + edge[ 1 ]; + Object3D.call( this ); - if ( edges[ key ] === undefined ) { + this.type = 'LOD'; - edges[ key ] = { index1: edge[ 0 ], index2: edge[ 1 ] }; + Object.defineProperties( this, { + levels: { + enumerable: true, + value: [] + } + } ); - } +} - } +LOD.prototype = Object.assign( Object.create( Object3D.prototype ), { - } + constructor: LOD, - } + copy: function ( source ) { - // generate vertices + Object3D.prototype.copy.call( this, source, false ); - for ( key in edges ) { + var levels = source.levels; - e = edges[ key ]; + for ( var i = 0, l = levels.length; i < l; i ++ ) { - vertex.fromBufferAttribute( position, e.index1 ); - vertices.push( vertex.x, vertex.y, vertex.z ); + var level = levels[ i ]; - vertex.fromBufferAttribute( position, e.index2 ); - vertices.push( vertex.x, vertex.y, vertex.z ); + this.addLevel( level.object.clone(), level.distance ); - } + } - } else { + return this; - // non-indexed BufferGeometry + }, - position = geometry.attributes.position; + addLevel: function ( object, distance ) { - for ( i = 0, l = ( position.count / 3 ); i < l; i ++ ) { + if ( distance === undefined ) distance = 0; - for ( j = 0; j < 3; j ++ ) { + distance = Math.abs( distance ); - // 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 levels = this.levels; - index1 = 3 * i + j; - vertex.fromBufferAttribute( position, index1 ); - vertices.push( vertex.x, vertex.y, vertex.z ); + for ( var l = 0; l < levels.length; l ++ ) { - index2 = 3 * i + ( ( j + 1 ) % 3 ); - vertex.fromBufferAttribute( position, index2 ); - vertices.push( vertex.x, vertex.y, vertex.z ); + if ( distance < levels[ l ].distance ) { - } + break; } } - } + levels.splice( l, 0, { distance: distance, object: object } ); - // build geometry + this.add( object ); - this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); + }, -} + getObjectForDistance: function ( distance ) { -WireframeGeometry.prototype = Object.create( BufferGeometry.prototype ); -WireframeGeometry.prototype.constructor = WireframeGeometry; + var levels = this.levels; -/** - * @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 - */ + for ( var i = 1, l = levels.length; i < l; i ++ ) { -// ParametricGeometry + if ( distance < levels[ i ].distance ) { -function ParametricGeometry( func, slices, stacks ) { + break; - Geometry.call( this ); + } - this.type = 'ParametricGeometry'; + } - this.parameters = { - func: func, - slices: slices, - stacks: stacks - }; + return levels[ i - 1 ].object; - this.fromBufferGeometry( new ParametricBufferGeometry( func, slices, stacks ) ); - this.mergeVertices(); + }, -} + raycast: ( function () { -ParametricGeometry.prototype = Object.create( Geometry.prototype ); -ParametricGeometry.prototype.constructor = ParametricGeometry; + var matrixPosition = new Vector3(); -// ParametricBufferGeometry + return function raycast( raycaster, intersects ) { -function ParametricBufferGeometry( func, slices, stacks ) { + matrixPosition.setFromMatrixPosition( this.matrixWorld ); - BufferGeometry.call( this ); + var distance = raycaster.ray.origin.distanceTo( matrixPosition ); - this.type = 'ParametricBufferGeometry'; + this.getObjectForDistance( distance ).raycast( raycaster, intersects ); - this.parameters = { - func: func, - slices: slices, - stacks: stacks - }; + }; - // buffers + }() ), - var indices = []; - var vertices = []; - var normals = []; - var uvs = []; + update: function () { - var EPS = 0.00001; + var v1 = new Vector3(); + var v2 = new Vector3(); - var normal = new Vector3(); + return function update( camera ) { - var p0 = new Vector3(), p1 = new Vector3(); - var pu = new Vector3(), pv = new Vector3(); + var levels = this.levels; - var i, j; + if ( levels.length > 1 ) { - // generate vertices, normals and uvs + v1.setFromMatrixPosition( camera.matrixWorld ); + v2.setFromMatrixPosition( this.matrixWorld ); - var sliceCount = slices + 1; + var distance = v1.distanceTo( v2 ); - for ( i = 0; i <= stacks; i ++ ) { + levels[ 0 ].object.visible = true; - var v = i / stacks; + for ( var i = 1, l = levels.length; i < l; i ++ ) { - for ( j = 0; j <= slices; j ++ ) { + if ( distance >= levels[ i ].distance ) { - var u = j / slices; + levels[ i - 1 ].object.visible = false; + levels[ i ].object.visible = true; - // vertex + } else { - p0 = func( u, v, p0 ); - vertices.push( p0.x, p0.y, p0.z ); + break; - // normal + } - // approximate tangent vectors via finite differences + } - if ( u - EPS >= 0 ) { + for ( ; i < l; i ++ ) { - p1 = func( u - EPS, v, p1 ); - pu.subVectors( p0, p1 ); + levels[ i ].object.visible = false; - } else { - - p1 = func( u + EPS, v, p1 ); - pu.subVectors( p1, p0 ); + } } - if ( v - EPS >= 0 ) { + }; - p1 = func( u, v - EPS, p1 ); - pv.subVectors( p0, p1 ); + }(), - } else { + toJSON: function ( meta ) { - p1 = func( u, v + EPS, p1 ); - pv.subVectors( p1, p0 ); + var data = Object3D.prototype.toJSON.call( this, meta ); - } + data.object.levels = []; - // cross product of tangent vectors returns surface normal + var levels = this.levels; - normal.crossVectors( pu, pv ).normalize(); - normals.push( normal.x, normal.y, normal.z ); + for ( var i = 0, l = levels.length; i < l; i ++ ) { - // uv + var level = levels[ i ]; - uvs.push( u, v ); + data.object.levels.push( { + object: level.object.uuid, + distance: level.distance + } ); } - } - - // generate indices + return data; - for ( i = 0; i < stacks; i ++ ) { + } - for ( j = 0; j < slices; j ++ ) { +} ); - var a = i * sliceCount + j; - var b = i * sliceCount + j + 1; - var c = ( i + 1 ) * sliceCount + j + 1; - var d = ( i + 1 ) * sliceCount + j; +/** + * @author mikael emtinger / http://gomo.se/ + * @author alteredq / http://alteredqualia.com/ + * @author ikerr / http://verold.com + */ - // faces one and two +function SkinnedMesh( geometry, material ) { - indices.push( a, b, d ); - indices.push( b, c, d ); + if ( geometry && geometry.isGeometry ) { - } + console.error( 'THREE.SkinnedMesh no longer supports THREE.Geometry. Use THREE.BufferGeometry instead.' ); } - // build geometry + Mesh.call( this, geometry, material ); - 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 = 'SkinnedMesh'; + + this.bindMode = 'attached'; + this.bindMatrix = new Matrix4(); + this.bindMatrixInverse = new Matrix4(); } -ParametricBufferGeometry.prototype = Object.create( BufferGeometry.prototype ); -ParametricBufferGeometry.prototype.constructor = ParametricBufferGeometry; +SkinnedMesh.prototype = Object.assign( Object.create( Mesh.prototype ), { -/** - * @author clockworkgeek / https://github.com/clockworkgeek - * @author timothypratley / https://github.com/timothypratley - * @author WestLangley / http://github.com/WestLangley - * @author Mugen87 / https://github.com/Mugen87 - */ + constructor: SkinnedMesh, -// PolyhedronGeometry + isSkinnedMesh: true, -function PolyhedronGeometry( vertices, indices, radius, detail ) { + bind: function ( skeleton, bindMatrix ) { - Geometry.call( this ); + this.skeleton = skeleton; - this.type = 'PolyhedronGeometry'; + if ( bindMatrix === undefined ) { - this.parameters = { - vertices: vertices, - indices: indices, - radius: radius, - detail: detail - }; + this.updateMatrixWorld( true ); - this.fromBufferGeometry( new PolyhedronBufferGeometry( vertices, indices, radius, detail ) ); - this.mergeVertices(); + this.skeleton.calculateInverses(); -} + bindMatrix = this.matrixWorld; -PolyhedronGeometry.prototype = Object.create( Geometry.prototype ); -PolyhedronGeometry.prototype.constructor = PolyhedronGeometry; + } -// PolyhedronBufferGeometry + this.bindMatrix.copy( bindMatrix ); + this.bindMatrixInverse.getInverse( bindMatrix ); -function PolyhedronBufferGeometry( vertices, indices, radius, detail ) { + }, - BufferGeometry.call( this ); + pose: function () { - this.type = 'PolyhedronBufferGeometry'; + this.skeleton.pose(); - this.parameters = { - vertices: vertices, - indices: indices, - radius: radius, - detail: detail - }; + }, - radius = radius || 1; - detail = detail || 0; + normalizeSkinWeights: function () { - // default buffer data + var vector = new Vector4(); - var vertexBuffer = []; - var uvBuffer = []; + var skinWeight = this.geometry.attributes.skinWeight; - // the subdivision creates the vertex buffer data + for ( var i = 0, l = skinWeight.count; i < l; i ++ ) { - subdivide( detail ); + vector.x = skinWeight.getX( i ); + vector.y = skinWeight.getY( i ); + vector.z = skinWeight.getZ( i ); + vector.w = skinWeight.getW( i ); - // all vertices should lie on a conceptual sphere with a given radius + var scale = 1.0 / vector.manhattanLength(); - appplyRadius( radius ); + if ( scale !== Infinity ) { - // finally, create the uv data + vector.multiplyScalar( scale ); - generateUVs(); + } else { - // build non-indexed geometry + vector.set( 1, 0, 0, 0 ); // do something reasonable - this.addAttribute( 'position', new Float32BufferAttribute( vertexBuffer, 3 ) ); - this.addAttribute( 'normal', new Float32BufferAttribute( vertexBuffer.slice(), 3 ) ); - this.addAttribute( 'uv', new Float32BufferAttribute( uvBuffer, 2 ) ); + } - if ( detail === 0 ) { + skinWeight.setXYZW( i, vector.x, vector.y, vector.z, vector.w ); - this.computeVertexNormals(); // flat normals + } - } else { + }, - this.normalizeNormals(); // smooth normals + updateMatrixWorld: function ( force ) { - } + Mesh.prototype.updateMatrixWorld.call( this, force ); - // helper functions + if ( this.bindMode === 'attached' ) { - function subdivide( detail ) { + this.bindMatrixInverse.getInverse( this.matrixWorld ); - var a = new Vector3(); - var b = new Vector3(); - var c = new Vector3(); + } else if ( this.bindMode === 'detached' ) { - // iterate over all faces and apply a subdivison with the given detail value + this.bindMatrixInverse.getInverse( this.bindMatrix ); - for ( var i = 0; i < indices.length; i += 3 ) { + } else { - // get the vertices of the face + console.warn( 'THREE.SkinnedMesh: Unrecognized bindMode: ' + this.bindMode ); - getVertexByIndex( indices[ i + 0 ], a ); - getVertexByIndex( indices[ i + 1 ], b ); - getVertexByIndex( indices[ i + 2 ], c ); + } - // perform subdivision + }, - subdivideFace( a, b, c, detail ); + clone: function () { - } + return new this.constructor( this.geometry, this.material ).copy( this ); } - function subdivideFace( a, b, c, detail ) { +} ); - var cols = Math.pow( 2, detail ); +/** + * @author mikael emtinger / http://gomo.se/ + * @author alteredq / http://alteredqualia.com/ + * @author michael guerrero / http://realitymeltdown.com + * @author ikerr / http://verold.com + */ - // we use this multidimensional array as a data structure for creating the subdivision +function Skeleton( bones, boneInverses ) { - var v = []; + // copy the bone array - var i, j; + bones = bones || []; - // construct all of the vertices for this subdivision + this.bones = bones.slice( 0 ); + this.boneMatrices = new Float32Array( this.bones.length * 16 ); - for ( i = 0; i <= cols; i ++ ) { + // use the supplied bone inverses or calculate the inverses - v[ i ] = []; + if ( boneInverses === undefined ) { - var aj = a.clone().lerp( c, i / cols ); - var bj = b.clone().lerp( c, i / cols ); + this.calculateInverses(); - var rows = cols - i; + } else { - for ( j = 0; j <= rows; j ++ ) { + if ( this.bones.length === boneInverses.length ) { - if ( j === 0 && i === cols ) { + this.boneInverses = boneInverses.slice( 0 ); - v[ i ][ j ] = aj; + } else { - } else { + console.warn( 'THREE.Skeleton boneInverses is the wrong length.' ); - v[ i ][ j ] = aj.clone().lerp( bj, j / rows ); + this.boneInverses = []; - } + for ( var i = 0, il = this.bones.length; i < il; i ++ ) { + + this.boneInverses.push( new Matrix4() ); } } - // construct all of the faces + } - for ( i = 0; i < cols; i ++ ) { +} - for ( j = 0; j < 2 * ( cols - i ) - 1; j ++ ) { +Object.assign( Skeleton.prototype, { - var k = Math.floor( j / 2 ); + calculateInverses: function () { - if ( j % 2 === 0 ) { + this.boneInverses = []; - pushVertex( v[ i ][ k + 1 ] ); - pushVertex( v[ i + 1 ][ k ] ); - pushVertex( v[ i ][ k ] ); + for ( var i = 0, il = this.bones.length; i < il; i ++ ) { - } else { + var inverse = new Matrix4(); - pushVertex( v[ i ][ k + 1 ] ); - pushVertex( v[ i + 1 ][ k + 1 ] ); - pushVertex( v[ i + 1 ][ k ] ); + if ( this.bones[ i ] ) { - } + inverse.getInverse( this.bones[ i ].matrixWorld ); } + this.boneInverses.push( inverse ); + } - } + }, - function appplyRadius( radius ) { + pose: function () { - var vertex = new Vector3(); + var bone, i, il; - // iterate over the entire buffer and apply the radius to each vertex + // recover the bind-time world matrices - for ( var i = 0; i < vertexBuffer.length; i += 3 ) { + for ( i = 0, il = this.bones.length; i < il; i ++ ) { - vertex.x = vertexBuffer[ i + 0 ]; - vertex.y = vertexBuffer[ i + 1 ]; - vertex.z = vertexBuffer[ i + 2 ]; + bone = this.bones[ i ]; - vertex.normalize().multiplyScalar( radius ); + if ( bone ) { - vertexBuffer[ i + 0 ] = vertex.x; - vertexBuffer[ i + 1 ] = vertex.y; - vertexBuffer[ i + 2 ] = vertex.z; + bone.matrixWorld.getInverse( this.boneInverses[ i ] ); + + } } - } + // compute the local matrices, positions, rotations and scales - function generateUVs() { + for ( i = 0, il = this.bones.length; i < il; i ++ ) { - var vertex = new Vector3(); + bone = this.bones[ i ]; - for ( var i = 0; i < vertexBuffer.length; i += 3 ) { + if ( bone ) { - vertex.x = vertexBuffer[ i + 0 ]; - vertex.y = vertexBuffer[ i + 1 ]; - vertex.z = vertexBuffer[ i + 2 ]; + if ( bone.parent && bone.parent.isBone ) { - var u = azimuth( vertex ) / 2 / Math.PI + 0.5; - var v = inclination( vertex ) / Math.PI + 0.5; - uvBuffer.push( u, 1 - v ); + bone.matrix.getInverse( bone.parent.matrixWorld ); + bone.matrix.multiply( bone.matrixWorld ); + + } else { + + bone.matrix.copy( bone.matrixWorld ); + + } + + bone.matrix.decompose( bone.position, bone.quaternion, bone.scale ); + + } } - correctUVs(); + }, - correctSeam(); + update: ( function () { - } + var offsetMatrix = new Matrix4(); + var identityMatrix = new Matrix4(); - function correctSeam() { + return function update() { - // handle case when face straddles the seam, see #3269 + var bones = this.bones; + var boneInverses = this.boneInverses; + var boneMatrices = this.boneMatrices; + var boneTexture = this.boneTexture; - for ( var i = 0; i < uvBuffer.length; i += 6 ) { + // flatten bone matrices to array - // uv data of a single face + for ( var i = 0, il = bones.length; i < il; i ++ ) { - var x0 = uvBuffer[ i + 0 ]; - var x1 = uvBuffer[ i + 2 ]; - var x2 = uvBuffer[ i + 4 ]; + // compute the offset between the current and the original transform - var max = Math.max( x0, x1, x2 ); - var min = Math.min( x0, x1, x2 ); + var matrix = bones[ i ] ? bones[ i ].matrixWorld : identityMatrix; - // 0.9 is somewhat arbitrary + offsetMatrix.multiplyMatrices( matrix, boneInverses[ i ] ); + offsetMatrix.toArray( boneMatrices, i * 16 ); - if ( max > 0.9 && min < 0.1 ) { + } - if ( x0 < 0.2 ) uvBuffer[ i + 0 ] += 1; - if ( x1 < 0.2 ) uvBuffer[ i + 2 ] += 1; - if ( x2 < 0.2 ) uvBuffer[ i + 4 ] += 1; + if ( boneTexture !== undefined ) { + + boneTexture.needsUpdate = true; } - } + }; - } + } )(), - function pushVertex( vertex ) { + clone: function () { - vertexBuffer.push( vertex.x, vertex.y, vertex.z ); + return new Skeleton( this.bones, this.boneInverses ); - } + }, - function getVertexByIndex( index, vertex ) { + getBoneByName: function ( name ) { - var stride = index * 3; + for ( var i = 0, il = this.bones.length; i < il; i ++ ) { - vertex.x = vertices[ stride + 0 ]; - vertex.y = vertices[ stride + 1 ]; - vertex.z = vertices[ stride + 2 ]; + var bone = this.bones[ i ]; - } + if ( bone.name === name ) { - function correctUVs() { + return bone; - var a = new Vector3(); - var b = new Vector3(); - var c = new Vector3(); + } - var centroid = new Vector3(); + } - var uvA = new Vector2(); - var uvB = new Vector2(); - var uvC = new Vector2(); + return undefined; - for ( var i = 0, j = 0; i < vertexBuffer.length; i += 9, j += 6 ) { + } - a.set( vertexBuffer[ i + 0 ], vertexBuffer[ i + 1 ], vertexBuffer[ i + 2 ] ); - b.set( vertexBuffer[ i + 3 ], vertexBuffer[ i + 4 ], vertexBuffer[ i + 5 ] ); - c.set( vertexBuffer[ i + 6 ], vertexBuffer[ i + 7 ], vertexBuffer[ i + 8 ] ); +} ); - uvA.set( uvBuffer[ j + 0 ], uvBuffer[ j + 1 ] ); - uvB.set( uvBuffer[ j + 2 ], uvBuffer[ j + 3 ] ); - uvC.set( uvBuffer[ j + 4 ], uvBuffer[ j + 5 ] ); +/** + * @author mikael emtinger / http://gomo.se/ + * @author alteredq / http://alteredqualia.com/ + * @author ikerr / http://verold.com + */ - centroid.copy( a ).add( b ).add( c ).divideScalar( 3 ); +function Bone() { - var azi = azimuth( centroid ); + Object3D.call( this ); - correctUV( uvA, j + 0, a, azi ); - correctUV( uvB, j + 2, b, azi ); - correctUV( uvC, j + 4, c, azi ); + this.type = 'Bone'; - } +} - } +Bone.prototype = Object.assign( Object.create( Object3D.prototype ), { - function correctUV( uv, stride, vector, azimuth ) { + constructor: Bone, - if ( ( azimuth < 0 ) && ( uv.x === 1 ) ) { + isBone: true - uvBuffer[ stride ] = uv.x - 1; +} ); - } +/** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + * + * parameters = { + * color: , + * opacity: , + * + * linewidth: , + * linecap: "round", + * linejoin: "round" + * } + */ - if ( ( vector.x === 0 ) && ( vector.z === 0 ) ) { +function LineBasicMaterial( parameters ) { - uvBuffer[ stride ] = azimuth / 2 / Math.PI + 0.5; + Material.call( this ); - } + this.type = 'LineBasicMaterial'; - } + this.color = new Color( 0xffffff ); - // Angle around the Y axis, counter-clockwise when looking from above. + this.linewidth = 1; + this.linecap = 'round'; + this.linejoin = 'round'; - function azimuth( vector ) { + this.lights = false; - return Math.atan2( vector.z, - vector.x ); + this.setValues( parameters ); - } +} +LineBasicMaterial.prototype = Object.create( Material.prototype ); +LineBasicMaterial.prototype.constructor = LineBasicMaterial; - // Angle above the XZ plane. +LineBasicMaterial.prototype.isLineBasicMaterial = true; - function inclination( vector ) { +LineBasicMaterial.prototype.copy = function ( source ) { - return Math.atan2( - vector.y, Math.sqrt( ( vector.x * vector.x ) + ( vector.z * vector.z ) ) ); + Material.prototype.copy.call( this, source ); - } + this.color.copy( source.color ); -} + this.linewidth = source.linewidth; + this.linecap = source.linecap; + this.linejoin = source.linejoin; -PolyhedronBufferGeometry.prototype = Object.create( BufferGeometry.prototype ); -PolyhedronBufferGeometry.prototype.constructor = PolyhedronBufferGeometry; + return this; + +}; /** - * @author timothypratley / https://github.com/timothypratley - * @author Mugen87 / https://github.com/Mugen87 + * @author mrdoob / http://mrdoob.com/ */ -// TetrahedronGeometry +function Line( geometry, material, mode ) { -function TetrahedronGeometry( radius, detail ) { + if ( mode === 1 ) { - Geometry.call( this ); + console.error( 'THREE.Line: parameter THREE.LinePieces no longer supported. Use THREE.LineSegments instead.' ); - this.type = 'TetrahedronGeometry'; + } - this.parameters = { - radius: radius, - detail: detail - }; + Object3D.call( this ); - this.fromBufferGeometry( new TetrahedronBufferGeometry( radius, detail ) ); - this.mergeVertices(); + this.type = 'Line'; + + this.geometry = geometry !== undefined ? geometry : new BufferGeometry(); + this.material = material !== undefined ? material : new LineBasicMaterial( { color: Math.random() * 0xffffff } ); } -TetrahedronGeometry.prototype = Object.create( Geometry.prototype ); -TetrahedronGeometry.prototype.constructor = TetrahedronGeometry; +Line.prototype = Object.assign( Object.create( Object3D.prototype ), { -// TetrahedronBufferGeometry + constructor: Line, -function TetrahedronBufferGeometry( radius, detail ) { + isLine: true, - var vertices = [ - 1, 1, 1, - 1, - 1, 1, - 1, 1, - 1, 1, - 1, - 1 - ]; + computeLineDistances: ( function () { - var indices = [ - 2, 1, 0, 0, 3, 2, 1, 3, 0, 2, 3, 1 - ]; + var start = new Vector3(); + var end = new Vector3(); - PolyhedronBufferGeometry.call( this, vertices, indices, radius, detail ); + return function computeLineDistances() { - this.type = 'TetrahedronBufferGeometry'; + var geometry = this.geometry; - this.parameters = { - radius: radius, - detail: detail - }; + if ( geometry.isBufferGeometry ) { -} + // we assume non-indexed geometry -TetrahedronBufferGeometry.prototype = Object.create( PolyhedronBufferGeometry.prototype ); -TetrahedronBufferGeometry.prototype.constructor = TetrahedronBufferGeometry; + if ( geometry.index === null ) { -/** - * @author timothypratley / https://github.com/timothypratley - * @author Mugen87 / https://github.com/Mugen87 - */ + var positionAttribute = geometry.attributes.position; + var lineDistances = [ 0 ]; -// OctahedronGeometry + for ( var i = 1, l = positionAttribute.count; i < l; i ++ ) { -function OctahedronGeometry( radius, detail ) { + start.fromBufferAttribute( positionAttribute, i - 1 ); + end.fromBufferAttribute( positionAttribute, i ); - Geometry.call( this ); + lineDistances[ i ] = lineDistances[ i - 1 ]; + lineDistances[ i ] += start.distanceTo( end ); - this.type = 'OctahedronGeometry'; + } - this.parameters = { - radius: radius, - detail: detail - }; + geometry.addAttribute( 'lineDistance', new Float32BufferAttribute( lineDistances, 1 ) ); - this.fromBufferGeometry( new OctahedronBufferGeometry( radius, detail ) ); - this.mergeVertices(); + } else { -} + console.warn( 'THREE.Line.computeLineDistances(): Computation only possible with non-indexed BufferGeometry.' ); -OctahedronGeometry.prototype = Object.create( Geometry.prototype ); -OctahedronGeometry.prototype.constructor = OctahedronGeometry; + } -// OctahedronBufferGeometry + } else if ( geometry.isGeometry ) { -function OctahedronBufferGeometry( radius, detail ) { + var vertices = geometry.vertices; + var lineDistances = geometry.lineDistances; - var vertices = [ - 1, 0, 0, - 1, 0, 0, 0, 1, 0, - 0, - 1, 0, 0, 0, 1, 0, 0, - 1 - ]; + lineDistances[ 0 ] = 0; - 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 - ]; + for ( var i = 1, l = vertices.length; i < l; i ++ ) { - PolyhedronBufferGeometry.call( this, vertices, indices, radius, detail ); + lineDistances[ i ] = lineDistances[ i - 1 ]; + lineDistances[ i ] += vertices[ i - 1 ].distanceTo( vertices[ i ] ); - this.type = 'OctahedronBufferGeometry'; + } - this.parameters = { - radius: radius, - detail: detail - }; + } -} + return this; -OctahedronBufferGeometry.prototype = Object.create( PolyhedronBufferGeometry.prototype ); -OctahedronBufferGeometry.prototype.constructor = OctahedronBufferGeometry; + }; -/** - * @author timothypratley / https://github.com/timothypratley - * @author Mugen87 / https://github.com/Mugen87 - */ + }() ), -// IcosahedronGeometry + raycast: ( function () { -function IcosahedronGeometry( radius, detail ) { + var inverseMatrix = new Matrix4(); + var ray = new Ray(); + var sphere = new Sphere(); - Geometry.call( this ); + return function raycast( raycaster, intersects ) { - this.type = 'IcosahedronGeometry'; + var precision = raycaster.linePrecision; - this.parameters = { - radius: radius, - detail: detail - }; + var geometry = this.geometry; + var matrixWorld = this.matrixWorld; - this.fromBufferGeometry( new IcosahedronBufferGeometry( radius, detail ) ); - this.mergeVertices(); + // Checking boundingSphere distance to ray -} + if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere(); -IcosahedronGeometry.prototype = Object.create( Geometry.prototype ); -IcosahedronGeometry.prototype.constructor = IcosahedronGeometry; + sphere.copy( geometry.boundingSphere ); + sphere.applyMatrix4( matrixWorld ); + sphere.radius += precision; -// IcosahedronBufferGeometry + if ( raycaster.ray.intersectsSphere( sphere ) === false ) return; -function IcosahedronBufferGeometry( radius, detail ) { + // - var t = ( 1 + Math.sqrt( 5 ) ) / 2; + inverseMatrix.getInverse( matrixWorld ); + ray.copy( raycaster.ray ).applyMatrix4( inverseMatrix ); - var vertices = [ - - 1, t, 0, 1, t, 0, - 1, - t, 0, 1, - t, 0, - 0, - 1, t, 0, 1, t, 0, - 1, - t, 0, 1, - t, - t, 0, - 1, t, 0, 1, - t, 0, - 1, - t, 0, 1 - ]; + var localPrecision = precision / ( ( this.scale.x + this.scale.y + this.scale.z ) / 3 ); + var localPrecisionSq = localPrecision * localPrecision; - 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 - ]; + var vStart = new Vector3(); + var vEnd = new Vector3(); + var interSegment = new Vector3(); + var interRay = new Vector3(); + var step = ( this && this.isLineSegments ) ? 2 : 1; - PolyhedronBufferGeometry.call( this, vertices, indices, radius, detail ); + if ( geometry.isBufferGeometry ) { - this.type = 'IcosahedronBufferGeometry'; + var index = geometry.index; + var attributes = geometry.attributes; + var positions = attributes.position.array; - this.parameters = { - radius: radius, - detail: detail - }; + if ( index !== null ) { -} + var indices = index.array; -IcosahedronBufferGeometry.prototype = Object.create( PolyhedronBufferGeometry.prototype ); -IcosahedronBufferGeometry.prototype.constructor = IcosahedronBufferGeometry; + for ( var i = 0, l = indices.length - 1; i < l; i += step ) { -/** - * @author Abe Pazos / https://hamoid.com - * @author Mugen87 / https://github.com/Mugen87 - */ + var a = indices[ i ]; + var b = indices[ i + 1 ]; -// DodecahedronGeometry + vStart.fromArray( positions, a * 3 ); + vEnd.fromArray( positions, b * 3 ); -function DodecahedronGeometry( radius, detail ) { + var distSq = ray.distanceSqToSegment( vStart, vEnd, interRay, interSegment ); - Geometry.call( this ); + if ( distSq > localPrecisionSq ) continue; - this.type = 'DodecahedronGeometry'; + interRay.applyMatrix4( this.matrixWorld ); //Move back to world space for distance calculation - this.parameters = { - radius: radius, - detail: detail - }; + var distance = raycaster.ray.origin.distanceTo( interRay ); - this.fromBufferGeometry( new DodecahedronBufferGeometry( radius, detail ) ); - this.mergeVertices(); + if ( distance < raycaster.near || distance > raycaster.far ) continue; -} + intersects.push( { -DodecahedronGeometry.prototype = Object.create( Geometry.prototype ); -DodecahedronGeometry.prototype.constructor = DodecahedronGeometry; + 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 -// DodecahedronBufferGeometry + } ); -function DodecahedronBufferGeometry( radius, detail ) { + } - var t = ( 1 + Math.sqrt( 5 ) ) / 2; - var r = 1 / t; + } else { - var vertices = [ + for ( var i = 0, l = positions.length / 3 - 1; i < l; i += step ) { - // (±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, + vStart.fromArray( positions, 3 * i ); + vEnd.fromArray( positions, 3 * i + 3 ); - // (0, ±1/φ, ±φ) - 0, - r, - t, 0, - r, t, - 0, r, - t, 0, r, t, + var distSq = ray.distanceSqToSegment( vStart, vEnd, interRay, interSegment ); - // (±1/φ, ±φ, 0) - - r, - t, 0, - r, t, 0, - r, - t, 0, r, t, 0, + if ( distSq > localPrecisionSq ) continue; - // (±φ, 0, ±1/φ) - - t, 0, - r, t, 0, - r, - - t, 0, r, t, 0, r - ]; + interRay.applyMatrix4( this.matrixWorld ); //Move back to world space for distance calculation - 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 - ]; + var distance = raycaster.ray.origin.distanceTo( interRay ); - PolyhedronBufferGeometry.call( this, vertices, indices, radius, detail ); + if ( distance < raycaster.near || distance > raycaster.far ) continue; - this.type = 'DodecahedronBufferGeometry'; + intersects.push( { - this.parameters = { - radius: radius, - detail: detail - }; + 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 -} + } ); -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 + } else if ( geometry.isGeometry ) { -function TubeGeometry( path, tubularSegments, radius, radialSegments, closed, taper ) { + var vertices = geometry.vertices; + var nbVertices = vertices.length; - Geometry.call( this ); + for ( var i = 0; i < nbVertices - 1; i += step ) { - this.type = 'TubeGeometry'; + var distSq = ray.distanceSqToSegment( vertices[ i ], vertices[ i + 1 ], interRay, interSegment ); - this.parameters = { - path: path, - tubularSegments: tubularSegments, - radius: radius, - radialSegments: radialSegments, - closed: closed - }; + if ( distSq > localPrecisionSq ) continue; - if ( taper !== undefined ) console.warn( 'THREE.TubeGeometry: taper has been removed.' ); + interRay.applyMatrix4( this.matrixWorld ); //Move back to world space for distance calculation - var bufferGeometry = new TubeBufferGeometry( path, tubularSegments, radius, radialSegments, closed ); + var distance = raycaster.ray.origin.distanceTo( interRay ); - // expose internals + if ( distance < raycaster.near || distance > raycaster.far ) continue; - this.tangents = bufferGeometry.tangents; - this.normals = bufferGeometry.normals; - this.binormals = bufferGeometry.binormals; + intersects.push( { - // create geometry + 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 - this.fromBufferGeometry( bufferGeometry ); - this.mergeVertices(); + } ); -} + } -TubeGeometry.prototype = Object.create( Geometry.prototype ); -TubeGeometry.prototype.constructor = TubeGeometry; + } -// TubeBufferGeometry + }; -function TubeBufferGeometry( path, tubularSegments, radius, radialSegments, closed ) { + }() ), - BufferGeometry.call( this ); + copy: function ( source ) { - this.type = 'TubeBufferGeometry'; + Object3D.prototype.copy.call( this, source ); - this.parameters = { - path: path, - tubularSegments: tubularSegments, - radius: radius, - radialSegments: radialSegments, - closed: closed - }; + this.geometry.copy( source.geometry ); + this.material.copy( source.material ); - tubularSegments = tubularSegments || 64; - radius = radius || 1; - radialSegments = radialSegments || 8; - closed = closed || false; + return this; - var frames = path.computeFrenetFrames( tubularSegments, closed ); + }, - // expose internals + clone: function () { - this.tangents = frames.tangents; - this.normals = frames.normals; - this.binormals = frames.binormals; + return new this.constructor().copy( this ); - // helper variables + } - var vertex = new Vector3(); - var normal = new Vector3(); - var uv = new Vector2(); - var P = new Vector3(); +} ); - var i, j; +/** + * @author mrdoob / http://mrdoob.com/ + */ - // buffer +function LineSegments( geometry, material ) { - var vertices = []; - var normals = []; - var uvs = []; - var indices = []; + Line.call( this, geometry, material ); - // create buffer data + this.type = 'LineSegments'; - generateBufferData(); +} - // build geometry +LineSegments.prototype = Object.assign( Object.create( Line.prototype ), { - this.setIndex( indices ); - this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - this.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); - this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); + constructor: LineSegments, - // functions + isLineSegments: true, - function generateBufferData() { + computeLineDistances: ( function () { - for ( i = 0; i < tubularSegments; i ++ ) { + var start = new Vector3(); + var end = new Vector3(); - generateSegment( i ); + return function computeLineDistances() { - } + var geometry = this.geometry; - // 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) + if ( geometry.isBufferGeometry ) { - generateSegment( ( closed === false ) ? tubularSegments : 0 ); + // we assume non-indexed geometry - // uvs are generated in a separate function. - // this makes it easy compute correct values for closed geometries + if ( geometry.index === null ) { - generateUVs(); + var positionAttribute = geometry.attributes.position; + var lineDistances = []; - // finally create faces + for ( var i = 0, l = positionAttribute.count; i < l; i += 2 ) { - generateIndices(); + start.fromBufferAttribute( positionAttribute, i ); + end.fromBufferAttribute( positionAttribute, i + 1 ); - } + lineDistances[ i ] = ( i === 0 ) ? 0 : lineDistances[ i - 1 ]; + lineDistances[ i + 1 ] = lineDistances[ i ] + start.distanceTo( end ); - function generateSegment( i ) { + } - // we use getPointAt to sample evenly distributed points from the given path + geometry.addAttribute( 'lineDistance', new Float32BufferAttribute( lineDistances, 1 ) ); - P = path.getPointAt( i / tubularSegments, P ); + } else { - // retrieve corresponding normal and binormal + console.warn( 'THREE.LineSegments.computeLineDistances(): Computation only possible with non-indexed BufferGeometry.' ); - var N = frames.normals[ i ]; - var B = frames.binormals[ i ]; + } - // generate normals and vertices for the current segment + } else if ( geometry.isGeometry ) { - for ( j = 0; j <= radialSegments; j ++ ) { + var vertices = geometry.vertices; + var lineDistances = geometry.lineDistances; - var v = j / radialSegments * Math.PI * 2; + for ( var i = 0, l = vertices.length; i < l; i += 2 ) { - var sin = Math.sin( v ); - var cos = - Math.cos( v ); + start.copy( vertices[ i ] ); + end.copy( vertices[ i + 1 ] ); - // normal + lineDistances[ i ] = ( i === 0 ) ? 0 : lineDistances[ i - 1 ]; + lineDistances[ i + 1 ] = lineDistances[ i ] + start.distanceTo( end ); - normal.x = ( cos * N.x + sin * B.x ); - normal.y = ( cos * N.y + sin * B.y ); - normal.z = ( cos * N.z + sin * B.z ); - normal.normalize(); + } - normals.push( normal.x, normal.y, normal.z ); + } - // vertex + return this; - vertex.x = P.x + radius * normal.x; - vertex.y = P.y + radius * normal.y; - vertex.z = P.z + radius * normal.z; + }; - vertices.push( vertex.x, vertex.y, vertex.z ); + }() ) - } +} ); - } +/** + * @author mgreter / http://github.com/mgreter + */ - function generateIndices() { +function LineLoop( geometry, material ) { - for ( j = 1; j <= tubularSegments; j ++ ) { + Line.call( this, geometry, material ); - for ( i = 1; i <= radialSegments; i ++ ) { + this.type = 'LineLoop'; - 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; +} - // faces +LineLoop.prototype = Object.assign( Object.create( Line.prototype ), { - indices.push( a, b, d ); - indices.push( b, c, d ); + constructor: LineLoop, - } + isLineLoop: true, - } +} ); - } +/** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + * + * parameters = { + * color: , + * opacity: , + * map: new THREE.Texture( ), + * + * size: , + * sizeAttenuation: + * + * morphTargets: + * } + */ - function generateUVs() { +function PointsMaterial( parameters ) { - for ( i = 0; i <= tubularSegments; i ++ ) { + Material.call( this ); - for ( j = 0; j <= radialSegments; j ++ ) { + this.type = 'PointsMaterial'; - uv.x = i / tubularSegments; - uv.y = j / radialSegments; + this.color = new Color( 0xffffff ); - uvs.push( uv.x, uv.y ); + this.map = null; - } + this.size = 1; + this.sizeAttenuation = true; - } + this.morphTargets = false; - } + this.lights = false; + + this.setValues( parameters ); } -TubeBufferGeometry.prototype = Object.create( BufferGeometry.prototype ); -TubeBufferGeometry.prototype.constructor = TubeBufferGeometry; +PointsMaterial.prototype = Object.create( Material.prototype ); +PointsMaterial.prototype.constructor = PointsMaterial; -/** - * @author oosmoxiecode - * @author Mugen87 / https://github.com/Mugen87 - * - * based on http://www.blackpawn.com/texts/pqtorus/ - */ +PointsMaterial.prototype.isPointsMaterial = true; -// TorusKnotGeometry +PointsMaterial.prototype.copy = function ( source ) { -function TorusKnotGeometry( radius, tube, tubularSegments, radialSegments, p, q, heightScale ) { + Material.prototype.copy.call( this, source ); - Geometry.call( this ); + this.color.copy( source.color ); - this.type = 'TorusKnotGeometry'; + this.map = source.map; - this.parameters = { - radius: radius, - tube: tube, - tubularSegments: tubularSegments, - radialSegments: radialSegments, - p: p, - q: q - }; + this.size = source.size; + this.sizeAttenuation = source.sizeAttenuation; - if ( heightScale !== undefined ) console.warn( 'THREE.TorusKnotGeometry: heightScale has been deprecated. Use .scale( x, y, z ) instead.' ); + this.morphTargets = source.morphTargets; - this.fromBufferGeometry( new TorusKnotBufferGeometry( radius, tube, tubularSegments, radialSegments, p, q ) ); - this.mergeVertices(); + return this; -} +}; -TorusKnotGeometry.prototype = Object.create( Geometry.prototype ); -TorusKnotGeometry.prototype.constructor = TorusKnotGeometry; +/** + * @author alteredq / http://alteredqualia.com/ + */ -// TorusKnotBufferGeometry +function Points( geometry, material ) { -function TorusKnotBufferGeometry( radius, tube, tubularSegments, radialSegments, p, q ) { + Object3D.call( this ); - BufferGeometry.call( this ); + this.type = 'Points'; - this.type = 'TorusKnotBufferGeometry'; + this.geometry = geometry !== undefined ? geometry : new BufferGeometry(); + this.material = material !== undefined ? material : new PointsMaterial( { color: Math.random() * 0xffffff } ); - this.parameters = { - radius: radius, - 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; +Points.prototype = Object.assign( Object.create( Object3D.prototype ), { - // buffers + constructor: Points, - var indices = []; - var vertices = []; - var normals = []; - var uvs = []; + isPoints: true, - // helper variables + raycast: ( function () { - var i, j; + var inverseMatrix = new Matrix4(); + var ray = new Ray(); + var sphere = new Sphere(); - var vertex = new Vector3(); - var normal = new Vector3(); + return function raycast( raycaster, intersects ) { - var P1 = new Vector3(); - var P2 = new Vector3(); + var object = this; + var geometry = this.geometry; + var matrixWorld = this.matrixWorld; + var threshold = raycaster.params.Points.threshold; - var B = new Vector3(); - var T = new Vector3(); - var N = new Vector3(); + // Checking boundingSphere distance to ray - // generate vertices, normals and uvs + if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere(); - for ( i = 0; i <= tubularSegments; ++ i ) { + sphere.copy( geometry.boundingSphere ); + sphere.applyMatrix4( matrixWorld ); + sphere.radius += threshold; - // the radian "u" is used to calculate the position on the torus curve of the current tubular segement + if ( raycaster.ray.intersectsSphere( sphere ) === false ) return; - var u = i / tubularSegments * p * Math.PI * 2; + // - // now we calculate two points. P1 is our current position on the curve, P2 is a little farther ahead. - // these points are used to create a special "coordinate space", which is necessary to calculate the correct vertex positions + inverseMatrix.getInverse( matrixWorld ); + ray.copy( raycaster.ray ).applyMatrix4( inverseMatrix ); - calculatePositionOnCurve( u, p, q, radius, P1 ); - calculatePositionOnCurve( u + 0.01, p, q, radius, P2 ); + 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(); - // calculate orthonormal basis + function testPoint( point, index ) { - T.subVectors( P2, P1 ); - N.addVectors( P2, P1 ); - B.crossVectors( T, N ); - N.crossVectors( B, T ); + var rayPointDistanceSq = ray.distanceSqToPoint( point ); - // normalize B, N. T can be ignored, we don't use it + if ( rayPointDistanceSq < localThresholdSq ) { - B.normalize(); - N.normalize(); + ray.closestPointToPoint( point, intersectPoint ); + intersectPoint.applyMatrix4( matrixWorld ); - for ( j = 0; j <= radialSegments; ++ j ) { + var distance = raycaster.ray.origin.distanceTo( intersectPoint ); - // 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. + if ( distance < raycaster.near || distance > raycaster.far ) return; - var v = j / radialSegments * Math.PI * 2; - var cx = - tube * Math.cos( v ); - var cy = tube * Math.sin( v ); + intersects.push( { - // 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 + distance: distance, + distanceToRay: Math.sqrt( rayPointDistanceSq ), + point: intersectPoint.clone(), + index: index, + face: null, + object: object - vertex.x = P1.x + ( cx * N.x + cy * B.x ); - vertex.y = P1.y + ( cx * N.y + cy * B.y ); - vertex.z = P1.z + ( cx * N.z + cy * B.z ); + } ); - vertices.push( vertex.x, vertex.y, vertex.z ); + } - // normal (P1 is always the center/origin of the extrusion, thus we can use it to calculate the normal) + } - normal.subVectors( vertex, P1 ).normalize(); + if ( geometry.isBufferGeometry ) { - normals.push( normal.x, normal.y, normal.z ); + var index = geometry.index; + var attributes = geometry.attributes; + var positions = attributes.position.array; - // uv + if ( index !== null ) { - uvs.push( i / tubularSegments ); - uvs.push( j / radialSegments ); + var indices = index.array; - } + for ( var i = 0, il = indices.length; i < il; i ++ ) { - } + var a = indices[ i ]; - // generate indices + position.fromArray( positions, a * 3 ); - for ( j = 1; j <= tubularSegments; j ++ ) { + testPoint( position, a ); - for ( i = 1; i <= radialSegments; i ++ ) { + } - // indices + } else { - 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; + for ( var i = 0, l = positions.length / 3; i < l; i ++ ) { - // faces + position.fromArray( positions, i * 3 ); - indices.push( a, b, d ); - indices.push( b, c, d ); + testPoint( position, i ); - } + } - } + } - // build geometry + } else { - this.setIndex( indices ); - this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - this.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); - this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); + var vertices = geometry.vertices; - // this function calculates the current position on the torus curve + for ( var i = 0, l = vertices.length; i < l; i ++ ) { - function calculatePositionOnCurve( u, p, q, radius, position ) { + testPoint( vertices[ i ], i ); - var cu = Math.cos( u ); - var su = Math.sin( u ); - var quOverP = q / p * u; - var cs = Math.cos( quOverP ); + } - position.x = radius * ( 2 + cs ) * 0.5 * cu; - position.y = radius * ( 2 + cs ) * su * 0.5; - position.z = radius * Math.sin( quOverP ) * 0.5; + } - } + }; -} + }() ), -TorusKnotBufferGeometry.prototype = Object.create( BufferGeometry.prototype ); -TorusKnotBufferGeometry.prototype.constructor = TorusKnotBufferGeometry; + clone: function () { + + return new this.constructor( this.geometry, this.material ).copy( this ); + + } + +} ); /** - * @author oosmoxiecode * @author mrdoob / http://mrdoob.com/ - * @author Mugen87 / https://github.com/Mugen87 */ -// TorusGeometry - -function TorusGeometry( radius, tube, radialSegments, tubularSegments, arc ) { +function VideoTexture( video, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ) { - Geometry.call( this ); + Texture.call( this, video, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ); - this.type = 'TorusGeometry'; + this.format = format !== undefined ? format : RGBFormat; - this.parameters = { - radius: radius, - tube: tube, - radialSegments: radialSegments, - tubularSegments: tubularSegments, - arc: arc - }; + this.minFilter = minFilter !== undefined ? minFilter : LinearFilter; + this.magFilter = magFilter !== undefined ? magFilter : LinearFilter; - this.fromBufferGeometry( new TorusBufferGeometry( radius, tube, radialSegments, tubularSegments, arc ) ); - this.mergeVertices(); + this.generateMipmaps = false; } -TorusGeometry.prototype = Object.create( Geometry.prototype ); -TorusGeometry.prototype.constructor = TorusGeometry; +VideoTexture.prototype = Object.assign( Object.create( Texture.prototype ), { -// TorusBufferGeometry + constructor: VideoTexture, -function TorusBufferGeometry( radius, tube, radialSegments, tubularSegments, arc ) { + isVideoTexture: true, - BufferGeometry.call( this ); + update: function () { - this.type = 'TorusBufferGeometry'; + var video = this.image; - this.parameters = { - radius: radius, - tube: tube, - radialSegments: radialSegments, - tubularSegments: tubularSegments, - arc: arc - }; + if ( video.readyState >= video.HAVE_CURRENT_DATA ) { - radius = radius || 1; - tube = tube || 0.4; - radialSegments = Math.floor( radialSegments ) || 8; - tubularSegments = Math.floor( tubularSegments ) || 6; - arc = arc || Math.PI * 2; + this.needsUpdate = true; - // buffers + } - var indices = []; - var vertices = []; - var normals = []; - var uvs = []; + } - // helper variables +} ); - var center = new Vector3(); - var vertex = new Vector3(); - var normal = new Vector3(); +/** + * @author alteredq / http://alteredqualia.com/ + */ - var j, i; +function CompressedTexture( mipmaps, width, height, format, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy, encoding ) { - // generate vertices, normals and uvs + Texture.call( this, null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding ); - for ( j = 0; j <= radialSegments; j ++ ) { + this.image = { width: width, height: height }; + this.mipmaps = mipmaps; - for ( i = 0; i <= tubularSegments; i ++ ) { + // no flipping for cube textures + // (also flipping doesn't work for compressed textures ) - var u = i / tubularSegments * arc; - var v = j / radialSegments * Math.PI * 2; + this.flipY = false; - // vertex + // can't generate mipmaps for compressed textures + // mips must be embedded in DDS files - 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.generateMipmaps = false; - vertices.push( vertex.x, vertex.y, vertex.z ); +} - // normal +CompressedTexture.prototype = Object.create( Texture.prototype ); +CompressedTexture.prototype.constructor = CompressedTexture; - center.x = radius * Math.cos( u ); - center.y = radius * Math.sin( u ); - normal.subVectors( vertex, center ).normalize(); +CompressedTexture.prototype.isCompressedTexture = true; - normals.push( normal.x, normal.y, normal.z ); +/** + * @author mrdoob / http://mrdoob.com/ + */ - // uv +function CanvasTexture( canvas, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ) { - uvs.push( i / tubularSegments ); - uvs.push( j / radialSegments ); + Texture.call( this, canvas, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ); - } + this.needsUpdate = true; - } +} - // generate indices +CanvasTexture.prototype = Object.create( Texture.prototype ); +CanvasTexture.prototype.constructor = CanvasTexture; +CanvasTexture.prototype.isCanvasTexture = true; - for ( j = 1; j <= radialSegments; j ++ ) { +/** + * @author Matt DesLauriers / @mattdesl + * @author atix / arthursilber.de + */ - for ( i = 1; i <= tubularSegments; i ++ ) { +function DepthTexture( width, height, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy, format ) { - // indices + format = format !== undefined ? format : DepthFormat; - 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; + if ( format !== DepthFormat && format !== DepthStencilFormat ) { - // faces + throw new Error( 'DepthTexture format must be either THREE.DepthFormat or THREE.DepthStencilFormat' ); - indices.push( a, b, d ); - indices.push( b, c, d ); + } - } + if ( type === undefined && format === DepthFormat ) type = UnsignedShortType; + if ( type === undefined && format === DepthStencilFormat ) type = UnsignedInt248Type; - } + Texture.call( this, null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ); - // build geometry + this.image = { width: width, height: height }; - 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.magFilter = magFilter !== undefined ? magFilter : NearestFilter; + this.minFilter = minFilter !== undefined ? minFilter : NearestFilter; + + this.flipY = false; + this.generateMipmaps = false; } -TorusBufferGeometry.prototype = Object.create( BufferGeometry.prototype ); -TorusBufferGeometry.prototype.constructor = TorusBufferGeometry; +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 - * Port from https://github.com/mapbox/earcut (v2.1.2) */ -var Earcut = { +function WireframeGeometry( geometry ) { - triangulate: function ( data, holeIndices, dim ) { + BufferGeometry.call( this ); - dim = dim || 2; + this.type = 'WireframeGeometry'; - var hasHoles = holeIndices && holeIndices.length, - outerLen = hasHoles ? holeIndices[ 0 ] * dim : data.length, - outerNode = linkedList( data, 0, outerLen, dim, true ), - triangles = []; + // buffer - if ( ! outerNode ) return triangles; + var vertices = []; - var minX, minY, maxX, maxY, x, y, invSize; + // helper variables - if ( hasHoles ) outerNode = eliminateHoles( data, holeIndices, outerNode, dim ); + var i, j, l, o, ol; + var edge = [ 0, 0 ], edges = {}, e, edge1, edge2; + var key, keys = [ 'a', 'b', 'c' ]; + var vertex; - // if the shape is not too simple, we'll use z-order curve hash later; calculate polygon bbox + // different logic for Geometry and BufferGeometry - if ( data.length > 80 * dim ) { + if ( geometry && geometry.isGeometry ) { - minX = maxX = data[ 0 ]; - minY = maxY = data[ 1 ]; + // create a data structure that contains all edges without duplicates - for ( var i = dim; i < outerLen; i += dim ) { + var faces = geometry.faces; - 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; + for ( i = 0, l = faces.length; i < l; i ++ ) { - } + var face = faces[ i ]; - // minX, minY and invSize are later used to transform coords into integers for z-order calculation + for ( j = 0; j < 3; j ++ ) { - invSize = Math.max( maxX - minX, maxY - minY ); - invSize = invSize !== 0 ? 1 / invSize : 0; + 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 ); - } + key = edge[ 0 ] + ',' + edge[ 1 ]; - earcutLinked( outerNode, triangles, dim, minX, minY, invSize ); + if ( edges[ key ] === undefined ) { - return triangles; + edges[ key ] = { index1: edge[ 0 ], index2: edge[ 1 ] }; - } + } -}; + } -// create a circular doubly linked list from polygon points in the specified winding order + } -function linkedList( data, start, end, dim, clockwise ) { + // generate vertices - var i, last; + for ( key in edges ) { - if ( clockwise === ( signedArea( data, start, end, dim ) > 0 ) ) { + e = edges[ key ]; - for ( i = start; i < end; i += dim ) last = insertNode( i, data[ i ], data[ i + 1 ], last ); + vertex = geometry.vertices[ e.index1 ]; + vertices.push( vertex.x, vertex.y, vertex.z ); - } else { + vertex = geometry.vertices[ e.index2 ]; + vertices.push( vertex.x, vertex.y, vertex.z ); - for ( i = end - dim; i >= start; i -= dim ) last = insertNode( i, data[ i ], data[ i + 1 ], last ); + } - } + } else if ( geometry && geometry.isBufferGeometry ) { - if ( last && equals( last, last.next ) ) { + var position, indices, groups; + var group, start, count; + var index1, index2; - removeNode( last ); - last = last.next; + vertex = new Vector3(); - } + if ( geometry.index !== null ) { - return last; + // indexed BufferGeometry -} + position = geometry.attributes.position; + indices = geometry.index; + groups = geometry.groups; -// eliminate colinear or duplicate points + if ( groups.length === 0 ) { -function filterPoints( start, end ) { + groups = [ { start: 0, count: indices.count, materialIndex: 0 } ]; - if ( ! start ) return start; - if ( ! end ) end = start; + } - var p = start, again; + // create a data structure that contains all eges without duplicates - do { + for ( o = 0, ol = groups.length; o < ol; ++ o ) { - again = false; + group = groups[ o ]; - if ( ! p.steiner && ( equals( p, p.next ) || area( p.prev, p, p.next ) === 0 ) ) { + start = group.start; + count = group.count; - removeNode( p ); - p = end = p.prev; - if ( p === p.next ) break; - again = true; + for ( i = start, l = ( start + count ); i < l; i += 3 ) { - } else { + for ( j = 0; j < 3; j ++ ) { - p = p.next; + 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 ); - } + key = edge[ 0 ] + ',' + edge[ 1 ]; - } while ( again || p !== end ); + if ( edges[ key ] === undefined ) { - return end; + edges[ key ] = { index1: edge[ 0 ], index2: edge[ 1 ] }; -} + } -// main ear slicing loop which triangulates a polygon (given as a linked list) + } -function earcutLinked( ear, triangles, dim, minX, minY, invSize, pass ) { + } - if ( ! ear ) return; + } - // interlink polygon nodes in z-order + // generate vertices - if ( ! pass && invSize ) indexCurve( ear, minX, minY, invSize ); + for ( key in edges ) { - var stop = ear, prev, next; + e = edges[ key ]; - // iterate through ears, slicing them one by one + vertex.fromBufferAttribute( position, e.index1 ); + vertices.push( vertex.x, vertex.y, vertex.z ); - while ( ear.prev !== ear.next ) { + vertex.fromBufferAttribute( position, e.index2 ); + vertices.push( vertex.x, vertex.y, vertex.z ); - prev = ear.prev; - next = ear.next; + } - if ( invSize ? isEarHashed( ear, minX, minY, invSize ) : isEar( ear ) ) { + } else { - // cut off the triangle - triangles.push( prev.i / dim ); - triangles.push( ear.i / dim ); - triangles.push( next.i / dim ); + // non-indexed BufferGeometry - removeNode( ear ); + position = geometry.attributes.position; - // skipping the next vertice leads to less sliver triangles - ear = next.next; - stop = next.next; + for ( i = 0, l = ( position.count / 3 ); i < l; i ++ ) { - continue; + for ( j = 0; j < 3; j ++ ) { - } + // three edges per triangle, an edge is represented as (index1, index2) + // e.g. the first triangle has the following edges: (0,1),(1,2),(2,0) - ear = next; + index1 = 3 * i + j; + vertex.fromBufferAttribute( position, index1 ); + vertices.push( vertex.x, vertex.y, vertex.z ); - // if we looped through the whole remaining polygon and can't find any more ears + index2 = 3 * i + ( ( j + 1 ) % 3 ); + vertex.fromBufferAttribute( position, index2 ); + vertices.push( vertex.x, vertex.y, vertex.z ); - if ( ear === stop ) { + } - // try filtering points and slicing again + } - if ( ! pass ) { + } - earcutLinked( filterPoints( ear ), triangles, dim, minX, minY, invSize, 1 ); + } - // if this didn't work, try curing all small self-intersections locally + // build geometry - } else if ( pass === 1 ) { + this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - ear = cureLocalIntersections( ear, triangles, dim ); - earcutLinked( ear, triangles, dim, minX, minY, invSize, 2 ); +} - // as a last resort, try splitting the remaining polygon into two +WireframeGeometry.prototype = Object.create( BufferGeometry.prototype ); +WireframeGeometry.prototype.constructor = WireframeGeometry; - } else if ( pass === 2 ) { +/** + * @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 + */ - splitEarcut( ear, triangles, dim, minX, minY, invSize ); +// ParametricGeometry - } +function ParametricGeometry( func, slices, stacks ) { - break; + Geometry.call( this ); - } + this.type = 'ParametricGeometry'; - } + this.parameters = { + func: func, + slices: slices, + stacks: stacks + }; + + this.fromBufferGeometry( new ParametricBufferGeometry( func, slices, stacks ) ); + this.mergeVertices(); } -// check whether a polygon node forms a valid ear with adjacent nodes +ParametricGeometry.prototype = Object.create( Geometry.prototype ); +ParametricGeometry.prototype.constructor = ParametricGeometry; -function isEar( ear ) { +// ParametricBufferGeometry - var a = ear.prev, - b = ear, - c = ear.next; +function ParametricBufferGeometry( func, slices, stacks ) { - if ( area( a, b, c ) >= 0 ) return false; // reflex, can't be an ear + BufferGeometry.call( this ); - // now make sure we don't have other points inside the potential ear - var p = ear.next.next; + this.type = 'ParametricBufferGeometry'; - while ( p !== ear.prev ) { + this.parameters = { + func: func, + slices: slices, + stacks: stacks + }; - 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 ) { + // buffers - return false; + var indices = []; + var vertices = []; + var normals = []; + var uvs = []; - } + var EPS = 0.00001; - p = p.next; + var normal = new Vector3(); + + var p0 = new Vector3(), p1 = new Vector3(); + var pu = new Vector3(), pv = new Vector3(); + + var i, j; + + if ( func.length < 3 ) { + + console.error( 'THREE.ParametricGeometry: Function must now modify a Vector3 as third parameter.' ); } - return true; + // generate vertices, normals and uvs -} + var sliceCount = slices + 1; -function isEarHashed( ear, minX, minY, invSize ) { + for ( i = 0; i <= stacks; i ++ ) { - var a = ear.prev, - b = ear, - c = ear.next; + var v = i / stacks; - if ( area( a, b, c ) >= 0 ) return false; // reflex, can't be an ear + for ( j = 0; j <= slices; j ++ ) { - // triangle bbox; min & max are calculated like this for speed + var u = j / slices; - 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 ); + // vertex - // z-order range for the current triangle bbox; + func( u, v, p0 ); + vertices.push( p0.x, p0.y, p0.z ); - var minZ = zOrder( minTX, minTY, minX, minY, invSize ), - maxZ = zOrder( maxTX, maxTY, minX, minY, invSize ); + // normal - // first look for points inside the triangle in increasing z-order + // approximate tangent vectors via finite differences - var p = ear.nextZ; + if ( u - EPS >= 0 ) { - while ( p && p.z <= maxZ ) { + func( u - EPS, v, p1 ); + pu.subVectors( p0, p1 ); - 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 { - } + func( u + EPS, v, p1 ); + pu.subVectors( p1, p0 ); - // then look for points in decreasing z-order + } - p = ear.prevZ; + if ( v - EPS >= 0 ) { - while ( p && p.z >= minZ ) { + func( u, v - EPS, p1 ); + pv.subVectors( p0, p1 ); - 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; + } else { - p = p.prevZ; + func( u, v + EPS, p1 ); + pv.subVectors( p1, p0 ); - } + } - return true; + // cross product of tangent vectors returns surface normal -} + normal.crossVectors( pu, pv ).normalize(); + normals.push( normal.x, normal.y, normal.z ); -// go through all polygon nodes and cure small local self-intersections + // uv -function cureLocalIntersections( start, triangles, dim ) { + uvs.push( u, v ); - var p = start; + } - do { + } - var a = p.prev, b = p.next.next; + // generate indices - if ( ! equals( a, b ) && intersects( a, p, p.next, b ) && locallyInside( a, b ) && locallyInside( b, a ) ) { + for ( i = 0; i < stacks; i ++ ) { - triangles.push( a.i / dim ); - triangles.push( p.i / dim ); - triangles.push( b.i / dim ); + for ( j = 0; j < slices; j ++ ) { - // remove two nodes involved + var a = i * sliceCount + j; + var b = i * sliceCount + j + 1; + var c = ( i + 1 ) * sliceCount + j + 1; + var d = ( i + 1 ) * sliceCount + j; - removeNode( p ); - removeNode( p.next ); + // faces one and two - p = start = b; + indices.push( a, b, d ); + indices.push( b, c, d ); } - p = p.next; + } - } while ( p !== start ); + // build geometry - return p; + this.setIndex( indices ); + this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); + this.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); + this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); } -// try splitting polygon into two and triangulate them independently +ParametricBufferGeometry.prototype = Object.create( BufferGeometry.prototype ); +ParametricBufferGeometry.prototype.constructor = ParametricBufferGeometry; -function splitEarcut( start, triangles, dim, minX, minY, invSize ) { +/** + * @author clockworkgeek / https://github.com/clockworkgeek + * @author timothypratley / https://github.com/timothypratley + * @author WestLangley / http://github.com/WestLangley + * @author Mugen87 / https://github.com/Mugen87 + */ - // look for a valid diagonal that divides the polygon into two +// PolyhedronGeometry - var a = start; +function PolyhedronGeometry( vertices, indices, radius, detail ) { - do { + Geometry.call( this ); - var b = a.next.next; + this.type = 'PolyhedronGeometry'; - while ( b !== a.prev ) { + this.parameters = { + vertices: vertices, + indices: indices, + radius: radius, + detail: detail + }; - if ( a.i !== b.i && isValidDiagonal( a, b ) ) { + this.fromBufferGeometry( new PolyhedronBufferGeometry( vertices, indices, radius, detail ) ); + this.mergeVertices(); - // split the polygon in two by the diagonal +} - var c = splitPolygon( a, b ); +PolyhedronGeometry.prototype = Object.create( Geometry.prototype ); +PolyhedronGeometry.prototype.constructor = PolyhedronGeometry; - // filter colinear points around the cuts +// PolyhedronBufferGeometry - a = filterPoints( a, a.next ); - c = filterPoints( c, c.next ); +function PolyhedronBufferGeometry( vertices, indices, radius, detail ) { - // run earcut on each half + BufferGeometry.call( this ); - earcutLinked( a, triangles, dim, minX, minY, invSize ); - earcutLinked( c, triangles, dim, minX, minY, invSize ); - return; + this.type = 'PolyhedronBufferGeometry'; - } + this.parameters = { + vertices: vertices, + indices: indices, + radius: radius, + detail: detail + }; - b = b.next; + radius = radius || 1; + detail = detail || 0; - } + // default buffer data - a = a.next; + var vertexBuffer = []; + var uvBuffer = []; - } while ( a !== start ); + // the subdivision creates the vertex buffer data -} + subdivide( detail ); -// link every hole into the outer loop, producing a single-ring polygon without holes + // all vertices should lie on a conceptual sphere with a given radius -function eliminateHoles( data, holeIndices, outerNode, dim ) { + appplyRadius( radius ); - var queue = [], i, len, start, end, list; + // finally, create the uv data - for ( i = 0, len = holeIndices.length; i < len; i ++ ) { + generateUVs(); - 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 ) ); + // build non-indexed geometry - } + this.addAttribute( 'position', new Float32BufferAttribute( vertexBuffer, 3 ) ); + this.addAttribute( 'normal', new Float32BufferAttribute( vertexBuffer.slice(), 3 ) ); + this.addAttribute( 'uv', new Float32BufferAttribute( uvBuffer, 2 ) ); - queue.sort( compareX ); + if ( detail === 0 ) { - // process holes from left to right + this.computeVertexNormals(); // flat normals - for ( i = 0; i < queue.length; i ++ ) { + } else { - eliminateHole( queue[ i ], outerNode ); - outerNode = filterPoints( outerNode, outerNode.next ); + this.normalizeNormals(); // smooth normals } - return outerNode; - -} + // helper functions -function compareX( a, b ) { + function subdivide( detail ) { - return a.x - b.x; + 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 -// find a bridge between vertices that connects hole with an outer ring and and link it + for ( var i = 0; i < indices.length; i += 3 ) { -function eliminateHole( hole, outerNode ) { + // get the vertices of the face - outerNode = findHoleBridge( hole, outerNode ); + getVertexByIndex( indices[ i + 0 ], a ); + getVertexByIndex( indices[ i + 1 ], b ); + getVertexByIndex( indices[ i + 2 ], c ); - if ( outerNode ) { + // perform subdivision - var b = splitPolygon( outerNode, hole ); + subdivideFace( a, b, c, detail ); - filterPoints( b, b.next ); + } } -} - -// David Eberly's algorithm for finding a bridge between hole and outer polygon + function subdivideFace( a, b, c, detail ) { -function findHoleBridge( hole, outerNode ) { + var cols = Math.pow( 2, detail ); - var p = outerNode, - hx = hole.x, - hy = hole.y, - qx = - Infinity, - m; + // we use this multidimensional array as a data structure for creating the subdivision - // 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 + var v = []; - do { + var i, j; - if ( hy <= p.y && hy >= p.next.y && p.next.y !== p.y ) { + // construct all of the vertices for this subdivision - var x = p.x + ( hy - p.y ) * ( p.next.x - p.x ) / ( p.next.y - p.y ); + for ( i = 0; i <= cols; i ++ ) { - if ( x <= hx && x > qx ) { + v[ i ] = []; - qx = x; + var aj = a.clone().lerp( c, i / cols ); + var bj = b.clone().lerp( c, i / cols ); - if ( x === hx ) { + var rows = cols - i; - if ( hy === p.y ) return p; - if ( hy === p.next.y ) return p.next; + for ( j = 0; j <= rows; j ++ ) { - } + if ( j === 0 && i === cols ) { - m = p.x < p.next.x ? p : p.next; + v[ i ][ j ] = aj; - } + } else { - } + v[ i ][ j ] = aj.clone().lerp( bj, j / rows ); - p = p.next; + } - } while ( p !== outerNode ); + } - if ( ! m ) return null; + } - if ( hx === qx ) return m.prev; // hole touches outer segment; pick lower endpoint + // construct all of the faces - // 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 + for ( i = 0; i < cols; i ++ ) { - var stop = m, - mx = m.x, - my = m.y, - tanMin = Infinity, - tan; + for ( j = 0; j < 2 * ( cols - i ) - 1; j ++ ) { - p = m.next; + var k = Math.floor( j / 2 ); - while ( p !== stop ) { + if ( j % 2 === 0 ) { - 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 ) ) { + pushVertex( v[ i ][ k + 1 ] ); + pushVertex( v[ i + 1 ][ k ] ); + pushVertex( v[ i ][ k ] ); - tan = Math.abs( hy - p.y ) / ( hx - p.x ); // tangential + } else { - if ( ( tan < tanMin || ( tan === tanMin && p.x > m.x ) ) && locallyInside( p, hole ) ) { + pushVertex( v[ i ][ k + 1 ] ); + pushVertex( v[ i + 1 ][ k + 1 ] ); + pushVertex( v[ i + 1 ][ k ] ); - m = p; - tanMin = tan; + } } } - p = p.next; - } - return m; + function appplyRadius( radius ) { -} + var vertex = new Vector3(); -// interlink polygon nodes in z-order + // iterate over the entire buffer and apply the radius to each vertex -function indexCurve( start, minX, minY, invSize ) { + for ( var i = 0; i < vertexBuffer.length; i += 3 ) { - var p = start; + vertex.x = vertexBuffer[ i + 0 ]; + vertex.y = vertexBuffer[ i + 1 ]; + vertex.z = vertexBuffer[ i + 2 ]; - do { + vertex.normalize().multiplyScalar( radius ); - 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; + vertexBuffer[ i + 0 ] = vertex.x; + vertexBuffer[ i + 1 ] = vertex.y; + vertexBuffer[ i + 2 ] = vertex.z; - } while ( p !== start ); + } - p.prevZ.nextZ = null; - p.prevZ = null; + } - sortLinked( p ); + function generateUVs() { -} + var vertex = new Vector3(); -// Simon Tatham's linked list merge sort algorithm -// http://www.chiark.greenend.org.uk/~sgtatham/algorithms/listsort.html + for ( var i = 0; i < vertexBuffer.length; i += 3 ) { -function sortLinked( list ) { + vertex.x = vertexBuffer[ i + 0 ]; + vertex.y = vertexBuffer[ i + 1 ]; + vertex.z = vertexBuffer[ i + 2 ]; - var i, p, q, e, tail, numMerges, pSize, qSize, inSize = 1; + var u = azimuth( vertex ) / 2 / Math.PI + 0.5; + var v = inclination( vertex ) / Math.PI + 0.5; + uvBuffer.push( u, 1 - v ); - do { + } - p = list; - list = null; - tail = null; - numMerges = 0; + correctUVs(); - while ( p ) { + correctSeam(); - numMerges ++; - q = p; - pSize = 0; + } - for ( i = 0; i < inSize; i ++ ) { + function correctSeam() { - pSize ++; - q = q.nextZ; - if ( ! q ) break; + // handle case when face straddles the seam, see #3269 - } + for ( var i = 0; i < uvBuffer.length; i += 6 ) { - qSize = inSize; + // uv data of a single face - while ( pSize > 0 || ( qSize > 0 && q ) ) { + var x0 = uvBuffer[ i + 0 ]; + var x1 = uvBuffer[ i + 2 ]; + var x2 = uvBuffer[ i + 4 ]; - if ( pSize !== 0 && ( qSize === 0 || ! q || p.z <= q.z ) ) { + var max = Math.max( x0, x1, x2 ); + var min = Math.min( x0, x1, x2 ); - e = p; - p = p.nextZ; - pSize --; + // 0.9 is somewhat arbitrary - } else { + if ( max > 0.9 && min < 0.1 ) { - e = q; - q = q.nextZ; - qSize --; + if ( x0 < 0.2 ) uvBuffer[ i + 0 ] += 1; + if ( x1 < 0.2 ) uvBuffer[ i + 2 ] += 1; + if ( x2 < 0.2 ) uvBuffer[ i + 4 ] += 1; - } + } - if ( tail ) tail.nextZ = e; - else list = e; + } - e.prevZ = tail; - tail = e; + } - } + function pushVertex( vertex ) { - p = q; + vertexBuffer.push( vertex.x, vertex.y, vertex.z ); - } + } - tail.nextZ = null; - inSize *= 2; + function getVertexByIndex( index, vertex ) { - } while ( numMerges > 1 ); + var stride = index * 3; - return list; + vertex.x = vertices[ stride + 0 ]; + vertex.y = vertices[ stride + 1 ]; + vertex.z = vertices[ stride + 2 ]; -} + } -// z-order of a point given coords and inverse of the longer side of data bbox + function correctUVs() { -function zOrder( x, y, minX, minY, invSize ) { + var a = new Vector3(); + var b = new Vector3(); + var c = new Vector3(); - // coords are transformed into non-negative 15-bit integer range + var centroid = new Vector3(); - x = 32767 * ( x - minX ) * invSize; - y = 32767 * ( y - minY ) * invSize; + var uvA = new Vector2(); + var uvB = new Vector2(); + var uvC = new Vector2(); - x = ( x | ( x << 8 ) ) & 0x00FF00FF; - x = ( x | ( x << 4 ) ) & 0x0F0F0F0F; - x = ( x | ( x << 2 ) ) & 0x33333333; - x = ( x | ( x << 1 ) ) & 0x55555555; + for ( var i = 0, j = 0; i < vertexBuffer.length; i += 9, j += 6 ) { - y = ( y | ( y << 8 ) ) & 0x00FF00FF; - y = ( y | ( y << 4 ) ) & 0x0F0F0F0F; - y = ( y | ( y << 2 ) ) & 0x33333333; - y = ( y | ( y << 1 ) ) & 0x55555555; + 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 ] ); - return x | ( y << 1 ); + 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 ); -// find the leftmost node of a polygon ring + var azi = azimuth( centroid ); -function getLeftmost( start ) { + correctUV( uvA, j + 0, a, azi ); + correctUV( uvB, j + 2, b, azi ); + correctUV( uvC, j + 4, c, azi ); - var p = start, leftmost = start; + } - do { + } - if ( p.x < leftmost.x ) leftmost = p; - p = p.next; + function correctUV( uv, stride, vector, azimuth ) { - } while ( p !== start ); + if ( ( azimuth < 0 ) && ( uv.x === 1 ) ) { - return leftmost; + uvBuffer[ stride ] = uv.x - 1; -} + } -// check if a point lies within a convex triangle + if ( ( vector.x === 0 ) && ( vector.z === 0 ) ) { -function pointInTriangle( ax, ay, bx, by, cx, cy, px, py ) { + uvBuffer[ stride ] = azimuth / 2 / Math.PI + 0.5; - return ( cx - px ) * ( ay - py ) - ( ax - px ) * ( cy - py ) >= 0 && - ( ax - px ) * ( by - py ) - ( bx - px ) * ( ay - py ) >= 0 && - ( bx - px ) * ( cy - py ) - ( cx - px ) * ( by - py ) >= 0; + } -} + } -// check if a diagonal between two polygon nodes is valid (lies in polygon interior) + // Angle around the Y axis, counter-clockwise when looking from above. -function isValidDiagonal( a, b ) { + function azimuth( vector ) { - return a.next.i !== b.i && a.prev.i !== b.i && ! intersectsPolygon( a, b ) && - locallyInside( a, b ) && locallyInside( b, a ) && middleInside( a, b ); + return Math.atan2( vector.z, - vector.x ); -} + } -// signed area of a triangle -function area( p, q, r ) { + // Angle above the XZ plane. - return ( q.y - p.y ) * ( r.x - q.x ) - ( q.x - p.x ) * ( r.y - q.y ); + function inclination( vector ) { -} + return Math.atan2( - vector.y, Math.sqrt( ( vector.x * vector.x ) + ( vector.z * vector.z ) ) ); -// check if two points are equal + } -function equals( p1, p2 ) { +} - return p1.x === p2.x && p1.y === p2.y; +PolyhedronBufferGeometry.prototype = Object.create( BufferGeometry.prototype ); +PolyhedronBufferGeometry.prototype.constructor = PolyhedronBufferGeometry; -} +/** + * @author timothypratley / https://github.com/timothypratley + * @author Mugen87 / https://github.com/Mugen87 + */ -// check if two segments intersect +// TetrahedronGeometry -function intersects( p1, q1, p2, q2 ) { +function TetrahedronGeometry( radius, detail ) { - if ( ( equals( p1, q1 ) && equals( p2, q2 ) ) || - ( equals( p1, q2 ) && equals( p2, q1 ) ) ) return true; + Geometry.call( this ); - 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 ) { - - var p = a; + this.type = 'TetrahedronGeometry'; - do { + this.parameters = { + radius: radius, + detail: detail + }; - 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 ) ) { + this.fromBufferGeometry( new TetrahedronBufferGeometry( radius, detail ) ); + this.mergeVertices(); - return true; +} - } +TetrahedronGeometry.prototype = Object.create( Geometry.prototype ); +TetrahedronGeometry.prototype.constructor = TetrahedronGeometry; - p = p.next; +// TetrahedronBufferGeometry - } while ( p !== a ); +function TetrahedronBufferGeometry( radius, detail ) { - return false; + var vertices = [ + 1, 1, 1, - 1, - 1, 1, - 1, 1, - 1, 1, - 1, - 1 + ]; -} + var indices = [ + 2, 1, 0, 0, 3, 2, 1, 3, 0, 2, 3, 1 + ]; -// check if a polygon diagonal is locally inside the polygon + PolyhedronBufferGeometry.call( this, vertices, indices, radius, detail ); -function locallyInside( a, b ) { + this.type = 'TetrahedronBufferGeometry'; - 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.parameters = { + radius: radius, + detail: detail + }; } -// check if the middle point of a polygon diagonal is inside the polygon - -function middleInside( a, b ) { - - var p = a, - inside = false, - px = ( a.x + b.x ) / 2, - py = ( a.y + b.y ) / 2; +TetrahedronBufferGeometry.prototype = Object.create( PolyhedronBufferGeometry.prototype ); +TetrahedronBufferGeometry.prototype.constructor = TetrahedronBufferGeometry; - do { +/** + * @author timothypratley / https://github.com/timothypratley + * @author Mugen87 / https://github.com/Mugen87 + */ - 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 ) ) { +// OctahedronGeometry - inside = ! inside; +function OctahedronGeometry( radius, detail ) { - } + Geometry.call( this ); - p = p.next; + this.type = 'OctahedronGeometry'; - } while ( p !== a ); + this.parameters = { + radius: radius, + detail: detail + }; - return inside; + this.fromBufferGeometry( new OctahedronBufferGeometry( radius, detail ) ); + this.mergeVertices(); } -// 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 +OctahedronGeometry.prototype = Object.create( Geometry.prototype ); +OctahedronGeometry.prototype.constructor = OctahedronGeometry; -function splitPolygon( a, b ) { +// OctahedronBufferGeometry - 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; +function OctahedronBufferGeometry( radius, detail ) { - a.next = b; - b.prev = a; + var vertices = [ + 1, 0, 0, - 1, 0, 0, 0, 1, 0, + 0, - 1, 0, 0, 0, 1, 0, 0, - 1 + ]; - a2.next = an; - an.prev = a2; + 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 + ]; - b2.next = a2; - a2.prev = b2; + PolyhedronBufferGeometry.call( this, vertices, indices, radius, detail ); - bp.next = b2; - b2.prev = bp; + this.type = 'OctahedronBufferGeometry'; - return b2; + this.parameters = { + radius: radius, + detail: detail + }; } -// create a node and optionally link it with previous one (in a circular doubly linked list) - -function insertNode( i, x, y, last ) { +OctahedronBufferGeometry.prototype = Object.create( PolyhedronBufferGeometry.prototype ); +OctahedronBufferGeometry.prototype.constructor = OctahedronBufferGeometry; - var p = new Node( i, x, y ); +/** + * @author timothypratley / https://github.com/timothypratley + * @author Mugen87 / https://github.com/Mugen87 + */ - if ( ! last ) { +// IcosahedronGeometry - p.prev = p; - p.next = p; +function IcosahedronGeometry( radius, detail ) { - } else { + Geometry.call( this ); - p.next = last.next; - p.prev = last; - last.next.prev = p; - last.next = p; + this.type = 'IcosahedronGeometry'; - } + this.parameters = { + radius: radius, + detail: detail + }; - return p; + this.fromBufferGeometry( new IcosahedronBufferGeometry( radius, detail ) ); + this.mergeVertices(); } -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; +IcosahedronGeometry.prototype = Object.create( Geometry.prototype ); +IcosahedronGeometry.prototype.constructor = IcosahedronGeometry; -} +// IcosahedronBufferGeometry -function Node( i, x, y ) { +function IcosahedronBufferGeometry( radius, detail ) { - // vertice index in coordinates array - this.i = i; + var t = ( 1 + Math.sqrt( 5 ) ) / 2; - // vertex coordinates - this.x = x; - this.y = y; + 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 + ]; - // previous and next vertice nodes in a polygon ring - this.prev = null; - this.next = null; + 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 + ]; - // z-order curve value - this.z = null; + PolyhedronBufferGeometry.call( this, vertices, indices, radius, detail ); - // previous and next nodes in z-order - this.prevZ = null; - this.nextZ = null; + this.type = 'IcosahedronBufferGeometry'; - // indicates whether this is a steiner point - this.steiner = false; + this.parameters = { + radius: radius, + detail: detail + }; } -function signedArea( data, start, end, dim ) { - - var sum = 0; - - for ( var i = start, j = end - dim; i < end; i += dim ) { - - sum += ( data[ j ] - data[ i ] ) * ( data[ i + 1 ] + data[ j + 1 ] ); - j = i; - - } - - return sum; - -} +IcosahedronBufferGeometry.prototype = Object.create( PolyhedronBufferGeometry.prototype ); +IcosahedronBufferGeometry.prototype.constructor = IcosahedronBufferGeometry; /** - * @author zz85 / http://www.lab4games.net/zz85/blog + * @author Abe Pazos / https://hamoid.com + * @author Mugen87 / https://github.com/Mugen87 */ -var ShapeUtils = { - - // calculate area of the contour polygon - - area: function ( contour ) { - - var n = contour.length; - var a = 0.0; - - for ( var p = n - 1, q = 0; q < n; p = q ++ ) { - - a += contour[ p ].x * contour[ q ].y - contour[ q ].x * contour[ p ].y; - - } - - return a * 0.5; - - }, - - isClockWise: function ( pts ) { - - return ShapeUtils.area( pts ) < 0; - - }, - - triangulateShape: function ( contour, holes ) { - - 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 ); - - // +// DodecahedronGeometry - var holeIndex = contour.length; +function DodecahedronGeometry( radius, detail ) { - holes.forEach( removeDupEndPts ); + Geometry.call( this ); - for ( var i = 0; i < holes.length; i ++ ) { + this.type = 'DodecahedronGeometry'; - holeIndices.push( holeIndex ); - holeIndex += holes[ i ].length; - addContour( vertices, holes[ i ] ); + this.parameters = { + radius: radius, + detail: detail + }; - } + this.fromBufferGeometry( new DodecahedronBufferGeometry( radius, detail ) ); + this.mergeVertices(); - // +} - var triangles = Earcut.triangulate( vertices, holeIndices ); +DodecahedronGeometry.prototype = Object.create( Geometry.prototype ); +DodecahedronGeometry.prototype.constructor = DodecahedronGeometry; - // +// DodecahedronBufferGeometry - for ( var i = 0; i < triangles.length; i += 3 ) { +function DodecahedronBufferGeometry( radius, detail ) { - faces.push( triangles.slice( i, i + 3 ) ); + var t = ( 1 + Math.sqrt( 5 ) ) / 2; + var r = 1 / t; - } + var vertices = [ - return faces; + // (±1, ±1, ±1) + - 1, - 1, - 1, - 1, - 1, 1, + - 1, 1, - 1, - 1, 1, 1, + 1, - 1, - 1, 1, - 1, 1, + 1, 1, - 1, 1, 1, 1, - } + // (0, ±1/φ, ±φ) + 0, - r, - t, 0, - r, t, + 0, r, - t, 0, r, t, -}; + // (±1/φ, ±φ, 0) + - r, - t, 0, - r, t, 0, + r, - t, 0, r, t, 0, -function removeDupEndPts( points ) { + // (±φ, 0, ±1/φ) + - t, 0, - r, t, 0, - r, + - t, 0, r, t, 0, r + ]; - var l = points.length; + 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 + ]; - if ( l > 2 && points[ l - 1 ].equals( points[ 0 ] ) ) { + PolyhedronBufferGeometry.call( this, vertices, indices, radius, detail ); - points.pop(); + this.type = 'DodecahedronBufferGeometry'; - } + this.parameters = { + radius: radius, + detail: detail + }; } -function addContour( vertices, contour ) { - - for ( var i = 0; i < contour.length; i ++ ) { - - vertices.push( contour[ i ].x ); - vertices.push( contour[ i ].y ); - - } - -} +DodecahedronBufferGeometry.prototype = Object.create( PolyhedronBufferGeometry.prototype ); +DodecahedronBufferGeometry.prototype.constructor = DodecahedronBufferGeometry; /** - * @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 - * amount: , // Depth to extrude the shape - * - * bevelEnabled: , // turn on bevel - * bevelThickness: , // how deep into the original shape bevel goes - * bevelSize: , // how far from shape outline is bevel - * bevelSegments: , // number of bevel layers - * - * extrudePath: // curve to extrude shape along - * frames: // containing arrays of tangents, normals, binormals - * - * UVGenerator: // object that provides UV generator functions + * @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 * - * } */ -// ExtrudeGeometry +// TubeGeometry -function ExtrudeGeometry( shapes, options ) { +function TubeGeometry( path, tubularSegments, radius, radialSegments, closed, taper ) { Geometry.call( this ); - this.type = 'ExtrudeGeometry'; + this.type = 'TubeGeometry'; this.parameters = { - shapes: shapes, - options: options + path: path, + tubularSegments: tubularSegments, + radius: radius, + radialSegments: radialSegments, + closed: closed }; - this.fromBufferGeometry( new ExtrudeBufferGeometry( shapes, options ) ); - this.mergeVertices(); + if ( taper !== undefined ) console.warn( 'THREE.TubeGeometry: taper has been removed.' ); -} + var bufferGeometry = new TubeBufferGeometry( path, tubularSegments, radius, radialSegments, closed ); -ExtrudeGeometry.prototype = Object.create( Geometry.prototype ); -ExtrudeGeometry.prototype.constructor = ExtrudeGeometry; + // expose internals -// ExtrudeBufferGeometry + this.tangents = bufferGeometry.tangents; + this.normals = bufferGeometry.normals; + this.binormals = bufferGeometry.binormals; -function ExtrudeBufferGeometry( shapes, options ) { + // create geometry - if ( typeof ( shapes ) === "undefined" ) { + this.fromBufferGeometry( bufferGeometry ); + this.mergeVertices(); - return; +} - } +TubeGeometry.prototype = Object.create( Geometry.prototype ); +TubeGeometry.prototype.constructor = TubeGeometry; - BufferGeometry.call( this ); +// TubeBufferGeometry - this.type = 'ExtrudeBufferGeometry'; +function TubeBufferGeometry( path, tubularSegments, radius, radialSegments, closed ) { - shapes = Array.isArray( shapes ) ? shapes : [ shapes ]; + BufferGeometry.call( this ); - this.addShapeList( shapes, options ); + this.type = 'TubeBufferGeometry'; - this.computeVertexNormals(); + this.parameters = { + path: path, + tubularSegments: tubularSegments, + radius: radius, + radialSegments: radialSegments, + closed: closed + }; - // can't really use automatic vertex normals - // as then front and back sides get smoothed too - // should do separate smoothing just for sides + tubularSegments = tubularSegments || 64; + radius = radius || 1; + radialSegments = radialSegments || 8; + closed = closed || false; - //this.computeVertexNormals(); + var frames = path.computeFrenetFrames( tubularSegments, closed ); - //console.log( "took", ( Date.now() - startTime ) ); + // expose internals -} + this.tangents = frames.tangents; + this.normals = frames.normals; + this.binormals = frames.binormals; -ExtrudeBufferGeometry.prototype = Object.create( BufferGeometry.prototype ); -ExtrudeBufferGeometry.prototype.constructor = ExtrudeBufferGeometry; + // helper variables -ExtrudeBufferGeometry.prototype.getArrays = function () { + var vertex = new Vector3(); + var normal = new Vector3(); + var uv = new Vector2(); + var P = new Vector3(); - var positionAttribute = this.getAttribute( "position" ); - var verticesArray = positionAttribute ? Array.prototype.slice.call( positionAttribute.array ) : []; + var i, j; - var uvAttribute = this.getAttribute( "uv" ); - var uvArray = uvAttribute ? Array.prototype.slice.call( uvAttribute.array ) : []; + // buffer - var IndexAttribute = this.index; - var indicesArray = IndexAttribute ? Array.prototype.slice.call( IndexAttribute.array ) : []; + var vertices = []; + var normals = []; + var uvs = []; + var indices = []; - return { - position: verticesArray, - uv: uvArray, - index: indicesArray - }; + // create buffer data -}; + generateBufferData(); -ExtrudeBufferGeometry.prototype.addShapeList = function ( shapes, options ) { + // build geometry - var sl = shapes.length; - options.arrays = this.getArrays(); + this.setIndex( indices ); + this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); + this.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); + this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); - for ( var s = 0; s < sl; s ++ ) { + // functions - var shape = shapes[ s ]; - this.addShape( shape, options ); + function generateBufferData() { - } + for ( i = 0; i < tubularSegments; i ++ ) { - this.setIndex( options.arrays.index ); - this.addAttribute( 'position', new Float32BufferAttribute( options.arrays.position, 3 ) ); - this.addAttribute( 'uv', new Float32BufferAttribute( options.arrays.uv, 2 ) ); + generateSegment( i ); -}; + } -ExtrudeBufferGeometry.prototype.addShape = function ( shape, options ) { + // 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) - var arrays = options.arrays ? options.arrays : this.getArrays(); - var verticesArray = arrays.position; - var indicesArray = arrays.index; - var uvArray = arrays.uv; + generateSegment( ( closed === false ) ? tubularSegments : 0 ); - var placeholder = []; + // uvs are generated in a separate function. + // this makes it easy compute correct values for closed geometries + generateUVs(); - var amount = options.amount !== undefined ? options.amount : 100; + // finally create faces - var bevelThickness = options.bevelThickness !== undefined ? options.bevelThickness : 6; // 10 - var bevelSize = options.bevelSize !== undefined ? options.bevelSize : bevelThickness - 2; // 8 - var bevelSegments = options.bevelSegments !== undefined ? options.bevelSegments : 3; + generateIndices(); - var bevelEnabled = options.bevelEnabled !== undefined ? options.bevelEnabled : true; // false + } - var curveSegments = options.curveSegments !== undefined ? options.curveSegments : 12; + function generateSegment( i ) { - var steps = options.steps !== undefined ? options.steps : 1; + // we use getPointAt to sample evenly distributed points from the given path - var extrudePath = options.extrudePath; - var extrudePts, extrudeByPath = false; + P = path.getPointAt( i / tubularSegments, P ); - // Use default WorldUVGenerator if no UV generators are specified. - var uvgen = options.UVGenerator !== undefined ? options.UVGenerator : ExtrudeGeometry.WorldUVGenerator; + // retrieve corresponding normal and binormal - var splineTube, binormal, normal, position2; - if ( extrudePath ) { + var N = frames.normals[ i ]; + var B = frames.binormals[ i ]; - extrudePts = extrudePath.getSpacedPoints( steps ); + // generate normals and vertices for the current segment - extrudeByPath = true; - bevelEnabled = false; // bevels not supported for path extrusion + for ( j = 0; j <= radialSegments; j ++ ) { - // SETUP TNB variables + var v = j / radialSegments * Math.PI * 2; - // TODO1 - have a .isClosed in spline? + var sin = Math.sin( v ); + var cos = - Math.cos( v ); - splineTube = options.frames !== undefined ? options.frames : extrudePath.computeFrenetFrames( steps, false ); + // normal - // console.log(splineTube, 'splineTube', splineTube.normals.length, 'steps', steps, 'extrudePts', extrudePts.length); + 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(); - binormal = new Vector3(); - normal = new Vector3(); - position2 = new Vector3(); + normals.push( normal.x, normal.y, normal.z ); - } + // vertex - // Safeguards if bevels are not enabled + vertex.x = P.x + radius * normal.x; + vertex.y = P.y + radius * normal.y; + vertex.z = P.z + radius * normal.z; - if ( ! bevelEnabled ) { + vertices.push( vertex.x, vertex.y, vertex.z ); - bevelSegments = 0; - bevelThickness = 0; - bevelSize = 0; + } } - // Variables initialization - - var ahole, h, hl; // looping of holes - var scope = this; - - var shapePoints = shape.extractPoints( curveSegments ); - - var vertices = shapePoints.shape; - var holes = shapePoints.holes; - - var reverse = ! ShapeUtils.isClockWise( vertices ); - - if ( reverse ) { - - vertices = vertices.reverse(); + function generateIndices() { - // Maybe we should also check if holes are in the opposite direction, just to be safe ... + for ( j = 1; j <= tubularSegments; j ++ ) { - for ( h = 0, hl = holes.length; h < hl; h ++ ) { + for ( i = 1; i <= radialSegments; i ++ ) { - ahole = holes[ h ]; + 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; - if ( ShapeUtils.isClockWise( ahole ) ) { + // faces - holes[ h ] = ahole.reverse(); + indices.push( a, b, d ); + indices.push( b, c, d ); } @@ -30457,5871 +29048,6052 @@ ExtrudeBufferGeometry.prototype.addShape = function ( shape, options ) { } + function generateUVs() { - var faces = ShapeUtils.triangulateShape( vertices, holes ); + for ( i = 0; i <= tubularSegments; i ++ ) { - /* Vertices */ + for ( j = 0; j <= radialSegments; j ++ ) { - var contour = vertices; // vertices has all points but contour has only points of circumference + uv.x = i / tubularSegments; + uv.y = j / radialSegments; - for ( h = 0, hl = holes.length; h < hl; h ++ ) { + uvs.push( uv.x, uv.y ); - ahole = holes[ h ]; + } - vertices = vertices.concat( ahole ); + } } +} - function scalePt2( pt, vec, size ) { - - if ( ! vec ) console.error( "THREE.ExtrudeGeometry: vec does not exist" ); - - return vec.clone().multiplyScalar( size ).add( pt ); - - } +TubeBufferGeometry.prototype = Object.create( BufferGeometry.prototype ); +TubeBufferGeometry.prototype.constructor = TubeBufferGeometry; - var b, bs, t, z, - vert, vlen = vertices.length, - face, flen = faces.length; +/** + * @author oosmoxiecode + * @author Mugen87 / https://github.com/Mugen87 + * + * based on http://www.blackpawn.com/texts/pqtorus/ + */ +// TorusKnotGeometry - // Find directions for point movement +function TorusKnotGeometry( radius, tube, tubularSegments, radialSegments, p, q, heightScale ) { + Geometry.call( this ); - function getBevelVec( inPt, inPrev, inNext ) { + this.type = 'TorusKnotGeometry'; - // 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. + this.parameters = { + radius: radius, + tube: tube, + tubularSegments: tubularSegments, + radialSegments: radialSegments, + p: p, + q: q + }; - var v_trans_x, v_trans_y, shrink_by; // resulting translation vector for inPt + if ( heightScale !== undefined ) console.warn( 'THREE.TorusKnotGeometry: heightScale has been deprecated. Use .scale( x, y, z ) instead.' ); - // good reading for geometry algorithms (here: line-line intersection) - // http://geomalgorithms.com/a05-_intersect-1.html + this.fromBufferGeometry( new TorusKnotBufferGeometry( radius, tube, tubularSegments, radialSegments, p, q ) ); + this.mergeVertices(); - var v_prev_x = inPt.x - inPrev.x, - v_prev_y = inPt.y - inPrev.y; - var v_next_x = inNext.x - inPt.x, - v_next_y = inNext.y - inPt.y; +} - var v_prev_lensq = ( v_prev_x * v_prev_x + v_prev_y * v_prev_y ); +TorusKnotGeometry.prototype = Object.create( Geometry.prototype ); +TorusKnotGeometry.prototype.constructor = TorusKnotGeometry; - // check for collinear edges - var collinear0 = ( v_prev_x * v_next_y - v_prev_y * v_next_x ); +// TorusKnotBufferGeometry - if ( Math.abs( collinear0 ) > Number.EPSILON ) { +function TorusKnotBufferGeometry( radius, tube, tubularSegments, radialSegments, p, q ) { - // not collinear + BufferGeometry.call( this ); - // length of vectors for normalizing + this.type = 'TorusKnotBufferGeometry'; - 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.parameters = { + radius: radius, + tube: tube, + tubularSegments: tubularSegments, + radialSegments: radialSegments, + p: p, + q: q + }; - // shift adjacent points by unit vectors to the left + radius = radius || 1; + tube = tube || 0.4; + tubularSegments = Math.floor( tubularSegments ) || 64; + radialSegments = Math.floor( radialSegments ) || 8; + p = p || 2; + q = q || 3; - var ptPrevShift_x = ( inPrev.x - v_prev_y / v_prev_len ); - var ptPrevShift_y = ( inPrev.y + v_prev_x / v_prev_len ); + // buffers - var ptNextShift_x = ( inNext.x - v_next_y / v_next_len ); - var ptNextShift_y = ( inNext.y + v_next_x / v_next_len ); + var indices = []; + var vertices = []; + var normals = []; + var uvs = []; - // scaling factor for v_prev to intersection point + // helper variables - 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 ); + var i, j; - // vector from inPt to intersection point + var vertex = new Vector3(); + var normal = new Vector3(); - v_trans_x = ( ptPrevShift_x + v_prev_x * sf - inPt.x ); - v_trans_y = ( ptPrevShift_y + v_prev_y * sf - inPt.y ); + var P1 = new Vector3(); + var P2 = new Vector3(); - // 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 B = new Vector3(); + var T = new Vector3(); + var N = new Vector3(); - return new Vector2( v_trans_x, v_trans_y ); + // generate vertices, normals and uvs - } else { + for ( i = 0; i <= tubularSegments; ++ i ) { - shrink_by = Math.sqrt( v_trans_lensq / 2 ); + // 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; - } else { + // 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 - // handle special case of collinear edges + calculatePositionOnCurve( u, p, q, radius, P1 ); + calculatePositionOnCurve( u + 0.01, p, q, radius, P2 ); - var direction_eq = false; // assumes: opposite - if ( v_prev_x > Number.EPSILON ) { + // calculate orthonormal basis - if ( v_next_x > Number.EPSILON ) { + T.subVectors( P2, P1 ); + N.addVectors( P2, P1 ); + B.crossVectors( T, N ); + N.crossVectors( B, T ); - direction_eq = true; + // normalize B, N. T can be ignored, we don't use it - } + B.normalize(); + N.normalize(); - } else { + for ( j = 0; j <= radialSegments; ++ j ) { - if ( v_prev_x < - Number.EPSILON ) { + // 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. - if ( v_next_x < - Number.EPSILON ) { + var v = j / radialSegments * Math.PI * 2; + var cx = - tube * Math.cos( v ); + var cy = tube * Math.sin( v ); - direction_eq = true; + // 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 ); - } else { + vertices.push( vertex.x, vertex.y, vertex.z ); - if ( Math.sign( v_prev_y ) === Math.sign( v_next_y ) ) { + // normal (P1 is always the center/origin of the extrusion, thus we can use it to calculate the normal) - direction_eq = true; + normal.subVectors( vertex, P1 ).normalize(); - } + normals.push( normal.x, normal.y, normal.z ); - } + // uv - } + uvs.push( i / tubularSegments ); + uvs.push( j / radialSegments ); - if ( direction_eq ) { + } - // console.log("Warning: lines are a straight sequence"); - v_trans_x = - v_prev_y; - v_trans_y = v_prev_x; - shrink_by = Math.sqrt( v_prev_lensq ); + } - } else { + // generate indices - // 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 ); + for ( j = 1; j <= tubularSegments; j ++ ) { - } + for ( i = 1; i <= radialSegments; i ++ ) { - } + // indices - return new Vector2( v_trans_x / shrink_by, v_trans_y / shrink_by ); + 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; + + // faces + + indices.push( a, b, d ); + indices.push( b, c, d ); + + } } + // build geometry - var contourMovements = []; + this.setIndex( indices ); + this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); + this.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); + this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); - for ( var i = 0, il = contour.length, j = il - 1, k = i + 1; i < il; i ++, j ++, k ++ ) { + // this function calculates the current position on the torus curve - if ( j === il ) j = 0; - if ( k === il ) k = 0; + function calculatePositionOnCurve( u, p, q, radius, position ) { - // (j)---(i)---(k) - // console.log('i,j,k', i, j , k) + var cu = Math.cos( u ); + var su = Math.sin( u ); + var quOverP = q / p * u; + var cs = Math.cos( quOverP ); - contourMovements[ i ] = getBevelVec( contour[ i ], contour[ j ], contour[ k ] ); + position.x = radius * ( 2 + cs ) * 0.5 * cu; + position.y = radius * ( 2 + cs ) * su * 0.5; + position.z = radius * Math.sin( quOverP ) * 0.5; } - var holesMovements = [], - oneHoleMovements, verticesMovements = contourMovements.concat(); +} - for ( h = 0, hl = holes.length; h < hl; h ++ ) { +TorusKnotBufferGeometry.prototype = Object.create( BufferGeometry.prototype ); +TorusKnotBufferGeometry.prototype.constructor = TorusKnotBufferGeometry; - ahole = holes[ h ]; +/** + * @author oosmoxiecode + * @author mrdoob / http://mrdoob.com/ + * @author Mugen87 / https://github.com/Mugen87 + */ - oneHoleMovements = []; +// TorusGeometry - for ( i = 0, il = ahole.length, j = il - 1, k = i + 1; i < il; i ++, j ++, k ++ ) { +function TorusGeometry( radius, tube, radialSegments, tubularSegments, arc ) { - if ( j === il ) j = 0; - if ( k === il ) k = 0; + Geometry.call( this ); - // (j)---(i)---(k) - oneHoleMovements[ i ] = getBevelVec( ahole[ i ], ahole[ j ], ahole[ k ] ); + this.type = 'TorusGeometry'; - } + this.parameters = { + radius: radius, + tube: tube, + radialSegments: radialSegments, + tubularSegments: tubularSegments, + arc: arc + }; - holesMovements.push( oneHoleMovements ); - verticesMovements = verticesMovements.concat( oneHoleMovements ); + this.fromBufferGeometry( new TorusBufferGeometry( radius, tube, radialSegments, tubularSegments, arc ) ); + this.mergeVertices(); - } +} +TorusGeometry.prototype = Object.create( Geometry.prototype ); +TorusGeometry.prototype.constructor = TorusGeometry; + +// TorusBufferGeometry - // Loop bevelSegments, 1 for the front, 1 for the back +function TorusBufferGeometry( radius, tube, radialSegments, tubularSegments, arc ) { - for ( b = 0; b < bevelSegments; b ++ ) { + BufferGeometry.call( this ); - //for ( b = bevelSegments; b > 0; b -- ) { + this.type = 'TorusBufferGeometry'; - t = b / bevelSegments; - z = bevelThickness * Math.cos( t * Math.PI / 2 ); - bs = bevelSize * Math.sin( t * Math.PI / 2 ); + this.parameters = { + radius: radius, + tube: tube, + radialSegments: radialSegments, + tubularSegments: tubularSegments, + arc: arc + }; - // contract shape + radius = radius || 1; + tube = tube || 0.4; + radialSegments = Math.floor( radialSegments ) || 8; + tubularSegments = Math.floor( tubularSegments ) || 6; + arc = arc || Math.PI * 2; - for ( i = 0, il = contour.length; i < il; i ++ ) { + // buffers - vert = scalePt2( contour[ i ], contourMovements[ i ], bs ); + var indices = []; + var vertices = []; + var normals = []; + var uvs = []; - v( vert.x, vert.y, - z ); + // helper variables - } + var center = new Vector3(); + var vertex = new Vector3(); + var normal = new Vector3(); - // expand holes + var j, i; - for ( h = 0, hl = holes.length; h < hl; h ++ ) { + // generate vertices, normals and uvs - ahole = holes[ h ]; - oneHoleMovements = holesMovements[ h ]; + for ( j = 0; j <= radialSegments; j ++ ) { - for ( i = 0, il = ahole.length; i < il; i ++ ) { + for ( i = 0; i <= tubularSegments; i ++ ) { - vert = scalePt2( ahole[ i ], oneHoleMovements[ i ], bs ); + var u = i / tubularSegments * arc; + var v = j / radialSegments * Math.PI * 2; - v( vert.x, vert.y, - z ); + // vertex - } + vertex.x = ( radius + tube * Math.cos( v ) ) * Math.cos( u ); + vertex.y = ( radius + tube * Math.cos( v ) ) * Math.sin( u ); + vertex.z = tube * Math.sin( v ); - } + vertices.push( vertex.x, vertex.y, vertex.z ); - } + // normal + + center.x = radius * Math.cos( u ); + center.y = radius * Math.sin( u ); + normal.subVectors( vertex, center ).normalize(); - bs = bevelSize; + normals.push( normal.x, normal.y, normal.z ); - // Back facing vertices + // uv - for ( i = 0; i < vlen; i ++ ) { + uvs.push( i / tubularSegments ); + uvs.push( j / radialSegments ); - vert = bevelEnabled ? scalePt2( vertices[ i ], verticesMovements[ i ], bs ) : vertices[ i ]; + } - if ( ! extrudeByPath ) { + } - v( vert.x, vert.y, 0 ); + // generate indices - } else { + for ( j = 1; j <= radialSegments; j ++ ) { - // v( vert.x, vert.y + extrudePts[ 0 ].y, extrudePts[ 0 ].x ); + for ( i = 1; i <= tubularSegments; i ++ ) { + + // indices - normal.copy( splineTube.normals[ 0 ] ).multiplyScalar( vert.x ); - binormal.copy( splineTube.binormals[ 0 ] ).multiplyScalar( vert.y ); + 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; - position2.copy( extrudePts[ 0 ] ).add( normal ).add( binormal ); + // faces - v( position2.x, position2.y, position2.z ); + indices.push( a, b, d ); + indices.push( b, c, d ); } } - // Add stepped vertices... - // Including front facing vertices + // 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 ) ); - var s; +} - for ( s = 1; s <= steps; s ++ ) { +TorusBufferGeometry.prototype = Object.create( BufferGeometry.prototype ); +TorusBufferGeometry.prototype.constructor = TorusBufferGeometry; - for ( i = 0; i < vlen; i ++ ) { +/** + * @author Mugen87 / https://github.com/Mugen87 + * Port from https://github.com/mapbox/earcut (v2.1.2) + */ - vert = bevelEnabled ? scalePt2( vertices[ i ], verticesMovements[ i ], bs ) : vertices[ i ]; +var Earcut = { - if ( ! extrudeByPath ) { + triangulate: function ( data, holeIndices, dim ) { - v( vert.x, vert.y, amount / steps * s ); + dim = dim || 2; - } else { + var hasHoles = holeIndices && holeIndices.length, + outerLen = hasHoles ? holeIndices[ 0 ] * dim : data.length, + outerNode = linkedList( data, 0, outerLen, dim, true ), + triangles = []; + + if ( ! outerNode ) return triangles; - // v( vert.x, vert.y + extrudePts[ s - 1 ].y, extrudePts[ s - 1 ].x ); + var minX, minY, maxX, maxY, x, y, invSize; - normal.copy( splineTube.normals[ s ] ).multiplyScalar( vert.x ); - binormal.copy( splineTube.binormals[ s ] ).multiplyScalar( vert.y ); + if ( hasHoles ) outerNode = eliminateHoles( data, holeIndices, outerNode, dim ); - position2.copy( extrudePts[ s ] ).add( normal ).add( binormal ); + // if the shape is not too simple, we'll use z-order curve hash later; calculate polygon bbox - v( position2.x, position2.y, position2.z ); + if ( data.length > 80 * dim ) { + + minX = maxX = data[ 0 ]; + minY = maxY = data[ 1 ]; + + for ( var i = dim; i < outerLen; i += dim ) { + + x = data[ i ]; + y = data[ i + 1 ]; + if ( x < minX ) minX = x; + if ( y < minY ) minY = y; + if ( x > maxX ) maxX = x; + if ( y > maxY ) maxY = y; } + // minX, minY and invSize are later used to transform coords into integers for z-order calculation + + invSize = Math.max( maxX - minX, maxY - minY ); + invSize = invSize !== 0 ? 1 / invSize : 0; + } + earcutLinked( outerNode, triangles, dim, minX, minY, invSize ); + + return triangles; + } +}; + +// create a circular doubly linked list from polygon points in the specified winding order - // Add bevel segments planes +function linkedList( data, start, end, dim, clockwise ) { - //for ( b = 1; b <= bevelSegments; b ++ ) { - for ( b = bevelSegments - 1; b >= 0; b -- ) { + var i, last; - t = b / bevelSegments; - z = bevelThickness * Math.cos( t * Math.PI / 2 ); - bs = bevelSize * Math.sin( t * Math.PI / 2 ); + if ( clockwise === ( signedArea( data, start, end, dim ) > 0 ) ) { - // contract shape + for ( i = start; i < end; i += dim ) last = insertNode( i, data[ i ], data[ i + 1 ], last ); - for ( i = 0, il = contour.length; i < il; i ++ ) { + } else { - vert = scalePt2( contour[ i ], contourMovements[ i ], bs ); - v( vert.x, vert.y, amount + z ); + for ( i = end - dim; i >= start; i -= dim ) last = insertNode( i, data[ i ], data[ i + 1 ], last ); - } + } - // expand holes + if ( last && equals( last, last.next ) ) { - for ( h = 0, hl = holes.length; h < hl; h ++ ) { + removeNode( last ); + last = last.next; - ahole = holes[ h ]; - oneHoleMovements = holesMovements[ h ]; + } + + return last; - for ( i = 0, il = ahole.length; i < il; i ++ ) { +} - vert = scalePt2( ahole[ i ], oneHoleMovements[ i ], bs ); +// eliminate colinear or duplicate points - if ( ! extrudeByPath ) { +function filterPoints( start, end ) { - v( vert.x, vert.y, amount + z ); + if ( ! start ) return start; + if ( ! end ) end = start; - } else { + var p = start, again; - v( vert.x, vert.y + extrudePts[ steps - 1 ].y, extrudePts[ steps - 1 ].x + z ); + do { - } + again = false; - } + if ( ! p.steiner && ( equals( p, p.next ) || area( p.prev, p, p.next ) === 0 ) ) { + + removeNode( p ); + p = end = p.prev; + if ( p === p.next ) break; + again = true; + + } else { + + p = p.next; } - } + } while ( again || p !== end ); + + return end; - /* Faces */ +} - // Top and bottom faces +// main ear slicing loop which triangulates a polygon (given as a linked list) - buildLidFaces(); +function earcutLinked( ear, triangles, dim, minX, minY, invSize, pass ) { - // Sides faces + if ( ! ear ) return; - buildSideFaces(); + // interlink polygon nodes in z-order + if ( ! pass && invSize ) indexCurve( ear, minX, minY, invSize ); - ///// Internal functions + var stop = ear, prev, next; - function buildLidFaces() { + // iterate through ears, slicing them one by one - var start = verticesArray.length / 3; + while ( ear.prev !== ear.next ) { - if ( bevelEnabled ) { + prev = ear.prev; + next = ear.next; - var layer = 0; // steps + 1 - var offset = vlen * layer; + if ( invSize ? isEarHashed( ear, minX, minY, invSize ) : isEar( ear ) ) { - // Bottom faces + // cut off the triangle + triangles.push( prev.i / dim ); + triangles.push( ear.i / dim ); + triangles.push( next.i / dim ); - for ( i = 0; i < flen; i ++ ) { + removeNode( ear ); - face = faces[ i ]; - f3( face[ 2 ] + offset, face[ 1 ] + offset, face[ 0 ] + offset ); + // skipping the next vertice leads to less sliver triangles + ear = next.next; + stop = next.next; - } + continue; - layer = steps + bevelSegments * 2; - offset = vlen * layer; + } - // Top faces + ear = next; - for ( i = 0; i < flen; i ++ ) { + // if we looped through the whole remaining polygon and can't find any more ears - face = faces[ i ]; - f3( face[ 0 ] + offset, face[ 1 ] + offset, face[ 2 ] + offset ); + if ( ear === stop ) { - } + // try filtering points and slicing again - } else { + if ( ! pass ) { - // Bottom faces + earcutLinked( filterPoints( ear ), triangles, dim, minX, minY, invSize, 1 ); - for ( i = 0; i < flen; i ++ ) { + // if this didn't work, try curing all small self-intersections locally - face = faces[ i ]; - f3( face[ 2 ], face[ 1 ], face[ 0 ] ); + } else if ( pass === 1 ) { - } + ear = cureLocalIntersections( ear, triangles, dim ); + earcutLinked( ear, triangles, dim, minX, minY, invSize, 2 ); - // Top faces + // as a last resort, try splitting the remaining polygon into two - for ( i = 0; i < flen; i ++ ) { + } else if ( pass === 2 ) { - face = faces[ i ]; - f3( face[ 0 ] + vlen * steps, face[ 1 ] + vlen * steps, face[ 2 ] + vlen * steps ); + splitEarcut( ear, triangles, dim, minX, minY, invSize ); } - } + break; - scope.addGroup( start, verticesArray.length / 3 - start, options.material !== undefined ? options.material : 0 ); + } } - // Create faces for the z-sides of the shape +} - function buildSideFaces() { +// check whether a polygon node forms a valid ear with adjacent nodes - var start = verticesArray.length / 3; - var layeroffset = 0; - sidewalls( contour, layeroffset ); - layeroffset += contour.length; +function isEar( ear ) { - for ( h = 0, hl = holes.length; h < hl; h ++ ) { + var a = ear.prev, + b = ear, + c = ear.next; - ahole = holes[ h ]; - sidewalls( ahole, layeroffset ); + if ( area( a, b, c ) >= 0 ) return false; // reflex, can't be an ear - //, true - layeroffset += ahole.length; + // now make sure we don't have other points inside the potential ear + var p = ear.next.next; - } + while ( p !== ear.prev ) { + + if ( pointInTriangle( a.x, a.y, b.x, b.y, c.x, c.y, p.x, p.y ) && area( p.prev, p, p.next ) >= 0 ) { + return false; - scope.addGroup( start, verticesArray.length / 3 - start, options.extrudeMaterial !== undefined ? options.extrudeMaterial : 1 ); + } + p = p.next; } - function sidewalls( contour, layeroffset ) { + return true; + +} - var j, k; - i = contour.length; +function isEarHashed( ear, minX, minY, invSize ) { - while ( -- i >= 0 ) { + var a = ear.prev, + b = ear, + c = ear.next; - j = i; - k = i - 1; - if ( k < 0 ) k = contour.length - 1; + if ( area( a, b, c ) >= 0 ) return false; // reflex, can't be an ear - //console.log('b', i,j, i-1, k,vertices.length); + // triangle bbox; min & max are calculated like this for speed - var s = 0, - sl = steps + bevelSegments * 2; + 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 ); - for ( s = 0; s < sl; s ++ ) { + // z-order range for the current triangle bbox; - var slen1 = vlen * s; - var slen2 = vlen * ( s + 1 ); + var minZ = zOrder( minTX, minTY, minX, minY, invSize ), + maxZ = zOrder( maxTX, maxTY, minX, minY, invSize ); - var a = layeroffset + j + slen1, - b = layeroffset + k + slen1, - c = layeroffset + k + slen2, - d = layeroffset + j + slen2; + // first look for points inside the triangle in increasing z-order - f4( a, b, c, d ); + 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; } - function v( x, y, z ) { + // then look for points in decreasing z-order - placeholder.push( x ); - placeholder.push( y ); - placeholder.push( z ); + p = ear.prevZ; - } + while ( p && p.z >= minZ ) { + if ( p !== ear.prev && p !== ear.next && + pointInTriangle( a.x, a.y, b.x, b.y, c.x, c.y, p.x, p.y ) && + area( p.prev, p, p.next ) >= 0 ) return false; - function f3( a, b, c ) { + p = p.prevZ; - addVertex( a ); - addVertex( b ); - addVertex( c ); + } - var nextIndex = verticesArray.length / 3; - var uvs = uvgen.generateTopUV( scope, verticesArray, nextIndex - 3, nextIndex - 2, nextIndex - 1 ); + return true; - addUV( uvs[ 0 ] ); - addUV( uvs[ 1 ] ); - addUV( uvs[ 2 ] ); +} - } +// go through all polygon nodes and cure small local self-intersections - function f4( a, b, c, d ) { +function cureLocalIntersections( start, triangles, dim ) { - addVertex( a ); - addVertex( b ); - addVertex( d ); + var p = start; - addVertex( b ); - addVertex( c ); - addVertex( d ); + do { + var a = p.prev, b = p.next.next; - var nextIndex = verticesArray.length / 3; - var uvs = uvgen.generateSideWallUV( scope, verticesArray, nextIndex - 6, nextIndex - 3, nextIndex - 2, nextIndex - 1 ); + if ( ! equals( a, b ) && intersects( a, p, p.next, b ) && locallyInside( a, b ) && locallyInside( b, a ) ) { - addUV( uvs[ 0 ] ); - addUV( uvs[ 1 ] ); - addUV( uvs[ 3 ] ); + triangles.push( a.i / dim ); + triangles.push( p.i / dim ); + triangles.push( b.i / dim ); - addUV( uvs[ 1 ] ); - addUV( uvs[ 2 ] ); - addUV( uvs[ 3 ] ); + // remove two nodes involved - } + removeNode( p ); + removeNode( p.next ); - function addVertex( index ) { + p = start = b; - indicesArray.push( verticesArray.length / 3 ); - verticesArray.push( placeholder[ index * 3 + 0 ] ); - verticesArray.push( placeholder[ index * 3 + 1 ] ); - verticesArray.push( placeholder[ index * 3 + 2 ] ); + } - } + p = p.next; + } while ( p !== start ); - function addUV( vector2 ) { + return p; - uvArray.push( vector2.x ); - uvArray.push( vector2.y ); +} - } +// try splitting polygon into two and triangulate them independently - if ( ! options.arrays ) { +function splitEarcut( start, triangles, dim, minX, minY, invSize ) { - this.setIndex( indicesArray ); - this.addAttribute( 'position', new Float32BufferAttribute( verticesArray, 3 ) ); - this.addAttribute( 'uv', new Float32BufferAttribute( uvArray, 2 ) ); + // look for a valid diagonal that divides the polygon into two - } + var a = start; -}; + do { -ExtrudeGeometry.WorldUVGenerator = { + var b = a.next.next; - generateTopUV: function ( geometry, vertices, indexA, indexB, indexC ) { + while ( b !== a.prev ) { - 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 ]; + if ( a.i !== b.i && isValidDiagonal( a, b ) ) { - return [ - new Vector2( a_x, a_y ), - new Vector2( b_x, b_y ), - new Vector2( c_x, c_y ) - ]; + // split the polygon in two by the diagonal - }, + var c = splitPolygon( a, b ); - generateSideWallUV: function ( geometry, vertices, indexA, indexB, indexC, indexD ) { + // filter colinear points around the cuts - 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 ]; + a = filterPoints( a, a.next ); + c = filterPoints( c, c.next ); - if ( Math.abs( a_y - b_y ) < 0.01 ) { + // run earcut on each half - 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 ) - ]; + earcutLinked( a, triangles, dim, minX, minY, invSize ); + earcutLinked( c, triangles, dim, minX, minY, invSize ); + return; - } else { + } - return [ - new Vector2( a_y, 1 - a_z ), - new Vector2( b_y, 1 - b_z ), - new Vector2( c_y, 1 - c_z ), - new Vector2( d_y, 1 - d_z ) - ]; + b = b.next; } - } -}; + a = a.next; -/** - * @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 ) { - - Geometry.call( this ); - - this.type = 'TextGeometry'; - - this.parameters = { - text: text, - parameters: parameters - }; - - this.fromBufferGeometry( new TextBufferGeometry( text, parameters ) ); - this.mergeVertices(); + } while ( a !== start ); } -TextGeometry.prototype = Object.create( Geometry.prototype ); -TextGeometry.prototype.constructor = TextGeometry; - -// TextBufferGeometry - -function TextBufferGeometry( text, parameters ) { +// link every hole into the outer loop, producing a single-ring polygon without holes - parameters = parameters || {}; +function eliminateHoles( data, holeIndices, outerNode, dim ) { - var font = parameters.font; + var queue = [], i, len, start, end, list; - if ( ! ( font && font.isFont ) ) { + for ( i = 0, len = holeIndices.length; i < len; i ++ ) { - console.error( 'THREE.TextGeometry: font parameter is not an instance of THREE.Font.' ); - return new Geometry(); + 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 ) ); } - var shapes = font.generateShapes( text, parameters.size, parameters.curveSegments ); - - // translate parameters to ExtrudeGeometry API + queue.sort( compareX ); - parameters.amount = parameters.height !== undefined ? parameters.height : 50; + // process holes from left to right - // defaults + for ( i = 0; i < queue.length; i ++ ) { - if ( parameters.bevelThickness === undefined ) parameters.bevelThickness = 10; - if ( parameters.bevelSize === undefined ) parameters.bevelSize = 8; - if ( parameters.bevelEnabled === undefined ) parameters.bevelEnabled = false; + eliminateHole( queue[ i ], outerNode ); + outerNode = filterPoints( outerNode, outerNode.next ); - ExtrudeBufferGeometry.call( this, shapes, parameters ); + } - this.type = 'TextBufferGeometry'; + return outerNode; } -TextBufferGeometry.prototype = Object.create( ExtrudeBufferGeometry.prototype ); -TextBufferGeometry.prototype.constructor = TextBufferGeometry; +function compareX( a, b ) { -/** - * @author mrdoob / http://mrdoob.com/ - * @author benaadams / https://twitter.com/ben_a_adams - * @author Mugen87 / https://github.com/Mugen87 - */ + return a.x - b.x; -// SphereGeometry +} -function SphereGeometry( radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength ) { +// find a bridge between vertices that connects hole with an outer ring and and link it - Geometry.call( this ); +function eliminateHole( hole, outerNode ) { - this.type = 'SphereGeometry'; + outerNode = findHoleBridge( hole, outerNode ); - this.parameters = { - radius: radius, - widthSegments: widthSegments, - heightSegments: heightSegments, - phiStart: phiStart, - phiLength: phiLength, - thetaStart: thetaStart, - thetaLength: thetaLength - }; + if ( outerNode ) { - this.fromBufferGeometry( new SphereBufferGeometry( radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength ) ); - this.mergeVertices(); + var b = splitPolygon( outerNode, hole ); -} + filterPoints( b, b.next ); -SphereGeometry.prototype = Object.create( Geometry.prototype ); -SphereGeometry.prototype.constructor = SphereGeometry; + } -// SphereBufferGeometry +} -function SphereBufferGeometry( radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength ) { +// David Eberly's algorithm for finding a bridge between hole and outer polygon - BufferGeometry.call( this ); +function findHoleBridge( hole, outerNode ) { - this.type = 'SphereBufferGeometry'; + var p = outerNode, + hx = hole.x, + hy = hole.y, + qx = - Infinity, + m; - this.parameters = { - radius: radius, - widthSegments: widthSegments, - heightSegments: heightSegments, - phiStart: phiStart, - phiLength: phiLength, - thetaStart: thetaStart, - thetaLength: thetaLength - }; + // 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 - radius = radius || 1; + do { - widthSegments = Math.max( 3, Math.floor( widthSegments ) || 8 ); - heightSegments = Math.max( 2, Math.floor( heightSegments ) || 6 ); + if ( hy <= p.y && hy >= p.next.y && p.next.y !== p.y ) { - phiStart = phiStart !== undefined ? phiStart : 0; - phiLength = phiLength !== undefined ? phiLength : Math.PI * 2; + var x = p.x + ( hy - p.y ) * ( p.next.x - p.x ) / ( p.next.y - p.y ); - thetaStart = thetaStart !== undefined ? thetaStart : 0; - thetaLength = thetaLength !== undefined ? thetaLength : Math.PI; + if ( x <= hx && x > qx ) { - var thetaEnd = thetaStart + thetaLength; + qx = x; - var ix, iy; + if ( x === hx ) { - var index = 0; - var grid = []; + if ( hy === p.y ) return p; + if ( hy === p.next.y ) return p.next; - var vertex = new Vector3(); - var normal = new Vector3(); + } - // buffers + m = p.x < p.next.x ? p : p.next; - var indices = []; - var vertices = []; - var normals = []; - var uvs = []; + } - // generate vertices, normals and uvs + } - for ( iy = 0; iy <= heightSegments; iy ++ ) { + p = p.next; - var verticesRow = []; + } while ( p !== outerNode ); - var v = iy / heightSegments; + if ( ! m ) return null; - for ( ix = 0; ix <= widthSegments; ix ++ ) { + if ( hx === qx ) return m.prev; // hole touches outer segment; pick lower endpoint - var u = ix / widthSegments; + // 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 - // vertex + var stop = m, + mx = m.x, + my = m.y, + tanMin = Infinity, + tan; - 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 ); + p = m.next; - vertices.push( vertex.x, vertex.y, vertex.z ); + while ( p !== stop ) { - // normal + 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 ) ) { - normal.set( vertex.x, vertex.y, vertex.z ).normalize(); - normals.push( normal.x, normal.y, normal.z ); + tan = Math.abs( hy - p.y ) / ( hx - p.x ); // tangential - // uv + if ( ( tan < tanMin || ( tan === tanMin && p.x > m.x ) ) && locallyInside( p, hole ) ) { - uvs.push( u, 1 - v ); + m = p; + tanMin = tan; - verticesRow.push( index ++ ); + } } - grid.push( verticesRow ); + p = p.next; } - // indices - - for ( iy = 0; iy < heightSegments; iy ++ ) { + return m; - for ( ix = 0; ix < widthSegments; ix ++ ) { +} - var a = grid[ iy ][ ix + 1 ]; - var b = grid[ iy ][ ix ]; - var c = grid[ iy + 1 ][ ix ]; - var d = grid[ iy + 1 ][ ix + 1 ]; +// interlink polygon nodes in z-order - if ( iy !== 0 || thetaStart > 0 ) indices.push( a, b, d ); - if ( iy !== heightSegments - 1 || thetaEnd < Math.PI ) indices.push( b, c, d ); +function indexCurve( start, minX, minY, invSize ) { - } + var p = start; - } + do { - // build geometry + 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; - 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 ); -} + p.prevZ.nextZ = null; + p.prevZ = null; -SphereBufferGeometry.prototype = Object.create( BufferGeometry.prototype ); -SphereBufferGeometry.prototype.constructor = SphereBufferGeometry; + sortLinked( p ); -/** - * @author Kaleb Murphy - * @author Mugen87 / https://github.com/Mugen87 - */ +} -// RingGeometry +// Simon Tatham's linked list merge sort algorithm +// http://www.chiark.greenend.org.uk/~sgtatham/algorithms/listsort.html -function RingGeometry( innerRadius, outerRadius, thetaSegments, phiSegments, thetaStart, thetaLength ) { +function sortLinked( list ) { - Geometry.call( this ); + var i, p, q, e, tail, numMerges, pSize, qSize, inSize = 1; - this.type = 'RingGeometry'; + do { - this.parameters = { - innerRadius: innerRadius, - outerRadius: outerRadius, - thetaSegments: thetaSegments, - phiSegments: phiSegments, - thetaStart: thetaStart, - thetaLength: thetaLength - }; + p = list; + list = null; + tail = null; + numMerges = 0; - this.fromBufferGeometry( new RingBufferGeometry( innerRadius, outerRadius, thetaSegments, phiSegments, thetaStart, thetaLength ) ); - this.mergeVertices(); + while ( p ) { -} + numMerges ++; + q = p; + pSize = 0; -RingGeometry.prototype = Object.create( Geometry.prototype ); -RingGeometry.prototype.constructor = RingGeometry; + for ( i = 0; i < inSize; i ++ ) { -// RingBufferGeometry + pSize ++; + q = q.nextZ; + if ( ! q ) break; -function RingBufferGeometry( innerRadius, outerRadius, thetaSegments, phiSegments, thetaStart, thetaLength ) { + } - BufferGeometry.call( this ); + qSize = inSize; - this.type = 'RingBufferGeometry'; + while ( pSize > 0 || ( qSize > 0 && q ) ) { - this.parameters = { - innerRadius: innerRadius, - outerRadius: outerRadius, - thetaSegments: thetaSegments, - phiSegments: phiSegments, - thetaStart: thetaStart, - thetaLength: thetaLength - }; + if ( pSize !== 0 && ( qSize === 0 || ! q || p.z <= q.z ) ) { - innerRadius = innerRadius || 0.5; - outerRadius = outerRadius || 1; + e = p; + p = p.nextZ; + pSize --; - thetaStart = thetaStart !== undefined ? thetaStart : 0; - thetaLength = thetaLength !== undefined ? thetaLength : Math.PI * 2; + } else { - thetaSegments = thetaSegments !== undefined ? Math.max( 3, thetaSegments ) : 8; - phiSegments = phiSegments !== undefined ? Math.max( 1, phiSegments ) : 1; + e = q; + q = q.nextZ; + qSize --; - // buffers + } - var indices = []; - var vertices = []; - var normals = []; - var uvs = []; + if ( tail ) tail.nextZ = e; + else list = e; - // some helper variables + e.prevZ = tail; + tail = e; - var segment; - var radius = innerRadius; - var radiusStep = ( ( outerRadius - innerRadius ) / phiSegments ); - var vertex = new Vector3(); - var uv = new Vector2(); - var j, i; + } - // generate vertices, normals and uvs + p = q; - for ( j = 0; j <= phiSegments; j ++ ) { + } - for ( i = 0; i <= thetaSegments; i ++ ) { + tail.nextZ = null; + inSize *= 2; - // values are generate from the inside of the ring to the outside + } while ( numMerges > 1 ); - segment = thetaStart + i / thetaSegments * thetaLength; + return list; - // vertex +} - vertex.x = radius * Math.cos( segment ); - vertex.y = radius * Math.sin( segment ); +// z-order of a point given coords and inverse of the longer side of data bbox - vertices.push( vertex.x, vertex.y, vertex.z ); +function zOrder( x, y, minX, minY, invSize ) { - // normal + // coords are transformed into non-negative 15-bit integer range - normals.push( 0, 0, 1 ); + x = 32767 * ( x - minX ) * invSize; + y = 32767 * ( y - minY ) * invSize; - // uv + x = ( x | ( x << 8 ) ) & 0x00FF00FF; + x = ( x | ( x << 4 ) ) & 0x0F0F0F0F; + x = ( x | ( x << 2 ) ) & 0x33333333; + x = ( x | ( x << 1 ) ) & 0x55555555; - uv.x = ( vertex.x / outerRadius + 1 ) / 2; - uv.y = ( vertex.y / outerRadius + 1 ) / 2; + y = ( y | ( y << 8 ) ) & 0x00FF00FF; + y = ( y | ( y << 4 ) ) & 0x0F0F0F0F; + y = ( y | ( y << 2 ) ) & 0x33333333; + y = ( y | ( y << 1 ) ) & 0x55555555; - uvs.push( uv.x, uv.y ); + return x | ( y << 1 ); - } +} - // increase the radius for next row of vertices +// find the leftmost node of a polygon ring - radius += radiusStep; +function getLeftmost( start ) { - } + var p = start, leftmost = start; - // indices + do { - for ( j = 0; j < phiSegments; j ++ ) { + if ( p.x < leftmost.x ) leftmost = p; + p = p.next; - var thetaSegmentLevel = j * ( thetaSegments + 1 ); + } while ( p !== start ); - for ( i = 0; i < thetaSegments; i ++ ) { + return leftmost; - segment = i + thetaSegmentLevel; +} - var a = segment; - var b = segment + thetaSegments + 1; - var c = segment + thetaSegments + 2; - var d = segment + 1; +// check if a point lies within a convex triangle - // faces +function pointInTriangle( ax, ay, bx, by, cx, cy, px, py ) { - indices.push( a, b, d ); - indices.push( b, c, d ); + return ( cx - px ) * ( ay - py ) - ( ax - px ) * ( cy - py ) >= 0 && + ( ax - px ) * ( by - py ) - ( bx - px ) * ( ay - py ) >= 0 && + ( bx - px ) * ( cy - py ) - ( cx - px ) * ( by - py ) >= 0; - } +} - } +// check if a diagonal between two polygon nodes is valid (lies in polygon interior) - // build geometry +function isValidDiagonal( a, b ) { - 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 a.next.i !== b.i && a.prev.i !== b.i && ! intersectsPolygon( a, b ) && + locallyInside( a, b ) && locallyInside( b, a ) && middleInside( a, b ); } -RingBufferGeometry.prototype = Object.create( BufferGeometry.prototype ); -RingBufferGeometry.prototype.constructor = RingBufferGeometry; - -/** - * @author astrodud / http://astrodud.isgreat.org/ - * @author zz85 / https://github.com/zz85 - * @author bhouston / http://clara.io - * @author Mugen87 / https://github.com/Mugen87 - */ +// signed area of a triangle -// LatheGeometry +function area( p, q, r ) { -function LatheGeometry( points, segments, phiStart, phiLength ) { + return ( q.y - p.y ) * ( r.x - q.x ) - ( q.x - p.x ) * ( r.y - q.y ); - Geometry.call( this ); +} - this.type = 'LatheGeometry'; +// check if two points are equal - this.parameters = { - points: points, - segments: segments, - phiStart: phiStart, - phiLength: phiLength - }; +function equals( p1, p2 ) { - this.fromBufferGeometry( new LatheBufferGeometry( points, segments, phiStart, phiLength ) ); - this.mergeVertices(); + return p1.x === p2.x && p1.y === p2.y; } -LatheGeometry.prototype = Object.create( Geometry.prototype ); -LatheGeometry.prototype.constructor = LatheGeometry; +// check if two segments intersect -// LatheBufferGeometry +function intersects( p1, q1, p2, q2 ) { -function LatheBufferGeometry( points, segments, phiStart, phiLength ) { + if ( ( equals( p1, q1 ) && equals( p2, q2 ) ) || + ( equals( p1, q2 ) && equals( p2, q1 ) ) ) return true; - BufferGeometry.call( this ); + return area( p1, q1, p2 ) > 0 !== area( p1, q1, q2 ) > 0 && + area( p2, q2, p1 ) > 0 !== area( p2, q2, q1 ) > 0; - this.type = 'LatheBufferGeometry'; +} - this.parameters = { - points: points, - segments: segments, - phiStart: phiStart, - phiLength: phiLength - }; +// check if a polygon diagonal intersects any polygon segments - segments = Math.floor( segments ) || 12; - phiStart = phiStart || 0; - phiLength = phiLength || Math.PI * 2; +function intersectsPolygon( a, b ) { - // clamp phiLength so it's in range of [ 0, 2PI ] + var p = a; - phiLength = _Math.clamp( phiLength, 0, Math.PI * 2 ); + do { + if ( p.i !== a.i && p.next.i !== a.i && p.i !== b.i && p.next.i !== b.i && + intersects( p, p.next, a, b ) ) { - // buffers + return true; - var indices = []; - var vertices = []; - var uvs = []; + } - // helper variables + p = p.next; - var base; - var inverseSegments = 1.0 / segments; - var vertex = new Vector3(); - var uv = new Vector2(); - var i, j; + } while ( p !== a ); - // generate vertices and uvs + return false; - for ( i = 0; i <= segments; i ++ ) { +} - var phi = phiStart + i * inverseSegments * phiLength; +// check if a polygon diagonal is locally inside the polygon - var sin = Math.sin( phi ); - var cos = Math.cos( phi ); +function locallyInside( a, b ) { - for ( j = 0; j <= ( points.length - 1 ); j ++ ) { + 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 = points[ j ].x * sin; - vertex.y = points[ j ].y; - vertex.z = points[ j ].x * cos; +// check if the middle point of a polygon diagonal is inside the polygon - vertices.push( vertex.x, vertex.y, vertex.z ); +function middleInside( a, b ) { - // uv + var p = a, + inside = false, + px = ( a.x + b.x ) / 2, + py = ( a.y + b.y ) / 2; - uv.x = i / segments; - uv.y = j / ( points.length - 1 ); + do { - uvs.push( uv.x, uv.y ); + 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; - // indices + } while ( p !== a ); - for ( i = 0; i < segments; i ++ ) { + return inside; - for ( j = 0; j < ( points.length - 1 ); j ++ ) { +} - base = j + i * points.length; +// 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 - var a = base; - var b = base + points.length; - var c = base + points.length + 1; - var d = base + 1; - - // faces +function splitPolygon( a, b ) { - indices.push( a, b, d ); - indices.push( b, c, d ); + 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; - } + a.next = b; + b.prev = a; - } + a2.next = an; + an.prev = a2; - // build geometry + b2.next = a2; + a2.prev = b2; - this.setIndex( indices ); - this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); + bp.next = b2; + b2.prev = bp; - // generate normals + return b2; - 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). +// create a node and optionally link it with previous one (in a circular doubly linked list) - if ( phiLength === Math.PI * 2 ) { +function insertNode( i, x, y, last ) { - var normals = this.attributes.normal.array; - var n1 = new Vector3(); - var n2 = new Vector3(); - var n = new Vector3(); + var p = new Node( i, x, y ); - // this is the buffer offset for the last line of vertices + if ( ! last ) { - base = segments * points.length * 3; + p.prev = p; + p.next = p; - for ( i = 0, j = 0; i < points.length; i ++, j += 3 ) { + } else { - // select the normal of the vertex in the first line + p.next = last.next; + p.prev = last; + last.next.prev = p; + last.next = p; - n1.x = normals[ j + 0 ]; - n1.y = normals[ j + 1 ]; - n1.z = normals[ j + 2 ]; + } - // select the normal of the vertex in the last line + return p; - n2.x = normals[ base + j + 0 ]; - n2.y = normals[ base + j + 1 ]; - n2.z = normals[ base + j + 2 ]; +} - // average normals +function removeNode( p ) { - n.addVectors( n1, n2 ).normalize(); + p.next.prev = p.prev; + p.prev.next = p.next; - // assign the new values to both normals + if ( p.prevZ ) p.prevZ.nextZ = p.nextZ; + if ( p.nextZ ) p.nextZ.prevZ = p.prevZ; - 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; +} - } +function Node( i, x, y ) { - } + // vertice index in coordinates array + this.i = i; -} + // vertex coordinates + this.x = x; + this.y = y; -LatheBufferGeometry.prototype = Object.create( BufferGeometry.prototype ); -LatheBufferGeometry.prototype.constructor = LatheBufferGeometry; + // previous and next vertice nodes in a polygon ring + this.prev = null; + this.next = null; -/** - * @author jonobr1 / http://jonobr1.com - * @author Mugen87 / https://github.com/Mugen87 - */ + // z-order curve value + this.z = null; -// ShapeGeometry + // previous and next nodes in z-order + this.prevZ = null; + this.nextZ = null; -function ShapeGeometry( shapes, curveSegments ) { + // indicates whether this is a steiner point + this.steiner = false; - Geometry.call( this ); +} - this.type = 'ShapeGeometry'; +function signedArea( data, start, end, dim ) { - if ( typeof curveSegments === 'object' ) { + var sum = 0; - console.warn( 'THREE.ShapeGeometry: Options parameter has been removed.' ); + for ( var i = start, j = end - dim; i < end; i += dim ) { - curveSegments = curveSegments.curveSegments; + sum += ( data[ j ] - data[ i ] ) * ( data[ i + 1 ] + data[ j + 1 ] ); + j = i; } - this.parameters = { - shapes: shapes, - curveSegments: curveSegments - }; - - this.fromBufferGeometry( new ShapeBufferGeometry( shapes, curveSegments ) ); - this.mergeVertices(); + return sum; } -ShapeGeometry.prototype = Object.create( Geometry.prototype ); -ShapeGeometry.prototype.constructor = ShapeGeometry; +/** + * @author zz85 / http://www.lab4games.net/zz85/blog + */ -ShapeGeometry.prototype.toJSON = function () { +var ShapeUtils = { - var data = Geometry.prototype.toJSON.call( this ); + // calculate area of the contour polygon - var shapes = this.parameters.shapes; + area: function ( contour ) { - return toJSON( shapes, data ); + var n = contour.length; + var a = 0.0; -}; + for ( var p = n - 1, q = 0; q < n; p = q ++ ) { -// ShapeBufferGeometry + a += contour[ p ].x * contour[ q ].y - contour[ q ].x * contour[ p ].y; -function ShapeBufferGeometry( shapes, curveSegments ) { + } - BufferGeometry.call( this ); + return a * 0.5; - this.type = 'ShapeBufferGeometry'; + }, - this.parameters = { - shapes: shapes, - curveSegments: curveSegments - }; + isClockWise: function ( pts ) { - curveSegments = curveSegments || 12; + return ShapeUtils.area( pts ) < 0; - // buffers + }, - var indices = []; - var vertices = []; - var normals = []; - var uvs = []; + triangulateShape: function ( contour, holes ) { - // helper variables + 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 groupStart = 0; - var groupCount = 0; + removeDupEndPts( contour ); + addContour( vertices, contour ); - // allow single and array values for "shapes" parameter + // - if ( Array.isArray( shapes ) === false ) { + var holeIndex = contour.length; - addShape( shapes ); + holes.forEach( removeDupEndPts ); - } else { + for ( var i = 0; i < holes.length; i ++ ) { - for ( var i = 0; i < shapes.length; i ++ ) { + holeIndices.push( holeIndex ); + holeIndex += holes[ i ].length; + addContour( vertices, holes[ i ] ); - addShape( shapes[ i ] ); + } - this.addGroup( groupStart, groupCount, i ); // enables MultiMaterial support + // - groupStart += groupCount; - groupCount = 0; + var triangles = Earcut.triangulate( vertices, holeIndices ); + + // + + for ( var i = 0; i < triangles.length; i += 3 ) { + + faces.push( triangles.slice( i, i + 3 ) ); } + return faces; + } - // 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 ) ); +function removeDupEndPts( points ) { + var l = points.length; - // helper functions + if ( l > 2 && points[ l - 1 ].equals( points[ 0 ] ) ) { - function addShape( shape ) { + points.pop(); - var i, l, shapeHole; + } - var indexOffset = vertices.length / 3; - var points = shape.extractPoints( curveSegments ); +} - var shapeVertices = points.shape; - var shapeHoles = points.holes; +function addContour( vertices, contour ) { - // check direction of vertices + for ( var i = 0; i < contour.length; i ++ ) { - if ( ShapeUtils.isClockWise( shapeVertices ) === false ) { + vertices.push( contour[ i ].x ); + vertices.push( contour[ i ].y ); - shapeVertices = shapeVertices.reverse(); + } - // also check if holes are in the opposite direction +} - for ( i = 0, l = shapeHoles.length; i < l; i ++ ) { +/** + * @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 + * + * } + */ - shapeHole = shapeHoles[ i ]; +// ExtrudeGeometry - if ( ShapeUtils.isClockWise( shapeHole ) === true ) { +function ExtrudeGeometry( shapes, options ) { - shapeHoles[ i ] = shapeHole.reverse(); + Geometry.call( this ); - } + this.type = 'ExtrudeGeometry'; - } + this.parameters = { + shapes: shapes, + options: options + }; - } + this.fromBufferGeometry( new ExtrudeBufferGeometry( shapes, options ) ); + this.mergeVertices(); - var faces = ShapeUtils.triangulateShape( shapeVertices, shapeHoles ); +} - // join vertices of inner and outer paths to a single array +ExtrudeGeometry.prototype = Object.create( Geometry.prototype ); +ExtrudeGeometry.prototype.constructor = ExtrudeGeometry; - for ( i = 0, l = shapeHoles.length; i < l; i ++ ) { +ExtrudeGeometry.prototype.toJSON = function () { - shapeHole = shapeHoles[ i ]; - shapeVertices = shapeVertices.concat( shapeHole ); + var data = Geometry.prototype.toJSON.call( this ); - } + var shapes = this.parameters.shapes; + var options = this.parameters.options; - // vertices, normals, uvs + return toJSON( shapes, options, data ); - for ( i = 0, l = shapeVertices.length; i < l; i ++ ) { +}; - var vertex = shapeVertices[ i ]; +// ExtrudeBufferGeometry - vertices.push( vertex.x, vertex.y, 0 ); - normals.push( 0, 0, 1 ); - uvs.push( vertex.x, vertex.y ); // world uvs +function ExtrudeBufferGeometry( shapes, options ) { - } + BufferGeometry.call( this ); - // incides + this.type = 'ExtrudeBufferGeometry'; - for ( i = 0, l = faces.length; i < l; i ++ ) { + this.parameters = { + shapes: shapes, + options: options + }; - var face = faces[ i ]; + shapes = Array.isArray( shapes ) ? shapes : [ shapes ]; - var a = face[ 0 ] + indexOffset; - var b = face[ 1 ] + indexOffset; - var c = face[ 2 ] + indexOffset; + var scope = this; - indices.push( a, b, c ); - groupCount += 3; + var verticesArray = []; + var uvArray = []; - } + for ( var i = 0, l = shapes.length; i < l; i ++ ) { + + var shape = shapes[ i ]; + addShape( shape ); } -} + // build geometry -ShapeBufferGeometry.prototype = Object.create( BufferGeometry.prototype ); -ShapeBufferGeometry.prototype.constructor = ShapeBufferGeometry; + this.addAttribute( 'position', new Float32BufferAttribute( verticesArray, 3 ) ); + this.addAttribute( 'uv', new Float32BufferAttribute( uvArray, 2 ) ); -ShapeBufferGeometry.prototype.toJSON = function () { + this.computeVertexNormals(); - var data = BufferGeometry.prototype.toJSON.call( this ); + // functions - var shapes = this.parameters.shapes; + function addShape( shape ) { - return toJSON( shapes, data ); + var placeholder = []; -}; + // 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; -function toJSON( shapes, data ) { + 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; - data.shapes = []; + var extrudePath = options.extrudePath; - if ( Array.isArray( shapes ) ) { + var uvgen = options.UVGenerator !== undefined ? options.UVGenerator : WorldUVGenerator; - for ( var i = 0, l = shapes.length; i < l; i ++ ) { + // deprecated options - var shape = shapes[ i ]; + if ( options.amount !== undefined ) { - data.shapes.push( shape.uuid ); + console.warn( 'THREE.ExtrudeBufferGeometry: amount has been renamed to depth.' ); + depth = options.amount; } - } else { + // - data.shapes.push( shapes.uuid ); + var extrudePts, extrudeByPath = false; + var splineTube, binormal, normal, position2; - } + if ( extrudePath ) { - return data; + extrudePts = extrudePath.getSpacedPoints( steps ); -} + extrudeByPath = true; + bevelEnabled = false; // bevels not supported for path extrusion -/** - * @author WestLangley / http://github.com/WestLangley - * @author Mugen87 / https://github.com/Mugen87 - */ + // SETUP TNB variables -function EdgesGeometry( geometry, thresholdAngle ) { + // TODO1 - have a .isClosed in spline? - BufferGeometry.call( this ); + splineTube = extrudePath.computeFrenetFrames( steps, false ); - this.type = 'EdgesGeometry'; + // console.log(splineTube, 'splineTube', splineTube.normals.length, 'steps', steps, 'extrudePts', extrudePts.length); - this.parameters = { - thresholdAngle: thresholdAngle - }; + binormal = new Vector3(); + normal = new Vector3(); + position2 = new Vector3(); - thresholdAngle = ( thresholdAngle !== undefined ) ? thresholdAngle : 1; + } - // buffer + // Safeguards if bevels are not enabled - var vertices = []; + if ( ! bevelEnabled ) { - // helper variables + bevelSegments = 0; + bevelThickness = 0; + bevelSize = 0; - var thresholdDot = Math.cos( _Math.DEG2RAD * thresholdAngle ); - var edge = [ 0, 0 ], edges = {}, edge1, edge2; - var key, keys = [ 'a', 'b', 'c' ]; + } - // prepare source geometry + // Variables initialization - var geometry2; + var ahole, h, hl; // looping of holes - if ( geometry.isBufferGeometry ) { + var shapePoints = shape.extractPoints( curveSegments ); - geometry2 = new Geometry(); - geometry2.fromBufferGeometry( geometry ); + var vertices = shapePoints.shape; + var holes = shapePoints.holes; - } else { + var reverse = ! ShapeUtils.isClockWise( vertices ); - geometry2 = geometry.clone(); + if ( reverse ) { - } + vertices = vertices.reverse(); - geometry2.mergeVertices(); - geometry2.computeFaceNormals(); + // Maybe we should also check if holes are in the opposite direction, just to be safe ... - var sourceVertices = geometry2.vertices; - var faces = geometry2.faces; + for ( h = 0, hl = holes.length; h < hl; h ++ ) { - // now create a data structure where each entry represents an edge with its adjoining faces + ahole = holes[ h ]; - for ( var i = 0, l = faces.length; i < l; i ++ ) { + if ( ShapeUtils.isClockWise( ahole ) ) { - var face = faces[ i ]; + holes[ h ] = ahole.reverse(); - for ( var j = 0; j < 3; j ++ ) { + } - edge1 = face[ keys[ j ] ]; - edge2 = face[ keys[ ( j + 1 ) % 3 ] ]; - edge[ 0 ] = Math.min( edge1, edge2 ); - edge[ 1 ] = Math.max( edge1, edge2 ); + } - key = edge[ 0 ] + ',' + edge[ 1 ]; + } - if ( edges[ key ] === undefined ) { - edges[ key ] = { index1: edge[ 0 ], index2: edge[ 1 ], face1: i, face2: undefined }; + var faces = ShapeUtils.triangulateShape( vertices, holes ); - } else { + /* Vertices */ - edges[ key ].face2 = i; + var contour = vertices; // vertices has all points but contour has only points of circumference - } + for ( h = 0, hl = holes.length; h < hl; h ++ ) { + + ahole = holes[ h ]; + + vertices = vertices.concat( ahole ); } - } - // generate vertices + function scalePt2( pt, vec, size ) { - for ( key in edges ) { + if ( ! vec ) console.error( "THREE.ExtrudeGeometry: vec does not exist" ); - var e = edges[ key ]; + return vec.clone().multiplyScalar( size ).add( pt ); - // 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 ( e.face2 === undefined || faces[ e.face1 ].normal.dot( faces[ e.face2 ].normal ) <= thresholdDot ) { + var b, bs, t, z, + vert, vlen = vertices.length, + face, flen = faces.length; - 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 ); + // Find directions for point movement - } - } + function getBevelVec( inPt, inPrev, inNext ) { - // build geometry + // 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. - this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); + var v_trans_x, v_trans_y, shrink_by; // resulting translation vector for inPt -} + // good reading for geometry algorithms (here: line-line intersection) + // http://geomalgorithms.com/a05-_intersect-1.html -EdgesGeometry.prototype = Object.create( BufferGeometry.prototype ); -EdgesGeometry.prototype.constructor = EdgesGeometry; + 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; -/** - * @author mrdoob / http://mrdoob.com/ - * @author Mugen87 / https://github.com/Mugen87 - */ + var v_prev_lensq = ( v_prev_x * v_prev_x + v_prev_y * v_prev_y ); -// CylinderGeometry + // check for collinear edges + var collinear0 = ( v_prev_x * v_next_y - v_prev_y * v_next_x ); -function CylinderGeometry( radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ) { + if ( Math.abs( collinear0 ) > Number.EPSILON ) { - Geometry.call( this ); + // not collinear - this.type = 'CylinderGeometry'; + // length of vectors for normalizing - this.parameters = { - radiusTop: radiusTop, - radiusBottom: radiusBottom, - height: height, - radialSegments: radialSegments, - heightSegments: heightSegments, - openEnded: openEnded, - thetaStart: thetaStart, - thetaLength: thetaLength - }; + 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.fromBufferGeometry( new CylinderBufferGeometry( radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ) ); - this.mergeVertices(); + // shift adjacent points by unit vectors to the left -} + var ptPrevShift_x = ( inPrev.x - v_prev_y / v_prev_len ); + var ptPrevShift_y = ( inPrev.y + v_prev_x / v_prev_len ); -CylinderGeometry.prototype = Object.create( Geometry.prototype ); -CylinderGeometry.prototype.constructor = CylinderGeometry; + var ptNextShift_x = ( inNext.x - v_next_y / v_next_len ); + var ptNextShift_y = ( inNext.y + v_next_x / v_next_len ); -// CylinderBufferGeometry + // scaling factor for v_prev to intersection point -function CylinderBufferGeometry( radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ) { + 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 ); - BufferGeometry.call( this ); + // vector from inPt to intersection point - this.type = 'CylinderBufferGeometry'; + v_trans_x = ( ptPrevShift_x + v_prev_x * sf - inPt.x ); + v_trans_y = ( ptPrevShift_y + v_prev_y * sf - inPt.y ); - this.parameters = { - radiusTop: radiusTop, - radiusBottom: radiusBottom, - height: height, - radialSegments: radialSegments, - heightSegments: heightSegments, - openEnded: openEnded, - thetaStart: thetaStart, - thetaLength: thetaLength - }; + // 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 scope = this; + return new Vector2( v_trans_x, v_trans_y ); - radiusTop = radiusTop !== undefined ? radiusTop : 1; - radiusBottom = radiusBottom !== undefined ? radiusBottom : 1; - height = height || 1; + } else { - radialSegments = Math.floor( radialSegments ) || 8; - heightSegments = Math.floor( heightSegments ) || 1; + shrink_by = Math.sqrt( v_trans_lensq / 2 ); - openEnded = openEnded !== undefined ? openEnded : false; - thetaStart = thetaStart !== undefined ? thetaStart : 0.0; - thetaLength = thetaLength !== undefined ? thetaLength : Math.PI * 2; + } - // buffers + } else { - var indices = []; - var vertices = []; - var normals = []; - var uvs = []; + // handle special case of collinear edges - // helper variables + var direction_eq = false; // assumes: opposite + if ( v_prev_x > Number.EPSILON ) { - var index = 0; - var indexArray = []; - var halfHeight = height / 2; - var groupStart = 0; + if ( v_next_x > Number.EPSILON ) { - // generate geometry + direction_eq = true; - generateTorso(); + } - if ( openEnded === false ) { + } else { - if ( radiusTop > 0 ) generateCap( true ); - if ( radiusBottom > 0 ) generateCap( false ); + if ( v_prev_x < - Number.EPSILON ) { - } + if ( v_next_x < - Number.EPSILON ) { - // build geometry + direction_eq = true; - 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() { + } else { - var x, y; - var normal = new Vector3(); - var vertex = new Vector3(); + if ( Math.sign( v_prev_y ) === Math.sign( v_next_y ) ) { - var groupCount = 0; + direction_eq = true; - // this will be used to calculate the normal - var slope = ( radiusBottom - radiusTop ) / height; + } - // generate vertices, normals and uvs + } - for ( y = 0; y <= heightSegments; y ++ ) { + } - var indexRow = []; + if ( direction_eq ) { - var v = y / heightSegments; + // 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 ); - // calculate the radius of the current row + } else { - var radius = v * ( radiusBottom - radiusTop ) + radiusTop; + // 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 ); - for ( x = 0; x <= radialSegments; x ++ ) { + } - var u = x / radialSegments; + } - var theta = u * thetaLength + thetaStart; + return new Vector2( v_trans_x / shrink_by, v_trans_y / shrink_by ); - var sinTheta = Math.sin( theta ); - var cosTheta = Math.cos( theta ); + } - // vertex - vertex.x = radius * sinTheta; - vertex.y = - v * height + halfHeight; - vertex.z = radius * cosTheta; - vertices.push( vertex.x, vertex.y, vertex.z ); + var contourMovements = []; - // normal + for ( var i = 0, il = contour.length, j = il - 1, k = i + 1; i < il; i ++, j ++, k ++ ) { - normal.set( sinTheta, slope, cosTheta ).normalize(); - normals.push( normal.x, normal.y, normal.z ); + if ( j === il ) j = 0; + if ( k === il ) k = 0; - // uv + // (j)---(i)---(k) + // console.log('i,j,k', i, j , k) - uvs.push( u, 1 - v ); + contourMovements[ i ] = getBevelVec( contour[ i ], contour[ j ], contour[ k ] ); - // save index of vertex in respective row + } - indexRow.push( index ++ ); + var holesMovements = [], + oneHoleMovements, verticesMovements = contourMovements.concat(); - } + for ( h = 0, hl = holes.length; h < hl; h ++ ) { - // now save vertices of the row in our index array + ahole = holes[ h ]; - indexArray.push( indexRow ); + oneHoleMovements = []; - } + for ( i = 0, il = ahole.length, j = il - 1, k = i + 1; i < il; i ++, j ++, k ++ ) { - // generate indices + if ( j === il ) j = 0; + if ( k === il ) k = 0; - for ( x = 0; x < radialSegments; x ++ ) { + // (j)---(i)---(k) + oneHoleMovements[ i ] = getBevelVec( ahole[ i ], ahole[ j ], ahole[ k ] ); - for ( y = 0; y < heightSegments; y ++ ) { + } - // we use the index array to access the correct indices + holesMovements.push( oneHoleMovements ); + verticesMovements = verticesMovements.concat( oneHoleMovements ); - var a = indexArray[ y ][ x ]; - var b = indexArray[ y + 1 ][ x ]; - var c = indexArray[ y + 1 ][ x + 1 ]; - var d = indexArray[ y ][ x + 1 ]; + } - // faces - indices.push( a, b, d ); - indices.push( b, c, d ); + // Loop bevelSegments, 1 for the front, 1 for the back - // update group counter + for ( b = 0; b < bevelSegments; b ++ ) { - groupCount += 6; + //for ( b = bevelSegments; b > 0; b -- ) { - } + t = b / bevelSegments; + z = bevelThickness * Math.cos( t * Math.PI / 2 ); + bs = bevelSize * Math.sin( t * Math.PI / 2 ); - } + // contract shape - // add a group to the geometry. this will ensure multi material support + for ( i = 0, il = contour.length; i < il; i ++ ) { - scope.addGroup( groupStart, groupCount, 0 ); + vert = scalePt2( contour[ i ], contourMovements[ i ], bs ); - // calculate new start value for groups + v( vert.x, vert.y, - z ); - groupStart += groupCount; + } - } + // expand holes - function generateCap( top ) { + for ( h = 0, hl = holes.length; h < hl; h ++ ) { - var x, centerIndexStart, centerIndexEnd; + ahole = holes[ h ]; + oneHoleMovements = holesMovements[ h ]; - var uv = new Vector2(); - var vertex = new Vector3(); + for ( i = 0, il = ahole.length; i < il; i ++ ) { - var groupCount = 0; + vert = scalePt2( ahole[ i ], oneHoleMovements[ i ], bs ); - var radius = ( top === true ) ? radiusTop : radiusBottom; - var sign = ( top === true ) ? 1 : - 1; + v( vert.x, vert.y, - z ); - // save the index of the first center vertex - centerIndexStart = index; + } - // first we generate the center vertex data of the cap. - // because the geometry needs one set of uvs per face, - // we must generate a center vertex per face/segment + } - for ( x = 1; x <= radialSegments; x ++ ) { + } - // vertex + bs = bevelSize; - vertices.push( 0, halfHeight * sign, 0 ); + // Back facing vertices - // normal + for ( i = 0; i < vlen; i ++ ) { - normals.push( 0, sign, 0 ); + vert = bevelEnabled ? scalePt2( vertices[ i ], verticesMovements[ i ], bs ) : vertices[ i ]; - // uv + if ( ! extrudeByPath ) { - uvs.push( 0.5, 0.5 ); + v( vert.x, vert.y, 0 ); - // increase index + } else { - index ++; + // v( vert.x, vert.y + extrudePts[ 0 ].y, extrudePts[ 0 ].x ); - } + normal.copy( splineTube.normals[ 0 ] ).multiplyScalar( vert.x ); + binormal.copy( splineTube.binormals[ 0 ] ).multiplyScalar( vert.y ); - // save the index of the last center vertex + position2.copy( extrudePts[ 0 ] ).add( normal ).add( binormal ); - centerIndexEnd = index; + v( position2.x, position2.y, position2.z ); - // now we generate the surrounding vertices, normals and uvs + } - for ( x = 0; x <= radialSegments; x ++ ) { + } - var u = x / radialSegments; - var theta = u * thetaLength + thetaStart; + // Add stepped vertices... + // Including front facing vertices - var cosTheta = Math.cos( theta ); - var sinTheta = Math.sin( theta ); + var s; - // vertex + for ( s = 1; s <= steps; s ++ ) { - vertex.x = radius * sinTheta; - vertex.y = halfHeight * sign; - vertex.z = radius * cosTheta; - vertices.push( vertex.x, vertex.y, vertex.z ); + for ( i = 0; i < vlen; i ++ ) { - // normal + vert = bevelEnabled ? scalePt2( vertices[ i ], verticesMovements[ i ], bs ) : vertices[ i ]; - normals.push( 0, sign, 0 ); + if ( ! extrudeByPath ) { - // uv + v( vert.x, vert.y, depth / steps * s ); - uv.x = ( cosTheta * 0.5 ) + 0.5; - uv.y = ( sinTheta * 0.5 * sign ) + 0.5; - uvs.push( uv.x, uv.y ); + } else { - // increase index + // v( vert.x, vert.y + extrudePts[ s - 1 ].y, extrudePts[ s - 1 ].x ); - index ++; + normal.copy( splineTube.normals[ s ] ).multiplyScalar( vert.x ); + binormal.copy( splineTube.binormals[ s ] ).multiplyScalar( vert.y ); - } + position2.copy( extrudePts[ s ] ).add( normal ).add( binormal ); - // generate indices + v( position2.x, position2.y, position2.z ); - for ( x = 0; x < radialSegments; x ++ ) { + } - var c = centerIndexStart + x; - var i = centerIndexEnd + x; + } - if ( top === true ) { + } - // face top - indices.push( i, i + 1, c ); + // Add bevel segments planes - } else { + //for ( b = 1; b <= bevelSegments; b ++ ) { + for ( b = bevelSegments - 1; b >= 0; b -- ) { - // face bottom + t = b / bevelSegments; + z = bevelThickness * Math.cos( t * Math.PI / 2 ); + bs = bevelSize * Math.sin( t * Math.PI / 2 ); - indices.push( i + 1, i, c ); + // contract shape + + for ( i = 0, il = contour.length; i < il; i ++ ) { + + vert = scalePt2( contour[ i ], contourMovements[ i ], bs ); + v( vert.x, vert.y, depth + z ); } - groupCount += 3; + // expand holes - } + for ( h = 0, hl = holes.length; h < hl; h ++ ) { - // add a group to the geometry. this will ensure multi material support + ahole = holes[ h ]; + oneHoleMovements = holesMovements[ h ]; - scope.addGroup( groupStart, groupCount, top === true ? 1 : 2 ); + for ( i = 0, il = ahole.length; i < il; i ++ ) { - // calculate new start value for groups + vert = scalePt2( ahole[ i ], oneHoleMovements[ i ], bs ); - groupStart += groupCount; + if ( ! extrudeByPath ) { - } + v( vert.x, vert.y, depth + z ); -} + } else { -CylinderBufferGeometry.prototype = Object.create( BufferGeometry.prototype ); -CylinderBufferGeometry.prototype.constructor = CylinderBufferGeometry; + v( vert.x, vert.y + extrudePts[ steps - 1 ].y, extrudePts[ steps - 1 ].x + z ); -/** - * @author abelnation / http://github.com/abelnation - */ + } -// ConeGeometry + } -function ConeGeometry( radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ) { + } - CylinderGeometry.call( this, 0, radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ); + } - this.type = 'ConeGeometry'; + /* Faces */ - this.parameters = { - radius: radius, - height: height, - radialSegments: radialSegments, - heightSegments: heightSegments, - openEnded: openEnded, - thetaStart: thetaStart, - thetaLength: thetaLength - }; + // Top and bottom faces -} + buildLidFaces(); -ConeGeometry.prototype = Object.create( CylinderGeometry.prototype ); -ConeGeometry.prototype.constructor = ConeGeometry; + // Sides faces -// ConeBufferGeometry + buildSideFaces(); -function ConeBufferGeometry( radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ) { - CylinderBufferGeometry.call( this, 0, radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ); + ///// Internal functions - this.type = 'ConeBufferGeometry'; + function buildLidFaces() { - this.parameters = { - radius: radius, - height: height, - radialSegments: radialSegments, - heightSegments: heightSegments, - openEnded: openEnded, - thetaStart: thetaStart, - thetaLength: thetaLength - }; + var start = verticesArray.length / 3; -} + if ( bevelEnabled ) { -ConeBufferGeometry.prototype = Object.create( CylinderBufferGeometry.prototype ); -ConeBufferGeometry.prototype.constructor = ConeBufferGeometry; + var layer = 0; // steps + 1 + var offset = vlen * layer; -/** - * @author benaadams / https://twitter.com/ben_a_adams - * @author Mugen87 / https://github.com/Mugen87 - * @author hughes - */ + // Bottom faces -// CircleGeometry + for ( i = 0; i < flen; i ++ ) { -function CircleGeometry( radius, segments, thetaStart, thetaLength ) { + face = faces[ i ]; + f3( face[ 2 ] + offset, face[ 1 ] + offset, face[ 0 ] + offset ); - Geometry.call( this ); + } - this.type = 'CircleGeometry'; + layer = steps + bevelSegments * 2; + offset = vlen * layer; - this.parameters = { - radius: radius, - segments: segments, - thetaStart: thetaStart, - thetaLength: thetaLength - }; + // Top faces - this.fromBufferGeometry( new CircleBufferGeometry( radius, segments, thetaStart, thetaLength ) ); - this.mergeVertices(); + for ( i = 0; i < flen; i ++ ) { -} + face = faces[ i ]; + f3( face[ 0 ] + offset, face[ 1 ] + offset, face[ 2 ] + offset ); -CircleGeometry.prototype = Object.create( Geometry.prototype ); -CircleGeometry.prototype.constructor = CircleGeometry; + } -// CircleBufferGeometry + } else { -function CircleBufferGeometry( radius, segments, thetaStart, thetaLength ) { + // Bottom faces - BufferGeometry.call( this ); + for ( i = 0; i < flen; i ++ ) { - this.type = 'CircleBufferGeometry'; + face = faces[ i ]; + f3( face[ 2 ], face[ 1 ], face[ 0 ] ); - this.parameters = { - radius: radius, - segments: segments, - thetaStart: thetaStart, - thetaLength: thetaLength - }; + } - radius = radius || 1; - segments = segments !== undefined ? Math.max( 3, segments ) : 8; + // Top faces - thetaStart = thetaStart !== undefined ? thetaStart : 0; - thetaLength = thetaLength !== undefined ? thetaLength : Math.PI * 2; + for ( i = 0; i < flen; i ++ ) { - // buffers + face = faces[ i ]; + f3( face[ 0 ] + vlen * steps, face[ 1 ] + vlen * steps, face[ 2 ] + vlen * steps ); - var indices = []; - var vertices = []; - var normals = []; - var uvs = []; + } - // helper variables + } - var i, s; - var vertex = new Vector3(); - var uv = new Vector2(); + scope.addGroup( start, verticesArray.length / 3 - start, 0 ); - // center point + } - vertices.push( 0, 0, 0 ); - normals.push( 0, 0, 1 ); - uvs.push( 0.5, 0.5 ); + // Create faces for the z-sides of the shape - for ( s = 0, i = 3; s <= segments; s ++, i += 3 ) { + function buildSideFaces() { - var segment = thetaStart + s / segments * thetaLength; + var start = verticesArray.length / 3; + var layeroffset = 0; + sidewalls( contour, layeroffset ); + layeroffset += contour.length; - // vertex + for ( h = 0, hl = holes.length; h < hl; h ++ ) { - vertex.x = radius * Math.cos( segment ); - vertex.y = radius * Math.sin( segment ); + ahole = holes[ h ]; + sidewalls( ahole, layeroffset ); - vertices.push( vertex.x, vertex.y, vertex.z ); + //, true + layeroffset += ahole.length; - // normal + } - normals.push( 0, 0, 1 ); - // uvs + scope.addGroup( start, verticesArray.length / 3 - start, 1 ); - uv.x = ( vertices[ i ] / radius + 1 ) / 2; - uv.y = ( vertices[ i + 1 ] / radius + 1 ) / 2; - uvs.push( uv.x, uv.y ); + } - } + function sidewalls( contour, layeroffset ) { - // indices + var j, k; + i = contour.length; - for ( i = 1; i <= segments; i ++ ) { + while ( -- i >= 0 ) { - indices.push( i, i + 1, 0 ); + j = i; + k = i - 1; + if ( k < 0 ) k = contour.length - 1; - } + //console.log('b', i,j, i-1, k,vertices.length); - // build geometry + var s = 0, + sl = steps + bevelSegments * 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 ) ); + for ( s = 0; s < sl; s ++ ) { -} + var slen1 = vlen * s; + var slen2 = vlen * ( s + 1 ); -CircleBufferGeometry.prototype = Object.create( BufferGeometry.prototype ); -CircleBufferGeometry.prototype.constructor = CircleBufferGeometry; + var a = layeroffset + j + slen1, + b = layeroffset + k + slen1, + c = layeroffset + k + slen2, + d = layeroffset + j + slen2; + f4( a, b, c, d ); + } -var Geometries = 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 -}); + } -/** - * @author mrdoob / http://mrdoob.com/ - * - * parameters = { - * color: , - * opacity: - * } - */ + } -function ShadowMaterial( parameters ) { + function v( x, y, z ) { - Material.call( this ); + placeholder.push( x ); + placeholder.push( y ); + placeholder.push( z ); - this.type = 'ShadowMaterial'; + } - this.color = new Color( 0x000000 ); - this.opacity = 1.0; - this.lights = true; - this.transparent = true; + function f3( a, b, c ) { - this.setValues( parameters ); + addVertex( a ); + addVertex( b ); + addVertex( c ); -} + var nextIndex = verticesArray.length / 3; + var uvs = uvgen.generateTopUV( scope, verticesArray, nextIndex - 3, nextIndex - 2, nextIndex - 1 ); -ShadowMaterial.prototype = Object.create( Material.prototype ); -ShadowMaterial.prototype.constructor = ShadowMaterial; + addUV( uvs[ 0 ] ); + addUV( uvs[ 1 ] ); + addUV( uvs[ 2 ] ); -ShadowMaterial.prototype.isShadowMaterial = true; + } -/** - * @author mrdoob / http://mrdoob.com/ - */ + function f4( a, b, c, d ) { -function RawShaderMaterial( parameters ) { + addVertex( a ); + addVertex( b ); + addVertex( d ); - ShaderMaterial.call( this, parameters ); + addVertex( b ); + addVertex( c ); + addVertex( d ); - this.type = 'RawShaderMaterial'; -} + var nextIndex = verticesArray.length / 3; + var uvs = uvgen.generateSideWallUV( scope, verticesArray, nextIndex - 6, nextIndex - 3, nextIndex - 2, nextIndex - 1 ); -RawShaderMaterial.prototype = Object.create( ShaderMaterial.prototype ); -RawShaderMaterial.prototype.constructor = RawShaderMaterial; + addUV( uvs[ 0 ] ); + addUV( uvs[ 1 ] ); + addUV( uvs[ 3 ] ); -RawShaderMaterial.prototype.isRawShaderMaterial = true; + addUV( uvs[ 1 ] ); + addUV( uvs[ 2 ] ); + addUV( uvs[ 3 ] ); -/** - * @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( ), - * 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 ) { + function addVertex( index ) { - Material.call( this ); + verticesArray.push( placeholder[ index * 3 + 0 ] ); + verticesArray.push( placeholder[ index * 3 + 1 ] ); + verticesArray.push( placeholder[ index * 3 + 2 ] ); - this.defines = { 'STANDARD': '' }; + } - this.type = 'MeshStandardMaterial'; - this.color = new Color( 0xffffff ); // diffuse - this.roughness = 0.5; - this.metalness = 0.5; + function addUV( vector2 ) { - this.map = null; + uvArray.push( vector2.x ); + uvArray.push( vector2.y ); - this.lightMap = null; - this.lightMapIntensity = 1.0; + } - this.aoMap = null; - this.aoMapIntensity = 1.0; + } - this.emissive = new Color( 0x000000 ); - this.emissiveIntensity = 1.0; - this.emissiveMap = null; +} - this.bumpMap = null; - this.bumpScale = 1; +ExtrudeBufferGeometry.prototype = Object.create( BufferGeometry.prototype ); +ExtrudeBufferGeometry.prototype.constructor = ExtrudeBufferGeometry; - this.normalMap = null; - this.normalScale = new Vector2( 1, 1 ); +ExtrudeBufferGeometry.prototype.toJSON = function () { - this.displacementMap = null; - this.displacementScale = 1; - this.displacementBias = 0; + var data = BufferGeometry.prototype.toJSON.call( this ); - this.roughnessMap = null; + var shapes = this.parameters.shapes; + var options = this.parameters.options; - this.metalnessMap = null; + return toJSON( shapes, options, data ); - this.alphaMap = null; +}; - this.envMap = null; - this.envMapIntensity = 1.0; +// - this.refractionRatio = 0.98; +var WorldUVGenerator = { - this.wireframe = false; - this.wireframeLinewidth = 1; - this.wireframeLinecap = 'round'; - this.wireframeLinejoin = 'round'; + generateTopUV: function ( geometry, vertices, indexA, indexB, indexC ) { - this.skinning = false; - this.morphTargets = false; - this.morphNormals = false; + 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 ]; - this.setValues( parameters ); + return [ + new Vector2( a_x, a_y ), + new Vector2( b_x, b_y ), + new Vector2( c_x, c_y ) + ]; -} + }, -MeshStandardMaterial.prototype = Object.create( Material.prototype ); -MeshStandardMaterial.prototype.constructor = MeshStandardMaterial; + generateSideWallUV: function ( geometry, vertices, indexA, indexB, indexC, indexD ) { -MeshStandardMaterial.prototype.isMeshStandardMaterial = true; + 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 ]; -MeshStandardMaterial.prototype.copy = function ( source ) { + if ( Math.abs( a_y - b_y ) < 0.01 ) { - Material.prototype.copy.call( this, source ); + 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 ) + ]; - this.defines = { 'STANDARD': '' }; + } else { - this.color.copy( source.color ); - this.roughness = source.roughness; - this.metalness = source.metalness; + 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 ) + ]; - this.map = source.map; + } - this.lightMap = source.lightMap; - this.lightMapIntensity = source.lightMapIntensity; + } +}; - this.aoMap = source.aoMap; - this.aoMapIntensity = source.aoMapIntensity; +function toJSON( shapes, options, data ) { - this.emissive.copy( source.emissive ); - this.emissiveMap = source.emissiveMap; - this.emissiveIntensity = source.emissiveIntensity; + // - this.bumpMap = source.bumpMap; - this.bumpScale = source.bumpScale; + data.shapes = []; - this.normalMap = source.normalMap; - this.normalScale.copy( source.normalScale ); + if ( Array.isArray( shapes ) ) { - this.displacementMap = source.displacementMap; - this.displacementScale = source.displacementScale; - this.displacementBias = source.displacementBias; + for ( var i = 0, l = shapes.length; i < l; i ++ ) { - this.roughnessMap = source.roughnessMap; + var shape = shapes[ i ]; - this.metalnessMap = source.metalnessMap; + data.shapes.push( shape.uuid ); - this.alphaMap = source.alphaMap; + } - this.envMap = source.envMap; - this.envMapIntensity = source.envMapIntensity; + } else { - this.refractionRatio = source.refractionRatio; + data.shapes.push( shapes.uuid ); - 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; + if ( options.extrudePath !== undefined ) data.options.extrudePath = options.extrudePath.toJSON(); -}; + return data; + +} /** - * @author WestLangley / http://github.com/WestLangley + * @author zz85 / http://www.lab4games.net/zz85/blog + * @author alteredq / http://alteredqualia.com/ + * + * Text = 3D Text * * parameters = { - * reflectivity: + * 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 * } */ -function MeshPhysicalMaterial( parameters ) { +// TextGeometry - MeshStandardMaterial.call( this ); +function TextGeometry( text, parameters ) { - this.defines = { 'PHYSICAL': '' }; - - this.type = 'MeshPhysicalMaterial'; + Geometry.call( this ); - this.reflectivity = 0.5; // maps to F0 = 0.04 + this.type = 'TextGeometry'; - this.clearCoat = 0.0; - this.clearCoatRoughness = 0.0; + this.parameters = { + text: text, + parameters: parameters + }; - this.setValues( parameters ); + this.fromBufferGeometry( new TextBufferGeometry( text, parameters ) ); + this.mergeVertices(); } -MeshPhysicalMaterial.prototype = Object.create( MeshStandardMaterial.prototype ); -MeshPhysicalMaterial.prototype.constructor = MeshPhysicalMaterial; +TextGeometry.prototype = Object.create( Geometry.prototype ); +TextGeometry.prototype.constructor = TextGeometry; -MeshPhysicalMaterial.prototype.isMeshPhysicalMaterial = true; +// TextBufferGeometry -MeshPhysicalMaterial.prototype.copy = function ( source ) { +function TextBufferGeometry( text, parameters ) { - MeshStandardMaterial.prototype.copy.call( this, source ); + parameters = parameters || {}; - this.defines = { 'PHYSICAL': '' }; + var font = parameters.font; - this.reflectivity = source.reflectivity; + if ( ! ( font && font.isFont ) ) { - this.clearCoat = source.clearCoat; - this.clearCoatRoughness = source.clearCoatRoughness; + console.error( 'THREE.TextGeometry: font parameter is not an instance of THREE.Font.' ); + return new Geometry(); - return this; + } -}; + 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; + + ExtrudeBufferGeometry.call( this, shapes, parameters ); + + this.type = 'TextBufferGeometry'; + +} + +TextBufferGeometry.prototype = Object.create( ExtrudeBufferGeometry.prototype ); +TextBufferGeometry.prototype.constructor = TextBufferGeometry; /** * @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( ), - * normalScale: , - * - * displacementMap: new THREE.Texture( ), - * displacementScale: , - * displacementBias: , - * - * specularMap: new THREE.Texture( ), - * - * alphaMap: new THREE.Texture( ), - * - * envMap: new THREE.TextureCube( [posx, negx, posy, negy, posz, negz] ), - * combine: THREE.Multiply, - * reflectivity: , - * refractionRatio: , - * - * wireframe: , - * wireframeLinewidth: , - * - * skinning: , - * morphTargets: , - * morphNormals: - * } + * @author benaadams / https://twitter.com/ben_a_adams + * @author Mugen87 / https://github.com/Mugen87 */ -function MeshPhongMaterial( parameters ) { - - Material.call( this ); +// SphereGeometry - this.type = 'MeshPhongMaterial'; +function SphereGeometry( radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength ) { - this.color = new Color( 0xffffff ); // diffuse - this.specular = new Color( 0x111111 ); - this.shininess = 30; + Geometry.call( this ); - this.map = null; + this.type = 'SphereGeometry'; - this.lightMap = null; - this.lightMapIntensity = 1.0; + this.parameters = { + radius: radius, + widthSegments: widthSegments, + heightSegments: heightSegments, + phiStart: phiStart, + phiLength: phiLength, + thetaStart: thetaStart, + thetaLength: thetaLength + }; - this.aoMap = null; - this.aoMapIntensity = 1.0; + this.fromBufferGeometry( new SphereBufferGeometry( radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength ) ); + this.mergeVertices(); - this.emissive = new Color( 0x000000 ); - this.emissiveIntensity = 1.0; - this.emissiveMap = null; +} - this.bumpMap = null; - this.bumpScale = 1; +SphereGeometry.prototype = Object.create( Geometry.prototype ); +SphereGeometry.prototype.constructor = SphereGeometry; - this.normalMap = null; - this.normalScale = new Vector2( 1, 1 ); +// SphereBufferGeometry - this.displacementMap = null; - this.displacementScale = 1; - this.displacementBias = 0; +function SphereBufferGeometry( radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength ) { - this.specularMap = null; + BufferGeometry.call( this ); - this.alphaMap = null; + this.type = 'SphereBufferGeometry'; - this.envMap = null; - this.combine = MultiplyOperation; - this.reflectivity = 1; - this.refractionRatio = 0.98; + this.parameters = { + radius: radius, + widthSegments: widthSegments, + heightSegments: heightSegments, + phiStart: phiStart, + phiLength: phiLength, + thetaStart: thetaStart, + thetaLength: thetaLength + }; - this.wireframe = false; - this.wireframeLinewidth = 1; - this.wireframeLinecap = 'round'; - this.wireframeLinejoin = 'round'; + radius = radius || 1; - this.skinning = false; - this.morphTargets = false; - this.morphNormals = false; + widthSegments = Math.max( 3, Math.floor( widthSegments ) || 8 ); + heightSegments = Math.max( 2, Math.floor( heightSegments ) || 6 ); - this.setValues( parameters ); + phiStart = phiStart !== undefined ? phiStart : 0; + phiLength = phiLength !== undefined ? phiLength : Math.PI * 2; -} + thetaStart = thetaStart !== undefined ? thetaStart : 0; + thetaLength = thetaLength !== undefined ? thetaLength : Math.PI; -MeshPhongMaterial.prototype = Object.create( Material.prototype ); -MeshPhongMaterial.prototype.constructor = MeshPhongMaterial; + var thetaEnd = thetaStart + thetaLength; -MeshPhongMaterial.prototype.isMeshPhongMaterial = true; + var ix, iy; -MeshPhongMaterial.prototype.copy = function ( source ) { + var index = 0; + var grid = []; - Material.prototype.copy.call( this, source ); + var vertex = new Vector3(); + var normal = new Vector3(); - this.color.copy( source.color ); - this.specular.copy( source.specular ); - this.shininess = source.shininess; + // buffers - this.map = source.map; + var indices = []; + var vertices = []; + var normals = []; + var uvs = []; - this.lightMap = source.lightMap; - this.lightMapIntensity = source.lightMapIntensity; + // generate vertices, normals and uvs - this.aoMap = source.aoMap; - this.aoMapIntensity = source.aoMapIntensity; + for ( iy = 0; iy <= heightSegments; iy ++ ) { - this.emissive.copy( source.emissive ); - this.emissiveMap = source.emissiveMap; - this.emissiveIntensity = source.emissiveIntensity; + var verticesRow = []; - this.bumpMap = source.bumpMap; - this.bumpScale = source.bumpScale; + var v = iy / heightSegments; - this.normalMap = source.normalMap; - this.normalScale.copy( source.normalScale ); + for ( ix = 0; ix <= widthSegments; ix ++ ) { - this.displacementMap = source.displacementMap; - this.displacementScale = source.displacementScale; - this.displacementBias = source.displacementBias; + var u = ix / widthSegments; - this.specularMap = source.specularMap; + // vertex - this.alphaMap = source.alphaMap; + vertex.x = - radius * Math.cos( phiStart + u * phiLength ) * Math.sin( thetaStart + v * thetaLength ); + vertex.y = radius * Math.cos( thetaStart + v * thetaLength ); + vertex.z = radius * Math.sin( phiStart + u * phiLength ) * Math.sin( thetaStart + v * thetaLength ); - this.envMap = source.envMap; - this.combine = source.combine; - this.reflectivity = source.reflectivity; - this.refractionRatio = source.refractionRatio; + vertices.push( vertex.x, vertex.y, vertex.z ); - this.wireframe = source.wireframe; - this.wireframeLinewidth = source.wireframeLinewidth; - this.wireframeLinecap = source.wireframeLinecap; - this.wireframeLinejoin = source.wireframeLinejoin; + // normal - this.skinning = source.skinning; - this.morphTargets = source.morphTargets; - this.morphNormals = source.morphNormals; + normal.set( vertex.x, vertex.y, vertex.z ).normalize(); + normals.push( normal.x, normal.y, normal.z ); - return this; + // uv -}; + uvs.push( u, 1 - v ); -/** - * @author takahirox / http://github.com/takahirox - * - * parameters = { - * gradientMap: new THREE.Texture( ) - * } - */ + verticesRow.push( index ++ ); -function MeshToonMaterial( parameters ) { + } - MeshPhongMaterial.call( this ); + grid.push( verticesRow ); - this.defines = { 'TOON': '' }; + } - this.type = 'MeshToonMaterial'; + // indices - this.gradientMap = null; + for ( iy = 0; iy < heightSegments; iy ++ ) { - this.setValues( parameters ); + for ( ix = 0; ix < widthSegments; ix ++ ) { -} + var a = grid[ iy ][ ix + 1 ]; + var b = grid[ iy ][ ix ]; + var c = grid[ iy + 1 ][ ix ]; + var d = grid[ iy + 1 ][ ix + 1 ]; -MeshToonMaterial.prototype = Object.create( MeshPhongMaterial.prototype ); -MeshToonMaterial.prototype.constructor = MeshToonMaterial; + if ( iy !== 0 || thetaStart > 0 ) indices.push( a, b, d ); + if ( iy !== heightSegments - 1 || thetaEnd < Math.PI ) indices.push( b, c, d ); -MeshToonMaterial.prototype.isMeshToonMaterial = true; + } -MeshToonMaterial.prototype.copy = function ( source ) { + } - MeshPhongMaterial.prototype.copy.call( this, source ); + // build geometry - this.gradientMap = source.gradientMap; + 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; +} -}; +SphereBufferGeometry.prototype = Object.create( BufferGeometry.prototype ); +SphereBufferGeometry.prototype.constructor = SphereBufferGeometry; /** - * @author mrdoob / http://mrdoob.com/ - * @author WestLangley / http://github.com/WestLangley - * - * parameters = { - * opacity: , - * - * bumpMap: new THREE.Texture( ), - * bumpScale: , - * - * normalMap: new THREE.Texture( ), - * normalScale: , - * - * displacementMap: new THREE.Texture( ), - * displacementScale: , - * displacementBias: , - * - * wireframe: , - * wireframeLinewidth: - * - * skinning: , - * morphTargets: , - * morphNormals: - * } + * @author Kaleb Murphy + * @author Mugen87 / https://github.com/Mugen87 */ -function MeshNormalMaterial( parameters ) { - - Material.call( this ); +// RingGeometry - this.type = 'MeshNormalMaterial'; +function RingGeometry( innerRadius, outerRadius, thetaSegments, phiSegments, thetaStart, thetaLength ) { - this.bumpMap = null; - this.bumpScale = 1; + Geometry.call( this ); - this.normalMap = null; - this.normalScale = new Vector2( 1, 1 ); + this.type = 'RingGeometry'; - this.displacementMap = null; - this.displacementScale = 1; - this.displacementBias = 0; + this.parameters = { + innerRadius: innerRadius, + outerRadius: outerRadius, + thetaSegments: thetaSegments, + phiSegments: phiSegments, + thetaStart: thetaStart, + thetaLength: thetaLength + }; - this.wireframe = false; - this.wireframeLinewidth = 1; + this.fromBufferGeometry( new RingBufferGeometry( innerRadius, outerRadius, thetaSegments, phiSegments, thetaStart, thetaLength ) ); + this.mergeVertices(); - this.fog = false; - this.lights = false; +} - this.skinning = false; - this.morphTargets = false; - this.morphNormals = false; +RingGeometry.prototype = Object.create( Geometry.prototype ); +RingGeometry.prototype.constructor = RingGeometry; - this.setValues( parameters ); +// RingBufferGeometry -} +function RingBufferGeometry( innerRadius, outerRadius, thetaSegments, phiSegments, thetaStart, thetaLength ) { -MeshNormalMaterial.prototype = Object.create( Material.prototype ); -MeshNormalMaterial.prototype.constructor = MeshNormalMaterial; + BufferGeometry.call( this ); -MeshNormalMaterial.prototype.isMeshNormalMaterial = true; + this.type = 'RingBufferGeometry'; -MeshNormalMaterial.prototype.copy = function ( source ) { + this.parameters = { + innerRadius: innerRadius, + outerRadius: outerRadius, + thetaSegments: thetaSegments, + phiSegments: phiSegments, + thetaStart: thetaStart, + thetaLength: thetaLength + }; - Material.prototype.copy.call( this, source ); + innerRadius = innerRadius || 0.5; + outerRadius = outerRadius || 1; - this.bumpMap = source.bumpMap; - this.bumpScale = source.bumpScale; + thetaStart = thetaStart !== undefined ? thetaStart : 0; + thetaLength = thetaLength !== undefined ? thetaLength : Math.PI * 2; - this.normalMap = source.normalMap; - this.normalScale.copy( source.normalScale ); + thetaSegments = thetaSegments !== undefined ? Math.max( 3, thetaSegments ) : 8; + phiSegments = phiSegments !== undefined ? Math.max( 1, phiSegments ) : 1; - this.displacementMap = source.displacementMap; - this.displacementScale = source.displacementScale; - this.displacementBias = source.displacementBias; + // buffers - this.wireframe = source.wireframe; - this.wireframeLinewidth = source.wireframeLinewidth; + var indices = []; + var vertices = []; + var normals = []; + var uvs = []; - this.skinning = source.skinning; - this.morphTargets = source.morphTargets; - this.morphNormals = source.morphNormals; + // some helper variables - return this; + var segment; + var radius = innerRadius; + var radiusStep = ( ( outerRadius - innerRadius ) / phiSegments ); + var vertex = new Vector3(); + var uv = new Vector2(); + var j, i; -}; + // generate vertices, normals and uvs -/** - * @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.TextureCube( [posx, negx, posy, negy, posz, negz] ), - * combine: THREE.Multiply, - * reflectivity: , - * refractionRatio: , - * - * wireframe: , - * wireframeLinewidth: , - * - * skinning: , - * morphTargets: , - * morphNormals: - * } - */ + for ( j = 0; j <= phiSegments; j ++ ) { -function MeshLambertMaterial( parameters ) { + for ( i = 0; i <= thetaSegments; i ++ ) { - Material.call( this ); + // values are generate from the inside of the ring to the outside - this.type = 'MeshLambertMaterial'; + segment = thetaStart + i / thetaSegments * thetaLength; - this.color = new Color( 0xffffff ); // diffuse + // vertex - this.map = null; + vertex.x = radius * Math.cos( segment ); + vertex.y = radius * Math.sin( segment ); - this.lightMap = null; - this.lightMapIntensity = 1.0; + vertices.push( vertex.x, vertex.y, vertex.z ); - this.aoMap = null; - this.aoMapIntensity = 1.0; + // normal - this.emissive = new Color( 0x000000 ); - this.emissiveIntensity = 1.0; - this.emissiveMap = null; + normals.push( 0, 0, 1 ); - this.specularMap = null; + // uv - this.alphaMap = null; + uv.x = ( vertex.x / outerRadius + 1 ) / 2; + uv.y = ( vertex.y / outerRadius + 1 ) / 2; - this.envMap = null; - this.combine = MultiplyOperation; - this.reflectivity = 1; - this.refractionRatio = 0.98; + uvs.push( uv.x, uv.y ); - this.wireframe = false; - this.wireframeLinewidth = 1; - this.wireframeLinecap = 'round'; - this.wireframeLinejoin = 'round'; + } - this.skinning = false; - this.morphTargets = false; - this.morphNormals = false; + // increase the radius for next row of vertices - this.setValues( parameters ); + radius += radiusStep; -} + } -MeshLambertMaterial.prototype = Object.create( Material.prototype ); -MeshLambertMaterial.prototype.constructor = MeshLambertMaterial; + // indices -MeshLambertMaterial.prototype.isMeshLambertMaterial = true; + for ( j = 0; j < phiSegments; j ++ ) { -MeshLambertMaterial.prototype.copy = function ( source ) { + var thetaSegmentLevel = j * ( thetaSegments + 1 ); - Material.prototype.copy.call( this, source ); + for ( i = 0; i < thetaSegments; i ++ ) { - this.color.copy( source.color ); + segment = i + thetaSegmentLevel; - this.map = source.map; + var a = segment; + var b = segment + thetaSegments + 1; + var c = segment + thetaSegments + 2; + var d = segment + 1; - this.lightMap = source.lightMap; - this.lightMapIntensity = source.lightMapIntensity; + // faces - this.aoMap = source.aoMap; - this.aoMapIntensity = source.aoMapIntensity; + indices.push( a, b, d ); + indices.push( b, c, d ); - this.emissive.copy( source.emissive ); - this.emissiveMap = source.emissiveMap; - this.emissiveIntensity = source.emissiveIntensity; + } - this.specularMap = source.specularMap; + } - this.alphaMap = source.alphaMap; + // build geometry - 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; - this.morphNormals = source.morphNormals; + 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; +} -}; +RingBufferGeometry.prototype = Object.create( BufferGeometry.prototype ); +RingBufferGeometry.prototype.constructor = RingBufferGeometry; /** - * @author alteredq / http://alteredqualia.com/ - * - * parameters = { - * color: , - * opacity: , - * - * linewidth: , - * - * scale: , - * dashSize: , - * gapSize: - * } + * @author zz85 / https://github.com/zz85 + * @author bhouston / http://clara.io + * @author Mugen87 / https://github.com/Mugen87 */ -function LineDashedMaterial( parameters ) { - - LineBasicMaterial.call( this ); +// LatheGeometry - this.type = 'LineDashedMaterial'; +function LatheGeometry( points, segments, phiStart, phiLength ) { - this.scale = 1; - this.dashSize = 3; - this.gapSize = 1; + Geometry.call( this ); - this.setValues( parameters ); + this.type = 'LatheGeometry'; -} + this.parameters = { + points: points, + segments: segments, + phiStart: phiStart, + phiLength: phiLength + }; -LineDashedMaterial.prototype = Object.create( LineBasicMaterial.prototype ); -LineDashedMaterial.prototype.constructor = LineDashedMaterial; + this.fromBufferGeometry( new LatheBufferGeometry( points, segments, phiStart, phiLength ) ); + this.mergeVertices(); -LineDashedMaterial.prototype.isLineDashedMaterial = true; +} -LineDashedMaterial.prototype.copy = function ( source ) { +LatheGeometry.prototype = Object.create( Geometry.prototype ); +LatheGeometry.prototype.constructor = LatheGeometry; - LineBasicMaterial.prototype.copy.call( this, source ); +// LatheBufferGeometry - this.scale = source.scale; - this.dashSize = source.dashSize; - this.gapSize = source.gapSize; +function LatheBufferGeometry( points, segments, phiStart, phiLength ) { - return this; + BufferGeometry.call( this ); -}; + this.type = 'LatheBufferGeometry'; + this.parameters = { + points: points, + segments: segments, + phiStart: phiStart, + phiLength: phiLength + }; + segments = Math.floor( segments ) || 12; + phiStart = phiStart || 0; + phiLength = phiLength || Math.PI * 2; -var Materials = 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, - LineDashedMaterial: LineDashedMaterial, - LineBasicMaterial: LineBasicMaterial, - Material: Material -}); + // clamp phiLength so it's in range of [ 0, 2PI ] -/** - * @author mrdoob / http://mrdoob.com/ - */ + phiLength = _Math.clamp( phiLength, 0, Math.PI * 2 ); -var Cache = { - enabled: false, + // buffers - files: {}, + var indices = []; + var vertices = []; + var uvs = []; - add: function ( key, file ) { + // helper variables - if ( this.enabled === false ) return; + var base; + var inverseSegments = 1.0 / segments; + var vertex = new Vector3(); + var uv = new Vector2(); + var i, j; - // console.log( 'THREE.Cache', 'Adding key:', key ); + // generate vertices and uvs - this.files[ key ] = file; + for ( i = 0; i <= segments; i ++ ) { - }, + var phi = phiStart + i * inverseSegments * phiLength; - get: function ( key ) { + var sin = Math.sin( phi ); + var cos = Math.cos( phi ); - if ( this.enabled === false ) return; + for ( j = 0; j <= ( points.length - 1 ); j ++ ) { - // console.log( 'THREE.Cache', 'Checking key:', key ); + // vertex - return this.files[ key ]; + 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 ); - remove: function ( key ) { + // uv - delete this.files[ key ]; + uv.x = i / segments; + uv.y = j / ( points.length - 1 ); - }, + uvs.push( uv.x, uv.y ); - clear: function () { - this.files = {}; + } } -}; + // indices -/** - * @author mrdoob / http://mrdoob.com/ - */ + for ( i = 0; i < segments; i ++ ) { -function LoadingManager( onLoad, onProgress, onError ) { + for ( j = 0; j < ( points.length - 1 ); j ++ ) { - var scope = this; + base = j + i * points.length; - var isLoading = false; - var itemsLoaded = 0; - var itemsTotal = 0; - var urlModifier = undefined; + var a = base; + var b = base + points.length; + var c = base + points.length + 1; + var d = base + 1; - this.onStart = undefined; - this.onLoad = onLoad; - this.onProgress = onProgress; - this.onError = onError; + // faces - this.itemStart = function ( url ) { + indices.push( a, b, d ); + indices.push( b, c, d ); - itemsTotal ++; + } - if ( isLoading === false ) { + } - if ( scope.onStart !== undefined ) { + // build geometry - scope.onStart( url, itemsLoaded, itemsTotal ); + this.setIndex( indices ); + this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); + this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); - } + // generate normals - } + this.computeVertexNormals(); - isLoading = true; + // if the geometry is closed, we need to average the normals along the seam. + // because the corresponding vertices are identical (but still have different UVs). - }; + if ( phiLength === Math.PI * 2 ) { - this.itemEnd = function ( url ) { + var normals = this.attributes.normal.array; + var n1 = new Vector3(); + var n2 = new Vector3(); + var n = new Vector3(); - itemsLoaded ++; + // this is the buffer offset for the last line of vertices - if ( scope.onProgress !== undefined ) { + base = segments * points.length * 3; - scope.onProgress( url, itemsLoaded, itemsTotal ); + for ( i = 0, j = 0; i < points.length; i ++, j += 3 ) { - } + // select the normal of the vertex in the first line - if ( itemsLoaded === itemsTotal ) { + n1.x = normals[ j + 0 ]; + n1.y = normals[ j + 1 ]; + n1.z = normals[ j + 2 ]; - isLoading = false; + // select the normal of the vertex in the last line - if ( scope.onLoad !== undefined ) { + n2.x = normals[ base + j + 0 ]; + n2.y = normals[ base + j + 1 ]; + n2.z = normals[ base + j + 2 ]; - scope.onLoad(); + // average normals - } + n.addVectors( n1, n2 ).normalize(); - } + // assign the new values to both normals - }; + normals[ j + 0 ] = normals[ base + j + 0 ] = n.x; + normals[ j + 1 ] = normals[ base + j + 1 ] = n.y; + normals[ j + 2 ] = normals[ base + j + 2 ] = n.z; - this.itemError = function ( url ) { + } - if ( scope.onError !== undefined ) { + } - scope.onError( url ); +} - } +LatheBufferGeometry.prototype = Object.create( BufferGeometry.prototype ); +LatheBufferGeometry.prototype.constructor = LatheBufferGeometry; - }; +/** + * @author jonobr1 / http://jonobr1.com + * @author Mugen87 / https://github.com/Mugen87 + */ - this.resolveURL = function ( url ) { +// ShapeGeometry - if ( urlModifier ) { +function ShapeGeometry( shapes, curveSegments ) { - return urlModifier( url ); + Geometry.call( this ); - } + this.type = 'ShapeGeometry'; - return url; + if ( typeof curveSegments === 'object' ) { - }; + console.warn( 'THREE.ShapeGeometry: Options parameter has been removed.' ); - this.setURLModifier = function ( transform ) { + curveSegments = curveSegments.curveSegments; - urlModifier = transform; - return this; + } + this.parameters = { + shapes: shapes, + curveSegments: curveSegments }; + this.fromBufferGeometry( new ShapeBufferGeometry( shapes, curveSegments ) ); + this.mergeVertices(); + } -var DefaultLoadingManager = new LoadingManager(); +ShapeGeometry.prototype = Object.create( Geometry.prototype ); +ShapeGeometry.prototype.constructor = ShapeGeometry; -/** - * @author mrdoob / http://mrdoob.com/ - */ +ShapeGeometry.prototype.toJSON = function () { -var loading = {}; + var data = Geometry.prototype.toJSON.call( this ); -function FileLoader( manager ) { + var shapes = this.parameters.shapes; - this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager; + return toJSON$1( shapes, data ); -} +}; -Object.assign( FileLoader.prototype, { +// ShapeBufferGeometry - load: function ( url, onLoad, onProgress, onError ) { +function ShapeBufferGeometry( shapes, curveSegments ) { - if ( url === undefined ) url = ''; + BufferGeometry.call( this ); - if ( this.path !== undefined ) url = this.path + url; + this.type = 'ShapeBufferGeometry'; - url = this.manager.resolveURL( url ); + this.parameters = { + shapes: shapes, + curveSegments: curveSegments + }; - var scope = this; + curveSegments = curveSegments || 12; - var cached = Cache.get( url ); + // buffers - if ( cached !== undefined ) { + var indices = []; + var vertices = []; + var normals = []; + var uvs = []; - scope.manager.itemStart( url ); + // helper variables - setTimeout( function () { + var groupStart = 0; + var groupCount = 0; - if ( onLoad ) onLoad( cached ); + // allow single and array values for "shapes" parameter - scope.manager.itemEnd( url ); + if ( Array.isArray( shapes ) === false ) { - }, 0 ); + addShape( shapes ); - return cached; + } else { - } + for ( var i = 0; i < shapes.length; i ++ ) { - // Check if request is duplicate + addShape( shapes[ i ] ); - if ( loading[ url ] !== undefined ) { + this.addGroup( groupStart, groupCount, i ); // enables MultiMaterial support - loading[ url ].push( { + groupStart += groupCount; + groupCount = 0; - onLoad: onLoad, - onProgress: onProgress, - onError: onError + } - } ); + } - 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 ) ); - // 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 ) { + // helper functions - var mimeType = dataUriRegexResult[ 1 ]; - var isBase64 = !! dataUriRegexResult[ 2 ]; - var data = dataUriRegexResult[ 3 ]; + function addShape( shape ) { - data = window.decodeURIComponent( data ); + var i, l, shapeHole; - if ( isBase64 ) data = window.atob( data ); + var indexOffset = vertices.length / 3; + var points = shape.extractPoints( curveSegments ); - try { + var shapeVertices = points.shape; + var shapeHoles = points.holes; - var response; - var responseType = ( this.responseType || '' ).toLowerCase(); + // check direction of vertices - switch ( responseType ) { + if ( ShapeUtils.isClockWise( shapeVertices ) === false ) { - case 'arraybuffer': - case 'blob': + shapeVertices = shapeVertices.reverse(); - var view = new Uint8Array( data.length ); + } - for ( var i = 0; i < data.length; i ++ ) { + for ( i = 0, l = shapeHoles.length; i < l; i ++ ) { - view[ i ] = data.charCodeAt( i ); + shapeHole = shapeHoles[ i ]; - } + if ( ShapeUtils.isClockWise( shapeHole ) === true ) { - if ( responseType === 'blob' ) { + shapeHoles[ i ] = shapeHole.reverse(); - response = new Blob( [ view.buffer ], { type: mimeType } ); + } - } else { + } - response = view.buffer; + var faces = ShapeUtils.triangulateShape( shapeVertices, shapeHoles ); - } + // join vertices of inner and outer paths to a single array - break; + for ( i = 0, l = shapeHoles.length; i < l; i ++ ) { - case 'document': + shapeHole = shapeHoles[ i ]; + shapeVertices = shapeVertices.concat( shapeHole ); - var parser = new DOMParser(); - response = parser.parseFromString( data, mimeType ); + } - break; + // vertices, normals, uvs - case 'json': + for ( i = 0, l = shapeVertices.length; i < l; i ++ ) { - response = JSON.parse( data ); + var vertex = shapeVertices[ i ]; - break; + vertices.push( vertex.x, vertex.y, 0 ); + normals.push( 0, 0, 1 ); + uvs.push( vertex.x, vertex.y ); // world uvs - default: // 'text' or other + } - response = data; + // incides - break; + for ( i = 0, l = faces.length; i < l; i ++ ) { - } + var face = faces[ i ]; - // Wait for next browser tick like standard XMLHttpRequest event dispatching does - window.setTimeout( function () { + var a = face[ 0 ] + indexOffset; + var b = face[ 1 ] + indexOffset; + var c = face[ 2 ] + indexOffset; - if ( onLoad ) onLoad( response ); + indices.push( a, b, c ); + groupCount += 3; - scope.manager.itemEnd( url ); + } - }, 0 ); + } - } catch ( error ) { +} - // Wait for next browser tick like standard XMLHttpRequest event dispatching does - window.setTimeout( function () { +ShapeBufferGeometry.prototype = Object.create( BufferGeometry.prototype ); +ShapeBufferGeometry.prototype.constructor = ShapeBufferGeometry; - if ( onError ) onError( error ); +ShapeBufferGeometry.prototype.toJSON = function () { - scope.manager.itemEnd( url ); - scope.manager.itemError( url ); + var data = BufferGeometry.prototype.toJSON.call( this ); - }, 0 ); + var shapes = this.parameters.shapes; - } + return toJSON$1( shapes, data ); - } else { +}; - // Initialise array for duplicate requests +// - loading[ url ] = []; +function toJSON$1( shapes, data ) { - loading[ url ].push( { + data.shapes = []; - onLoad: onLoad, - onProgress: onProgress, - onError: onError + if ( Array.isArray( shapes ) ) { - } ); + for ( var i = 0, l = shapes.length; i < l; i ++ ) { - var request = new XMLHttpRequest(); + var shape = shapes[ i ]; - request.open( 'GET', url, true ); + data.shapes.push( shape.uuid ); - request.addEventListener( 'load', function ( event ) { + } - var response = this.response; + } else { - Cache.add( url, response ); + data.shapes.push( shapes.uuid ); - var callbacks = loading[ url ]; + } - delete loading[ url ]; + return data; - if ( this.status === 200 ) { +} - for ( var i = 0, il = callbacks.length; i < il; i ++ ) { +/** + * @author WestLangley / http://github.com/WestLangley + * @author Mugen87 / https://github.com/Mugen87 + */ - var callback = callbacks[ i ]; - if ( callback.onLoad ) callback.onLoad( response ); +function EdgesGeometry( geometry, thresholdAngle ) { - } + BufferGeometry.call( this ); - scope.manager.itemEnd( url ); + this.type = 'EdgesGeometry'; - } else if ( this.status === 0 ) { + this.parameters = { + thresholdAngle: thresholdAngle + }; - // Some browsers return HTTP Status 0 when using non-http protocol - // e.g. 'file://' or 'data://'. Handle as success. + thresholdAngle = ( thresholdAngle !== undefined ) ? thresholdAngle : 1; - console.warn( 'THREE.FileLoader: HTTP Status 0 received.' ); + // buffer - for ( var i = 0, il = callbacks.length; i < il; i ++ ) { + var vertices = []; - var callback = callbacks[ i ]; - if ( callback.onLoad ) callback.onLoad( response ); + // helper variables - } + var thresholdDot = Math.cos( _Math.DEG2RAD * thresholdAngle ); + var edge = [ 0, 0 ], edges = {}, edge1, edge2; + var key, keys = [ 'a', 'b', 'c' ]; - scope.manager.itemEnd( url ); + // prepare source geometry - } else { + var geometry2; - for ( var i = 0, il = callbacks.length; i < il; i ++ ) { + if ( geometry.isBufferGeometry ) { - var callback = callbacks[ i ]; - if ( callback.onError ) callback.onError( event ); + geometry2 = new Geometry(); + geometry2.fromBufferGeometry( geometry ); - } + } else { - scope.manager.itemEnd( url ); - scope.manager.itemError( url ); + geometry2 = geometry.clone(); - } + } - }, false ); + geometry2.mergeVertices(); + geometry2.computeFaceNormals(); - request.addEventListener( 'progress', function ( event ) { + var sourceVertices = geometry2.vertices; + var faces = geometry2.faces; - var callbacks = loading[ url ]; + // now create a data structure where each entry represents an edge with its adjoining faces - for ( var i = 0, il = callbacks.length; i < il; i ++ ) { + for ( var i = 0, l = faces.length; i < l; i ++ ) { - var callback = callbacks[ i ]; - if ( callback.onProgress ) callback.onProgress( event ); + var face = faces[ i ]; - } + for ( var j = 0; j < 3; j ++ ) { - }, false ); + edge1 = face[ keys[ j ] ]; + edge2 = face[ keys[ ( j + 1 ) % 3 ] ]; + edge[ 0 ] = Math.min( edge1, edge2 ); + edge[ 1 ] = Math.max( edge1, edge2 ); - request.addEventListener( 'error', function ( event ) { + key = edge[ 0 ] + ',' + edge[ 1 ]; - var callbacks = loading[ url ]; + if ( edges[ key ] === undefined ) { - delete loading[ url ]; + edges[ key ] = { index1: edge[ 0 ], index2: edge[ 1 ], face1: i, face2: undefined }; - for ( var i = 0, il = callbacks.length; i < il; i ++ ) { + } else { - var callback = callbacks[ i ]; - if ( callback.onError ) callback.onError( event ); + edges[ key ].face2 = i; - } + } - scope.manager.itemEnd( url ); - scope.manager.itemError( url ); + } - }, false ); + } - if ( this.responseType !== undefined ) request.responseType = this.responseType; - if ( this.withCredentials !== undefined ) request.withCredentials = this.withCredentials; + // generate vertices - if ( request.overrideMimeType ) request.overrideMimeType( this.mimeType !== undefined ? this.mimeType : 'text/plain' ); + for ( key in edges ) { - for ( var header in this.requestHeader ) { + var e = edges[ key ]; - request.setRequestHeader( header, this.requestHeader[ header ] ); + // 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 ( e.face2 === undefined || faces[ e.face1 ].normal.dot( faces[ e.face2 ].normal ) <= thresholdDot ) { - request.send( null ); + 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 ); } - scope.manager.itemStart( url ); + } - return request; + // build geometry - }, + this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - setPath: function ( value ) { +} - this.path = value; - return this; +EdgesGeometry.prototype = Object.create( BufferGeometry.prototype ); +EdgesGeometry.prototype.constructor = EdgesGeometry; - }, +/** + * @author mrdoob / http://mrdoob.com/ + * @author Mugen87 / https://github.com/Mugen87 + */ - setResponseType: function ( value ) { +// CylinderGeometry - this.responseType = value; - return this; +function CylinderGeometry( radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ) { - }, + Geometry.call( this ); - setWithCredentials: function ( value ) { + this.type = 'CylinderGeometry'; - this.withCredentials = value; - return this; + 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(); - setMimeType: function ( value ) { +} - this.mimeType = value; - return this; +CylinderGeometry.prototype = Object.create( Geometry.prototype ); +CylinderGeometry.prototype.constructor = CylinderGeometry; - }, +// CylinderBufferGeometry - setRequestHeader: function ( value ) { +function CylinderBufferGeometry( radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ) { - this.requestHeader = value; - return this; + BufferGeometry.call( this ); - } + this.type = 'CylinderBufferGeometry'; -} ); + this.parameters = { + radiusTop: radiusTop, + radiusBottom: radiusBottom, + height: height, + radialSegments: radialSegments, + heightSegments: heightSegments, + openEnded: openEnded, + thetaStart: thetaStart, + thetaLength: thetaLength + }; -/** - * @author mrdoob / http://mrdoob.com/ - * - * Abstract Base class to block based textures loader (dds, pvr, ...) - */ + var scope = this; -function CompressedTextureLoader( manager ) { + radiusTop = radiusTop !== undefined ? radiusTop : 1; + radiusBottom = radiusBottom !== undefined ? radiusBottom : 1; + height = height || 1; - this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager; + radialSegments = Math.floor( radialSegments ) || 8; + heightSegments = Math.floor( heightSegments ) || 1; - // override in sub classes - this._parser = null; + openEnded = openEnded !== undefined ? openEnded : false; + thetaStart = thetaStart !== undefined ? thetaStart : 0.0; + thetaLength = thetaLength !== undefined ? thetaLength : Math.PI * 2; -} + // buffers -Object.assign( CompressedTextureLoader.prototype, { + var indices = []; + var vertices = []; + var normals = []; + var uvs = []; - load: function ( url, onLoad, onProgress, onError ) { + // helper variables - var scope = this; + var index = 0; + var indexArray = []; + var halfHeight = height / 2; + var groupStart = 0; - var images = []; + // generate geometry - var texture = new CompressedTexture(); - texture.image = images; + generateTorso(); - var loader = new FileLoader( this.manager ); - loader.setPath( this.path ); - loader.setResponseType( 'arraybuffer' ); + if ( openEnded === false ) { - function loadTexture( i ) { + if ( radiusTop > 0 ) generateCap( true ); + if ( radiusBottom > 0 ) generateCap( false ); - loader.load( url[ i ], function ( buffer ) { + } - var texDatas = scope._parser( buffer, true ); + // build geometry - images[ i ] = { - width: texDatas.width, - height: texDatas.height, - format: texDatas.format, - mipmaps: texDatas.mipmaps - }; + this.setIndex( indices ); + this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); + this.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); + this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); - loaded += 1; + function generateTorso() { - if ( loaded === 6 ) { + var x, y; + var normal = new Vector3(); + var vertex = new Vector3(); - if ( texDatas.mipmapCount === 1 ) - texture.minFilter = LinearFilter; + var groupCount = 0; - texture.format = texDatas.format; - texture.needsUpdate = true; + // this will be used to calculate the normal + var slope = ( radiusBottom - radiusTop ) / height; - if ( onLoad ) onLoad( texture ); + // generate vertices, normals and uvs - } + for ( y = 0; y <= heightSegments; y ++ ) { - }, onProgress, onError ); + var indexRow = []; - } + var v = y / heightSegments; - if ( Array.isArray( url ) ) { + // calculate the radius of the current row - var loaded = 0; + var radius = v * ( radiusBottom - radiusTop ) + radiusTop; - for ( var i = 0, il = url.length; i < il; ++ i ) { + for ( x = 0; x <= radialSegments; x ++ ) { - loadTexture( i ); + var u = x / radialSegments; - } + var theta = u * thetaLength + thetaStart; - } else { + var sinTheta = Math.sin( theta ); + var cosTheta = Math.cos( theta ); - // compressed cubemap texture stored in a single DDS file + // vertex - loader.load( url, function ( buffer ) { + vertex.x = radius * sinTheta; + vertex.y = - v * height + halfHeight; + vertex.z = radius * cosTheta; + vertices.push( vertex.x, vertex.y, vertex.z ); - var texDatas = scope._parser( buffer, true ); + // normal - if ( texDatas.isCubemap ) { + normal.set( sinTheta, slope, cosTheta ).normalize(); + normals.push( normal.x, normal.y, normal.z ); - var faces = texDatas.mipmaps.length / texDatas.mipmapCount; + // uv - for ( var f = 0; f < faces; f ++ ) { + uvs.push( u, 1 - v ); - images[ f ] = { mipmaps: [] }; + // save index of vertex in respective row - for ( var i = 0; i < texDatas.mipmapCount; i ++ ) { + indexRow.push( index ++ ); - 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; + } - } + // now save vertices of the row in our index array - } + indexArray.push( indexRow ); - } else { + } - texture.image.width = texDatas.width; - texture.image.height = texDatas.height; - texture.mipmaps = texDatas.mipmaps; + // generate indices - } + for ( x = 0; x < radialSegments; x ++ ) { - if ( texDatas.mipmapCount === 1 ) { + for ( y = 0; y < heightSegments; y ++ ) { - texture.minFilter = LinearFilter; + // we use the index array to access the correct indices - } + var a = indexArray[ y ][ x ]; + var b = indexArray[ y + 1 ][ x ]; + var c = indexArray[ y + 1 ][ x + 1 ]; + var d = indexArray[ y ][ x + 1 ]; - texture.format = texDatas.format; - texture.needsUpdate = true; + // faces - if ( onLoad ) onLoad( texture ); + indices.push( a, b, d ); + indices.push( b, c, d ); - }, onProgress, onError ); + // update group counter + + groupCount += 6; + + } } - return texture; + // add a group to the geometry. this will ensure multi material support - }, + scope.addGroup( groupStart, groupCount, 0 ); - setPath: function ( value ) { + // calculate new start value for groups - this.path = value; - return this; + groupStart += groupCount; } -} ); + function generateCap( top ) { -/** - * @author Nikos M. / https://github.com/foo123/ - * - * Abstract Base class to load generic binary textures formats (rgbe, hdr, ...) - */ + var x, centerIndexStart, centerIndexEnd; -function DataTextureLoader( manager ) { + var uv = new Vector2(); + var vertex = new Vector3(); - this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager; + var groupCount = 0; - // override in sub classes - this._parser = null; + var radius = ( top === true ) ? radiusTop : radiusBottom; + var sign = ( top === true ) ? 1 : - 1; -} + // save the index of the first center vertex + centerIndexStart = index; -Object.assign( DataTextureLoader.prototype, { + // 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 - load: function ( url, onLoad, onProgress, onError ) { + for ( x = 1; x <= radialSegments; x ++ ) { - var scope = this; + // vertex - var texture = new DataTexture(); + vertices.push( 0, halfHeight * sign, 0 ); - var loader = new FileLoader( this.manager ); - loader.setResponseType( 'arraybuffer' ); + // normal - loader.load( url, function ( buffer ) { + normals.push( 0, sign, 0 ); - var texData = scope._parser( buffer ); + // uv - if ( ! texData ) return; + uvs.push( 0.5, 0.5 ); - if ( undefined !== texData.image ) { + // increase index - texture.image = texData.image; + index ++; - } else if ( undefined !== texData.data ) { + } - texture.image.width = texData.width; - texture.image.height = texData.height; - texture.image.data = texData.data; + // save the index of the last center vertex - } + centerIndexEnd = index; - texture.wrapS = undefined !== texData.wrapS ? texData.wrapS : ClampToEdgeWrapping; - texture.wrapT = undefined !== texData.wrapT ? texData.wrapT : ClampToEdgeWrapping; + // now we generate the surrounding vertices, normals and uvs - texture.magFilter = undefined !== texData.magFilter ? texData.magFilter : LinearFilter; - texture.minFilter = undefined !== texData.minFilter ? texData.minFilter : LinearMipMapLinearFilter; + for ( x = 0; x <= radialSegments; x ++ ) { - texture.anisotropy = undefined !== texData.anisotropy ? texData.anisotropy : 1; + var u = x / radialSegments; + var theta = u * thetaLength + thetaStart; - if ( undefined !== texData.format ) { + var cosTheta = Math.cos( theta ); + var sinTheta = Math.sin( theta ); - texture.format = texData.format; + // vertex - } - if ( undefined !== texData.type ) { + vertex.x = radius * sinTheta; + vertex.y = halfHeight * sign; + vertex.z = radius * cosTheta; + vertices.push( vertex.x, vertex.y, vertex.z ); - texture.type = texData.type; + // normal - } + normals.push( 0, sign, 0 ); - if ( undefined !== texData.mipmaps ) { + // uv - texture.mipmaps = texData.mipmaps; + uv.x = ( cosTheta * 0.5 ) + 0.5; + uv.y = ( sinTheta * 0.5 * sign ) + 0.5; + uvs.push( uv.x, uv.y ); - } + // increase index - if ( 1 === texData.mipmapCount ) { + index ++; - texture.minFilter = LinearFilter; + } - } + // generate indices - texture.needsUpdate = true; + for ( x = 0; x < radialSegments; x ++ ) { - if ( onLoad ) onLoad( texture, texData ); + var c = centerIndexStart + x; + var i = centerIndexEnd + x; - }, onProgress, onError ); + if ( top === true ) { + // face top - return texture; + indices.push( i, i + 1, c ); - } + } else { -} ); + // face bottom -/** - * @author mrdoob / http://mrdoob.com/ - */ + indices.push( i + 1, i, c ); -function ImageLoader( manager ) { + } - this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager; + groupCount += 3; -} + } -Object.assign( ImageLoader.prototype, { + // add a group to the geometry. this will ensure multi material support - crossOrigin: 'Anonymous', + scope.addGroup( groupStart, groupCount, top === true ? 1 : 2 ); - load: function ( url, onLoad, onProgress, onError ) { + // calculate new start value for groups - if ( url === undefined ) url = ''; + groupStart += groupCount; - if ( this.path !== undefined ) url = this.path + url; + } - url = this.manager.resolveURL( url ); +} - var scope = this; +CylinderBufferGeometry.prototype = Object.create( BufferGeometry.prototype ); +CylinderBufferGeometry.prototype.constructor = CylinderBufferGeometry; - var cached = Cache.get( url ); +/** + * @author abelnation / http://github.com/abelnation + */ - if ( cached !== undefined ) { +// ConeGeometry - scope.manager.itemStart( url ); +function ConeGeometry( radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ) { - setTimeout( function () { + CylinderGeometry.call( this, 0, radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ); - if ( onLoad ) onLoad( cached ); + this.type = 'ConeGeometry'; - scope.manager.itemEnd( url ); + this.parameters = { + radius: radius, + height: height, + radialSegments: radialSegments, + heightSegments: heightSegments, + openEnded: openEnded, + thetaStart: thetaStart, + thetaLength: thetaLength + }; - }, 0 ); +} - return cached; +ConeGeometry.prototype = Object.create( CylinderGeometry.prototype ); +ConeGeometry.prototype.constructor = ConeGeometry; - } +// ConeBufferGeometry - var image = document.createElementNS( 'http://www.w3.org/1999/xhtml', 'img' ); +function ConeBufferGeometry( radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ) { - image.addEventListener( 'load', function () { + CylinderBufferGeometry.call( this, 0, radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ); - Cache.add( url, this ); + this.type = 'ConeBufferGeometry'; - if ( onLoad ) onLoad( this ); + this.parameters = { + radius: radius, + height: height, + radialSegments: radialSegments, + heightSegments: heightSegments, + openEnded: openEnded, + thetaStart: thetaStart, + thetaLength: thetaLength + }; - scope.manager.itemEnd( url ); +} - }, false ); +ConeBufferGeometry.prototype = Object.create( CylinderBufferGeometry.prototype ); +ConeBufferGeometry.prototype.constructor = ConeBufferGeometry; - /* - image.addEventListener( 'progress', function ( event ) { +/** + * @author benaadams / https://twitter.com/ben_a_adams + * @author Mugen87 / https://github.com/Mugen87 + * @author hughes + */ - if ( onProgress ) onProgress( event ); +// CircleGeometry - }, false ); - */ +function CircleGeometry( radius, segments, thetaStart, thetaLength ) { - image.addEventListener( 'error', function ( event ) { + Geometry.call( this ); - if ( onError ) onError( event ); + this.type = 'CircleGeometry'; - scope.manager.itemEnd( url ); - scope.manager.itemError( url ); + this.parameters = { + radius: radius, + segments: segments, + thetaStart: thetaStart, + thetaLength: thetaLength + }; - }, false ); + this.fromBufferGeometry( new CircleBufferGeometry( radius, segments, thetaStart, thetaLength ) ); + this.mergeVertices(); - if ( url.substr( 0, 5 ) !== 'data:' ) { +} - if ( this.crossOrigin !== undefined ) image.crossOrigin = this.crossOrigin; +CircleGeometry.prototype = Object.create( Geometry.prototype ); +CircleGeometry.prototype.constructor = CircleGeometry; - } +// CircleBufferGeometry - scope.manager.itemStart( url ); +function CircleBufferGeometry( radius, segments, thetaStart, thetaLength ) { - image.src = url; + BufferGeometry.call( this ); - return image; + this.type = 'CircleBufferGeometry'; - }, + this.parameters = { + radius: radius, + segments: segments, + thetaStart: thetaStart, + thetaLength: thetaLength + }; - setCrossOrigin: function ( value ) { + radius = radius || 1; + segments = segments !== undefined ? Math.max( 3, segments ) : 8; - this.crossOrigin = value; - return this; + thetaStart = thetaStart !== undefined ? thetaStart : 0; + thetaLength = thetaLength !== undefined ? thetaLength : Math.PI * 2; - }, + // buffers - setPath: function ( value ) { + var indices = []; + var vertices = []; + var normals = []; + var uvs = []; - this.path = value; - return this; + // helper variables - } + var i, s; + var vertex = new Vector3(); + var uv = new Vector2(); -} ); + // center point -/** - * @author mrdoob / http://mrdoob.com/ - */ + vertices.push( 0, 0, 0 ); + normals.push( 0, 0, 1 ); + uvs.push( 0.5, 0.5 ); -function CubeTextureLoader( manager ) { + for ( s = 0, i = 3; s <= segments; s ++, i += 3 ) { - this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager; + var segment = thetaStart + s / segments * thetaLength; -} + // vertex -Object.assign( CubeTextureLoader.prototype, { + vertex.x = radius * Math.cos( segment ); + vertex.y = radius * Math.sin( segment ); - crossOrigin: 'Anonymous', + vertices.push( vertex.x, vertex.y, vertex.z ); - load: function ( urls, onLoad, onProgress, onError ) { - - var texture = new CubeTexture(); - - var loader = new ImageLoader( this.manager ); - loader.setCrossOrigin( this.crossOrigin ); - loader.setPath( this.path ); - - var loaded = 0; - - function loadTexture( i ) { - - loader.load( urls[ i ], function ( image ) { - - texture.images[ i ] = image; - - loaded ++; - - if ( loaded === 6 ) { - - texture.needsUpdate = true; + // normal - if ( onLoad ) onLoad( texture ); + normals.push( 0, 0, 1 ); - } + // uvs - }, undefined, onError ); + uv.x = ( vertices[ i ] / radius + 1 ) / 2; + uv.y = ( vertices[ i + 1 ] / radius + 1 ) / 2; - } + uvs.push( uv.x, uv.y ); - for ( var i = 0; i < urls.length; ++ i ) { + } - loadTexture( i ); + // indices - } + for ( i = 1; i <= segments; i ++ ) { - return texture; + indices.push( i, i + 1, 0 ); - }, + } - setCrossOrigin: function ( value ) { + // build geometry - this.crossOrigin = value; - return 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 ) ); - }, +} - setPath: function ( value ) { +CircleBufferGeometry.prototype = Object.create( BufferGeometry.prototype ); +CircleBufferGeometry.prototype.constructor = CircleBufferGeometry; - this.path = value; - return this; - } -} ); +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 +}); /** * @author mrdoob / http://mrdoob.com/ + * + * parameters = { + * color: + * } */ -function TextureLoader( manager ) { - - this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager; - -} - -Object.assign( TextureLoader.prototype, { - - crossOrigin: 'Anonymous', - - load: function ( url, onLoad, onProgress, onError ) { +function ShadowMaterial( parameters ) { - var texture = new Texture(); + Material.call( this ); - var loader = new ImageLoader( this.manager ); - loader.setCrossOrigin( this.crossOrigin ); - loader.setPath( this.path ); + this.type = 'ShadowMaterial'; - loader.load( url, function ( image ) { + this.color = new Color( 0x000000 ); + this.transparent = true; - texture.image = image; + this.setValues( parameters ); - // JPEGs can't have an alpha channel, so memory can be saved by storing them as RGB. - var isJPEG = url.search( /\.(jpg|jpeg)$/ ) > 0 || url.search( /^data\:image\/jpeg/ ) === 0; +} - texture.format = isJPEG ? RGBFormat : RGBAFormat; - texture.needsUpdate = true; +ShadowMaterial.prototype = Object.create( Material.prototype ); +ShadowMaterial.prototype.constructor = ShadowMaterial; - if ( onLoad !== undefined ) { +ShadowMaterial.prototype.isShadowMaterial = true; - onLoad( texture ); +ShadowMaterial.prototype.copy = function ( source ) { - } + Material.prototype.copy.call( this, source ); - }, onProgress, onError ); + this.color.copy( source.color ); - return texture; + return this; - }, +}; - setCrossOrigin: function ( value ) { +/** + * @author mrdoob / http://mrdoob.com/ + */ - this.crossOrigin = value; - return this; +function RawShaderMaterial( parameters ) { - }, + ShaderMaterial.call( this, parameters ); - setPath: function ( value ) { + this.type = 'RawShaderMaterial'; - this.path = value; - return this; +} - } +RawShaderMaterial.prototype = Object.create( ShaderMaterial.prototype ); +RawShaderMaterial.prototype.constructor = RawShaderMaterial; -} ); +RawShaderMaterial.prototype.isRawShaderMaterial = true; /** - * @author zz85 / http://www.lab4games.net/zz85/blog - * Extensible curve object + * @author WestLangley / http://github.com/WestLangley * - * Some common of curve methods: - * .getPoint( t, optionalTarget ), .getTangent( t ) - * .getPointAt( u, optionalTarget ), .getTangentAt( u ) - * .getPoints(), .getSpacedPoints() - * .getLength() - * .updateArcLengths() + * parameters = { + * color: , + * roughness: , + * metalness: , + * opacity: , * - * This following curves inherit from THREE.Curve: + * map: new THREE.Texture( ), * - * -- 2D curves -- - * THREE.ArcCurve - * THREE.CubicBezierCurve - * THREE.EllipseCurve - * THREE.LineCurve - * THREE.QuadraticBezierCurve - * THREE.SplineCurve + * lightMap: new THREE.Texture( ), + * lightMapIntensity: * - * -- 3D curves -- - * THREE.CatmullRomCurve3 - * THREE.CubicBezierCurve3 - * THREE.LineCurve3 - * THREE.QuadraticBezierCurve3 + * aoMap: new THREE.Texture( ), + * aoMapIntensity: * - * A series of curves can be represented as a THREE.CurvePath. + * 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: + * } + */ -/************************************************************** - * Abstract Curve base class - **************************************************************/ +function MeshStandardMaterial( parameters ) { -function Curve() { + Material.call( this ); - this.type = 'Curve'; + this.defines = { 'STANDARD': '' }; - this.arcLengthDivisions = 200; + this.type = 'MeshStandardMaterial'; -} + this.color = new Color( 0xffffff ); // diffuse + this.roughness = 0.5; + this.metalness = 0.5; -Object.assign( Curve.prototype, { + this.map = null; - // Virtual base class method to overwrite and implement in subclasses - // - t [0 .. 1] + this.lightMap = null; + this.lightMapIntensity = 1.0; - getPoint: function ( /* t, optionalTarget */ ) { + this.aoMap = null; + this.aoMapIntensity = 1.0; - console.warn( 'THREE.Curve: .getPoint() not implemented.' ); - return null; + this.emissive = new Color( 0x000000 ); + this.emissiveIntensity = 1.0; + this.emissiveMap = null; - }, + this.bumpMap = null; + this.bumpScale = 1; - // Get point at relative position in curve according to arc length - // - u [0 .. 1] + this.normalMap = null; + this.normalMapType = TangentSpaceNormalMap; + this.normalScale = new Vector2( 1, 1 ); - getPointAt: function ( u, optionalTarget ) { + this.displacementMap = null; + this.displacementScale = 1; + this.displacementBias = 0; - var t = this.getUtoTmapping( u ); - return this.getPoint( t, optionalTarget ); + this.roughnessMap = null; - }, + this.metalnessMap = null; - // Get sequence of points using getPoint( t ) + this.alphaMap = null; - getPoints: function ( divisions ) { + this.envMap = null; + this.envMapIntensity = 1.0; - if ( divisions === undefined ) divisions = 5; + this.refractionRatio = 0.98; - var points = []; + this.wireframe = false; + this.wireframeLinewidth = 1; + this.wireframeLinecap = 'round'; + this.wireframeLinejoin = 'round'; - for ( var d = 0; d <= divisions; d ++ ) { + this.skinning = false; + this.morphTargets = false; + this.morphNormals = false; - points.push( this.getPoint( d / divisions ) ); + this.setValues( parameters ); - } +} - return points; +MeshStandardMaterial.prototype = Object.create( Material.prototype ); +MeshStandardMaterial.prototype.constructor = MeshStandardMaterial; - }, +MeshStandardMaterial.prototype.isMeshStandardMaterial = true; - // Get sequence of points using getPointAt( u ) +MeshStandardMaterial.prototype.copy = function ( source ) { - getSpacedPoints: function ( divisions ) { + Material.prototype.copy.call( this, source ); - if ( divisions === undefined ) divisions = 5; + this.defines = { 'STANDARD': '' }; - var points = []; + this.color.copy( source.color ); + this.roughness = source.roughness; + this.metalness = source.metalness; - for ( var d = 0; d <= divisions; d ++ ) { + this.map = source.map; - points.push( this.getPointAt( d / divisions ) ); + this.lightMap = source.lightMap; + this.lightMapIntensity = source.lightMapIntensity; - } + this.aoMap = source.aoMap; + this.aoMapIntensity = source.aoMapIntensity; - return points; + this.emissive.copy( source.emissive ); + this.emissiveMap = source.emissiveMap; + this.emissiveIntensity = source.emissiveIntensity; - }, + this.bumpMap = source.bumpMap; + this.bumpScale = source.bumpScale; - // Get total curve arc length + this.normalMap = source.normalMap; + this.normalMapType = source.normalMapType; + this.normalScale.copy( source.normalScale ); - getLength: function () { + this.displacementMap = source.displacementMap; + this.displacementScale = source.displacementScale; + this.displacementBias = source.displacementBias; - var lengths = this.getLengths(); - return lengths[ lengths.length - 1 ]; + this.roughnessMap = source.roughnessMap; - }, + this.metalnessMap = source.metalnessMap; - // Get list of cumulative segment lengths + this.alphaMap = source.alphaMap; - getLengths: function ( divisions ) { + this.envMap = source.envMap; + this.envMapIntensity = source.envMapIntensity; - if ( divisions === undefined ) divisions = this.arcLengthDivisions; + this.refractionRatio = source.refractionRatio; - if ( this.cacheArcLengths && - ( this.cacheArcLengths.length === divisions + 1 ) && - ! this.needsUpdate ) { + this.wireframe = source.wireframe; + this.wireframeLinewidth = source.wireframeLinewidth; + this.wireframeLinecap = source.wireframeLinecap; + this.wireframeLinejoin = source.wireframeLinejoin; - return this.cacheArcLengths; + this.skinning = source.skinning; + this.morphTargets = source.morphTargets; + this.morphNormals = source.morphNormals; - } + return this; - this.needsUpdate = false; +}; - var cache = []; - var current, last = this.getPoint( 0 ); - var p, sum = 0; +/** + * @author WestLangley / http://github.com/WestLangley + * + * parameters = { + * reflectivity: + * } + */ - cache.push( 0 ); +function MeshPhysicalMaterial( parameters ) { - for ( p = 1; p <= divisions; p ++ ) { + MeshStandardMaterial.call( this ); - current = this.getPoint( p / divisions ); - sum += current.distanceTo( last ); - cache.push( sum ); - last = current; + this.defines = { 'PHYSICAL': '' }; - } + this.type = 'MeshPhysicalMaterial'; - this.cacheArcLengths = cache; + this.reflectivity = 0.5; // maps to F0 = 0.04 - return cache; // { sums: cache, sum: sum }; Sum is in the last element. + this.clearCoat = 0.0; + this.clearCoatRoughness = 0.0; - }, + this.setValues( parameters ); - updateArcLengths: function () { +} - this.needsUpdate = true; - this.getLengths(); +MeshPhysicalMaterial.prototype = Object.create( MeshStandardMaterial.prototype ); +MeshPhysicalMaterial.prototype.constructor = MeshPhysicalMaterial; - }, +MeshPhysicalMaterial.prototype.isMeshPhysicalMaterial = true; - // Given u ( 0 .. 1 ), get a t to find p. This gives you points which are equidistant +MeshPhysicalMaterial.prototype.copy = function ( source ) { - getUtoTmapping: function ( u, distance ) { + MeshStandardMaterial.prototype.copy.call( this, source ); - var arcLengths = this.getLengths(); + this.defines = { 'PHYSICAL': '' }; - var i = 0, il = arcLengths.length; + this.reflectivity = source.reflectivity; - var targetArcLength; // The targeted u distance value to get + this.clearCoat = source.clearCoat; + this.clearCoatRoughness = source.clearCoatRoughness; - if ( distance ) { + return this; - targetArcLength = distance; +}; - } else { +/** + * @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: + * } + */ - targetArcLength = u * arcLengths[ il - 1 ]; +function MeshPhongMaterial( parameters ) { - } + Material.call( this ); - // binary search for the index with largest value smaller than target u distance + this.type = 'MeshPhongMaterial'; - var low = 0, high = il - 1, comparison; + this.color = new Color( 0xffffff ); // diffuse + this.specular = new Color( 0x111111 ); + this.shininess = 30; - while ( low <= high ) { + this.map = null; - 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 + this.lightMap = null; + this.lightMapIntensity = 1.0; - comparison = arcLengths[ i ] - targetArcLength; + this.aoMap = null; + this.aoMapIntensity = 1.0; - if ( comparison < 0 ) { + this.emissive = new Color( 0x000000 ); + this.emissiveIntensity = 1.0; + this.emissiveMap = null; - low = i + 1; + this.bumpMap = null; + this.bumpScale = 1; - } else if ( comparison > 0 ) { + this.normalMap = null; + this.normalMapType = TangentSpaceNormalMap; + this.normalScale = new Vector2( 1, 1 ); - high = i - 1; + this.displacementMap = null; + this.displacementScale = 1; + this.displacementBias = 0; - } else { + this.specularMap = null; - high = i; - break; + this.alphaMap = null; - // DONE + this.envMap = null; + this.combine = MultiplyOperation; + this.reflectivity = 1; + this.refractionRatio = 0.98; - } + this.wireframe = false; + this.wireframeLinewidth = 1; + this.wireframeLinecap = 'round'; + this.wireframeLinejoin = 'round'; - } + this.skinning = false; + this.morphTargets = false; + this.morphNormals = false; - i = high; + this.setValues( parameters ); - if ( arcLengths[ i ] === targetArcLength ) { +} - return i / ( il - 1 ); +MeshPhongMaterial.prototype = Object.create( Material.prototype ); +MeshPhongMaterial.prototype.constructor = MeshPhongMaterial; - } +MeshPhongMaterial.prototype.isMeshPhongMaterial = true; - // we could get finer grain at lengths, or use simple interpolation between two points +MeshPhongMaterial.prototype.copy = function ( source ) { - var lengthBefore = arcLengths[ i ]; - var lengthAfter = arcLengths[ i + 1 ]; + Material.prototype.copy.call( this, source ); - var segmentLength = lengthAfter - lengthBefore; + this.color.copy( source.color ); + this.specular.copy( source.specular ); + this.shininess = source.shininess; - // determine where we are between the 'before' and 'after' points + this.map = source.map; - var segmentFraction = ( targetArcLength - lengthBefore ) / segmentLength; + this.lightMap = source.lightMap; + this.lightMapIntensity = source.lightMapIntensity; - // add that fractional amount to t + this.aoMap = source.aoMap; + this.aoMapIntensity = source.aoMapIntensity; - var t = ( i + segmentFraction ) / ( il - 1 ); + this.emissive.copy( source.emissive ); + this.emissiveMap = source.emissiveMap; + this.emissiveIntensity = source.emissiveIntensity; - return t; + this.bumpMap = source.bumpMap; + this.bumpScale = source.bumpScale; - }, + this.normalMap = source.normalMap; + this.normalMapType = source.normalMapType; + this.normalScale.copy( source.normalScale ); - // 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 + this.displacementMap = source.displacementMap; + this.displacementScale = source.displacementScale; + this.displacementBias = source.displacementBias; - getTangent: function ( t ) { + this.specularMap = source.specularMap; - var delta = 0.0001; - var t1 = t - delta; - var t2 = t + delta; + this.alphaMap = source.alphaMap; - // Capping in case of danger + this.envMap = source.envMap; + this.combine = source.combine; + this.reflectivity = source.reflectivity; + this.refractionRatio = source.refractionRatio; - if ( t1 < 0 ) t1 = 0; - if ( t2 > 1 ) t2 = 1; + this.wireframe = source.wireframe; + this.wireframeLinewidth = source.wireframeLinewidth; + this.wireframeLinecap = source.wireframeLinecap; + this.wireframeLinejoin = source.wireframeLinejoin; - var pt1 = this.getPoint( t1 ); - var pt2 = this.getPoint( t2 ); + this.skinning = source.skinning; + this.morphTargets = source.morphTargets; + this.morphNormals = source.morphNormals; - var vec = pt2.clone().sub( pt1 ); - return vec.normalize(); + return this; - }, +}; - getTangentAt: function ( u ) { +/** + * @author takahirox / http://github.com/takahirox + * + * parameters = { + * gradientMap: new THREE.Texture( ) + * } + */ - var t = this.getUtoTmapping( u ); - return this.getTangent( t ); +function MeshToonMaterial( parameters ) { - }, + MeshPhongMaterial.call( this ); - computeFrenetFrames: function ( segments, closed ) { + this.defines = { 'TOON': '' }; - // see http://www.cs.indiana.edu/pub/techreports/TR425.pdf + this.type = 'MeshToonMaterial'; - var normal = new Vector3(); + this.gradientMap = null; - var tangents = []; - var normals = []; - var binormals = []; + this.setValues( parameters ); - var vec = new Vector3(); - var mat = new Matrix4(); +} - var i, u, theta; +MeshToonMaterial.prototype = Object.create( MeshPhongMaterial.prototype ); +MeshToonMaterial.prototype.constructor = MeshToonMaterial; - // compute the tangent vectors for each segment on the curve +MeshToonMaterial.prototype.isMeshToonMaterial = true; - for ( i = 0; i <= segments; i ++ ) { +MeshToonMaterial.prototype.copy = function ( source ) { - u = i / segments; + MeshPhongMaterial.prototype.copy.call( this, source ); - tangents[ i ] = this.getTangentAt( u ); - tangents[ i ].normalize(); + this.gradientMap = source.gradientMap; - } + return this; - // select an initial normal vector perpendicular to the first tangent vector, - // and in the direction of the minimum tangent xyz component +}; - normals[ 0 ] = new Vector3(); - binormals[ 0 ] = new Vector3(); - var min = Number.MAX_VALUE; - var tx = Math.abs( tangents[ 0 ].x ); - var ty = Math.abs( tangents[ 0 ].y ); - var tz = Math.abs( tangents[ 0 ].z ); +/** + * @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: + * } + */ - if ( tx <= min ) { +function MeshNormalMaterial( parameters ) { - min = tx; - normal.set( 1, 0, 0 ); + Material.call( this ); - } + this.type = 'MeshNormalMaterial'; - if ( ty <= min ) { + this.bumpMap = null; + this.bumpScale = 1; - min = ty; - normal.set( 0, 1, 0 ); + this.normalMap = null; + this.normalMapType = TangentSpaceNormalMap; + this.normalScale = new Vector2( 1, 1 ); - } + this.displacementMap = null; + this.displacementScale = 1; + this.displacementBias = 0; - if ( tz <= min ) { + this.wireframe = false; + this.wireframeLinewidth = 1; - normal.set( 0, 0, 1 ); + this.fog = false; + this.lights = false; - } + this.skinning = false; + this.morphTargets = false; + this.morphNormals = false; - vec.crossVectors( tangents[ 0 ], normal ).normalize(); + this.setValues( parameters ); - normals[ 0 ].crossVectors( tangents[ 0 ], vec ); - binormals[ 0 ].crossVectors( tangents[ 0 ], normals[ 0 ] ); +} +MeshNormalMaterial.prototype = Object.create( Material.prototype ); +MeshNormalMaterial.prototype.constructor = MeshNormalMaterial; - // compute the slowly-varying normal and binormal vectors for each segment on the curve +MeshNormalMaterial.prototype.isMeshNormalMaterial = true; - for ( i = 1; i <= segments; i ++ ) { +MeshNormalMaterial.prototype.copy = function ( source ) { - normals[ i ] = normals[ i - 1 ].clone(); + Material.prototype.copy.call( this, source ); - binormals[ i ] = binormals[ i - 1 ].clone(); + this.bumpMap = source.bumpMap; + this.bumpScale = source.bumpScale; - vec.crossVectors( tangents[ i - 1 ], tangents[ i ] ); + this.normalMap = source.normalMap; + this.normalMapType = source.normalMapType; + this.normalScale.copy( source.normalScale ); - if ( vec.length() > Number.EPSILON ) { + this.displacementMap = source.displacementMap; + this.displacementScale = source.displacementScale; + this.displacementBias = source.displacementBias; - vec.normalize(); + this.wireframe = source.wireframe; + this.wireframeLinewidth = source.wireframeLinewidth; - theta = Math.acos( _Math.clamp( tangents[ i - 1 ].dot( tangents[ i ] ), - 1, 1 ) ); // clamp for floating pt errors + this.skinning = source.skinning; + this.morphTargets = source.morphTargets; + this.morphNormals = source.morphNormals; - normals[ i ].applyMatrix4( mat.makeRotationAxis( vec, theta ) ); + return this; - } +}; - binormals[ i ].crossVectors( tangents[ i ], normals[ i ] ); +/** + * @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: + * } + */ - } +function MeshLambertMaterial( parameters ) { - // if the curve is closed, postprocess the vectors so the first and last normal vectors are the same + Material.call( this ); - if ( closed === true ) { + this.type = 'MeshLambertMaterial'; - theta = Math.acos( _Math.clamp( normals[ 0 ].dot( normals[ segments ] ), - 1, 1 ) ); - theta /= segments; + this.color = new Color( 0xffffff ); // diffuse - if ( tangents[ 0 ].dot( vec.crossVectors( normals[ 0 ], normals[ segments ] ) ) > 0 ) { + this.map = null; - theta = - theta; + this.lightMap = null; + this.lightMapIntensity = 1.0; - } + this.aoMap = null; + this.aoMapIntensity = 1.0; - for ( i = 1; i <= segments; i ++ ) { + this.emissive = new Color( 0x000000 ); + this.emissiveIntensity = 1.0; + this.emissiveMap = null; - // twist a little... - normals[ i ].applyMatrix4( mat.makeRotationAxis( tangents[ i ], theta * i ) ); - binormals[ i ].crossVectors( tangents[ i ], normals[ i ] ); + this.specularMap = null; - } + this.alphaMap = null; - } + this.envMap = null; + this.combine = MultiplyOperation; + this.reflectivity = 1; + this.refractionRatio = 0.98; - return { - tangents: tangents, - normals: normals, - binormals: binormals - }; + this.wireframe = false; + this.wireframeLinewidth = 1; + this.wireframeLinecap = 'round'; + this.wireframeLinejoin = 'round'; - }, + this.skinning = false; + this.morphTargets = false; + this.morphNormals = false; - clone: function () { + this.setValues( parameters ); - return new this.constructor().copy( this ); +} - }, +MeshLambertMaterial.prototype = Object.create( Material.prototype ); +MeshLambertMaterial.prototype.constructor = MeshLambertMaterial; - copy: function ( source ) { +MeshLambertMaterial.prototype.isMeshLambertMaterial = true; - this.arcLengthDivisions = source.arcLengthDivisions; +MeshLambertMaterial.prototype.copy = function ( source ) { - return this; + Material.prototype.copy.call( this, source ); - }, + this.color.copy( source.color ); - toJSON: function () { + this.map = source.map; - var data = { - metadata: { - version: 4.5, - type: 'Curve', - generator: 'Curve.toJSON' - } - }; + this.lightMap = source.lightMap; + this.lightMapIntensity = source.lightMapIntensity; - data.arcLengthDivisions = this.arcLengthDivisions; - data.type = this.type; + this.aoMap = source.aoMap; + this.aoMapIntensity = source.aoMapIntensity; - return data; + this.emissive.copy( source.emissive ); + this.emissiveMap = source.emissiveMap; + this.emissiveIntensity = source.emissiveIntensity; - }, + this.specularMap = source.specularMap; - fromJSON: function ( json ) { + this.alphaMap = source.alphaMap; - this.arcLengthDivisions = json.arcLengthDivisions; + this.envMap = source.envMap; + this.combine = source.combine; + this.reflectivity = source.reflectivity; + this.refractionRatio = source.refractionRatio; - return this; + 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; -function EllipseCurve( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ) { +}; - Curve.call( this ); +/** + * @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: + * } + */ - this.type = 'EllipseCurve'; +function MeshMatcapMaterial( parameters ) { - this.aX = aX || 0; - this.aY = aY || 0; + Material.call( this ); - this.xRadius = xRadius || 1; - this.yRadius = yRadius || 1; + this.defines = { 'MATCAP': '' }; - this.aStartAngle = aStartAngle || 0; - this.aEndAngle = aEndAngle || 2 * Math.PI; + this.type = 'MeshMatcapMaterial'; - this.aClockwise = aClockwise || false; + this.color = new Color( 0xffffff ); // diffuse - this.aRotation = aRotation || 0; + this.matcap = null; -} + this.map = null; -EllipseCurve.prototype = Object.create( Curve.prototype ); -EllipseCurve.prototype.constructor = EllipseCurve; + this.bumpMap = null; + this.bumpScale = 1; -EllipseCurve.prototype.isEllipseCurve = true; + this.normalMap = null; + this.normalMapType = TangentSpaceNormalMap; + this.normalScale = new Vector2( 1, 1 ); -EllipseCurve.prototype.getPoint = function ( t, optionalTarget ) { + this.displacementMap = null; + this.displacementScale = 1; + this.displacementBias = 0; - var point = optionalTarget || new Vector2(); + this.alphaMap = null; - var twoPi = Math.PI * 2; - var deltaAngle = this.aEndAngle - this.aStartAngle; - var samePoints = Math.abs( deltaAngle ) < Number.EPSILON; + this.skinning = false; + this.morphTargets = false; + this.morphNormals = false; - // ensures that deltaAngle is 0 .. 2 PI - while ( deltaAngle < 0 ) deltaAngle += twoPi; - while ( deltaAngle > twoPi ) deltaAngle -= twoPi; + this.lights = false; - if ( deltaAngle < Number.EPSILON ) { + this.setValues( parameters ); - if ( samePoints ) { +} - deltaAngle = 0; +MeshMatcapMaterial.prototype = Object.create( Material.prototype ); +MeshMatcapMaterial.prototype.constructor = MeshMatcapMaterial; - } else { +MeshMatcapMaterial.prototype.isMeshMatcapMaterial = true; - deltaAngle = twoPi; +MeshMatcapMaterial.prototype.copy = function ( source ) { - } + Material.prototype.copy.call( this, source ); - } + this.defines = { 'MATCAP': '' }; - if ( this.aClockwise === true && ! samePoints ) { + this.color.copy( source.color ); - if ( deltaAngle === twoPi ) { + this.matcap = source.matcap; - deltaAngle = - twoPi; + this.map = source.map; - } else { + this.bumpMap = source.bumpMap; + this.bumpScale = source.bumpScale; - deltaAngle = deltaAngle - twoPi; + this.normalMap = source.normalMap; + this.normalMapType = source.normalMapType; + this.normalScale.copy( source.normalScale ); - } + this.displacementMap = source.displacementMap; + this.displacementScale = source.displacementScale; + this.displacementBias = source.displacementBias; - } + this.alphaMap = source.alphaMap; - var angle = this.aStartAngle + t * deltaAngle; - var x = this.aX + this.xRadius * Math.cos( angle ); - var y = this.aY + this.yRadius * Math.sin( angle ); + this.skinning = source.skinning; + this.morphTargets = source.morphTargets; + this.morphNormals = source.morphNormals; - if ( this.aRotation !== 0 ) { + return this; - var cos = Math.cos( this.aRotation ); - var sin = Math.sin( this.aRotation ); +}; - var tx = x - this.aX; - var ty = y - this.aY; +/** + * @author alteredq / http://alteredqualia.com/ + * + * parameters = { + * color: , + * opacity: , + * + * linewidth: , + * + * scale: , + * dashSize: , + * gapSize: + * } + */ - // Rotate the point about the center of the ellipse. - x = tx * cos - ty * sin + this.aX; - y = tx * sin + ty * cos + this.aY; +function LineDashedMaterial( parameters ) { - } + LineBasicMaterial.call( this ); - return point.set( x, y ); + this.type = 'LineDashedMaterial'; -}; + this.scale = 1; + this.dashSize = 3; + this.gapSize = 1; -EllipseCurve.prototype.copy = function ( source ) { + this.setValues( parameters ); - Curve.prototype.copy.call( this, source ); +} - this.aX = source.aX; - this.aY = source.aY; +LineDashedMaterial.prototype = Object.create( LineBasicMaterial.prototype ); +LineDashedMaterial.prototype.constructor = LineDashedMaterial; - this.xRadius = source.xRadius; - this.yRadius = source.yRadius; +LineDashedMaterial.prototype.isLineDashedMaterial = true; - this.aStartAngle = source.aStartAngle; - this.aEndAngle = source.aEndAngle; +LineDashedMaterial.prototype.copy = function ( source ) { - this.aClockwise = source.aClockwise; + LineBasicMaterial.prototype.copy.call( this, source ); - this.aRotation = source.aRotation; + this.scale = source.scale; + this.dashSize = source.dashSize; + this.gapSize = source.gapSize; return this; }; -EllipseCurve.prototype.toJSON = function () { - var data = Curve.prototype.toJSON.call( this ); +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 +}); - data.aX = this.aX; - data.aY = this.aY; - - data.xRadius = this.xRadius; - data.yRadius = this.yRadius; - - data.aStartAngle = this.aStartAngle; - data.aEndAngle = this.aEndAngle; +/** + * @author tschw + * @author Ben Houston / http://clara.io/ + * @author David Sarno / http://lighthaus.us/ + */ - data.aClockwise = this.aClockwise; +var AnimationUtils = { - data.aRotation = this.aRotation; + // same as Array.prototype.slice, but also works on typed arrays + arraySlice: function ( array, from, to ) { - return data; + 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 ) ); -EllipseCurve.prototype.fromJSON = function ( json ) { + } - Curve.prototype.fromJSON.call( this, json ); + return array.slice( from, to ); - this.aX = json.aX; - this.aY = json.aY; + }, - this.xRadius = json.xRadius; - this.yRadius = json.yRadius; + // converts an array to a specific type + convertArray: function ( array, type, forceClone ) { - this.aStartAngle = json.aStartAngle; - this.aEndAngle = json.aEndAngle; + if ( ! array || // let 'undefined' and 'null' pass + ! forceClone && array.constructor === type ) return array; - this.aClockwise = json.aClockwise; + if ( typeof type.BYTES_PER_ELEMENT === 'number' ) { - this.aRotation = json.aRotation; + return new type( array ); // create typed array - return this; + } -}; + return Array.prototype.slice.call( array ); // create Array -function ArcCurve( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) { + }, - EllipseCurve.call( this, aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise ); + isTypedArray: function ( object ) { - this.type = 'ArcCurve'; + return ArrayBuffer.isView( object ) && + ! ( object instanceof DataView ); -} + }, -ArcCurve.prototype = Object.create( EllipseCurve.prototype ); -ArcCurve.prototype.constructor = ArcCurve; + // returns an array by which times and values can be sorted + getKeyframeOrder: function ( times ) { -ArcCurve.prototype.isArcCurve = true; + function compareTime( i, j ) { -/** - * @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 - */ + return times[ i ] - times[ j ]; + } -/* -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 + var n = times.length; + var result = new Array( n ); + for ( var i = 0; i !== n; ++ i ) result[ i ] = i; -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. -*/ + result.sort( compareTime ); -function CubicPoly() { + return result; - 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 ) { + // uses the array previously returned by 'getKeyframeOrder' to sort data + sortedArray: function ( values, stride, order ) { - c0 = x0; - c1 = t0; - c2 = - 3 * x0 + 3 * x1 - 2 * t0 - t1; - c3 = 2 * x0 - 2 * x1 + t0 + t1; + var nValues = values.length; + var result = new values.constructor( nValues ); - } + for ( var i = 0, dstOffset = 0; dstOffset !== nValues; ++ i ) { - return { + var srcOffset = order[ i ] * stride; - initCatmullRom: function ( x0, x1, x2, x3, tension ) { + for ( var j = 0; j !== stride; ++ j ) { - init( x1, x2, tension * ( x2 - x0 ), tension * ( x3 - x1 ) ); + result[ dstOffset ++ ] = values[ srcOffset + j ]; - }, + } - 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; + return result; - // rescale tangents for parametrization in [0,1] - t1 *= dt1; - t2 *= dt1; + }, - init( x1, x2, t1, t2 ); + // function for parsing AOS keyframe formats + flattenJSON: function ( jsonKeys, times, values, valuePropertyName ) { - }, + var i = 1, key = jsonKeys[ 0 ]; - calc: function ( t ) { + while ( key !== undefined && key[ valuePropertyName ] === undefined ) { - var t2 = t * t; - var t3 = t2 * t; - return c0 + c1 * t + c2 * t2 + c3 * t3; + key = jsonKeys[ i ++ ]; } - }; + if ( key === undefined ) return; // no data -} + var value = key[ valuePropertyName ]; + if ( value === undefined ) return; // no data -// + if ( Array.isArray( value ) ) { -var tmp = new Vector3(); -var px = new CubicPoly(); -var py = new CubicPoly(); -var pz = new CubicPoly(); + do { -function CatmullRomCurve3( points, closed, curveType, tension ) { + value = key[ valuePropertyName ]; - Curve.call( this ); + if ( value !== undefined ) { - this.type = 'CatmullRomCurve3'; + times.push( key.time ); + values.push.apply( values, value ); // push all elements - this.points = points || []; - this.closed = closed || false; - this.curveType = curveType || 'centripetal'; - this.tension = tension || 0.5; + } -} + key = jsonKeys[ i ++ ]; -CatmullRomCurve3.prototype = Object.create( Curve.prototype ); -CatmullRomCurve3.prototype.constructor = CatmullRomCurve3; + } while ( key !== undefined ); -CatmullRomCurve3.prototype.isCatmullRomCurve3 = true; + } else if ( value.toArray !== undefined ) { -CatmullRomCurve3.prototype.getPoint = function ( t, optionalTarget ) { + // ...assume THREE.Math-ish - var point = optionalTarget || new Vector3(); + do { - var points = this.points; - var l = points.length; + value = key[ valuePropertyName ]; - var p = ( l - ( this.closed ? 0 : 1 ) ) * t; - var intPoint = Math.floor( p ); - var weight = p - intPoint; + if ( value !== undefined ) { - if ( this.closed ) { + times.push( key.time ); + value.toArray( values, values.length ); - intPoint += intPoint > 0 ? 0 : ( Math.floor( Math.abs( intPoint ) / points.length ) + 1 ) * points.length; + } - } else if ( weight === 0 && intPoint === l - 1 ) { + key = jsonKeys[ i ++ ]; - intPoint = l - 2; - weight = 1; + } while ( key !== undefined ); - } + } else { - var p0, p1, p2, p3; // 4 points + // otherwise push as-is - if ( this.closed || intPoint > 0 ) { + do { - p0 = points[ ( intPoint - 1 ) % l ]; + value = key[ valuePropertyName ]; - } else { + if ( value !== undefined ) { - // extrapolate first point - tmp.subVectors( points[ 0 ], points[ 1 ] ).add( points[ 0 ] ); - p0 = tmp; + times.push( key.time ); + values.push( value ); - } + } - p1 = points[ intPoint % l ]; - p2 = points[ ( intPoint + 1 ) % l ]; + key = jsonKeys[ i ++ ]; - if ( this.closed || intPoint + 2 < l ) { + } while ( key !== undefined ); - p3 = points[ ( intPoint + 2 ) % l ]; + } - } else { + } - // extrapolate last point - tmp.subVectors( points[ l - 1 ], points[ l - 2 ] ).add( points[ l - 1 ] ); - p3 = tmp; +}; - } +/** + * 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 + */ - if ( this.curveType === 'centripetal' || this.curveType === 'chordal' ) { +function Interpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) { - // 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 ); + this.parameterPositions = parameterPositions; + this._cachedIndex = 0; - // safety check for repeated points - if ( dt1 < 1e-4 ) dt1 = 1.0; - if ( dt0 < 1e-4 ) dt0 = dt1; - if ( dt2 < 1e-4 ) dt2 = dt1; + this.resultBuffer = resultBuffer !== undefined ? + resultBuffer : new sampleValues.constructor( sampleSize ); + this.sampleValues = sampleValues; + this.valueSize = sampleSize; - px.initNonuniformCatmullRom( p0.x, p1.x, p2.x, p3.x, dt0, dt1, dt2 ); - py.initNonuniformCatmullRom( p0.y, p1.y, p2.y, p3.y, dt0, dt1, dt2 ); - pz.initNonuniformCatmullRom( p0.z, p1.z, p2.z, p3.z, dt0, dt1, dt2 ); +} - } else if ( this.curveType === 'catmullrom' ) { +Object.assign( Interpolant.prototype, { - 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 ); + evaluate: function ( t ) { - } + var pp = this.parameterPositions, + i1 = this._cachedIndex, - point.set( - px.calc( weight ), - py.calc( weight ), - pz.calc( weight ) - ); + t1 = pp[ i1 ], + t0 = pp[ i1 - 1 ]; - return point; + validate_interval: { -}; + seek: { -CatmullRomCurve3.prototype.copy = function ( source ) { + var right; - Curve.prototype.copy.call( this, source ); + linear_scan: { - this.points = []; + //- See http://jsperf.com/comparison-to-undefined/3 + //- slower code: + //- + //- if ( t >= t1 || t1 === undefined ) { + forward_scan: if ( ! ( t < t1 ) ) { - for ( var i = 0, l = source.points.length; i < l; i ++ ) { + for ( var giveUpAt = i1 + 2; ; ) { - var point = source.points[ i ]; + if ( t1 === undefined ) { - this.points.push( point.clone() ); + if ( t < t0 ) break forward_scan; - } + // after end - this.closed = source.closed; - this.curveType = source.curveType; - this.tension = source.tension; + i1 = pp.length; + this._cachedIndex = i1; + return this.afterEnd_( i1 - 1, t, t0 ); - return this; + } -}; + if ( i1 === giveUpAt ) break; // this loop -CatmullRomCurve3.prototype.toJSON = function () { + t0 = t1; + t1 = pp[ ++ i1 ]; - var data = Curve.prototype.toJSON.call( this ); + if ( t < t1 ) { - data.points = []; + // we have arrived at the sought interval + break seek; - for ( var i = 0, l = this.points.length; i < l; i ++ ) { + } - var point = this.points[ i ]; - data.points.push( point.toArray() ); + } - } + // prepare binary search on the right side of the index + right = pp.length; + break linear_scan; - data.closed = this.closed; - data.curveType = this.curveType; - data.tension = this.tension; + } - return data; + //- slower code: + //- if ( t < t0 || t0 === undefined ) { + if ( ! ( t >= t0 ) ) { -}; + // looping? -CatmullRomCurve3.prototype.fromJSON = function ( json ) { + var t1global = pp[ 1 ]; - Curve.prototype.fromJSON.call( this, json ); + if ( t < t1global ) { - this.points = []; + i1 = 2; // + 1, using the scan for the details + t0 = t1global; - for ( var i = 0, l = json.points.length; i < l; i ++ ) { + } - var point = json.points[ i ]; - this.points.push( new Vector3().fromArray( point ) ); + // linear reverse scan - } + for ( var giveUpAt = i1 - 2; ; ) { - this.closed = json.closed; - this.curveType = json.curveType; - this.tension = json.tension; + if ( t0 === undefined ) { - return this; + // before start -}; + this._cachedIndex = 0; + return this.beforeStart_( 0, t, t1 ); -/** - * @author zz85 / http://www.lab4games.net/zz85/blog - * - * Bezier Curves formulas obtained from - * http://en.wikipedia.org/wiki/Bézier_curve - */ + } -function CatmullRom( t, p0, p1, p2, p3 ) { + if ( i1 === giveUpAt ) break; // this loop - 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; + t1 = t0; + t0 = pp[ -- i1 - 1 ]; -} + if ( t >= t0 ) { -// + // we have arrived at the sought interval + break seek; -function QuadraticBezierP0( t, p ) { + } - var k = 1 - t; - return k * k * p; + } -} + // prepare binary search on the left side of the index + right = i1; + i1 = 0; + break linear_scan; -function QuadraticBezierP1( t, p ) { + } - return 2 * ( 1 - t ) * t * p; + // the interval is valid -} + break validate_interval; -function QuadraticBezierP2( t, p ) { + } // linear scan - return t * t * p; + // binary search -} + while ( i1 < right ) { -function QuadraticBezier( t, p0, p1, p2 ) { + var mid = ( i1 + right ) >>> 1; - return QuadraticBezierP0( t, p0 ) + QuadraticBezierP1( t, p1 ) + - QuadraticBezierP2( t, p2 ); + if ( t < pp[ mid ] ) { -} + right = mid; -// + } else { -function CubicBezierP0( t, p ) { + i1 = mid + 1; - var k = 1 - t; - return k * k * k * p; + } -} + } -function CubicBezierP1( t, p ) { + t1 = pp[ i1 ]; + t0 = pp[ i1 - 1 ]; - var k = 1 - t; - return 3 * k * k * t * p; + // check boundary cases, again -} + if ( t0 === undefined ) { -function CubicBezierP2( t, p ) { + this._cachedIndex = 0; + return this.beforeStart_( 0, t, t1 ); - return 3 * ( 1 - t ) * t * t * p; + } -} + if ( t1 === undefined ) { -function CubicBezierP3( t, p ) { + i1 = pp.length; + this._cachedIndex = i1; + return this.afterEnd_( i1 - 1, t0, t ); - return t * t * t * p; + } -} + } // seek -function CubicBezier( t, p0, p1, p2, p3 ) { + this._cachedIndex = i1; - return CubicBezierP0( t, p0 ) + CubicBezierP1( t, p1 ) + CubicBezierP2( t, p2 ) + - CubicBezierP3( t, p3 ); + this.intervalChanged_( i1, t0, t1 ); -} + } // validate_interval -function CubicBezierCurve( v0, v1, v2, v3 ) { + return this.interpolate_( i1, t0, t, t1 ); - Curve.call( this ); + }, - this.type = 'CubicBezierCurve'; + settings: null, // optional, subclass-specific settings structure + // Note: The indirection allows central control of many interpolants. - this.v0 = v0 || new Vector2(); - this.v1 = v1 || new Vector2(); - this.v2 = v2 || new Vector2(); - this.v3 = v3 || new Vector2(); + // --- Protected interface -} + DefaultSettings_: {}, -CubicBezierCurve.prototype = Object.create( Curve.prototype ); -CubicBezierCurve.prototype.constructor = CubicBezierCurve; + getSettings_: function () { -CubicBezierCurve.prototype.isCubicBezierCurve = true; + return this.settings || this.DefaultSettings_; -CubicBezierCurve.prototype.getPoint = function ( t, optionalTarget ) { + }, - var point = optionalTarget || new Vector2(); + copySampleValue_: function ( index ) { - var v0 = this.v0, v1 = this.v1, v2 = this.v2, v3 = this.v3; + // copies a sample value to the result buffer - point.set( - CubicBezier( t, v0.x, v1.x, v2.x, v3.x ), - CubicBezier( t, v0.y, v1.y, v2.y, v3.y ) - ); + var result = this.resultBuffer, + values = this.sampleValues, + stride = this.valueSize, + offset = index * stride; - return point; + for ( var i = 0; i !== stride; ++ i ) { -}; + result[ i ] = values[ offset + i ]; -CubicBezierCurve.prototype.copy = function ( source ) { + } - Curve.prototype.copy.call( this, source ); + return result; - this.v0.copy( source.v0 ); - this.v1.copy( source.v1 ); - this.v2.copy( source.v2 ); - this.v3.copy( source.v3 ); + }, - return this; + // Template methods for derived classes: -}; + interpolate_: function ( /* i1, t0, t, t1 */ ) { -CubicBezierCurve.prototype.toJSON = function () { + throw new Error( 'call to abstract method' ); + // implementations shall return this.resultBuffer - 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(); + intervalChanged_: function ( /* i1, t0, t1 */ ) { - return data; + // empty -}; + } -CubicBezierCurve.prototype.fromJSON = function ( json ) { +} ); - Curve.prototype.fromJSON.call( this, json ); +//!\ DECLARE ALIAS AFTER assign prototype ! +Object.assign( Interpolant.prototype, { - this.v0.fromArray( json.v0 ); - this.v1.fromArray( json.v1 ); - this.v2.fromArray( json.v2 ); - this.v3.fromArray( json.v3 ); + //( 0, t, t0 ), returns this.resultBuffer + beforeStart_: Interpolant.prototype.copySampleValue_, - return this; + //( N-1, tN-1, t ), returns this.resultBuffer + afterEnd_: Interpolant.prototype.copySampleValue_, -}; +} ); -function CubicBezierCurve3( v0, v1, v2, v3 ) { +/** + * 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 + */ - Curve.call( this ); +function CubicInterpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) { - this.type = 'CubicBezierCurve3'; + Interpolant.call( this, parameterPositions, sampleValues, sampleSize, resultBuffer ); - this.v0 = v0 || new Vector3(); - this.v1 = v1 || new Vector3(); - this.v2 = v2 || new Vector3(); - this.v3 = v3 || new Vector3(); + this._weightPrev = - 0; + this._offsetPrev = - 0; + this._weightNext = - 0; + this._offsetNext = - 0; } -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(); +CubicInterpolant.prototype = Object.assign( Object.create( Interpolant.prototype ), { - var v0 = this.v0, v1 = this.v1, v2 = this.v2, v3 = this.v3; + constructor: CubicInterpolant, - 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 ) - ); + DefaultSettings_: { - return point; + endingStart: ZeroCurvatureEnding, + endingEnd: ZeroCurvatureEnding -}; + }, -CubicBezierCurve3.prototype.copy = function ( source ) { + intervalChanged_: function ( i1, t0, t1 ) { - Curve.prototype.copy.call( this, source ); + var pp = this.parameterPositions, + iPrev = i1 - 2, + iNext = i1 + 1, - this.v0.copy( source.v0 ); - this.v1.copy( source.v1 ); - this.v2.copy( source.v2 ); - this.v3.copy( source.v3 ); + tPrev = pp[ iPrev ], + tNext = pp[ iNext ]; - return this; + if ( tPrev === undefined ) { -}; + switch ( this.getSettings_().endingStart ) { -CubicBezierCurve3.prototype.toJSON = function () { + case ZeroSlopeEnding: - var data = Curve.prototype.toJSON.call( this ); + // f'(t0) = 0 + iPrev = i1; + tPrev = 2 * t0 - t1; - data.v0 = this.v0.toArray(); - data.v1 = this.v1.toArray(); - data.v2 = this.v2.toArray(); - data.v3 = this.v3.toArray(); + break; - return data; + case WrapAroundEnding: -}; + // use the other end of the curve + iPrev = pp.length - 2; + tPrev = t0 + pp[ iPrev ] - pp[ iPrev + 1 ]; -CubicBezierCurve3.prototype.fromJSON = function ( json ) { + break; - Curve.prototype.fromJSON.call( this, json ); + default: // ZeroCurvatureEnding - this.v0.fromArray( json.v0 ); - this.v1.fromArray( json.v1 ); - this.v2.fromArray( json.v2 ); - this.v3.fromArray( json.v3 ); + // f''(t0) = 0 a.k.a. Natural Spline + iPrev = i1; + tPrev = t1; - return this; + } -}; + } -function LineCurve( v1, v2 ) { + if ( tNext === undefined ) { - Curve.call( this ); + switch ( this.getSettings_().endingEnd ) { - this.type = 'LineCurve'; + case ZeroSlopeEnding: - this.v1 = v1 || new Vector2(); - this.v2 = v2 || new Vector2(); + // f'(tN) = 0 + iNext = i1; + tNext = 2 * t1 - t0; -} + break; -LineCurve.prototype = Object.create( Curve.prototype ); -LineCurve.prototype.constructor = LineCurve; + case WrapAroundEnding: -LineCurve.prototype.isLineCurve = true; + // use the other end of the curve + iNext = 1; + tNext = t1 + pp[ 1 ] - pp[ 0 ]; -LineCurve.prototype.getPoint = function ( t, optionalTarget ) { + break; - var point = optionalTarget || new Vector2(); + default: // ZeroCurvatureEnding - if ( t === 1 ) { + // f''(tN) = 0, a.k.a. Natural Spline + iNext = i1 - 1; + tNext = t0; - point.copy( this.v2 ); + } - } else { + } - point.copy( this.v2 ).sub( this.v1 ); - point.multiplyScalar( t ).add( this.v1 ); + 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; - return point; + }, -}; + interpolate_: function ( i1, t0, t, t1 ) { -// Line curve is linear, so we can overwrite default getPointAt + var result = this.resultBuffer, + values = this.sampleValues, + stride = this.valueSize, -LineCurve.prototype.getPointAt = function ( u, optionalTarget ) { + o1 = i1 * stride, o0 = o1 - stride, + oP = this._offsetPrev, oN = this._offsetNext, + wP = this._weightPrev, wN = this._weightNext, - return this.getPoint( u, optionalTarget ); + p = ( t - t0 ) / ( t1 - t0 ), + pp = p * p, + ppp = pp * p; -}; + // evaluate polynomials -LineCurve.prototype.getTangent = function ( /* t */ ) { + 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 tangent = this.v2.clone().sub( this.v1 ); + // combine data linearly - return tangent.normalize(); + for ( var i = 0; i !== stride; ++ i ) { -}; + result[ i ] = + sP * values[ oP + i ] + + s0 * values[ o0 + i ] + + s1 * values[ o1 + i ] + + sN * values[ oN + i ]; -LineCurve.prototype.copy = function ( source ) { + } - Curve.prototype.copy.call( this, source ); + return result; - this.v1.copy( source.v1 ); - this.v2.copy( source.v2 ); + } - return this; +} ); -}; +/** + * @author tschw + */ -LineCurve.prototype.toJSON = function () { +function LinearInterpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) { - var data = Curve.prototype.toJSON.call( this ); + Interpolant.call( this, parameterPositions, sampleValues, sampleSize, resultBuffer ); - data.v1 = this.v1.toArray(); - data.v2 = this.v2.toArray(); +} - return data; +LinearInterpolant.prototype = Object.assign( Object.create( Interpolant.prototype ), { -}; + constructor: LinearInterpolant, -LineCurve.prototype.fromJSON = function ( json ) { + interpolate_: function ( i1, t0, t, t1 ) { - Curve.prototype.fromJSON.call( this, json ); + var result = this.resultBuffer, + values = this.sampleValues, + stride = this.valueSize, - this.v1.fromArray( json.v1 ); - this.v2.fromArray( json.v2 ); + offset1 = i1 * stride, + offset0 = offset1 - stride, - return this; + weight1 = ( t - t0 ) / ( t1 - t0 ), + weight0 = 1 - weight1; -}; + for ( var i = 0; i !== stride; ++ i ) { -function LineCurve3( v1, v2 ) { + result[ i ] = + values[ offset0 + i ] * weight0 + + values[ offset1 + i ] * weight1; - Curve.call( this ); + } - this.type = 'LineCurve3'; + return result; - this.v1 = v1 || new Vector3(); - this.v2 = v2 || new Vector3(); + } -} +} ); -LineCurve3.prototype = Object.create( Curve.prototype ); -LineCurve3.prototype.constructor = LineCurve3; +/** + * + * Interpolant that evaluates to the sample value at the position preceeding + * the parameter. + * + * @author tschw + */ -LineCurve3.prototype.isLineCurve3 = true; +function DiscreteInterpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) { -LineCurve3.prototype.getPoint = function ( t, optionalTarget ) { + Interpolant.call( this, parameterPositions, sampleValues, sampleSize, resultBuffer ); - var point = optionalTarget || new Vector3(); +} - if ( t === 1 ) { +DiscreteInterpolant.prototype = Object.assign( Object.create( Interpolant.prototype ), { - point.copy( this.v2 ); + constructor: DiscreteInterpolant, - } else { + interpolate_: function ( i1 /*, t0, t, t1 */ ) { - point.copy( this.v2 ).sub( this.v1 ); - point.multiplyScalar( t ).add( this.v1 ); + return this.copySampleValue_( i1 - 1 ); } - return point; +} ); -}; +/** + * + * A timed sequence of keyframes for a specific property. + * + * + * @author Ben Houston / http://clara.io/ + * @author David Sarno / http://lighthaus.us/ + * @author tschw + */ -// Line curve is linear, so we can overwrite default getPointAt +function KeyframeTrack( name, times, values, interpolation ) { -LineCurve3.prototype.getPointAt = function ( u, optionalTarget ) { + 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 ); - return this.getPoint( u, optionalTarget ); + this.name = name; -}; + this.times = AnimationUtils.convertArray( times, this.TimeBufferType ); + this.values = AnimationUtils.convertArray( values, this.ValueBufferType ); -LineCurve3.prototype.copy = function ( source ) { + this.setInterpolation( interpolation || this.DefaultInterpolation ); - Curve.prototype.copy.call( this, source ); +} - this.v1.copy( source.v1 ); - this.v2.copy( source.v2 ); +// Static methods - return this; +Object.assign( KeyframeTrack, { -}; + // Serialization (in static context, because of constructor invocation + // and automatic invocation of .toJSON): -LineCurve3.prototype.toJSON = function () { + toJSON: function ( track ) { - var data = Curve.prototype.toJSON.call( this ); + var trackType = track.constructor; - data.v1 = this.v1.toArray(); - data.v2 = this.v2.toArray(); + var json; - return data; + // derived classes can define a static toJSON method + if ( trackType.toJSON !== undefined ) { -}; + json = trackType.toJSON( track ); -LineCurve3.prototype.fromJSON = function ( json ) { + } else { - Curve.prototype.fromJSON.call( this, json ); + // by default, we assume the data can be serialized as-is + json = { - this.v1.fromArray( json.v1 ); - this.v2.fromArray( json.v2 ); + 'name': track.name, + 'times': AnimationUtils.convertArray( track.times, Array ), + 'values': AnimationUtils.convertArray( track.values, Array ) - return this; + }; -}; + var interpolation = track.getInterpolation(); -function QuadraticBezierCurve( v0, v1, v2 ) { + if ( interpolation !== track.DefaultInterpolation ) { - Curve.call( this ); + json.interpolation = interpolation; - this.type = 'QuadraticBezierCurve'; + } - this.v0 = v0 || new Vector2(); - this.v1 = v1 || new Vector2(); - this.v2 = v2 || new Vector2(); + } -} + json.type = track.ValueTypeName; // mandatory -QuadraticBezierCurve.prototype = Object.create( Curve.prototype ); -QuadraticBezierCurve.prototype.constructor = QuadraticBezierCurve; + return json; -QuadraticBezierCurve.prototype.isQuadraticBezierCurve = true; + } -QuadraticBezierCurve.prototype.getPoint = function ( t, optionalTarget ) { +} ); - var point = optionalTarget || new Vector2(); +Object.assign( KeyframeTrack.prototype, { - var v0 = this.v0, v1 = this.v1, v2 = this.v2; + constructor: KeyframeTrack, - point.set( - QuadraticBezier( t, v0.x, v1.x, v2.x ), - QuadraticBezier( t, v0.y, v1.y, v2.y ) - ); + TimeBufferType: Float32Array, - return point; + ValueBufferType: Float32Array, -}; + DefaultInterpolation: InterpolateLinear, -QuadraticBezierCurve.prototype.copy = function ( source ) { + InterpolantFactoryMethodDiscrete: function ( result ) { - Curve.prototype.copy.call( this, source ); + return new DiscreteInterpolant( this.times, this.values, this.getValueSize(), result ); - this.v0.copy( source.v0 ); - this.v1.copy( source.v1 ); - this.v2.copy( source.v2 ); + }, - return this; + InterpolantFactoryMethodLinear: function ( result ) { -}; + return new LinearInterpolant( this.times, this.values, this.getValueSize(), result ); -QuadraticBezierCurve.prototype.toJSON = function () { + }, - var data = Curve.prototype.toJSON.call( this ); + InterpolantFactoryMethodSmooth: function ( result ) { - data.v0 = this.v0.toArray(); - data.v1 = this.v1.toArray(); - data.v2 = this.v2.toArray(); + return new CubicInterpolant( this.times, this.values, this.getValueSize(), result ); - return data; + }, -}; + setInterpolation: function ( interpolation ) { -QuadraticBezierCurve.prototype.fromJSON = function ( json ) { + var factoryMethod; - Curve.prototype.fromJSON.call( this, json ); + switch ( interpolation ) { - this.v0.fromArray( json.v0 ); - this.v1.fromArray( json.v1 ); - this.v2.fromArray( json.v2 ); + case InterpolateDiscrete: - return this; + factoryMethod = this.InterpolantFactoryMethodDiscrete; -}; + break; -function QuadraticBezierCurve3( v0, v1, v2 ) { + case InterpolateLinear: - Curve.call( this ); + factoryMethod = this.InterpolantFactoryMethodLinear; - this.type = 'QuadraticBezierCurve3'; + break; - this.v0 = v0 || new Vector3(); - this.v1 = v1 || new Vector3(); - this.v2 = v2 || new Vector3(); + case InterpolateSmooth: -} + factoryMethod = this.InterpolantFactoryMethodSmooth; -QuadraticBezierCurve3.prototype = Object.create( Curve.prototype ); -QuadraticBezierCurve3.prototype.constructor = QuadraticBezierCurve3; + break; -QuadraticBezierCurve3.prototype.isQuadraticBezierCurve3 = true; + } -QuadraticBezierCurve3.prototype.getPoint = function ( t, optionalTarget ) { + if ( factoryMethod === undefined ) { - var point = optionalTarget || new Vector3(); + var message = "unsupported interpolation for " + + this.ValueTypeName + " keyframe track named " + this.name; - var v0 = this.v0, v1 = this.v1, v2 = this.v2; + if ( this.createInterpolant === undefined ) { - 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 ) - ); + // fall back to default, unless the default itself is messed up + if ( interpolation !== this.DefaultInterpolation ) { - return point; + this.setInterpolation( this.DefaultInterpolation ); -}; + } else { -QuadraticBezierCurve3.prototype.copy = function ( source ) { + throw new Error( message ); // fatal, in this case - Curve.prototype.copy.call( this, source ); + } - this.v0.copy( source.v0 ); - this.v1.copy( source.v1 ); - this.v2.copy( source.v2 ); + } - return this; + console.warn( 'THREE.KeyframeTrack:', message ); + return this; -}; + } -QuadraticBezierCurve3.prototype.toJSON = function () { + this.createInterpolant = factoryMethod; - var data = Curve.prototype.toJSON.call( this ); + return this; - data.v0 = this.v0.toArray(); - data.v1 = this.v1.toArray(); - data.v2 = this.v2.toArray(); + }, - return data; + getInterpolation: function () { -}; + switch ( this.createInterpolant ) { -QuadraticBezierCurve3.prototype.fromJSON = function ( json ) { + case this.InterpolantFactoryMethodDiscrete: - Curve.prototype.fromJSON.call( this, json ); + return InterpolateDiscrete; - this.v0.fromArray( json.v0 ); - this.v1.fromArray( json.v1 ); - this.v2.fromArray( json.v2 ); + case this.InterpolantFactoryMethodLinear: - return this; + return InterpolateLinear; -}; + case this.InterpolantFactoryMethodSmooth: -function SplineCurve( points /* array of Vector2 */ ) { + return InterpolateSmooth; - Curve.call( this ); + } - this.type = 'SplineCurve'; + }, - this.points = points || []; + getValueSize: function () { -} + return this.values.length / this.times.length; -SplineCurve.prototype = Object.create( Curve.prototype ); -SplineCurve.prototype.constructor = SplineCurve; + }, -SplineCurve.prototype.isSplineCurve = true; + // move all keyframes either forwards or backwards in time + shift: function ( timeOffset ) { -SplineCurve.prototype.getPoint = function ( t, optionalTarget ) { + if ( timeOffset !== 0.0 ) { - var point = optionalTarget || new Vector2(); + var times = this.times; - var points = this.points; - var p = ( points.length - 1 ) * t; + for ( var i = 0, n = times.length; i !== n; ++ i ) { - var intPoint = Math.floor( p ); - var weight = p - intPoint; + times[ i ] += timeOffset; - 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 ]; + } - point.set( - CatmullRom( weight, p0.x, p1.x, p2.x, p3.x ), - CatmullRom( weight, p0.y, p1.y, p2.y, p3.y ) - ); + } - return point; + return this; -}; + }, -SplineCurve.prototype.copy = function ( source ) { + // scale all keyframe times by a factor (useful for frame <-> seconds conversions) + scale: function ( timeScale ) { - Curve.prototype.copy.call( this, source ); + if ( timeScale !== 1.0 ) { - this.points = []; + var times = this.times; - for ( var i = 0, l = source.points.length; i < l; i ++ ) { + for ( var i = 0, n = times.length; i !== n; ++ i ) { - var point = source.points[ i ]; + times[ i ] *= timeScale; - this.points.push( point.clone() ); + } - } + } - return this; + return this; -}; + }, -SplineCurve.prototype.toJSON = function () { + // 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 ) { - var data = Curve.prototype.toJSON.call( this ); + var times = this.times, + nKeys = times.length, + from = 0, + to = nKeys - 1; - data.points = []; + while ( from !== nKeys && times[ from ] < startTime ) { - for ( var i = 0, l = this.points.length; i < l; i ++ ) { + ++ from; - var point = this.points[ i ]; - data.points.push( point.toArray() ); + } - } + while ( to !== - 1 && times[ to ] > endTime ) { - return data; + -- to; -}; + } -SplineCurve.prototype.fromJSON = function ( json ) { + ++ to; // inclusive -> exclusive bound - Curve.prototype.fromJSON.call( this, json ); + if ( from !== 0 || to !== nKeys ) { - this.points = []; + // empty tracks are forbidden, so keep at least one keyframe + if ( from >= to ) to = Math.max( to, 1 ), from = to - 1; - for ( var i = 0, l = json.points.length; i < l; i ++ ) { + var stride = this.getValueSize(); + this.times = AnimationUtils.arraySlice( times, from, to ); + this.values = AnimationUtils.arraySlice( this.values, from * stride, to * stride ); - var point = json.points[ i ]; - this.points.push( new Vector2().fromArray( point ) ); + } - } + return this; - return this; + }, -}; + // 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 ) { -var Curves = Object.freeze({ - ArcCurve: ArcCurve, - CatmullRomCurve3: CatmullRomCurve3, - CubicBezierCurve: CubicBezierCurve, - CubicBezierCurve3: CubicBezierCurve3, - EllipseCurve: EllipseCurve, - LineCurve: LineCurve, - LineCurve3: LineCurve3, - QuadraticBezierCurve: QuadraticBezierCurve, - QuadraticBezierCurve3: QuadraticBezierCurve3, - SplineCurve: SplineCurve -}); + console.error( 'THREE.KeyframeTrack: Invalid value size in track.', this ); + valid = false; -/** - * @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 - **************************************************************/ + var times = this.times, + values = this.values, -function CurvePath() { + nKeys = times.length; - Curve.call( this ); + if ( nKeys === 0 ) { - this.type = 'CurvePath'; + console.error( 'THREE.KeyframeTrack: Track is empty.', this ); + valid = false; - this.curves = []; - this.autoClose = false; // Automatically closes the path + } -} + var prevTime = null; -CurvePath.prototype = Object.assign( Object.create( Curve.prototype ), { + for ( var i = 0; i !== nKeys; i ++ ) { - constructor: CurvePath, + var currTime = times[ i ]; - add: function ( curve ) { + if ( typeof currTime === 'number' && isNaN( currTime ) ) { - this.curves.push( curve ); + console.error( 'THREE.KeyframeTrack: Time is not a valid number.', this, i, currTime ); + valid = false; + break; - }, + } - closePath: function () { + if ( prevTime !== null && prevTime > currTime ) { - // 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 ); + console.error( 'THREE.KeyframeTrack: Out of order keys.', this, i, currTime, prevTime ); + valid = false; + break; - if ( ! startPoint.equals( endPoint ) ) { + } - this.curves.push( new LineCurve( endPoint, startPoint ) ); + prevTime = currTime; } - }, - - // To get accurate point with reference to - // entire path distance at time t, - // following has to be done: - - // 1. Length of each sub path have to be known - // 2. Locate and identify type of curve - // 3. Get t for the curve - // 4. Return curve.getPointAt(t') - - getPoint: function ( t ) { + if ( values !== undefined ) { - var d = t * this.getLength(); - var curveLengths = this.getCurveLengths(); - var i = 0; + if ( AnimationUtils.isTypedArray( values ) ) { - // To think about boundaries points. + for ( var i = 0, n = values.length; i !== n; ++ i ) { - while ( i < curveLengths.length ) { + var value = values[ i ]; - if ( curveLengths[ i ] >= d ) { + if ( isNaN( value ) ) { - var diff = curveLengths[ i ] - d; - var curve = this.curves[ i ]; + console.error( 'THREE.KeyframeTrack: Value is not a valid number.', this, i, value ); + valid = false; + break; - var segmentLength = curve.getLength(); - var u = segmentLength === 0 ? 0 : 1 - diff / segmentLength; + } - return curve.getPointAt( u ); + } } - i ++; - } - return null; - - // loop where sum != 0, sum > d , sum+1 (0,0,1,1,0,0) + optimize: function () { - // cacheLengths must be recalculated. - updateArcLengths: function () { + var times = this.times, + values = this.values, + stride = this.getValueSize(), - this.needsUpdate = true; - this.cacheLengths = null; - this.getCurveLengths(); + smoothInterpolation = this.getInterpolation() === InterpolateSmooth, - }, + writeIndex = 1, + lastIndex = times.length - 1; - // Compute lengths and cache them - // We cannot overwrite getLengths() because UtoT mapping uses it. + for ( var i = 1; i < lastIndex; ++ i ) { - getCurveLengths: function () { + var keep = false; - // We use cache values if curves and cache array are same length + var time = times[ i ]; + var timeNext = times[ i + 1 ]; - if ( this.cacheLengths && this.cacheLengths.length === this.curves.length ) { + // remove adjacent keyframes scheduled at the same time - return this.cacheLengths; + if ( time !== timeNext && ( i !== 1 || time !== time[ 0 ] ) ) { - } + if ( ! smoothInterpolation ) { - // Get length of sub-curve - // Push sums into cached array + // remove unnecessary keyframes same as their neighbors - var lengths = [], sums = 0; + var offset = i * stride, + offsetP = offset - stride, + offsetN = offset + stride; - for ( var i = 0, l = this.curves.length; i < l; i ++ ) { + for ( var j = 0; j !== stride; ++ j ) { - sums += this.curves[ i ].getLength(); - lengths.push( sums ); + var value = values[ offset + j ]; - } + if ( value !== values[ offsetP + j ] || + value !== values[ offsetN + j ] ) { - this.cacheLengths = lengths; + keep = true; + break; - return lengths; + } - }, + } - getSpacedPoints: function ( divisions ) { + } else { - if ( divisions === undefined ) divisions = 40; + keep = true; - var points = []; + } - for ( var i = 0; i <= divisions; i ++ ) { + } - points.push( this.getPoint( i / divisions ) ); + // in-place compaction - } + if ( keep ) { - if ( this.autoClose ) { + if ( i !== writeIndex ) { - points.push( points[ 0 ] ); + times[ writeIndex ] = times[ i ]; - } + var readOffset = i * stride, + writeOffset = writeIndex * stride; - return points; + for ( var j = 0; j !== stride; ++ j ) { - }, + values[ writeOffset + j ] = values[ readOffset + j ]; - getPoints: function ( divisions ) { + } - divisions = divisions || 12; + } - var points = [], last; + ++ writeIndex; - for ( var i = 0, curves = this.curves; i < curves.length; i ++ ) { + } - var curve = curves[ i ]; - var resolution = ( curve && curve.isEllipseCurve ) ? divisions * 2 - : ( curve && curve.isLineCurve ) ? 1 - : ( curve && curve.isSplineCurve ) ? divisions * curve.points.length - : divisions; + } - var pts = curve.getPoints( resolution ); + // flush last keyframe (compaction looks ahead) - for ( var j = 0; j < pts.length; j ++ ) { + if ( lastIndex > 0 ) { - var point = pts[ j ]; + times[ writeIndex ] = times[ lastIndex ]; - if ( last && last.equals( point ) ) continue; // ensures no consecutive points are duplicates + for ( var readOffset = lastIndex * stride, writeOffset = writeIndex * stride, j = 0; j !== stride; ++ j ) { - points.push( point ); - last = point; + values[ writeOffset + j ] = values[ readOffset + j ]; } - } - - if ( this.autoClose && points.length > 1 && ! points[ points.length - 1 ].equals( points[ 0 ] ) ) { - - points.push( points[ 0 ] ); + ++ writeIndex; } - return points; - - }, + if ( writeIndex !== times.length ) { - copy: function ( source ) { + this.times = AnimationUtils.arraySlice( times, 0, writeIndex ); + this.values = AnimationUtils.arraySlice( values, 0, writeIndex * stride ); - Curve.prototype.copy.call( this, source ); + } - this.curves = []; + return this; - for ( var i = 0, l = source.curves.length; i < l; i ++ ) { + } - var curve = source.curves[ i ]; +} ); - this.curves.push( curve.clone() ); +/** + * + * A Track of Boolean keyframe values. + * + * + * @author Ben Houston / http://clara.io/ + * @author David Sarno / http://lighthaus.us/ + * @author tschw + */ - } +function BooleanKeyframeTrack( name, times, values ) { - this.autoClose = source.autoClose; + KeyframeTrack.call( this, name, times, values ); - return this; +} - }, +BooleanKeyframeTrack.prototype = Object.assign( Object.create( KeyframeTrack.prototype ), { - toJSON: function () { + constructor: BooleanKeyframeTrack, - var data = Curve.prototype.toJSON.call( this ); + ValueTypeName: 'bool', + ValueBufferType: Array, - data.autoClose = this.autoClose; - data.curves = []; + DefaultInterpolation: InterpolateDiscrete, - for ( var i = 0, l = this.curves.length; i < l; i ++ ) { + InterpolantFactoryMethodLinear: undefined, + InterpolantFactoryMethodSmooth: undefined - var curve = this.curves[ i ]; - data.curves.push( curve.toJSON() ); + // Note: Actually this track could have a optimized / compressed + // representation of a single value and a custom interpolant that + // computes "firstValue ^ isOdd( index )". - } +} ); - return data; +/** + * + * A Track of keyframe values that represent color. + * + * + * @author Ben Houston / http://clara.io/ + * @author David Sarno / http://lighthaus.us/ + * @author tschw + */ - }, +function ColorKeyframeTrack( name, times, values, interpolation ) { - fromJSON: function ( json ) { + KeyframeTrack.call( this, name, times, values, interpolation ); - Curve.prototype.fromJSON.call( this, json ); +} - this.autoClose = json.autoClose; - this.curves = []; +ColorKeyframeTrack.prototype = Object.assign( Object.create( KeyframeTrack.prototype ), { - for ( var i = 0, l = json.curves.length; i < l; i ++ ) { + constructor: ColorKeyframeTrack, - var curve = json.curves[ i ]; - this.curves.push( new Curves[ curve.type ]().fromJSON( curve ) ); + ValueTypeName: 'color' - } + // ValueBufferType is inherited - return this; + // DefaultInterpolation is inherited - } + // Note: Very basic implementation and nothing special yet. + // However, this is the place for color space parameterization. } ); /** - * @author zz85 / http://www.lab4games.net/zz85/blog - * Creates free form 2d path using series of points, lines or curves. - **/ - -function Path( points ) { + * + * A Track of numeric keyframe values. + * + * @author Ben Houston / http://clara.io/ + * @author David Sarno / http://lighthaus.us/ + * @author tschw + */ - CurvePath.call( this ); +function NumberKeyframeTrack( name, times, values, interpolation ) { - this.type = 'Path'; + KeyframeTrack.call( this, name, times, values, interpolation ); - this.currentPoint = new Vector2(); +} - if ( points ) { +NumberKeyframeTrack.prototype = Object.assign( Object.create( KeyframeTrack.prototype ), { - this.setFromPoints( points ); + constructor: NumberKeyframeTrack, - } + ValueTypeName: 'number' -} + // ValueBufferType is inherited -Path.prototype = Object.assign( Object.create( CurvePath.prototype ), { + // DefaultInterpolation is inherited - constructor: Path, +} ); - setFromPoints: function ( points ) { +/** + * Spherical linear unit quaternion interpolant. + * + * @author tschw + */ - this.moveTo( points[ 0 ].x, points[ 0 ].y ); +function QuaternionLinearInterpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) { - for ( var i = 1, l = points.length; i < l; i ++ ) { + Interpolant.call( this, parameterPositions, sampleValues, sampleSize, resultBuffer ); - this.lineTo( points[ i ].x, points[ i ].y ); +} - } +QuaternionLinearInterpolant.prototype = Object.assign( Object.create( Interpolant.prototype ), { - }, + constructor: QuaternionLinearInterpolant, - moveTo: function ( x, y ) { + interpolate_: function ( i1, t0, t, t1 ) { - this.currentPoint.set( x, y ); // TODO consider referencing vectors instead of copying? + var result = this.resultBuffer, + values = this.sampleValues, + stride = this.valueSize, - }, + offset = i1 * stride, - lineTo: function ( x, y ) { + alpha = ( t - t0 ) / ( t1 - t0 ); - var curve = new LineCurve( this.currentPoint.clone(), new Vector2( x, y ) ); - this.curves.push( curve ); + for ( var end = offset + stride; offset !== end; offset += 4 ) { - this.currentPoint.set( x, y ); + Quaternion.slerpFlat( result, 0, values, offset - stride, values, offset, alpha ); - }, + } - quadraticCurveTo: function ( aCPx, aCPy, aX, aY ) { + return result; - var curve = new QuadraticBezierCurve( - this.currentPoint.clone(), - new Vector2( aCPx, aCPy ), - new Vector2( aX, aY ) - ); + } - this.curves.push( curve ); +} ); - this.currentPoint.set( aX, aY ); +/** + * + * A Track of quaternion keyframe values. + * + * @author Ben Houston / http://clara.io/ + * @author David Sarno / http://lighthaus.us/ + * @author tschw + */ - }, +function QuaternionKeyframeTrack( name, times, values, interpolation ) { - bezierCurveTo: function ( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY ) { + KeyframeTrack.call( this, name, times, values, interpolation ); - var curve = new CubicBezierCurve( - this.currentPoint.clone(), - new Vector2( aCP1x, aCP1y ), - new Vector2( aCP2x, aCP2y ), - new Vector2( aX, aY ) - ); +} - this.curves.push( curve ); +QuaternionKeyframeTrack.prototype = Object.assign( Object.create( KeyframeTrack.prototype ), { - this.currentPoint.set( aX, aY ); + constructor: QuaternionKeyframeTrack, - }, + ValueTypeName: 'quaternion', - splineThru: function ( pts /*Array of Vector*/ ) { + // ValueBufferType is inherited - var npts = [ this.currentPoint.clone() ].concat( pts ); + DefaultInterpolation: InterpolateLinear, - var curve = new SplineCurve( npts ); - this.curves.push( curve ); + InterpolantFactoryMethodLinear: function ( result ) { - this.currentPoint.copy( pts[ pts.length - 1 ] ); + return new QuaternionLinearInterpolant( this.times, this.values, this.getValueSize(), result ); }, - arc: function ( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) { + InterpolantFactoryMethodSmooth: undefined // not yet implemented - var x0 = this.currentPoint.x; - var y0 = this.currentPoint.y; +} ); - this.absarc( aX + x0, aY + y0, aRadius, - aStartAngle, aEndAngle, aClockwise ); +/** + * + * A Track that interpolates Strings + * + * + * @author Ben Houston / http://clara.io/ + * @author David Sarno / http://lighthaus.us/ + * @author tschw + */ - }, +function StringKeyframeTrack( name, times, values, interpolation ) { - absarc: function ( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) { + KeyframeTrack.call( this, name, times, values, interpolation ); - this.absellipse( aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise ); +} - }, +StringKeyframeTrack.prototype = Object.assign( Object.create( KeyframeTrack.prototype ), { - ellipse: function ( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ) { + constructor: StringKeyframeTrack, - var x0 = this.currentPoint.x; - var y0 = this.currentPoint.y; + ValueTypeName: 'string', + ValueBufferType: Array, - this.absellipse( aX + x0, aY + y0, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ); + DefaultInterpolation: InterpolateDiscrete, - }, + InterpolantFactoryMethodLinear: undefined, - absellipse: function ( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ) { + InterpolantFactoryMethodSmooth: undefined - var curve = new EllipseCurve( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ); +} ); - if ( this.curves.length > 0 ) { +/** + * + * A Track of vectored keyframe values. + * + * + * @author Ben Houston / http://clara.io/ + * @author David Sarno / http://lighthaus.us/ + * @author tschw + */ - // if a previous curve is present, attempt to join - var firstPoint = curve.getPoint( 0 ); +function VectorKeyframeTrack( name, times, values, interpolation ) { - if ( ! firstPoint.equals( this.currentPoint ) ) { + KeyframeTrack.call( this, name, times, values, interpolation ); - this.lineTo( firstPoint.x, firstPoint.y ); +} - } +VectorKeyframeTrack.prototype = Object.assign( Object.create( KeyframeTrack.prototype ), { - } + constructor: VectorKeyframeTrack, - this.curves.push( curve ); + ValueTypeName: 'vector' - var lastPoint = curve.getPoint( 1 ); - this.currentPoint.copy( lastPoint ); + // ValueBufferType is inherited - }, + // DefaultInterpolation is inherited - copy: function ( source ) { +} ); - CurvePath.prototype.copy.call( this, source ); +/** + * + * Reusable set of Tracks that represent an animation. + * + * @author Ben Houston / http://clara.io/ + * @author David Sarno / http://lighthaus.us/ + */ - this.currentPoint.copy( source.currentPoint ); +function AnimationClip( name, duration, tracks ) { - return this; + this.name = name; + this.tracks = tracks; + this.duration = ( duration !== undefined ) ? duration : - 1; - }, + this.uuid = _Math.generateUUID(); - toJSON: function () { + // this means it should figure out its duration by scanning the tracks + if ( this.duration < 0 ) { - var data = CurvePath.prototype.toJSON.call( this ); + this.resetDuration(); - data.currentPoint = this.currentPoint.toArray(); + } - return data; +} - }, +function getTrackTypeForValueTypeName( typeName ) { - fromJSON: function ( json ) { + switch ( typeName.toLowerCase() ) { - CurvePath.prototype.fromJSON.call( this, json ); + case 'scalar': + case 'double': + case 'float': + case 'number': + case 'integer': - this.currentPoint.fromArray( json.currentPoint ); + return NumberKeyframeTrack; - return this; + case 'vector': + case 'vector2': + case 'vector3': + case 'vector4': - } + return VectorKeyframeTrack; -} ); + case 'color': -/** - * @author zz85 / http://www.lab4games.net/zz85/blog - * Defines a 2d shape plane using paths. - **/ + return ColorKeyframeTrack; -// 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. + case 'quaternion': -function Shape( points ) { + return QuaternionKeyframeTrack; - Path.call( this, points ); + case 'bool': + case 'boolean': - this.uuid = _Math.generateUUID(); + return BooleanKeyframeTrack; - this.type = 'Shape'; + case 'string': - this.holes = []; + return StringKeyframeTrack; + + } + + throw new Error( 'THREE.KeyframeTrack: Unsupported typeName: ' + typeName ); } -Shape.prototype = Object.assign( Object.create( Path.prototype ), { +function parseKeyframeTrack( json ) { - constructor: Shape, + if ( json.type === undefined ) { - getPointsHoles: function ( divisions ) { + throw new Error( 'THREE.KeyframeTrack: track type undefined, can not parse' ); - var holesPts = []; + } - for ( var i = 0, l = this.holes.length; i < l; i ++ ) { + var trackType = getTrackTypeForValueTypeName( json.type ); - holesPts[ i ] = this.holes[ i ].getPoints( divisions ); + if ( json.times === undefined ) { - } + var times = [], values = []; - return holesPts; + AnimationUtils.flattenJSON( json.keys, times, values, 'value' ); - }, + json.times = times; + json.values = values; - // get points of shape and holes (keypoints based on segments parameter) + } - extractPoints: function ( divisions ) { + // derived classes can define a static parse method + if ( trackType.parse !== undefined ) { - return { + return trackType.parse( json ); - shape: this.getPoints( divisions ), - holes: this.getPointsHoles( divisions ) + } else { - }; + // by default, we assume a constructor compatible with the base + return new trackType( json.name, json.times, json.values, json.interpolation ); - }, + } - copy: function ( source ) { +} - Path.prototype.copy.call( this, source ); +Object.assign( AnimationClip, { - this.holes = []; + parse: function ( json ) { - for ( var i = 0, l = source.holes.length; i < l; i ++ ) { + var tracks = [], + jsonTracks = json.tracks, + frameTime = 1.0 / ( json.fps || 1.0 ); - var hole = source.holes[ i ]; + for ( var i = 0, n = jsonTracks.length; i !== n; ++ i ) { - this.holes.push( hole.clone() ); + tracks.push( parseKeyframeTrack( jsonTracks[ i ] ).scale( frameTime ) ); } - return this; + return new AnimationClip( json.name, json.duration, tracks ); }, - toJSON: function () { + toJSON: function ( clip ) { - var data = Path.prototype.toJSON.call( this ); + var tracks = [], + clipTracks = clip.tracks; - data.uuid = this.uuid; - data.holes = []; + var json = { - for ( var i = 0, l = this.holes.length; i < l; i ++ ) { + 'name': clip.name, + 'duration': clip.duration, + 'tracks': tracks, + 'uuid': clip.uuid - var hole = this.holes[ i ]; - data.holes.push( hole.toJSON() ); + }; + + for ( var i = 0, n = clipTracks.length; i !== n; ++ i ) { + + tracks.push( KeyframeTrack.toJSON( clipTracks[ i ] ) ); } - return data; + return json; }, - fromJSON: function ( json ) { + CreateFromMorphTargetSequence: function ( name, morphTargetSequence, fps, noLoop ) { - Path.prototype.fromJSON.call( this, json ); + var numMorphTargets = morphTargetSequence.length; + var tracks = []; - this.uuid = json.uuid; - this.holes = []; + for ( var i = 0; i < numMorphTargets; i ++ ) { - for ( var i = 0, l = json.holes.length; i < l; i ++ ) { + var times = []; + var values = []; - var hole = json.holes[ i ]; - this.holes.push( new Path().fromJSON( hole ) ); + times.push( + ( i + numMorphTargets - 1 ) % numMorphTargets, + i, + ( i + 1 ) % numMorphTargets ); - } + values.push( 0, 1, 0 ); - return this; + var order = AnimationUtils.getKeyframeOrder( times ); + times = AnimationUtils.sortedArray( times, 1, order ); + values = AnimationUtils.sortedArray( values, 1, order ); - } + // if there is a key at the first frame, duplicate it as the + // last frame as well for perfect loop. + if ( ! noLoop && times[ 0 ] === 0 ) { -} ); + times.push( numMorphTargets ); + values.push( values[ 0 ] ); -/** - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - */ + } -function Light( color, intensity ) { + tracks.push( + new NumberKeyframeTrack( + '.morphTargetInfluences[' + morphTargetSequence[ i ].name + ']', + times, values + ).scale( 1.0 / fps ) ); - Object3D.call( this ); + } - this.type = 'Light'; + return new AnimationClip( name, - 1, tracks ); - this.color = new Color( color ); - this.intensity = intensity !== undefined ? intensity : 1; + }, - this.receiveShadow = undefined; + findByName: function ( objectOrClipArray, name ) { -} + var clipArray = objectOrClipArray; -Light.prototype = Object.assign( Object.create( Object3D.prototype ), { + if ( ! Array.isArray( objectOrClipArray ) ) { - constructor: Light, + var o = objectOrClipArray; + clipArray = o.geometry && o.geometry.animations || o.animations; - isLight: true, + } - copy: function ( source ) { + for ( var i = 0; i < clipArray.length; i ++ ) { - Object3D.prototype.copy.call( this, source ); + if ( clipArray[ i ].name === name ) { - this.color.copy( source.color ); - this.intensity = source.intensity; + return clipArray[ i ]; - return this; + } + + } + + return null; }, - toJSON: function ( meta ) { + CreateClipsFromMorphTargetSequences: function ( morphTargets, fps, noLoop ) { - var data = Object3D.prototype.toJSON.call( this, meta ); + var animationToMorphTargets = {}; - data.object.color = this.color.getHex(); - data.object.intensity = this.intensity; + // tested with https://regex101.com/ on trick sequences + // such flamingo_flyA_003, flamingo_run1_003, crdeath0059 + var pattern = /^([\w-]*?)([\d]+)$/; - if ( this.groundColor !== undefined ) data.object.groundColor = this.groundColor.getHex(); + // 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 ++ ) { - 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; + var morphTarget = morphTargets[ i ]; + var parts = morphTarget.name.match( pattern ); - if ( this.shadow !== undefined ) data.object.shadow = this.shadow.toJSON(); + if ( parts && parts.length > 1 ) { - return data; + var name = parts[ 1 ]; - } + var animationMorphTargets = animationToMorphTargets[ name ]; + if ( ! animationMorphTargets ) { -} ); + animationToMorphTargets[ name ] = animationMorphTargets = []; -/** - * @author alteredq / http://alteredqualia.com/ - */ + } -function HemisphereLight( skyColor, groundColor, intensity ) { + animationMorphTargets.push( morphTarget ); - Light.call( this, skyColor, intensity ); + } - this.type = 'HemisphereLight'; + } - this.castShadow = undefined; + var clips = []; - this.position.copy( Object3D.DefaultUp ); - this.updateMatrix(); + for ( var name in animationToMorphTargets ) { - this.groundColor = new Color( groundColor ); + clips.push( AnimationClip.CreateFromMorphTargetSequence( name, animationToMorphTargets[ name ], fps, noLoop ) ); -} + } -HemisphereLight.prototype = Object.assign( Object.create( Light.prototype ), { + return clips; - constructor: HemisphereLight, + }, - isHemisphereLight: true, + // parse the animation.hierarchy format + parseAnimation: function ( animation, bones ) { - copy: function ( source ) { + if ( ! animation ) { - Light.prototype.copy.call( this, source ); + console.error( 'THREE.AnimationClip: No animation in JSONLoader data.' ); + return null; - this.groundColor.copy( source.groundColor ); + } - return this; + var addNonemptyTrack = function ( trackType, trackName, animationKeys, propertyName, destTracks ) { - } + // only return track if there are actually keys. + if ( animationKeys.length !== 0 ) { -} ); + var times = []; + var values = []; -/** - * @author mrdoob / http://mrdoob.com/ - */ + AnimationUtils.flattenJSON( animationKeys, times, values, propertyName ); -function LightShadow( camera ) { + // empty keys are filtered out, so check again + if ( times.length !== 0 ) { - this.camera = camera; + destTracks.push( new trackType( trackName, times, values ) ); - this.bias = 0; - this.radius = 1; + } - this.mapSize = new Vector2( 512, 512 ); + } - this.map = null; - this.matrix = new Matrix4(); + }; -} + var tracks = []; -Object.assign( LightShadow.prototype, { + var clipName = animation.name || 'default'; + // automatic length determination in AnimationClip. + var duration = animation.length || - 1; + var fps = animation.fps || 30; - copy: function ( source ) { + var hierarchyTracks = animation.hierarchy || []; - this.camera = source.camera.clone(); + for ( var h = 0; h < hierarchyTracks.length; h ++ ) { - this.bias = source.bias; - this.radius = source.radius; + var animationKeys = hierarchyTracks[ h ].keys; - this.mapSize.copy( source.mapSize ); + // skip empty tracks + if ( ! animationKeys || animationKeys.length === 0 ) continue; - return this; + // process morph targets + if ( animationKeys[ 0 ].morphTargets ) { - }, + // figure out all morph targets used in this track + var morphTargetNames = {}; - clone: function () { + for ( var k = 0; k < animationKeys.length; k ++ ) { - return new this.constructor().copy( this ); + if ( animationKeys[ k ].morphTargets ) { - }, + for ( var m = 0; m < animationKeys[ k ].morphTargets.length; m ++ ) { - toJSON: function () { + morphTargetNames[ animationKeys[ k ].morphTargets[ m ] ] = - 1; - var object = {}; + } - 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(); + } - object.camera = this.camera.toJSON( false ).object; - delete object.camera.matrix; + } - return object; + // 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 ) { - } + var times = []; + var values = []; -} ); + for ( var m = 0; m !== animationKeys[ k ].morphTargets.length; ++ m ) { -/** - * @author mrdoob / http://mrdoob.com/ - */ + var animationKey = animationKeys[ k ]; -function SpotLightShadow() { + times.push( animationKey.time ); + values.push( ( animationKey.morphTarget === morphTargetName ) ? 1 : 0 ); - LightShadow.call( this, new PerspectiveCamera( 50, 1, 0.5, 500 ) ); + } -} + tracks.push( new NumberKeyframeTrack( '.morphTargetInfluence[' + morphTargetName + ']', times, values ) ); -SpotLightShadow.prototype = Object.assign( Object.create( LightShadow.prototype ), { + } - constructor: SpotLightShadow, + duration = morphTargetNames.length * ( fps || 1.0 ); - isSpotLightShadow: true, + } else { - update: function ( light ) { + // ...assume skeletal animation - var camera = this.camera; + var boneName = '.bones[' + bones[ h ].name + ']'; - var fov = _Math.RAD2DEG * 2 * light.angle; - var aspect = this.mapSize.width / this.mapSize.height; - var far = light.distance || camera.far; + addNonemptyTrack( + VectorKeyframeTrack, boneName + '.position', + animationKeys, 'pos', tracks ); - if ( fov !== camera.fov || aspect !== camera.aspect || far !== camera.far ) { + addNonemptyTrack( + QuaternionKeyframeTrack, boneName + '.quaternion', + animationKeys, 'rot', tracks ); - camera.fov = fov; - camera.aspect = aspect; - camera.far = far; - camera.updateProjectionMatrix(); + addNonemptyTrack( + VectorKeyframeTrack, boneName + '.scale', + animationKeys, 'scl', tracks ); + + } + + } + + if ( tracks.length === 0 ) { + + return null; } + var clip = new AnimationClip( clipName, duration, tracks ); + + return clip; + } } ); -/** - * @author alteredq / http://alteredqualia.com/ - */ +Object.assign( AnimationClip.prototype, { -function SpotLight( color, intensity, distance, angle, penumbra, decay ) { + resetDuration: function () { - Light.call( this, color, intensity ); + var tracks = this.tracks, duration = 0; - this.type = 'SpotLight'; + for ( var i = 0, n = tracks.length; i !== n; ++ i ) { - this.position.copy( Object3D.DefaultUp ); - this.updateMatrix(); + var track = this.tracks[ i ]; - this.target = new Object3D(); + duration = Math.max( duration, track.times[ track.times.length - 1 ] ); - Object.defineProperty( this, 'power', { - get: function () { + } - // 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.duration = duration; - }, - 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; + }, + + trim: function () { + + for ( var i = 0; i < this.tracks.length; i ++ ) { + + this.tracks[ i ].trim( 0, this.duration ); } - } ); - this.distance = ( distance !== undefined ) ? distance : 0; - this.angle = ( angle !== undefined ) ? angle : Math.PI / 3; - this.penumbra = ( penumbra !== undefined ) ? penumbra : 0; - this.decay = ( decay !== undefined ) ? decay : 1; // for physically correct lights, should be 2. + return this; - this.shadow = new SpotLightShadow(); + }, -} + validate: function () { -SpotLight.prototype = Object.assign( Object.create( Light.prototype ), { + var valid = true; - constructor: SpotLight, + for ( var i = 0; i < this.tracks.length; i ++ ) { - isSpotLight: true, + valid = valid && this.tracks[ i ].validate(); - copy: function ( source ) { + } - Light.prototype.copy.call( this, source ); + return valid; - this.distance = source.distance; - this.angle = source.angle; - this.penumbra = source.penumbra; - this.decay = source.decay; + }, - this.target = source.target.clone(); + optimize: function () { - this.shadow = source.shadow.clone(); + for ( var i = 0; i < this.tracks.length; i ++ ) { + + this.tracks[ i ].optimize(); + + } return this; @@ -36333,4020 +35105,3908 @@ SpotLight.prototype = Object.assign( Object.create( Light.prototype ), { * @author mrdoob / http://mrdoob.com/ */ +var Cache = { -function PointLight( color, intensity, distance, decay ) { - - Light.call( this, color, intensity ); - - this.type = 'PointLight'; + enabled: false, - Object.defineProperty( this, 'power', { - get: function () { + files: {}, - // 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; + add: function ( key, file ) { - }, - set: function ( power ) { + if ( this.enabled === false ) return; - // 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 ); + // console.log( 'THREE.Cache', 'Adding key:', key ); - } - } ); + this.files[ key ] = file; - this.distance = ( distance !== undefined ) ? distance : 0; - this.decay = ( decay !== undefined ) ? decay : 1; // for physically correct lights, should be 2. + }, - this.shadow = new LightShadow( new PerspectiveCamera( 90, 1, 0.5, 500 ) ); + get: function ( key ) { -} + if ( this.enabled === false ) return; -PointLight.prototype = Object.assign( Object.create( Light.prototype ), { + // console.log( 'THREE.Cache', 'Checking key:', key ); - constructor: PointLight, + return this.files[ key ]; - isPointLight: true, + }, - copy: function ( source ) { + remove: function ( key ) { - Light.prototype.copy.call( this, source ); + delete this.files[ key ]; - this.distance = source.distance; - this.decay = source.decay; + }, - this.shadow = source.shadow.clone(); + clear: function () { - return this; + this.files = {}; } -} ); +}; /** * @author mrdoob / http://mrdoob.com/ */ -function DirectionalLightShadow( ) { +function LoadingManager( onLoad, onProgress, onError ) { - LightShadow.call( this, new OrthographicCamera( - 5, 5, 5, - 5, 0.5, 500 ) ); + var scope = this; -} + var isLoading = false; + var itemsLoaded = 0; + var itemsTotal = 0; + var urlModifier = undefined; -DirectionalLightShadow.prototype = Object.assign( Object.create( LightShadow.prototype ), { + // Refer to #5689 for the reason why we don't set .onStart + // in the constructor - constructor: DirectionalLightShadow + this.onStart = undefined; + this.onLoad = onLoad; + this.onProgress = onProgress; + this.onError = onError; -} ); + this.itemStart = function ( url ) { -/** - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - */ + itemsTotal ++; -function DirectionalLight( color, intensity ) { + if ( isLoading === false ) { - Light.call( this, color, intensity ); + if ( scope.onStart !== undefined ) { - this.type = 'DirectionalLight'; + scope.onStart( url, itemsLoaded, itemsTotal ); - this.position.copy( Object3D.DefaultUp ); - this.updateMatrix(); + } - this.target = new Object3D(); + } - this.shadow = new DirectionalLightShadow(); + isLoading = true; -} + }; -DirectionalLight.prototype = Object.assign( Object.create( Light.prototype ), { + this.itemEnd = function ( url ) { - constructor: DirectionalLight, + itemsLoaded ++; - isDirectionalLight: true, + if ( scope.onProgress !== undefined ) { - copy: function ( source ) { + scope.onProgress( url, itemsLoaded, itemsTotal ); - Light.prototype.copy.call( this, source ); + } - this.target = source.target.clone(); + if ( itemsLoaded === itemsTotal ) { - this.shadow = source.shadow.clone(); + isLoading = false; - return this; + if ( scope.onLoad !== undefined ) { - } + scope.onLoad(); -} ); + } -/** - * @author mrdoob / http://mrdoob.com/ - */ + } -function AmbientLight( color, intensity ) { + }; - Light.call( this, color, intensity ); + this.itemError = function ( url ) { - this.type = 'AmbientLight'; + if ( scope.onError !== undefined ) { - this.castShadow = undefined; + scope.onError( url ); -} + } -AmbientLight.prototype = Object.assign( Object.create( Light.prototype ), { + }; - constructor: AmbientLight, + this.resolveURL = function ( url ) { - isAmbientLight: true + if ( urlModifier ) { -} ); + return urlModifier( url ); -/** - * @author abelnation / http://github.com/abelnation - */ + } -function RectAreaLight( color, intensity, width, height ) { + return url; - Light.call( this, color, intensity ); + }; - this.type = 'RectAreaLight'; + this.setURLModifier = function ( transform ) { - this.width = ( width !== undefined ) ? width : 10; - this.height = ( height !== undefined ) ? height : 10; + urlModifier = transform; + return this; + + }; } -RectAreaLight.prototype = Object.assign( Object.create( Light.prototype ), { +var DefaultLoadingManager = new LoadingManager(); - constructor: RectAreaLight, +/** + * @author mrdoob / http://mrdoob.com/ + */ - isRectAreaLight: true, +var loading = {}; - copy: function ( source ) { +function FileLoader( manager ) { - Light.prototype.copy.call( this, source ); + this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager; - this.width = source.width; - this.height = source.height; +} - return this; +Object.assign( FileLoader.prototype, { - }, + load: function ( url, onLoad, onProgress, onError ) { - toJSON: function ( meta ) { + if ( url === undefined ) url = ''; - var data = Light.prototype.toJSON.call( this, meta ); + if ( this.path !== undefined ) url = this.path + url; - data.object.width = this.width; - data.object.height = this.height; + url = this.manager.resolveURL( url ); - return data; + var scope = this; - } + var cached = Cache.get( url ); -} ); + if ( cached !== undefined ) { -/** - * - * A Track that interpolates Strings - * - * - * @author Ben Houston / http://clara.io/ - * @author David Sarno / http://lighthaus.us/ - * @author tschw - */ + scope.manager.itemStart( url ); -function StringKeyframeTrack( name, times, values, interpolation ) { + setTimeout( function () { - KeyframeTrack.call( this, name, times, values, interpolation ); + if ( onLoad ) onLoad( cached ); -} + scope.manager.itemEnd( url ); -StringKeyframeTrack.prototype = Object.assign( Object.create( KeyframeTrack.prototype ), { + }, 0 ); - constructor: StringKeyframeTrack, + return cached; - ValueTypeName: 'string', - ValueBufferType: Array, + } - DefaultInterpolation: InterpolateDiscrete, + // Check if request is duplicate - InterpolantFactoryMethodLinear: undefined, + if ( loading[ url ] !== undefined ) { - InterpolantFactoryMethodSmooth: undefined + loading[ url ].push( { -} ); + onLoad: onLoad, + onProgress: onProgress, + onError: onError -/** - * - * A Track of Boolean keyframe values. - * - * - * @author Ben Houston / http://clara.io/ - * @author David Sarno / http://lighthaus.us/ - * @author tschw - */ + } ); -function BooleanKeyframeTrack( name, times, values ) { + return; - KeyframeTrack.call( this, name, times, values ); + } -} + // Check for data: URI + var dataUriRegex = /^data:(.*?)(;base64)?,(.*)$/; + var dataUriRegexResult = url.match( dataUriRegex ); -BooleanKeyframeTrack.prototype = Object.assign( Object.create( KeyframeTrack.prototype ), { + // Safari can not handle Data URIs through XMLHttpRequest so process manually + if ( dataUriRegexResult ) { - constructor: BooleanKeyframeTrack, + var mimeType = dataUriRegexResult[ 1 ]; + var isBase64 = !! dataUriRegexResult[ 2 ]; + var data = dataUriRegexResult[ 3 ]; - ValueTypeName: 'bool', - ValueBufferType: Array, + data = decodeURIComponent( data ); - DefaultInterpolation: InterpolateDiscrete, + if ( isBase64 ) data = atob( data ); - InterpolantFactoryMethodLinear: undefined, - InterpolantFactoryMethodSmooth: undefined + try { - // Note: Actually this track could have a optimized / compressed - // representation of a single value and a custom interpolant that - // computes "firstValue ^ isOdd( index )". + var response; + var responseType = ( this.responseType || '' ).toLowerCase(); -} ); + switch ( responseType ) { -/** - * 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 - */ + case 'arraybuffer': + case 'blob': -function Interpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) { + var view = new Uint8Array( data.length ); - this.parameterPositions = parameterPositions; - this._cachedIndex = 0; + for ( var i = 0; i < data.length; i ++ ) { - this.resultBuffer = resultBuffer !== undefined ? - resultBuffer : new sampleValues.constructor( sampleSize ); - this.sampleValues = sampleValues; - this.valueSize = sampleSize; + view[ i ] = data.charCodeAt( i ); -} + } -Object.assign( Interpolant.prototype, { + if ( responseType === 'blob' ) { - evaluate: function ( t ) { + response = new Blob( [ view.buffer ], { type: mimeType } ); - var pp = this.parameterPositions, - i1 = this._cachedIndex, + } else { - t1 = pp[ i1 ], - t0 = pp[ i1 - 1 ]; + response = view.buffer; - validate_interval: { + } - seek: { + break; - var right; + case 'document': - linear_scan: { + var parser = new DOMParser(); + response = parser.parseFromString( data, mimeType ); - //- See http://jsperf.com/comparison-to-undefined/3 - //- slower code: - //- - //- if ( t >= t1 || t1 === undefined ) { - forward_scan: if ( ! ( t < t1 ) ) { + break; - for ( var giveUpAt = i1 + 2; ; ) { + case 'json': - if ( t1 === undefined ) { + response = JSON.parse( data ); - if ( t < t0 ) break forward_scan; + break; - // after end + default: // 'text' or other - i1 = pp.length; - this._cachedIndex = i1; - return this.afterEnd_( i1 - 1, t, t0 ); + response = data; - } + break; - if ( i1 === giveUpAt ) break; // this loop + } - t0 = t1; - t1 = pp[ ++ i1 ]; + // Wait for next browser tick like standard XMLHttpRequest event dispatching does + setTimeout( function () { - if ( t < t1 ) { + if ( onLoad ) onLoad( response ); - // we have arrived at the sought interval - break seek; + scope.manager.itemEnd( url ); - } + }, 0 ); - } + } catch ( error ) { - // prepare binary search on the right side of the index - right = pp.length; - break linear_scan; + // Wait for next browser tick like standard XMLHttpRequest event dispatching does + setTimeout( function () { - } + if ( onError ) onError( error ); - //- slower code: - //- if ( t < t0 || t0 === undefined ) { - if ( ! ( t >= t0 ) ) { + scope.manager.itemError( url ); + scope.manager.itemEnd( url ); - // looping? + }, 0 ); - var t1global = pp[ 1 ]; + } - if ( t < t1global ) { + } else { - i1 = 2; // + 1, using the scan for the details - t0 = t1global; + // Initialise array for duplicate requests - } + loading[ url ] = []; - // linear reverse scan + loading[ url ].push( { - for ( var giveUpAt = i1 - 2; ; ) { + onLoad: onLoad, + onProgress: onProgress, + onError: onError - if ( t0 === undefined ) { + } ); - // before start + var request = new XMLHttpRequest(); - this._cachedIndex = 0; - return this.beforeStart_( 0, t, t1 ); + request.open( 'GET', url, true ); - } + request.addEventListener( 'load', function ( event ) { - if ( i1 === giveUpAt ) break; // this loop + var response = this.response; - t1 = t0; - t0 = pp[ -- i1 - 1 ]; + Cache.add( url, response ); - if ( t >= t0 ) { + var callbacks = loading[ url ]; - // we have arrived at the sought interval - break seek; + delete loading[ url ]; - } + if ( this.status === 200 || this.status === 0 ) { - } + // Some browsers return HTTP Status 0 when using non-http protocol + // e.g. 'file://' or 'data://'. Handle as success. - // prepare binary search on the left side of the index - right = i1; - i1 = 0; - break linear_scan; + if ( this.status === 0 ) console.warn( 'THREE.FileLoader: HTTP Status 0 received.' ); + + for ( var i = 0, il = callbacks.length; i < il; i ++ ) { + + var callback = callbacks[ i ]; + if ( callback.onLoad ) callback.onLoad( response ); } - // the interval is valid + scope.manager.itemEnd( url ); - break validate_interval; + } else { - } // linear scan + for ( var i = 0, il = callbacks.length; i < il; i ++ ) { - // binary search + var callback = callbacks[ i ]; + if ( callback.onError ) callback.onError( event ); - while ( i1 < right ) { + } - var mid = ( i1 + right ) >>> 1; + scope.manager.itemError( url ); + scope.manager.itemEnd( url ); - if ( t < pp[ mid ] ) { + } - right = mid; + }, false ); - } else { + request.addEventListener( 'progress', function ( event ) { - i1 = mid + 1; + var callbacks = loading[ url ]; - } + for ( var i = 0, il = callbacks.length; i < il; i ++ ) { - } + var callback = callbacks[ i ]; + if ( callback.onProgress ) callback.onProgress( event ); - t1 = pp[ i1 ]; - t0 = pp[ i1 - 1 ]; + } - // check boundary cases, again + }, false ); - if ( t0 === undefined ) { + request.addEventListener( 'error', function ( event ) { - this._cachedIndex = 0; - return this.beforeStart_( 0, t, t1 ); + var callbacks = loading[ url ]; - } + delete loading[ url ]; - if ( t1 === undefined ) { + for ( var i = 0, il = callbacks.length; i < il; i ++ ) { - i1 = pp.length; - this._cachedIndex = i1; - return this.afterEnd_( i1 - 1, t0, t ); + var callback = callbacks[ i ]; + if ( callback.onError ) callback.onError( event ); } - } // seek - - this._cachedIndex = i1; + scope.manager.itemError( url ); + scope.manager.itemEnd( url ); - this.intervalChanged_( i1, t0, t1 ); + }, false ); - } // validate_interval + request.addEventListener( 'abort', function ( event ) { - return this.interpolate_( i1, t0, t, t1 ); + var callbacks = loading[ url ]; - }, + delete loading[ url ]; - settings: null, // optional, subclass-specific settings structure - // Note: The indirection allows central control of many interpolants. + for ( var i = 0, il = callbacks.length; i < il; i ++ ) { - // --- Protected interface + var callback = callbacks[ i ]; + if ( callback.onError ) callback.onError( event ); - DefaultSettings_: {}, + } - getSettings_: function () { + scope.manager.itemError( url ); + scope.manager.itemEnd( url ); - return this.settings || this.DefaultSettings_; + }, false ); - }, + if ( this.responseType !== undefined ) request.responseType = this.responseType; + if ( this.withCredentials !== undefined ) request.withCredentials = this.withCredentials; - copySampleValue_: function ( index ) { + if ( request.overrideMimeType ) request.overrideMimeType( this.mimeType !== undefined ? this.mimeType : 'text/plain' ); - // copies a sample value to the result buffer + for ( var header in this.requestHeader ) { - var result = this.resultBuffer, - values = this.sampleValues, - stride = this.valueSize, - offset = index * stride; + request.setRequestHeader( header, this.requestHeader[ header ] ); - for ( var i = 0; i !== stride; ++ i ) { + } - result[ i ] = values[ offset + i ]; + request.send( null ); } - return result; + scope.manager.itemStart( url ); + + return request; }, - // Template methods for derived classes: + setPath: function ( value ) { - interpolate_: function ( /* i1, t0, t, t1 */ ) { + this.path = value; + return this; - throw new Error( 'call to abstract method' ); - // implementations shall return this.resultBuffer + }, + + setResponseType: function ( value ) { + + this.responseType = value; + return this; }, - intervalChanged_: function ( /* i1, t0, t1 */ ) { + setWithCredentials: function ( value ) { - // empty + this.withCredentials = value; + return this; - } + }, -} ); + setMimeType: function ( value ) { -//!\ DECLARE ALIAS AFTER assign prototype ! -Object.assign( Interpolant.prototype, { + this.mimeType = value; + return this; - //( 0, t, t0 ), returns this.resultBuffer - beforeStart_: Interpolant.prototype.copySampleValue_, + }, - //( N-1, tN-1, t ), returns this.resultBuffer - afterEnd_: Interpolant.prototype.copySampleValue_, + setRequestHeader: function ( value ) { + + this.requestHeader = value; + return this; + + } } ); /** - * Spherical linear unit quaternion interpolant. - * - * @author tschw + * @author bhouston / http://clara.io/ */ -function QuaternionLinearInterpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) { +function AnimationLoader( manager ) { - Interpolant.call( this, parameterPositions, sampleValues, sampleSize, resultBuffer ); + this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager; } -QuaternionLinearInterpolant.prototype = Object.assign( Object.create( Interpolant.prototype ), { +Object.assign( AnimationLoader.prototype, { - constructor: QuaternionLinearInterpolant, + load: function ( url, onLoad, onProgress, onError ) { - interpolate_: function ( i1, t0, t, t1 ) { + var scope = this; - var result = this.resultBuffer, - values = this.sampleValues, - stride = this.valueSize, + var loader = new FileLoader( scope.manager ); + loader.setPath( scope.path ); + loader.load( url, function ( text ) { - offset = i1 * stride, + onLoad( scope.parse( JSON.parse( text ) ) ); - alpha = ( t - t0 ) / ( t1 - t0 ); + }, onProgress, onError ); - for ( var end = offset + stride; offset !== end; offset += 4 ) { + }, - Quaternion.slerpFlat( result, 0, values, offset - stride, values, offset, alpha ); + parse: function ( json, onLoad ) { + + var animations = []; + + for ( var i = 0; i < json.length; i ++ ) { + + var clip = AnimationClip.parse( json[ i ] ); + + animations.push( clip ); } - return result; + onLoad( animations ); + + }, + + setPath: function ( value ) { + + this.path = value; + return this; } } ); /** + * @author mrdoob / http://mrdoob.com/ * - * A Track of quaternion keyframe values. - * - * @author Ben Houston / http://clara.io/ - * @author David Sarno / http://lighthaus.us/ - * @author tschw + * Abstract Base class to block based textures loader (dds, pvr, ...) */ -function QuaternionKeyframeTrack( name, times, values, interpolation ) { +function CompressedTextureLoader( manager ) { - KeyframeTrack.call( this, name, times, values, interpolation ); + this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager; + + // override in sub classes + this._parser = null; } -QuaternionKeyframeTrack.prototype = Object.assign( Object.create( KeyframeTrack.prototype ), { +Object.assign( CompressedTextureLoader.prototype, { - constructor: QuaternionKeyframeTrack, + load: function ( url, onLoad, onProgress, onError ) { - ValueTypeName: 'quaternion', + var scope = this; - // ValueBufferType is inherited + var images = []; - DefaultInterpolation: InterpolateLinear, - - InterpolantFactoryMethodLinear: function ( result ) { - - return new QuaternionLinearInterpolant( this.times, this.values, this.getValueSize(), result ); - - }, - - InterpolantFactoryMethodSmooth: undefined // not yet implemented - -} ); - -/** - * - * A Track of keyframe values that represent color. - * - * - * @author Ben Houston / http://clara.io/ - * @author David Sarno / http://lighthaus.us/ - * @author tschw - */ - -function ColorKeyframeTrack( name, times, values, interpolation ) { - - KeyframeTrack.call( this, name, times, values, interpolation ); + var texture = new CompressedTexture(); + texture.image = images; -} + var loader = new FileLoader( this.manager ); + loader.setPath( this.path ); + loader.setResponseType( 'arraybuffer' ); -ColorKeyframeTrack.prototype = Object.assign( Object.create( KeyframeTrack.prototype ), { + function loadTexture( i ) { - constructor: ColorKeyframeTrack, + loader.load( url[ i ], function ( buffer ) { - ValueTypeName: 'color' + var texDatas = scope._parser( buffer, true ); - // ValueBufferType is inherited + images[ i ] = { + width: texDatas.width, + height: texDatas.height, + format: texDatas.format, + mipmaps: texDatas.mipmaps + }; - // DefaultInterpolation is inherited + loaded += 1; - // Note: Very basic implementation and nothing special yet. - // However, this is the place for color space parameterization. + if ( loaded === 6 ) { -} ); + if ( texDatas.mipmapCount === 1 ) + texture.minFilter = LinearFilter; -/** - * - * A Track of numeric keyframe values. - * - * @author Ben Houston / http://clara.io/ - * @author David Sarno / http://lighthaus.us/ - * @author tschw - */ + texture.format = texDatas.format; + texture.needsUpdate = true; -function NumberKeyframeTrack( name, times, values, interpolation ) { + if ( onLoad ) onLoad( texture ); - KeyframeTrack.call( this, name, times, values, interpolation ); + } -} + }, onProgress, onError ); -NumberKeyframeTrack.prototype = Object.assign( Object.create( KeyframeTrack.prototype ), { + } - constructor: NumberKeyframeTrack, + if ( Array.isArray( url ) ) { - ValueTypeName: 'number' + var loaded = 0; - // ValueBufferType is inherited + for ( var i = 0, il = url.length; i < il; ++ i ) { - // DefaultInterpolation is inherited + loadTexture( i ); -} ); + } -/** - * 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 - */ + } else { -function CubicInterpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) { + // compressed cubemap texture stored in a single DDS file - Interpolant.call( this, parameterPositions, sampleValues, sampleSize, resultBuffer ); + loader.load( url, function ( buffer ) { - this._weightPrev = - 0; - this._offsetPrev = - 0; - this._weightNext = - 0; - this._offsetNext = - 0; + var texDatas = scope._parser( buffer, true ); -} + if ( texDatas.isCubemap ) { -CubicInterpolant.prototype = Object.assign( Object.create( Interpolant.prototype ), { + var faces = texDatas.mipmaps.length / texDatas.mipmapCount; - constructor: CubicInterpolant, + for ( var f = 0; f < faces; f ++ ) { - DefaultSettings_: { + images[ f ] = { mipmaps: [] }; - endingStart: ZeroCurvatureEnding, - endingEnd: ZeroCurvatureEnding + for ( var i = 0; i < texDatas.mipmapCount; i ++ ) { - }, + images[ f ].mipmaps.push( texDatas.mipmaps[ f * texDatas.mipmapCount + i ] ); + images[ f ].format = texDatas.format; + images[ f ].width = texDatas.width; + images[ f ].height = texDatas.height; - intervalChanged_: function ( i1, t0, t1 ) { + } - var pp = this.parameterPositions, - iPrev = i1 - 2, - iNext = i1 + 1, + } - tPrev = pp[ iPrev ], - tNext = pp[ iNext ]; + } else { - if ( tPrev === undefined ) { + texture.image.width = texDatas.width; + texture.image.height = texDatas.height; + texture.mipmaps = texDatas.mipmaps; - switch ( this.getSettings_().endingStart ) { + } - case ZeroSlopeEnding: + if ( texDatas.mipmapCount === 1 ) { - // f'(t0) = 0 - iPrev = i1; - tPrev = 2 * t0 - t1; + texture.minFilter = LinearFilter; - break; + } - case WrapAroundEnding: + texture.format = texDatas.format; + texture.needsUpdate = true; - // use the other end of the curve - iPrev = pp.length - 2; - tPrev = t0 + pp[ iPrev ] - pp[ iPrev + 1 ]; + if ( onLoad ) onLoad( texture ); - break; + }, onProgress, onError ); - default: // ZeroCurvatureEnding + } - // f''(t0) = 0 a.k.a. Natural Spline - iPrev = i1; - tPrev = t1; + return texture; - } + }, - } + setPath: function ( value ) { - if ( tNext === undefined ) { + this.path = value; + return this; - switch ( this.getSettings_().endingEnd ) { + } - case ZeroSlopeEnding: +} ); - // f'(tN) = 0 - iNext = i1; - tNext = 2 * t1 - t0; +/** + * @author Nikos M. / https://github.com/foo123/ + * + * Abstract Base class to load generic binary textures formats (rgbe, hdr, ...) + */ - break; +function DataTextureLoader( manager ) { - case WrapAroundEnding: + this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager; - // use the other end of the curve - iNext = 1; - tNext = t1 + pp[ 1 ] - pp[ 0 ]; + // override in sub classes + this._parser = null; - break; +} - default: // ZeroCurvatureEnding +Object.assign( DataTextureLoader.prototype, { - // f''(tN) = 0, a.k.a. Natural Spline - iNext = i1 - 1; - tNext = t0; + load: function ( url, onLoad, onProgress, onError ) { - } + var scope = this; - } + var texture = new DataTexture(); - var halfDt = ( t1 - t0 ) * 0.5, - stride = this.valueSize; + var loader = new FileLoader( this.manager ); + loader.setResponseType( 'arraybuffer' ); + loader.setPath( this.path ); + loader.load( url, function ( buffer ) { - this._weightPrev = halfDt / ( t0 - tPrev ); - this._weightNext = halfDt / ( tNext - t1 ); - this._offsetPrev = iPrev * stride; - this._offsetNext = iNext * stride; + var texData = scope._parser( buffer ); - }, + if ( ! texData ) return; - interpolate_: function ( i1, t0, t, t1 ) { + if ( texData.image !== undefined ) { - var result = this.resultBuffer, - values = this.sampleValues, - stride = this.valueSize, + texture.image = texData.image; - o1 = i1 * stride, o0 = o1 - stride, - oP = this._offsetPrev, oN = this._offsetNext, - wP = this._weightPrev, wN = this._weightNext, + } else if ( texData.data !== undefined ) { - p = ( t - t0 ) / ( t1 - t0 ), - pp = p * p, - ppp = pp * p; + texture.image.width = texData.width; + texture.image.height = texData.height; + texture.image.data = texData.data; - // evaluate polynomials + } - var sP = - wP * ppp + 2 * wP * pp - wP * p; - var s0 = ( 1 + wP ) * ppp + ( - 1.5 - 2 * wP ) * pp + ( - 0.5 + wP ) * p + 1; - var s1 = ( - 1 - wN ) * ppp + ( 1.5 + wN ) * pp + 0.5 * p; - var sN = wN * ppp - wN * pp; + texture.wrapS = texData.wrapS !== undefined ? texData.wrapS : ClampToEdgeWrapping; + texture.wrapT = texData.wrapT !== undefined ? texData.wrapT : ClampToEdgeWrapping; - // combine data linearly + texture.magFilter = texData.magFilter !== undefined ? texData.magFilter : LinearFilter; + texture.minFilter = texData.minFilter !== undefined ? texData.minFilter : LinearMipMapLinearFilter; - for ( var i = 0; i !== stride; ++ i ) { + texture.anisotropy = texData.anisotropy !== undefined ? texData.anisotropy : 1; - result[ i ] = - sP * values[ oP + i ] + - s0 * values[ o0 + i ] + - s1 * values[ o1 + i ] + - sN * values[ oN + i ]; + if ( texData.format !== undefined ) { - } + texture.format = texData.format; - return result; + } + if ( texData.type !== undefined ) { - } + texture.type = texData.type; -} ); + } -/** - * @author tschw - */ + if ( texData.mipmaps !== undefined ) { -function LinearInterpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) { + texture.mipmaps = texData.mipmaps; - Interpolant.call( this, parameterPositions, sampleValues, sampleSize, resultBuffer ); + } -} + if ( texData.mipmapCount === 1 ) { -LinearInterpolant.prototype = Object.assign( Object.create( Interpolant.prototype ), { + texture.minFilter = LinearFilter; - constructor: LinearInterpolant, + } - interpolate_: function ( i1, t0, t, t1 ) { + texture.needsUpdate = true; - var result = this.resultBuffer, - values = this.sampleValues, - stride = this.valueSize, + if ( onLoad ) onLoad( texture, texData ); - offset1 = i1 * stride, - offset0 = offset1 - stride, + }, onProgress, onError ); - weight1 = ( t - t0 ) / ( t1 - t0 ), - weight0 = 1 - weight1; - for ( var i = 0; i !== stride; ++ i ) { + return texture; - result[ i ] = - values[ offset0 + i ] * weight0 + - values[ offset1 + i ] * weight1; + }, - } + setPath: function ( value ) { - return result; + this.path = value; + return this; } } ); /** - * - * Interpolant that evaluates to the sample value at the position preceeding - * the parameter. - * - * @author tschw + * @author mrdoob / http://mrdoob.com/ */ -function DiscreteInterpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) { - - Interpolant.call( this, parameterPositions, sampleValues, sampleSize, resultBuffer ); - -} -DiscreteInterpolant.prototype = Object.assign( Object.create( Interpolant.prototype ), { +function ImageLoader( manager ) { - constructor: DiscreteInterpolant, + this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager; - interpolate_: function ( i1 /*, t0, t, t1 */ ) { +} - return this.copySampleValue_( i1 - 1 ); +Object.assign( ImageLoader.prototype, { - } + crossOrigin: 'anonymous', -} ); + load: function ( url, onLoad, onProgress, onError ) { -/** - * @author tschw - * @author Ben Houston / http://clara.io/ - * @author David Sarno / http://lighthaus.us/ - */ + if ( url === undefined ) url = ''; -var AnimationUtils = { + if ( this.path !== undefined ) url = this.path + url; - // same as Array.prototype.slice, but also works on typed arrays - arraySlice: function ( array, from, to ) { + url = this.manager.resolveURL( url ); - if ( AnimationUtils.isTypedArray( array ) ) { + var scope = this; - // 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 cached = Cache.get( url ); - } + if ( cached !== undefined ) { - return array.slice( from, to ); + scope.manager.itemStart( url ); - }, + setTimeout( function () { - // converts an array to a specific type - convertArray: function ( array, type, forceClone ) { + if ( onLoad ) onLoad( cached ); - if ( ! array || // let 'undefined' and 'null' pass - ! forceClone && array.constructor === type ) return array; + scope.manager.itemEnd( url ); - if ( typeof type.BYTES_PER_ELEMENT === 'number' ) { + }, 0 ); - return new type( array ); // create typed array + return cached; } - return Array.prototype.slice.call( array ); // create Array + var image = document.createElementNS( 'http://www.w3.org/1999/xhtml', 'img' ); - }, + function onImageLoad() { - isTypedArray: function ( object ) { + image.removeEventListener( 'load', onImageLoad, false ); + image.removeEventListener( 'error', onImageError, false ); - return ArrayBuffer.isView( object ) && - ! ( object instanceof DataView ); + Cache.add( url, this ); - }, + if ( onLoad ) onLoad( this ); - // returns an array by which times and values can be sorted - getKeyframeOrder: function ( times ) { + scope.manager.itemEnd( url ); - function compareTime( i, j ) { + } - return times[ i ] - times[ j ]; + function onImageError( event ) { - } + image.removeEventListener( 'load', onImageLoad, false ); + image.removeEventListener( 'error', onImageError, false ); - var n = times.length; - var result = new Array( n ); - for ( var i = 0; i !== n; ++ i ) result[ i ] = i; + if ( onError ) onError( event ); - result.sort( compareTime ); + scope.manager.itemError( url ); + scope.manager.itemEnd( url ); - return result; + } - }, + image.addEventListener( 'load', onImageLoad, false ); + image.addEventListener( 'error', onImageError, false ); - // uses the array previously returned by 'getKeyframeOrder' to sort data - sortedArray: function ( values, stride, order ) { + if ( url.substr( 0, 5 ) !== 'data:' ) { - var nValues = values.length; - var result = new values.constructor( nValues ); + if ( this.crossOrigin !== undefined ) image.crossOrigin = this.crossOrigin; - for ( var i = 0, dstOffset = 0; dstOffset !== nValues; ++ i ) { + } - var srcOffset = order[ i ] * stride; + scope.manager.itemStart( url ); - for ( var j = 0; j !== stride; ++ j ) { + image.src = url; - result[ dstOffset ++ ] = values[ srcOffset + j ]; + return image; - } + }, - } + setCrossOrigin: function ( value ) { - return result; + this.crossOrigin = value; + return this; }, - // function for parsing AOS keyframe formats - flattenJSON: function ( jsonKeys, times, values, valuePropertyName ) { + setPath: function ( value ) { - var i = 1, key = jsonKeys[ 0 ]; + this.path = value; + return this; - while ( key !== undefined && key[ valuePropertyName ] === undefined ) { + } - key = jsonKeys[ i ++ ]; +} ); - } +/** + * @author mrdoob / http://mrdoob.com/ + */ - if ( key === undefined ) return; // no data - var value = key[ valuePropertyName ]; - if ( value === undefined ) return; // no data +function CubeTextureLoader( manager ) { - if ( Array.isArray( value ) ) { + this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager; - do { +} - value = key[ valuePropertyName ]; +Object.assign( CubeTextureLoader.prototype, { - if ( value !== undefined ) { + crossOrigin: 'anonymous', - times.push( key.time ); - values.push.apply( values, value ); // push all elements + load: function ( urls, onLoad, onProgress, onError ) { - } + var texture = new CubeTexture(); - key = jsonKeys[ i ++ ]; + var loader = new ImageLoader( this.manager ); + loader.setCrossOrigin( this.crossOrigin ); + loader.setPath( this.path ); - } while ( key !== undefined ); + var loaded = 0; - } else if ( value.toArray !== undefined ) { + function loadTexture( i ) { - // ...assume THREE.Math-ish + loader.load( urls[ i ], function ( image ) { - do { + texture.images[ i ] = image; - value = key[ valuePropertyName ]; + loaded ++; - if ( value !== undefined ) { + if ( loaded === 6 ) { - times.push( key.time ); - value.toArray( values, values.length ); + texture.needsUpdate = true; + + if ( onLoad ) onLoad( texture ); } - key = jsonKeys[ i ++ ]; + }, undefined, onError ); - } while ( key !== undefined ); + } - } else { + for ( var i = 0; i < urls.length; ++ i ) { - // otherwise push as-is + loadTexture( i ); - do { + } - value = key[ valuePropertyName ]; + return texture; - if ( value !== undefined ) { + }, - times.push( key.time ); - values.push( value ); + setCrossOrigin: function ( value ) { - } + this.crossOrigin = value; + return this; - key = jsonKeys[ i ++ ]; + }, - } while ( key !== undefined ); + setPath: function ( value ) { - } + this.path = value; + return this; } -}; +} ); /** - * - * A timed sequence of keyframes for a specific property. - * - * - * @author Ben Houston / http://clara.io/ - * @author David Sarno / http://lighthaus.us/ - * @author tschw + * @author mrdoob / http://mrdoob.com/ */ -function KeyframeTrack( name, times, values, interpolation ) { - - if ( name === undefined ) throw new Error( 'THREE.KeyframeTrack: track name is undefined' ); - if ( times === undefined || times.length === 0 ) throw new Error( 'THREE.KeyframeTrack: no keyframes in track named ' + name ); - - this.name = name; - this.times = AnimationUtils.convertArray( times, this.TimeBufferType ); - this.values = AnimationUtils.convertArray( values, this.ValueBufferType ); - - this.setInterpolation( interpolation || this.DefaultInterpolation ); +function TextureLoader( manager ) { - this.validate(); - this.optimize(); + this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager; } -// Static methods: - -Object.assign( KeyframeTrack, { +Object.assign( TextureLoader.prototype, { - // Serialization (in static context, because of constructor invocation - // and automatic invocation of .toJSON): + crossOrigin: 'anonymous', - parse: function ( json ) { + load: function ( url, onLoad, onProgress, onError ) { - if ( json.type === undefined ) { + var texture = new Texture(); - throw new Error( 'THREE.KeyframeTrack: track type undefined, can not parse' ); + var loader = new ImageLoader( this.manager ); + loader.setCrossOrigin( this.crossOrigin ); + loader.setPath( this.path ); - } + loader.load( url, function ( image ) { - var trackType = KeyframeTrack._getTrackTypeForValueTypeName( json.type ); + texture.image = image; - if ( json.times === undefined ) { + // 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; - var times = [], values = []; + texture.format = isJPEG ? RGBFormat : RGBAFormat; + texture.needsUpdate = true; - AnimationUtils.flattenJSON( json.keys, times, values, 'value' ); + if ( onLoad !== undefined ) { - json.times = times; - json.values = values; + onLoad( texture ); - } + } - // derived classes can define a static parse method - if ( trackType.parse !== undefined ) { + }, onProgress, onError ); - return trackType.parse( json ); + return texture; - } else { + }, - // by default, we assume a constructor compatible with the base - return new trackType( json.name, json.times, json.values, json.interpolation ); + setCrossOrigin: function ( value ) { - } + this.crossOrigin = value; + return this; }, - toJSON: function ( track ) { + setPath: function ( value ) { - var trackType = track.constructor; + this.path = value; + return this; - var json; + } - // derived classes can define a static toJSON method - if ( trackType.toJSON !== undefined ) { - - json = trackType.toJSON( track ); - - } else { +} ); - // by default, we assume the data can be serialized as-is - json = { +/** + * @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. + * + **/ - 'name': track.name, - 'times': AnimationUtils.convertArray( track.times, Array ), - 'values': AnimationUtils.convertArray( track.values, Array ) +/************************************************************** + * Abstract Curve base class + **************************************************************/ - }; +function Curve() { - var interpolation = track.getInterpolation(); + this.type = 'Curve'; - if ( interpolation !== track.DefaultInterpolation ) { + this.arcLengthDivisions = 200; - json.interpolation = interpolation; +} - } +Object.assign( Curve.prototype, { - } + // Virtual base class method to overwrite and implement in subclasses + // - t [0 .. 1] - json.type = track.ValueTypeName; // mandatory + getPoint: function ( /* t, optionalTarget */ ) { - return json; + console.warn( 'THREE.Curve: .getPoint() not implemented.' ); + return null; }, - _getTrackTypeForValueTypeName: function ( typeName ) { + // Get point at relative position in curve according to arc length + // - u [0 .. 1] - switch ( typeName.toLowerCase() ) { + getPointAt: function ( u, optionalTarget ) { - case 'scalar': - case 'double': - case 'float': - case 'number': - case 'integer': + var t = this.getUtoTmapping( u ); + return this.getPoint( t, optionalTarget ); - return NumberKeyframeTrack; + }, - case 'vector': - case 'vector2': - case 'vector3': - case 'vector4': + // Get sequence of points using getPoint( t ) - return VectorKeyframeTrack; + getPoints: function ( divisions ) { - case 'color': + if ( divisions === undefined ) divisions = 5; - return ColorKeyframeTrack; + var points = []; - case 'quaternion': + for ( var d = 0; d <= divisions; d ++ ) { - return QuaternionKeyframeTrack; + points.push( this.getPoint( d / divisions ) ); - case 'bool': - case 'boolean': + } - return BooleanKeyframeTrack; + return points; - case 'string': + }, - return StringKeyframeTrack; + // Get sequence of points using getPointAt( u ) - } + getSpacedPoints: function ( divisions ) { - throw new Error( 'THREE.KeyframeTrack: Unsupported typeName: ' + typeName ); + if ( divisions === undefined ) divisions = 5; - } + var points = []; -} ); + for ( var d = 0; d <= divisions; d ++ ) { -Object.assign( KeyframeTrack.prototype, { + points.push( this.getPointAt( d / divisions ) ); - constructor: KeyframeTrack, + } - TimeBufferType: Float32Array, + return points; - ValueBufferType: Float32Array, + }, - DefaultInterpolation: InterpolateLinear, + // Get total curve arc length - InterpolantFactoryMethodDiscrete: function ( result ) { + getLength: function () { - return new DiscreteInterpolant( this.times, this.values, this.getValueSize(), result ); + var lengths = this.getLengths(); + return lengths[ lengths.length - 1 ]; }, - InterpolantFactoryMethodLinear: function ( result ) { + // Get list of cumulative segment lengths - return new LinearInterpolant( this.times, this.values, this.getValueSize(), result ); + getLengths: function ( divisions ) { - }, + if ( divisions === undefined ) divisions = this.arcLengthDivisions; - InterpolantFactoryMethodSmooth: function ( result ) { + if ( this.cacheArcLengths && + ( this.cacheArcLengths.length === divisions + 1 ) && + ! this.needsUpdate ) { - return new CubicInterpolant( this.times, this.values, this.getValueSize(), result ); + return this.cacheArcLengths; - }, + } - setInterpolation: function ( interpolation ) { + this.needsUpdate = false; - var factoryMethod; + var cache = []; + var current, last = this.getPoint( 0 ); + var p, sum = 0; - switch ( interpolation ) { + cache.push( 0 ); - case InterpolateDiscrete: + for ( p = 1; p <= divisions; p ++ ) { - factoryMethod = this.InterpolantFactoryMethodDiscrete; + current = this.getPoint( p / divisions ); + sum += current.distanceTo( last ); + cache.push( sum ); + last = current; - break; + } - case InterpolateLinear: + this.cacheArcLengths = cache; - factoryMethod = this.InterpolantFactoryMethodLinear; + return cache; // { sums: cache, sum: sum }; Sum is in the last element. - break; + }, - case InterpolateSmooth: + updateArcLengths: function () { - factoryMethod = this.InterpolantFactoryMethodSmooth; + this.needsUpdate = true; + this.getLengths(); - break; + }, - } + // Given u ( 0 .. 1 ), get a t to find p. This gives you points which are equidistant - if ( factoryMethod === undefined ) { + getUtoTmapping: function ( u, distance ) { - var message = "unsupported interpolation for " + - this.ValueTypeName + " keyframe track named " + this.name; + var arcLengths = this.getLengths(); - if ( this.createInterpolant === undefined ) { + var i = 0, il = arcLengths.length; - // fall back to default, unless the default itself is messed up - if ( interpolation !== this.DefaultInterpolation ) { + var targetArcLength; // The targeted u distance value to get - this.setInterpolation( this.DefaultInterpolation ); + if ( distance ) { - } else { + targetArcLength = distance; - throw new Error( message ); // fatal, in this case + } else { - } + targetArcLength = u * arcLengths[ il - 1 ]; - } + } - console.warn( 'THREE.KeyframeTrack:', message ); - return; + // binary search for the index with largest value smaller than target u distance - } + var low = 0, high = il - 1, comparison; - this.createInterpolant = factoryMethod; + while ( low <= high ) { - }, + i = Math.floor( low + ( high - low ) / 2 ); // less likely to overflow, though probably not issue here, JS doesn't really have integers, all numbers are floats - getInterpolation: function () { + comparison = arcLengths[ i ] - targetArcLength; - switch ( this.createInterpolant ) { + if ( comparison < 0 ) { - case this.InterpolantFactoryMethodDiscrete: + low = i + 1; - return InterpolateDiscrete; + } else if ( comparison > 0 ) { - case this.InterpolantFactoryMethodLinear: + high = i - 1; - return InterpolateLinear; + } else { - case this.InterpolantFactoryMethodSmooth: + high = i; + break; - return InterpolateSmooth; + // DONE + + } } - }, + i = high; - getValueSize: function () { + if ( arcLengths[ i ] === targetArcLength ) { - return this.values.length / this.times.length; + return i / ( il - 1 ); - }, + } - // move all keyframes either forwards or backwards in time - shift: function ( timeOffset ) { + // we could get finer grain at lengths, or use simple interpolation between two points - if ( timeOffset !== 0.0 ) { + var lengthBefore = arcLengths[ i ]; + var lengthAfter = arcLengths[ i + 1 ]; - var times = this.times; + var segmentLength = lengthAfter - lengthBefore; - for ( var i = 0, n = times.length; i !== n; ++ i ) { + // determine where we are between the 'before' and 'after' points - times[ i ] += timeOffset; + var segmentFraction = ( targetArcLength - lengthBefore ) / segmentLength; - } + // add that fractional amount to t - } + var t = ( i + segmentFraction ) / ( il - 1 ); - return this; + return t; }, - // scale all keyframe times by a factor (useful for frame <-> seconds conversions) - scale: function ( timeScale ) { - - if ( timeScale !== 1.0 ) { + // Returns a unit vector tangent at t + // In case any sub curve does not implement its tangent derivation, + // 2 points a small delta apart will be used to find its gradient + // which seems to give a reasonable approximation - var times = this.times; + getTangent: function ( t ) { - for ( var i = 0, n = times.length; i !== n; ++ i ) { + var delta = 0.0001; + var t1 = t - delta; + var t2 = t + delta; - times[ i ] *= timeScale; + // Capping in case of danger - } + if ( t1 < 0 ) t1 = 0; + if ( t2 > 1 ) t2 = 1; - } + var pt1 = this.getPoint( t1 ); + var pt2 = this.getPoint( t2 ); - return this; + var vec = pt2.clone().sub( pt1 ); + return vec.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 ) { + getTangentAt: function ( u ) { - var times = this.times, - nKeys = times.length, - from = 0, - to = nKeys - 1; + var t = this.getUtoTmapping( u ); + return this.getTangent( t ); - while ( from !== nKeys && times[ from ] < startTime ) { + }, - ++ from; + computeFrenetFrames: function ( segments, closed ) { - } + // see http://www.cs.indiana.edu/pub/techreports/TR425.pdf - while ( to !== - 1 && times[ to ] > endTime ) { + var normal = new Vector3(); - -- to; + var tangents = []; + var normals = []; + var binormals = []; - } + var vec = new Vector3(); + var mat = new Matrix4(); - ++ to; // inclusive -> exclusive bound + var i, u, theta; - if ( from !== 0 || to !== nKeys ) { + // compute the tangent vectors for each segment on the curve - // empty tracks are forbidden, so keep at least one keyframe - if ( from >= to ) to = Math.max( to, 1 ), from = to - 1; + for ( i = 0; i <= segments; i ++ ) { - var stride = this.getValueSize(); - this.times = AnimationUtils.arraySlice( times, from, to ); - this.values = AnimationUtils.arraySlice( this.values, from * stride, to * stride ); + u = i / segments; + + tangents[ i ] = this.getTangentAt( u ); + tangents[ i ].normalize(); } - return this; + // select an initial normal vector perpendicular to the first tangent vector, + // and in the direction of the minimum tangent xyz component - }, + normals[ 0 ] = new Vector3(); + binormals[ 0 ] = new Vector3(); + var min = Number.MAX_VALUE; + var tx = Math.abs( tangents[ 0 ].x ); + var ty = Math.abs( tangents[ 0 ].y ); + var tz = Math.abs( tangents[ 0 ].z ); - // ensure we do not get a GarbageInGarbageOut situation, make sure tracks are at least minimally viable - validate: function () { + if ( tx <= min ) { - var valid = true; + min = tx; + normal.set( 1, 0, 0 ); - var valueSize = this.getValueSize(); - if ( valueSize - Math.floor( valueSize ) !== 0 ) { + } - console.error( 'THREE.KeyframeTrack: Invalid value size in track.', this ); - valid = false; + if ( ty <= min ) { + + min = ty; + normal.set( 0, 1, 0 ); } - var times = this.times, - values = this.values, + if ( tz <= min ) { - nKeys = times.length; + normal.set( 0, 0, 1 ); - if ( nKeys === 0 ) { + } - console.error( 'THREE.KeyframeTrack: Track is empty.', this ); - valid = false; + vec.crossVectors( tangents[ 0 ], normal ).normalize(); - } + normals[ 0 ].crossVectors( tangents[ 0 ], vec ); + binormals[ 0 ].crossVectors( tangents[ 0 ], normals[ 0 ] ); - var prevTime = null; - for ( var i = 0; i !== nKeys; i ++ ) { + // compute the slowly-varying normal and binormal vectors for each segment on the curve - var currTime = times[ i ]; + for ( i = 1; i <= segments; i ++ ) { - if ( typeof currTime === 'number' && isNaN( currTime ) ) { + normals[ i ] = normals[ i - 1 ].clone(); - console.error( 'THREE.KeyframeTrack: Time is not a valid number.', this, i, currTime ); - valid = false; - break; + binormals[ i ] = binormals[ i - 1 ].clone(); - } + vec.crossVectors( tangents[ i - 1 ], tangents[ i ] ); - if ( prevTime !== null && prevTime > currTime ) { + if ( vec.length() > Number.EPSILON ) { - console.error( 'THREE.KeyframeTrack: Out of order keys.', this, i, currTime, prevTime ); - valid = false; - break; + vec.normalize(); + + theta = Math.acos( _Math.clamp( tangents[ i - 1 ].dot( tangents[ i ] ), - 1, 1 ) ); // clamp for floating pt errors + + normals[ i ].applyMatrix4( mat.makeRotationAxis( vec, theta ) ); } - prevTime = currTime; + binormals[ i ].crossVectors( tangents[ i ], normals[ i ] ); } - if ( values !== undefined ) { + // if the curve is closed, postprocess the vectors so the first and last normal vectors are the same - if ( AnimationUtils.isTypedArray( values ) ) { + if ( closed === true ) { - for ( var i = 0, n = values.length; i !== n; ++ i ) { + theta = Math.acos( _Math.clamp( normals[ 0 ].dot( normals[ segments ] ), - 1, 1 ) ); + theta /= segments; - var value = values[ i ]; + if ( tangents[ 0 ].dot( vec.crossVectors( normals[ 0 ], normals[ segments ] ) ) > 0 ) { - if ( isNaN( value ) ) { + theta = - theta; - console.error( 'THREE.KeyframeTrack: Value is not a valid number.', this, i, value ); - valid = false; - break; + } - } + for ( i = 1; i <= segments; i ++ ) { - } + // twist a little... + normals[ i ].applyMatrix4( mat.makeRotationAxis( tangents[ i ], theta * i ) ); + binormals[ i ].crossVectors( tangents[ i ], normals[ i ] ); } } - return valid; + return { + tangents: tangents, + normals: normals, + binormals: binormals + }; }, - // 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 () { + clone: function () { - var times = this.times, - values = this.values, - stride = this.getValueSize(), + return new this.constructor().copy( this ); - smoothInterpolation = this.getInterpolation() === InterpolateSmooth, + }, - writeIndex = 1, - lastIndex = times.length - 1; + copy: function ( source ) { - for ( var i = 1; i < lastIndex; ++ i ) { + this.arcLengthDivisions = source.arcLengthDivisions; - var keep = false; + return this; - var time = times[ i ]; - var timeNext = times[ i + 1 ]; + }, - // remove adjacent keyframes scheduled at the same time + toJSON: function () { - if ( time !== timeNext && ( i !== 1 || time !== time[ 0 ] ) ) { + var data = { + metadata: { + version: 4.5, + type: 'Curve', + generator: 'Curve.toJSON' + } + }; - if ( ! smoothInterpolation ) { + data.arcLengthDivisions = this.arcLengthDivisions; + data.type = this.type; - // remove unnecessary keyframes same as their neighbors + return data; - var offset = i * stride, - offsetP = offset - stride, - offsetN = offset + stride; + }, - for ( var j = 0; j !== stride; ++ j ) { + fromJSON: function ( json ) { - var value = values[ offset + j ]; + this.arcLengthDivisions = json.arcLengthDivisions; - if ( value !== values[ offsetP + j ] || - value !== values[ offsetN + j ] ) { + return this; - keep = true; - break; + } - } +} ); - } +function EllipseCurve( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ) { - } else { + Curve.call( this ); - keep = true; + this.type = 'EllipseCurve'; - } + this.aX = aX || 0; + this.aY = aY || 0; - } + this.xRadius = xRadius || 1; + this.yRadius = yRadius || 1; - // in-place compaction + this.aStartAngle = aStartAngle || 0; + this.aEndAngle = aEndAngle || 2 * Math.PI; - if ( keep ) { + this.aClockwise = aClockwise || false; - if ( i !== writeIndex ) { + this.aRotation = aRotation || 0; - times[ writeIndex ] = times[ i ]; +} - var readOffset = i * stride, - writeOffset = writeIndex * stride; +EllipseCurve.prototype = Object.create( Curve.prototype ); +EllipseCurve.prototype.constructor = EllipseCurve; - for ( var j = 0; j !== stride; ++ j ) { +EllipseCurve.prototype.isEllipseCurve = true; - values[ writeOffset + j ] = values[ readOffset + j ]; +EllipseCurve.prototype.getPoint = function ( t, optionalTarget ) { - } + var point = optionalTarget || new Vector2(); - } + var twoPi = Math.PI * 2; + var deltaAngle = this.aEndAngle - this.aStartAngle; + var samePoints = Math.abs( deltaAngle ) < Number.EPSILON; - ++ writeIndex; + // ensures that deltaAngle is 0 .. 2 PI + while ( deltaAngle < 0 ) deltaAngle += twoPi; + while ( deltaAngle > twoPi ) deltaAngle -= twoPi; - } + if ( deltaAngle < Number.EPSILON ) { - } + if ( samePoints ) { - // flush last keyframe (compaction looks ahead) + deltaAngle = 0; - if ( lastIndex > 0 ) { + } else { - times[ writeIndex ] = times[ lastIndex ]; + deltaAngle = twoPi; - for ( var readOffset = lastIndex * stride, writeOffset = writeIndex * stride, j = 0; j !== stride; ++ j ) { + } - values[ writeOffset + j ] = values[ readOffset + j ]; + } - } + if ( this.aClockwise === true && ! samePoints ) { - ++ writeIndex; + if ( deltaAngle === twoPi ) { - } + deltaAngle = - twoPi; - if ( writeIndex !== times.length ) { + } else { - this.times = AnimationUtils.arraySlice( times, 0, writeIndex ); - this.values = AnimationUtils.arraySlice( values, 0, writeIndex * stride ); + deltaAngle = deltaAngle - twoPi; } - return this; - } -} ); - -/** - * - * A Track of vectored keyframe values. - * - * - * @author Ben Houston / http://clara.io/ - * @author David Sarno / http://lighthaus.us/ - * @author tschw - */ + var angle = this.aStartAngle + t * deltaAngle; + var x = this.aX + this.xRadius * Math.cos( angle ); + var y = this.aY + this.yRadius * Math.sin( angle ); -function VectorKeyframeTrack( name, times, values, interpolation ) { + if ( this.aRotation !== 0 ) { - KeyframeTrack.call( this, name, times, values, interpolation ); + var cos = Math.cos( this.aRotation ); + var sin = Math.sin( this.aRotation ); -} + var tx = x - this.aX; + var ty = y - this.aY; -VectorKeyframeTrack.prototype = Object.assign( Object.create( KeyframeTrack.prototype ), { + // Rotate the point about the center of the ellipse. + x = tx * cos - ty * sin + this.aX; + y = tx * sin + ty * cos + this.aY; - constructor: VectorKeyframeTrack, + } - ValueTypeName: 'vector' + return point.set( x, y ); - // ValueBufferType is inherited +}; - // DefaultInterpolation is inherited +EllipseCurve.prototype.copy = function ( source ) { -} ); + Curve.prototype.copy.call( this, source ); -/** - * - * Reusable set of Tracks that represent an animation. - * - * @author Ben Houston / http://clara.io/ - * @author David Sarno / http://lighthaus.us/ - */ + this.aX = source.aX; + this.aY = source.aY; -function AnimationClip( name, duration, tracks ) { + this.xRadius = source.xRadius; + this.yRadius = source.yRadius; - this.name = name; - this.tracks = tracks; - this.duration = ( duration !== undefined ) ? duration : - 1; + this.aStartAngle = source.aStartAngle; + this.aEndAngle = source.aEndAngle; - this.uuid = _Math.generateUUID(); + this.aClockwise = source.aClockwise; - // this means it should figure out its duration by scanning the tracks - if ( this.duration < 0 ) { + this.aRotation = source.aRotation; - this.resetDuration(); + return this; - } +}; - this.optimize(); -} +EllipseCurve.prototype.toJSON = function () { -Object.assign( AnimationClip, { + var data = Curve.prototype.toJSON.call( this ); - parse: function ( json ) { + data.aX = this.aX; + data.aY = this.aY; - var tracks = [], - jsonTracks = json.tracks, - frameTime = 1.0 / ( json.fps || 1.0 ); + data.xRadius = this.xRadius; + data.yRadius = this.yRadius; - for ( var i = 0, n = jsonTracks.length; i !== n; ++ i ) { + data.aStartAngle = this.aStartAngle; + data.aEndAngle = this.aEndAngle; - tracks.push( KeyframeTrack.parse( jsonTracks[ i ] ).scale( frameTime ) ); + data.aClockwise = this.aClockwise; - } + data.aRotation = this.aRotation; - return new AnimationClip( json.name, json.duration, tracks ); + return data; - }, +}; - toJSON: function ( clip ) { +EllipseCurve.prototype.fromJSON = function ( json ) { - var tracks = [], - clipTracks = clip.tracks; + Curve.prototype.fromJSON.call( this, json ); - var json = { + this.aX = json.aX; + this.aY = json.aY; - 'name': clip.name, - 'duration': clip.duration, - 'tracks': tracks + this.xRadius = json.xRadius; + this.yRadius = json.yRadius; - }; + this.aStartAngle = json.aStartAngle; + this.aEndAngle = json.aEndAngle; - for ( var i = 0, n = clipTracks.length; i !== n; ++ i ) { + this.aClockwise = json.aClockwise; - tracks.push( KeyframeTrack.toJSON( clipTracks[ i ] ) ); + this.aRotation = json.aRotation; - } + return this; - return json; +}; - }, +function ArcCurve( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) { - CreateFromMorphTargetSequence: function ( name, morphTargetSequence, fps, noLoop ) { + EllipseCurve.call( this, aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise ); - var numMorphTargets = morphTargetSequence.length; - var tracks = []; + this.type = 'ArcCurve'; - for ( var i = 0; i < numMorphTargets; i ++ ) { +} - var times = []; - var values = []; +ArcCurve.prototype = Object.create( EllipseCurve.prototype ); +ArcCurve.prototype.constructor = ArcCurve; - times.push( - ( i + numMorphTargets - 1 ) % numMorphTargets, - i, - ( i + 1 ) % numMorphTargets ); +ArcCurve.prototype.isArcCurve = true; - values.push( 0, 1, 0 ); +/** + * @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 + */ - var order = AnimationUtils.getKeyframeOrder( times ); - times = AnimationUtils.sortedArray( times, 1, order ); - values = AnimationUtils.sortedArray( values, 1, order ); - // if there is a key at the first frame, duplicate it as the - // last frame as well for perfect loop. - if ( ! noLoop && times[ 0 ] === 0 ) { +/* +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 - times.push( numMorphTargets ); - values.push( values[ 0 ] ); +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() { - tracks.push( - new NumberKeyframeTrack( - '.morphTargetInfluences[' + morphTargetSequence[ i ].name + ']', - times, values - ).scale( 1.0 / fps ) ); + 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 new AnimationClip( name, - 1, tracks ); + c0 = x0; + c1 = t0; + c2 = - 3 * x0 + 3 * x1 - 2 * t0 - t1; + c3 = 2 * x0 - 2 * x1 + t0 + t1; - }, + } - findByName: function ( objectOrClipArray, name ) { + return { - var clipArray = objectOrClipArray; + initCatmullRom: function ( x0, x1, x2, x3, tension ) { - if ( ! Array.isArray( objectOrClipArray ) ) { + init( x1, x2, tension * ( x2 - x0 ), tension * ( x3 - x1 ) ); - var o = objectOrClipArray; - clipArray = o.geometry && o.geometry.animations || o.animations; + }, - } + initNonuniformCatmullRom: function ( x0, x1, x2, x3, dt0, dt1, dt2 ) { - for ( var i = 0; i < clipArray.length; i ++ ) { + // 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; - if ( clipArray[ i ].name === name ) { + // rescale tangents for parametrization in [0,1] + t1 *= dt1; + t2 *= dt1; - return clipArray[ i ]; + init( x1, x2, t1, t2 ); - } + }, + + calc: function ( t ) { + + var t2 = t * t; + var t3 = t2 * t; + return c0 + c1 * t + c2 * t2 + c3 * t3; } - return null; + }; - }, +} - CreateClipsFromMorphTargetSequences: function ( morphTargets, fps, noLoop ) { +// - var animationToMorphTargets = {}; +var tmp = new Vector3(); +var px = new CubicPoly(), py = new CubicPoly(), pz = new CubicPoly(); - // tested with https://regex101.com/ on trick sequences - // such flamingo_flyA_003, flamingo_run1_003, crdeath0059 - var pattern = /^([\w-]*?)([\d]+)$/; +function CatmullRomCurve3( points, closed, curveType, tension ) { - // 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 ++ ) { + Curve.call( this ); - var morphTarget = morphTargets[ i ]; - var parts = morphTarget.name.match( pattern ); + this.type = 'CatmullRomCurve3'; - if ( parts && parts.length > 1 ) { + this.points = points || []; + this.closed = closed || false; + this.curveType = curveType || 'centripetal'; + this.tension = tension || 0.5; - var name = parts[ 1 ]; +} - var animationMorphTargets = animationToMorphTargets[ name ]; - if ( ! animationMorphTargets ) { +CatmullRomCurve3.prototype = Object.create( Curve.prototype ); +CatmullRomCurve3.prototype.constructor = CatmullRomCurve3; - animationToMorphTargets[ name ] = animationMorphTargets = []; +CatmullRomCurve3.prototype.isCatmullRomCurve3 = true; - } +CatmullRomCurve3.prototype.getPoint = function ( t, optionalTarget ) { - animationMorphTargets.push( morphTarget ); + var point = optionalTarget || new Vector3(); - } + var points = this.points; + var l = points.length; - } + var p = ( l - ( this.closed ? 0 : 1 ) ) * t; + var intPoint = Math.floor( p ); + var weight = p - intPoint; - var clips = []; + if ( this.closed ) { - for ( var name in animationToMorphTargets ) { + intPoint += intPoint > 0 ? 0 : ( Math.floor( Math.abs( intPoint ) / l ) + 1 ) * l; - clips.push( AnimationClip.CreateFromMorphTargetSequence( name, animationToMorphTargets[ name ], fps, noLoop ) ); + } else if ( weight === 0 && intPoint === l - 1 ) { - } + intPoint = l - 2; + weight = 1; - return clips; + } - }, + var p0, p1, p2, p3; // 4 points - // parse the animation.hierarchy format - parseAnimation: function ( animation, bones ) { + if ( this.closed || intPoint > 0 ) { - if ( ! animation ) { + p0 = points[ ( intPoint - 1 ) % l ]; - console.error( 'THREE.AnimationClip: No animation in JSONLoader data.' ); - return null; + } else { - } + // extrapolate first point + tmp.subVectors( points[ 0 ], points[ 1 ] ).add( points[ 0 ] ); + p0 = tmp; - var addNonemptyTrack = function ( trackType, trackName, animationKeys, propertyName, destTracks ) { + } - // only return track if there are actually keys. - if ( animationKeys.length !== 0 ) { + p1 = points[ intPoint % l ]; + p2 = points[ ( intPoint + 1 ) % l ]; - var times = []; - var values = []; + if ( this.closed || intPoint + 2 < l ) { - AnimationUtils.flattenJSON( animationKeys, times, values, propertyName ); + p3 = points[ ( intPoint + 2 ) % l ]; - // empty keys are filtered out, so check again - if ( times.length !== 0 ) { + } else { - destTracks.push( new trackType( trackName, times, values ) ); + // extrapolate last point + tmp.subVectors( points[ l - 1 ], points[ l - 2 ] ).add( points[ l - 1 ] ); + p3 = tmp; - } + } - } + if ( this.curveType === 'centripetal' || this.curveType === 'chordal' ) { - }; + // init Centripetal / Chordal Catmull-Rom + var pow = this.curveType === 'chordal' ? 0.5 : 0.25; + var dt0 = Math.pow( p0.distanceToSquared( p1 ), pow ); + var dt1 = Math.pow( p1.distanceToSquared( p2 ), pow ); + var dt2 = Math.pow( p2.distanceToSquared( p3 ), pow ); - var tracks = []; + // 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 clipName = animation.name || 'default'; - // automatic length determination in AnimationClip. - var duration = animation.length || - 1; - var fps = animation.fps || 30; + 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 ); - var hierarchyTracks = animation.hierarchy || []; + } else if ( this.curveType === 'catmullrom' ) { - for ( var h = 0; h < hierarchyTracks.length; h ++ ) { + 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 ); - var animationKeys = hierarchyTracks[ h ].keys; + } - // skip empty tracks - if ( ! animationKeys || animationKeys.length === 0 ) continue; + point.set( + px.calc( weight ), + py.calc( weight ), + pz.calc( weight ) + ); - // process morph targets - if ( animationKeys[ 0 ].morphTargets ) { + return point; - // figure out all morph targets used in this track - var morphTargetNames = {}; +}; - for ( var k = 0; k < animationKeys.length; k ++ ) { +CatmullRomCurve3.prototype.copy = function ( source ) { - if ( animationKeys[ k ].morphTargets ) { + Curve.prototype.copy.call( this, source ); - for ( var m = 0; m < animationKeys[ k ].morphTargets.length; m ++ ) { + this.points = []; - morphTargetNames[ animationKeys[ k ].morphTargets[ m ] ] = - 1; + for ( var i = 0, l = source.points.length; i < l; i ++ ) { - } + var point = source.points[ i ]; - } + this.points.push( point.clone() ); - } + } - // create a track for each morph target with all zero - // morphTargetInfluences except for the keys in which - // the morphTarget is named. - for ( var morphTargetName in morphTargetNames ) { + this.closed = source.closed; + this.curveType = source.curveType; + this.tension = source.tension; - var times = []; - var values = []; + return this; - for ( var m = 0; m !== animationKeys[ k ].morphTargets.length; ++ m ) { +}; - var animationKey = animationKeys[ k ]; +CatmullRomCurve3.prototype.toJSON = function () { - times.push( animationKey.time ); - values.push( ( animationKey.morphTarget === morphTargetName ) ? 1 : 0 ); + var data = Curve.prototype.toJSON.call( this ); - } + data.points = []; - tracks.push( new NumberKeyframeTrack( '.morphTargetInfluence[' + morphTargetName + ']', times, values ) ); + for ( var i = 0, l = this.points.length; i < l; i ++ ) { - } + var point = this.points[ i ]; + data.points.push( point.toArray() ); - duration = morphTargetNames.length * ( fps || 1.0 ); + } - } else { + data.closed = this.closed; + data.curveType = this.curveType; + data.tension = this.tension; - // ...assume skeletal animation + return data; - var boneName = '.bones[' + bones[ h ].name + ']'; +}; - addNonemptyTrack( - VectorKeyframeTrack, boneName + '.position', - animationKeys, 'pos', tracks ); +CatmullRomCurve3.prototype.fromJSON = function ( json ) { - addNonemptyTrack( - QuaternionKeyframeTrack, boneName + '.quaternion', - animationKeys, 'rot', tracks ); + Curve.prototype.fromJSON.call( this, json ); - addNonemptyTrack( - VectorKeyframeTrack, boneName + '.scale', - animationKeys, 'scl', tracks ); + this.points = []; - } + for ( var i = 0, l = json.points.length; i < l; i ++ ) { - } + var point = json.points[ i ]; + this.points.push( new Vector3().fromArray( point ) ); - if ( tracks.length === 0 ) { + } - return null; + this.closed = json.closed; + this.curveType = json.curveType; + this.tension = json.tension; - } + return this; - var clip = new AnimationClip( clipName, duration, tracks ); +}; - return clip; +/** + * @author zz85 / http://www.lab4games.net/zz85/blog + * + * Bezier Curves formulas obtained from + * http://en.wikipedia.org/wiki/Bézier_curve + */ - } +function CatmullRom( t, p0, p1, p2, p3 ) { -} ); + 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; -Object.assign( AnimationClip.prototype, { +} - resetDuration: function () { +// - var tracks = this.tracks, duration = 0; +function QuadraticBezierP0( t, p ) { - for ( var i = 0, n = tracks.length; i !== n; ++ i ) { + var k = 1 - t; + return k * k * p; - var track = this.tracks[ i ]; +} - duration = Math.max( duration, track.times[ track.times.length - 1 ] ); +function QuadraticBezierP1( t, p ) { - } + return 2 * ( 1 - t ) * t * p; - this.duration = duration; +} - }, +function QuadraticBezierP2( t, p ) { - trim: function () { + return t * t * p; - for ( var i = 0; i < this.tracks.length; i ++ ) { +} - this.tracks[ i ].trim( 0, this.duration ); +function QuadraticBezier( t, p0, p1, p2 ) { - } + return QuadraticBezierP0( t, p0 ) + QuadraticBezierP1( t, p1 ) + + QuadraticBezierP2( t, p2 ); - return this; +} - }, +// - optimize: function () { +function CubicBezierP0( t, p ) { - for ( var i = 0; i < this.tracks.length; i ++ ) { + var k = 1 - t; + return k * k * k * p; - this.tracks[ i ].optimize(); +} - } +function CubicBezierP1( t, p ) { - return this; + var k = 1 - t; + return 3 * k * k * t * p; - } +} -} ); +function CubicBezierP2( t, p ) { -/** - * @author mrdoob / http://mrdoob.com/ - */ + return 3 * ( 1 - t ) * t * t * p; -function MaterialLoader( manager ) { +} - this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager; - this.textures = {}; +function CubicBezierP3( t, p ) { + + return t * t * t * p; } -Object.assign( MaterialLoader.prototype, { +function CubicBezier( t, p0, p1, p2, p3 ) { - load: function ( url, onLoad, onProgress, onError ) { + return CubicBezierP0( t, p0 ) + CubicBezierP1( t, p1 ) + CubicBezierP2( t, p2 ) + + CubicBezierP3( t, p3 ); - var scope = this; +} - var loader = new FileLoader( scope.manager ); - loader.load( url, function ( text ) { +function CubicBezierCurve( v0, v1, v2, v3 ) { - onLoad( scope.parse( JSON.parse( text ) ) ); + Curve.call( this ); - }, onProgress, onError ); + this.type = 'CubicBezierCurve'; - }, + this.v0 = v0 || new Vector2(); + this.v1 = v1 || new Vector2(); + this.v2 = v2 || new Vector2(); + this.v3 = v3 || new Vector2(); - setTextures: function ( value ) { +} - this.textures = value; +CubicBezierCurve.prototype = Object.create( Curve.prototype ); +CubicBezierCurve.prototype.constructor = CubicBezierCurve; - }, +CubicBezierCurve.prototype.isCubicBezierCurve = true; - parse: function ( json ) { +CubicBezierCurve.prototype.getPoint = function ( t, optionalTarget ) { - var textures = this.textures; + var point = optionalTarget || new Vector2(); - function getTexture( name ) { + var v0 = this.v0, v1 = this.v1, v2 = this.v2, v3 = this.v3; - if ( textures[ name ] === undefined ) { + point.set( + CubicBezier( t, v0.x, v1.x, v2.x, v3.x ), + CubicBezier( t, v0.y, v1.y, v2.y, v3.y ) + ); - console.warn( 'THREE.MaterialLoader: Undefined texture', name ); + return point; - } +}; - return textures[ name ]; +CubicBezierCurve.prototype.copy = function ( source ) { - } + Curve.prototype.copy.call( this, source ); - var material = new Materials[ json.type ](); + this.v0.copy( source.v0 ); + this.v1.copy( source.v1 ); + this.v2.copy( source.v2 ); + this.v3.copy( source.v3 ); - if ( json.uuid !== undefined ) material.uuid = json.uuid; - if ( json.name !== undefined ) material.name = json.name; - if ( json.color !== undefined ) material.color.setHex( json.color ); - if ( json.roughness !== undefined ) material.roughness = json.roughness; - if ( json.metalness !== undefined ) material.metalness = json.metalness; - if ( json.emissive !== undefined ) material.emissive.setHex( json.emissive ); - if ( json.specular !== undefined ) material.specular.setHex( json.specular ); - if ( json.shininess !== undefined ) material.shininess = json.shininess; - if ( json.clearCoat !== undefined ) material.clearCoat = json.clearCoat; - if ( json.clearCoatRoughness !== undefined ) material.clearCoatRoughness = json.clearCoatRoughness; - if ( json.uniforms !== undefined ) material.uniforms = json.uniforms; - if ( json.vertexShader !== undefined ) material.vertexShader = json.vertexShader; - if ( json.fragmentShader !== undefined ) material.fragmentShader = json.fragmentShader; - if ( json.vertexColors !== undefined ) material.vertexColors = json.vertexColors; - if ( json.fog !== undefined ) material.fog = json.fog; - if ( json.flatShading !== undefined ) material.flatShading = json.flatShading; - if ( json.blending !== undefined ) material.blending = json.blending; - if ( json.side !== undefined ) material.side = json.side; - if ( json.opacity !== undefined ) material.opacity = json.opacity; - if ( json.transparent !== undefined ) material.transparent = json.transparent; - if ( json.alphaTest !== undefined ) material.alphaTest = json.alphaTest; - if ( json.depthTest !== undefined ) material.depthTest = json.depthTest; - if ( json.depthWrite !== undefined ) material.depthWrite = json.depthWrite; - if ( json.colorWrite !== undefined ) material.colorWrite = json.colorWrite; - if ( json.wireframe !== undefined ) material.wireframe = json.wireframe; - if ( json.wireframeLinewidth !== undefined ) material.wireframeLinewidth = json.wireframeLinewidth; - if ( json.wireframeLinecap !== undefined ) material.wireframeLinecap = json.wireframeLinecap; - if ( json.wireframeLinejoin !== undefined ) material.wireframeLinejoin = json.wireframeLinejoin; + return this; - 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; +CubicBezierCurve.prototype.toJSON = function () { - if ( json.skinning !== undefined ) material.skinning = json.skinning; - if ( json.morphTargets !== undefined ) material.morphTargets = json.morphTargets; - if ( json.dithering !== undefined ) material.dithering = json.dithering; + var data = Curve.prototype.toJSON.call( this ); - if ( json.visible !== undefined ) material.visible = json.visible; - if ( json.userData !== undefined ) material.userData = json.userData; + data.v0 = this.v0.toArray(); + data.v1 = this.v1.toArray(); + data.v2 = this.v2.toArray(); + data.v3 = this.v3.toArray(); - // Deprecated + return data; - if ( json.shading !== undefined ) material.flatShading = json.shading === 1; // THREE.FlatShading +}; - // for PointsMaterial +CubicBezierCurve.prototype.fromJSON = function ( json ) { - if ( json.size !== undefined ) material.size = json.size; - if ( json.sizeAttenuation !== undefined ) material.sizeAttenuation = json.sizeAttenuation; + Curve.prototype.fromJSON.call( this, json ); - // maps + this.v0.fromArray( json.v0 ); + this.v1.fromArray( json.v1 ); + this.v2.fromArray( json.v2 ); + this.v3.fromArray( json.v3 ); - if ( json.map !== undefined ) material.map = getTexture( json.map ); + return this; - if ( json.alphaMap !== undefined ) { +}; - material.alphaMap = getTexture( json.alphaMap ); - material.transparent = true; +function CubicBezierCurve3( v0, v1, v2, v3 ) { - } + Curve.call( this ); - if ( json.bumpMap !== undefined ) material.bumpMap = getTexture( json.bumpMap ); - if ( json.bumpScale !== undefined ) material.bumpScale = json.bumpScale; + this.type = 'CubicBezierCurve3'; - if ( json.normalMap !== undefined ) material.normalMap = getTexture( json.normalMap ); - if ( json.normalScale !== undefined ) { + this.v0 = v0 || new Vector3(); + this.v1 = v1 || new Vector3(); + this.v2 = v2 || new Vector3(); + this.v3 = v3 || new Vector3(); - var normalScale = json.normalScale; +} - if ( Array.isArray( normalScale ) === false ) { +CubicBezierCurve3.prototype = Object.create( Curve.prototype ); +CubicBezierCurve3.prototype.constructor = CubicBezierCurve3; - // Blender exporter used to export a scalar. See #7459 +CubicBezierCurve3.prototype.isCubicBezierCurve3 = true; - normalScale = [ normalScale, normalScale ]; +CubicBezierCurve3.prototype.getPoint = function ( t, optionalTarget ) { - } + var point = optionalTarget || new Vector3(); - material.normalScale = new Vector2().fromArray( normalScale ); + var v0 = this.v0, v1 = this.v1, v2 = this.v2, v3 = this.v3; - } + point.set( + CubicBezier( t, v0.x, v1.x, v2.x, v3.x ), + CubicBezier( t, v0.y, v1.y, v2.y, v3.y ), + CubicBezier( t, v0.z, v1.z, v2.z, v3.z ) + ); - 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; + return point; - 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; +CubicBezierCurve3.prototype.copy = function ( source ) { - if ( json.specularMap !== undefined ) material.specularMap = getTexture( json.specularMap ); + Curve.prototype.copy.call( this, source ); - if ( json.envMap !== undefined ) material.envMap = getTexture( json.envMap ); + this.v0.copy( source.v0 ); + this.v1.copy( source.v1 ); + this.v2.copy( source.v2 ); + this.v3.copy( source.v3 ); - if ( json.reflectivity !== undefined ) material.reflectivity = json.reflectivity; + return 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; +CubicBezierCurve3.prototype.toJSON = function () { - if ( json.gradientMap !== undefined ) material.gradientMap = getTexture( json.gradientMap ); + var data = Curve.prototype.toJSON.call( this ); - return material; + data.v0 = this.v0.toArray(); + data.v1 = this.v1.toArray(); + data.v2 = this.v2.toArray(); + data.v3 = this.v3.toArray(); - } + return data; -} ); +}; -/** - * @author mrdoob / http://mrdoob.com/ - */ +CubicBezierCurve3.prototype.fromJSON = function ( json ) { -function BufferGeometryLoader( manager ) { + Curve.prototype.fromJSON.call( this, json ); - this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager; + this.v0.fromArray( json.v0 ); + this.v1.fromArray( json.v1 ); + this.v2.fromArray( json.v2 ); + this.v3.fromArray( json.v3 ); + + return this; + +}; + +function LineCurve( v1, v2 ) { + + Curve.call( this ); + + this.type = 'LineCurve'; + + this.v1 = v1 || new Vector2(); + this.v2 = v2 || new Vector2(); } -Object.assign( BufferGeometryLoader.prototype, { +LineCurve.prototype = Object.create( Curve.prototype ); +LineCurve.prototype.constructor = LineCurve; - load: function ( url, onLoad, onProgress, onError ) { +LineCurve.prototype.isLineCurve = true; - var scope = this; +LineCurve.prototype.getPoint = function ( t, optionalTarget ) { - var loader = new FileLoader( scope.manager ); - loader.load( url, function ( text ) { + var point = optionalTarget || new Vector2(); - onLoad( scope.parse( JSON.parse( text ) ) ); + if ( t === 1 ) { - }, onProgress, onError ); + point.copy( this.v2 ); - }, + } else { - parse: function ( json ) { + point.copy( this.v2 ).sub( this.v1 ); + point.multiplyScalar( t ).add( this.v1 ); - var geometry = new BufferGeometry(); + } - var index = json.data.index; + return point; - if ( index !== undefined ) { +}; - var typedArray = new TYPED_ARRAYS[ index.type ]( index.array ); - geometry.setIndex( new BufferAttribute( typedArray, 1 ) ); +// Line curve is linear, so we can overwrite default getPointAt - } +LineCurve.prototype.getPointAt = function ( u, optionalTarget ) { - var attributes = json.data.attributes; + return this.getPoint( u, optionalTarget ); - for ( var key in attributes ) { +}; - var attribute = attributes[ key ]; - var typedArray = new TYPED_ARRAYS[ attribute.type ]( attribute.array ); +LineCurve.prototype.getTangent = function ( /* t */ ) { - geometry.addAttribute( key, new BufferAttribute( typedArray, attribute.itemSize, attribute.normalized ) ); + var tangent = this.v2.clone().sub( this.v1 ); - } + return tangent.normalize(); - var groups = json.data.groups || json.data.drawcalls || json.data.offsets; +}; - if ( groups !== undefined ) { +LineCurve.prototype.copy = function ( source ) { - for ( var i = 0, n = groups.length; i !== n; ++ i ) { + Curve.prototype.copy.call( this, source ); - var group = groups[ i ]; + this.v1.copy( source.v1 ); + this.v2.copy( source.v2 ); - geometry.addGroup( group.start, group.count, group.materialIndex ); + return this; - } +}; - } +LineCurve.prototype.toJSON = function () { - var boundingSphere = json.data.boundingSphere; + var data = Curve.prototype.toJSON.call( this ); - if ( boundingSphere !== undefined ) { + data.v1 = this.v1.toArray(); + data.v2 = this.v2.toArray(); - var center = new Vector3(); + return data; - if ( boundingSphere.center !== undefined ) { +}; - center.fromArray( boundingSphere.center ); +LineCurve.prototype.fromJSON = function ( json ) { - } + Curve.prototype.fromJSON.call( this, json ); - geometry.boundingSphere = new Sphere( center, boundingSphere.radius ); + this.v1.fromArray( json.v1 ); + this.v2.fromArray( json.v2 ); - } + return this; - return geometry; +}; + +function LineCurve3( v1, v2 ) { + + Curve.call( this ); + + this.type = 'LineCurve3'; + + this.v1 = v1 || new Vector3(); + this.v2 = v2 || new Vector3(); + +} + +LineCurve3.prototype = Object.create( Curve.prototype ); +LineCurve3.prototype.constructor = LineCurve3; + +LineCurve3.prototype.isLineCurve3 = true; + +LineCurve3.prototype.getPoint = function ( t, optionalTarget ) { + + var point = optionalTarget || new Vector3(); + + if ( t === 1 ) { + + point.copy( this.v2 ); + + } else { + + point.copy( this.v2 ).sub( this.v1 ); + point.multiplyScalar( t ).add( this.v1 ); } -} ); + return point; -var TYPED_ARRAYS = { - Int8Array: Int8Array, - Uint8Array: Uint8Array, - // Workaround for IE11 pre KB2929437. See #11440 - Uint8ClampedArray: typeof Uint8ClampedArray !== 'undefined' ? Uint8ClampedArray : Uint8Array, - Int16Array: Int16Array, - Uint16Array: Uint16Array, - Int32Array: Int32Array, - Uint32Array: Uint32Array, - Float32Array: Float32Array, - Float64Array: Float64Array }; -/** - * @author alteredq / http://alteredqualia.com/ - */ +// Line curve is linear, so we can overwrite default getPointAt + +LineCurve3.prototype.getPointAt = function ( u, optionalTarget ) { + + return this.getPoint( u, optionalTarget ); + +}; + +LineCurve3.prototype.copy = function ( source ) { + + Curve.prototype.copy.call( this, source ); + + this.v1.copy( source.v1 ); + this.v2.copy( source.v2 ); + + return this; + +}; + +LineCurve3.prototype.toJSON = function () { + + var data = Curve.prototype.toJSON.call( this ); + + data.v1 = this.v1.toArray(); + data.v2 = this.v2.toArray(); + + return data; + +}; + +LineCurve3.prototype.fromJSON = function ( json ) { + + Curve.prototype.fromJSON.call( this, json ); + + this.v1.fromArray( json.v1 ); + this.v2.fromArray( json.v2 ); + + return this; + +}; + +function QuadraticBezierCurve( v0, v1, v2 ) { + + Curve.call( this ); -function Loader() { + this.type = 'QuadraticBezierCurve'; - this.onLoadStart = function () {}; - this.onLoadProgress = function () {}; - this.onLoadComplete = function () {}; + this.v0 = v0 || new Vector2(); + this.v1 = v1 || new Vector2(); + this.v2 = v2 || new Vector2(); } -Loader.Handlers = { +QuadraticBezierCurve.prototype = Object.create( Curve.prototype ); +QuadraticBezierCurve.prototype.constructor = QuadraticBezierCurve; - handlers: [], +QuadraticBezierCurve.prototype.isQuadraticBezierCurve = true; - add: function ( regex, loader ) { +QuadraticBezierCurve.prototype.getPoint = function ( t, optionalTarget ) { - this.handlers.push( regex, loader ); + var point = optionalTarget || new Vector2(); - }, + var v0 = this.v0, v1 = this.v1, v2 = this.v2; - get: function ( file ) { + point.set( + QuadraticBezier( t, v0.x, v1.x, v2.x ), + QuadraticBezier( t, v0.y, v1.y, v2.y ) + ); - var handlers = this.handlers; + return point; - for ( var i = 0, l = handlers.length; i < l; i += 2 ) { +}; - var regex = handlers[ i ]; - var loader = handlers[ i + 1 ]; +QuadraticBezierCurve.prototype.copy = function ( source ) { - if ( regex.test( file ) ) { + Curve.prototype.copy.call( this, source ); - return loader; + this.v0.copy( source.v0 ); + this.v1.copy( source.v1 ); + this.v2.copy( source.v2 ); - } + return this; - } +}; - return null; +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(); + + return data; }; -Object.assign( Loader.prototype, { +QuadraticBezierCurve.prototype.fromJSON = function ( json ) { - crossOrigin: undefined, + Curve.prototype.fromJSON.call( this, json ); - initMaterials: function ( materials, texturePath, crossOrigin ) { + this.v0.fromArray( json.v0 ); + this.v1.fromArray( json.v1 ); + this.v2.fromArray( json.v2 ); - var array = []; + return this; - for ( var i = 0; i < materials.length; ++ i ) { +}; - array[ i ] = this.createMaterial( materials[ i ], texturePath, crossOrigin ); +function QuadraticBezierCurve3( v0, v1, v2 ) { - } + Curve.call( this ); - return array; + this.type = 'QuadraticBezierCurve3'; - }, + this.v0 = v0 || new Vector3(); + this.v1 = v1 || new Vector3(); + this.v2 = v2 || new Vector3(); - createMaterial: ( function () { +} - var BlendingMode = { - NoBlending: NoBlending, - NormalBlending: NormalBlending, - AdditiveBlending: AdditiveBlending, - SubtractiveBlending: SubtractiveBlending, - MultiplyBlending: MultiplyBlending, - CustomBlending: CustomBlending - }; +QuadraticBezierCurve3.prototype = Object.create( Curve.prototype ); +QuadraticBezierCurve3.prototype.constructor = QuadraticBezierCurve3; - var color = new Color(); - var textureLoader = new TextureLoader(); - var materialLoader = new MaterialLoader(); +QuadraticBezierCurve3.prototype.isQuadraticBezierCurve3 = true; - return function createMaterial( m, texturePath, crossOrigin ) { +QuadraticBezierCurve3.prototype.getPoint = function ( t, optionalTarget ) { - // convert from old material format + var point = optionalTarget || new Vector3(); - var textures = {}; + var v0 = this.v0, v1 = this.v1, v2 = this.v2; - function loadTexture( path, repeat, offset, wrap, anisotropy ) { + 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 ) + ); - var fullPath = texturePath + path; - var loader = Loader.Handlers.get( fullPath ); + return point; - var texture; +}; - if ( loader !== null ) { +QuadraticBezierCurve3.prototype.copy = function ( source ) { - texture = loader.load( fullPath ); + Curve.prototype.copy.call( this, source ); - } else { + this.v0.copy( source.v0 ); + this.v1.copy( source.v1 ); + this.v2.copy( source.v2 ); - textureLoader.setCrossOrigin( crossOrigin ); - texture = textureLoader.load( fullPath ); + return this; - } +}; - if ( repeat !== undefined ) { +QuadraticBezierCurve3.prototype.toJSON = function () { - texture.repeat.fromArray( repeat ); + var data = Curve.prototype.toJSON.call( this ); - if ( repeat[ 0 ] !== 1 ) texture.wrapS = RepeatWrapping; - if ( repeat[ 1 ] !== 1 ) texture.wrapT = RepeatWrapping; + data.v0 = this.v0.toArray(); + data.v1 = this.v1.toArray(); + data.v2 = this.v2.toArray(); - } + return data; - if ( offset !== undefined ) { +}; - texture.offset.fromArray( offset ); +QuadraticBezierCurve3.prototype.fromJSON = function ( json ) { - } + Curve.prototype.fromJSON.call( this, json ); - if ( wrap !== undefined ) { + this.v0.fromArray( json.v0 ); + this.v1.fromArray( json.v1 ); + this.v2.fromArray( json.v2 ); - if ( wrap[ 0 ] === 'repeat' ) texture.wrapS = RepeatWrapping; - if ( wrap[ 0 ] === 'mirror' ) texture.wrapS = MirroredRepeatWrapping; + return this; - if ( wrap[ 1 ] === 'repeat' ) texture.wrapT = RepeatWrapping; - if ( wrap[ 1 ] === 'mirror' ) texture.wrapT = MirroredRepeatWrapping; +}; - } +function SplineCurve( points /* array of Vector2 */ ) { - if ( anisotropy !== undefined ) { + Curve.call( this ); - texture.anisotropy = anisotropy; + this.type = 'SplineCurve'; - } + this.points = points || []; - var uuid = _Math.generateUUID(); +} - textures[ uuid ] = texture; +SplineCurve.prototype = Object.create( Curve.prototype ); +SplineCurve.prototype.constructor = SplineCurve; - return uuid; +SplineCurve.prototype.isSplineCurve = true; - } +SplineCurve.prototype.getPoint = function ( t, optionalTarget ) { - // + var point = optionalTarget || new Vector2(); - var json = { - uuid: _Math.generateUUID(), - type: 'MeshLambertMaterial' - }; + var points = this.points; + var p = ( points.length - 1 ) * t; - for ( var name in m ) { + var intPoint = Math.floor( p ); + var weight = p - intPoint; - var value = m[ name ]; + var p0 = points[ intPoint === 0 ? intPoint : intPoint - 1 ]; + var p1 = points[ intPoint ]; + var p2 = points[ intPoint > points.length - 2 ? points.length - 1 : intPoint + 1 ]; + var p3 = points[ intPoint > points.length - 3 ? points.length - 1 : intPoint + 2 ]; - switch ( name ) { + point.set( + CatmullRom( weight, p0.x, p1.x, p2.x, p3.x ), + CatmullRom( weight, p0.y, p1.y, p2.y, p3.y ) + ); - case 'DbgColor': - case 'DbgIndex': - case 'opticalDensity': - case 'illumination': - break; - case 'DbgName': - json.name = value; - break; - case 'blending': - json.blending = BlendingMode[ value ]; - break; - case 'colorAmbient': - case 'mapAmbient': - console.warn( 'THREE.Loader.createMaterial:', name, 'is no longer supported.' ); - break; - case 'colorDiffuse': - json.color = color.fromArray( value ).getHex(); - break; - case 'colorSpecular': - json.specular = color.fromArray( value ).getHex(); - break; - case 'colorEmissive': - json.emissive = color.fromArray( value ).getHex(); - break; - case 'specularCoef': - json.shininess = value; - break; - case 'shading': - if ( value.toLowerCase() === 'basic' ) json.type = 'MeshBasicMaterial'; - if ( value.toLowerCase() === 'phong' ) json.type = 'MeshPhongMaterial'; - if ( value.toLowerCase() === 'standard' ) json.type = 'MeshStandardMaterial'; - break; - case 'mapDiffuse': - json.map = loadTexture( value, m.mapDiffuseRepeat, m.mapDiffuseOffset, m.mapDiffuseWrap, m.mapDiffuseAnisotropy ); - break; - case 'mapDiffuseRepeat': - case 'mapDiffuseOffset': - case 'mapDiffuseWrap': - case 'mapDiffuseAnisotropy': - break; - case 'mapEmissive': - json.emissiveMap = loadTexture( value, m.mapEmissiveRepeat, m.mapEmissiveOffset, m.mapEmissiveWrap, m.mapEmissiveAnisotropy ); - break; - case 'mapEmissiveRepeat': - case 'mapEmissiveOffset': - case 'mapEmissiveWrap': - case 'mapEmissiveAnisotropy': - break; - case 'mapLight': - json.lightMap = loadTexture( value, m.mapLightRepeat, m.mapLightOffset, m.mapLightWrap, m.mapLightAnisotropy ); - break; - case 'mapLightRepeat': - case 'mapLightOffset': - case 'mapLightWrap': - case 'mapLightAnisotropy': - break; - case 'mapAO': - json.aoMap = loadTexture( value, m.mapAORepeat, m.mapAOOffset, m.mapAOWrap, m.mapAOAnisotropy ); - break; - case 'mapAORepeat': - case 'mapAOOffset': - case 'mapAOWrap': - case 'mapAOAnisotropy': - break; - case 'mapBump': - json.bumpMap = loadTexture( value, m.mapBumpRepeat, m.mapBumpOffset, m.mapBumpWrap, m.mapBumpAnisotropy ); - break; - case 'mapBumpScale': - json.bumpScale = value; - break; - case 'mapBumpRepeat': - case 'mapBumpOffset': - case 'mapBumpWrap': - case 'mapBumpAnisotropy': - break; - case 'mapNormal': - json.normalMap = loadTexture( value, m.mapNormalRepeat, m.mapNormalOffset, m.mapNormalWrap, m.mapNormalAnisotropy ); - break; - case 'mapNormalFactor': - json.normalScale = [ value, value ]; - break; - case 'mapNormalRepeat': - case 'mapNormalOffset': - case 'mapNormalWrap': - case 'mapNormalAnisotropy': - break; - case 'mapSpecular': - json.specularMap = loadTexture( value, m.mapSpecularRepeat, m.mapSpecularOffset, m.mapSpecularWrap, m.mapSpecularAnisotropy ); - break; - case 'mapSpecularRepeat': - case 'mapSpecularOffset': - case 'mapSpecularWrap': - case 'mapSpecularAnisotropy': - break; - case 'mapMetalness': - json.metalnessMap = loadTexture( value, m.mapMetalnessRepeat, m.mapMetalnessOffset, m.mapMetalnessWrap, m.mapMetalnessAnisotropy ); - break; - case 'mapMetalnessRepeat': - case 'mapMetalnessOffset': - case 'mapMetalnessWrap': - case 'mapMetalnessAnisotropy': - break; - case 'mapRoughness': - json.roughnessMap = loadTexture( value, m.mapRoughnessRepeat, m.mapRoughnessOffset, m.mapRoughnessWrap, m.mapRoughnessAnisotropy ); - break; - case 'mapRoughnessRepeat': - case 'mapRoughnessOffset': - case 'mapRoughnessWrap': - case 'mapRoughnessAnisotropy': - break; - case 'mapAlpha': - json.alphaMap = loadTexture( value, m.mapAlphaRepeat, m.mapAlphaOffset, m.mapAlphaWrap, m.mapAlphaAnisotropy ); - break; - case 'mapAlphaRepeat': - case 'mapAlphaOffset': - case 'mapAlphaWrap': - case 'mapAlphaAnisotropy': - break; - case 'flipSided': - json.side = BackSide; - break; - case 'doubleSided': - json.side = DoubleSide; - break; - case 'transparency': - console.warn( 'THREE.Loader.createMaterial: transparency has been renamed to opacity' ); - json.opacity = value; - break; - case 'depthTest': - case 'depthWrite': - case 'colorWrite': - case 'opacity': - case 'reflectivity': - case 'transparent': - case 'visible': - case 'wireframe': - json[ name ] = value; - break; - case 'vertexColors': - if ( value === true ) json.vertexColors = VertexColors; - if ( value === 'face' ) json.vertexColors = FaceColors; - break; - default: - console.error( 'THREE.Loader.createMaterial: Unsupported', name, value ); - break; + return point; - } +}; - } +SplineCurve.prototype.copy = function ( source ) { - if ( json.type === 'MeshBasicMaterial' ) delete json.emissive; - if ( json.type !== 'MeshPhongMaterial' ) delete json.specular; + Curve.prototype.copy.call( this, source ); - if ( json.opacity < 1 ) json.transparent = true; + this.points = []; - materialLoader.setTextures( textures ); + for ( var i = 0, l = source.points.length; i < l; i ++ ) { - return materialLoader.parse( json ); + var point = source.points[ i ]; - }; + this.points.push( point.clone() ); - } )() + } -} ); + return this; -/** - * @author Don McCurdy / https://www.donmccurdy.com - */ +}; -var LoaderUtils = { +SplineCurve.prototype.toJSON = function () { - decodeText: function ( array ) { + var data = Curve.prototype.toJSON.call( this ); - if ( typeof TextDecoder !== 'undefined' ) { + data.points = []; - return new TextDecoder().decode( array ); + for ( var i = 0, l = this.points.length; i < l; i ++ ) { - } + var point = this.points[ i ]; + data.points.push( point.toArray() ); - // Avoid the String.fromCharCode.apply(null, array) shortcut, which - // throws a "maximum call stack size exceeded" error for large arrays. + } - var s = ''; + return data; - for ( var i = 0, il = array.length; i < il; i ++ ) { +}; - // Implicitly assumes little-endian. - s += String.fromCharCode( array[ i ] ); +SplineCurve.prototype.fromJSON = function ( json ) { - } + Curve.prototype.fromJSON.call( this, json ); - // Merges multi-byte utf-8 characters. - return decodeURIComponent( escape( s ) ); + this.points = []; - }, + for ( var i = 0, l = json.points.length; i < l; i ++ ) { - extractUrlBase: function ( url ) { + var point = json.points[ i ]; + this.points.push( new Vector2().fromArray( point ) ); - var parts = url.split( '/' ); + } - if ( parts.length === 1 ) return './'; + return this; - parts.pop(); +}; - return parts.join( '/' ) + '/'; - } -}; +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 +}); /** - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - */ - -function JSONLoader( manager ) { + * @author zz85 / http://www.lab4games.net/zz85/blog + * + **/ - if ( typeof manager === 'boolean' ) { +/************************************************************** + * Curved Path - a curve path is simply a array of connected + * curves, but retains the api of a curve + **************************************************************/ - console.warn( 'THREE.JSONLoader: showStatus parameter has been removed from constructor.' ); - manager = undefined; +function CurvePath() { - } + Curve.call( this ); - this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager; + this.type = 'CurvePath'; - this.withCredentials = false; + this.curves = []; + this.autoClose = false; // Automatically closes the path } -Object.assign( JSONLoader.prototype, { - - load: function ( url, onLoad, onProgress, onError ) { - - var scope = this; - - var texturePath = this.texturePath && ( typeof this.texturePath === 'string' ) ? this.texturePath : LoaderUtils.extractUrlBase( url ); - - var loader = new FileLoader( this.manager ); - loader.setWithCredentials( this.withCredentials ); - loader.load( url, function ( text ) { - - var json = JSON.parse( text ); - var metadata = json.metadata; - - if ( metadata !== undefined ) { +CurvePath.prototype = Object.assign( Object.create( Curve.prototype ), { - var type = metadata.type; + constructor: CurvePath, - if ( type !== undefined ) { + add: function ( curve ) { - if ( type.toLowerCase() === 'object' ) { + this.curves.push( curve ); - console.error( 'THREE.JSONLoader: ' + url + ' should be loaded with THREE.ObjectLoader instead.' ); - return; + }, - } + closePath: function () { - if ( type.toLowerCase() === 'scene' ) { + // 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 ); - console.error( 'THREE.JSONLoader: ' + url + ' should be loaded with THREE.SceneLoader instead.' ); - return; + if ( ! startPoint.equals( endPoint ) ) { - } + this.curves.push( new LineCurve( endPoint, startPoint ) ); - } + } - } + }, - var object = scope.parse( json, texturePath ); - onLoad( object.geometry, object.materials ); + // To get accurate point with reference to + // entire path distance at time t, + // following has to be done: - }, onProgress, onError ); + // 1. Length of each sub path have to be known + // 2. Locate and identify type of curve + // 3. Get t for the curve + // 4. Return curve.getPointAt(t') - }, + getPoint: function ( t ) { - setTexturePath: function ( value ) { + var d = t * this.getLength(); + var curveLengths = this.getCurveLengths(); + var i = 0; - this.texturePath = value; + // To think about boundaries points. - }, + while ( i < curveLengths.length ) { - parse: ( function () { + if ( curveLengths[ i ] >= d ) { - function parseModel( json, geometry ) { + var diff = curveLengths[ i ] - d; + var curve = this.curves[ i ]; - function isBitSet( value, position ) { + var segmentLength = curve.getLength(); + var u = segmentLength === 0 ? 0 : 1 - diff / segmentLength; - return value & ( 1 << position ); + return curve.getPointAt( u ); } - var i, j, fi, - - offset, zLength, + i ++; - colorIndex, normalIndex, uvIndex, materialIndex, + } - type, - isQuad, - hasMaterial, - hasFaceVertexUv, - hasFaceNormal, hasFaceVertexNormal, - hasFaceColor, hasFaceVertexColor, + return null; - vertex, face, faceA, faceB, hex, normal, + // loop where sum != 0, sum > d , sum+1 uv index correspondence + }, - fi = geometry.faces.length; + getPoints: function ( divisions ) { - if ( hasFaceVertexUv ) { + divisions = divisions || 12; - for ( i = 0; i < nUvLayers; i ++ ) { + var points = [], last; - uvLayer = json.uvs[ i ]; + for ( var i = 0, curves = this.curves; i < curves.length; i ++ ) { - geometry.faceVertexUvs[ i ][ fi ] = []; - geometry.faceVertexUvs[ i ][ fi + 1 ] = []; + var curve = curves[ i ]; + var resolution = ( curve && curve.isEllipseCurve ) ? divisions * 2 + : ( curve && ( curve.isLineCurve || curve.isLineCurve3 ) ) ? 1 + : ( curve && curve.isSplineCurve ) ? divisions * curve.points.length + : divisions; - for ( j = 0; j < 4; j ++ ) { + var pts = curve.getPoints( resolution ); - uvIndex = faces[ offset ++ ]; + for ( var j = 0; j < pts.length; j ++ ) { - u = uvLayer[ uvIndex * 2 ]; - v = uvLayer[ uvIndex * 2 + 1 ]; + var point = pts[ j ]; - uv = new Vector2( u, v ); + if ( last && last.equals( point ) ) continue; // ensures no consecutive points are duplicates - if ( j !== 2 ) geometry.faceVertexUvs[ i ][ fi ].push( uv ); - if ( j !== 0 ) geometry.faceVertexUvs[ i ][ fi + 1 ].push( uv ); + points.push( point ); + last = point; - } + } - } + } - } + if ( this.autoClose && points.length > 1 && ! points[ points.length - 1 ].equals( points[ 0 ] ) ) { - if ( hasFaceNormal ) { + points.push( points[ 0 ] ); - normalIndex = faces[ offset ++ ] * 3; + } - faceA.normal.set( - normals[ normalIndex ++ ], - normals[ normalIndex ++ ], - normals[ normalIndex ] - ); + return points; - faceB.normal.copy( faceA.normal ); + }, - } + copy: function ( source ) { - if ( hasFaceVertexNormal ) { + Curve.prototype.copy.call( this, source ); - for ( i = 0; i < 4; i ++ ) { + this.curves = []; - normalIndex = faces[ offset ++ ] * 3; + for ( var i = 0, l = source.curves.length; i < l; i ++ ) { - normal = new Vector3( - normals[ normalIndex ++ ], - normals[ normalIndex ++ ], - normals[ normalIndex ] - ); + var curve = source.curves[ i ]; + this.curves.push( curve.clone() ); - if ( i !== 2 ) faceA.vertexNormals.push( normal ); - if ( i !== 0 ) faceB.vertexNormals.push( normal ); + } - } + this.autoClose = source.autoClose; - } + return this; + }, - if ( hasFaceColor ) { + toJSON: function () { - colorIndex = faces[ offset ++ ]; - hex = colors[ colorIndex ]; + var data = Curve.prototype.toJSON.call( this ); - faceA.color.setHex( hex ); - faceB.color.setHex( hex ); + 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() ); - if ( hasFaceVertexColor ) { + } - for ( i = 0; i < 4; i ++ ) { + return data; - colorIndex = faces[ offset ++ ]; - hex = colors[ colorIndex ]; + }, - if ( i !== 2 ) faceA.vertexColors.push( new Color( hex ) ); - if ( i !== 0 ) faceB.vertexColors.push( new Color( hex ) ); + fromJSON: function ( json ) { - } + Curve.prototype.fromJSON.call( this, json ); - } + this.autoClose = json.autoClose; + this.curves = []; - geometry.faces.push( faceA ); - geometry.faces.push( faceB ); + for ( var i = 0, l = json.curves.length; i < l; i ++ ) { - } else { + var curve = json.curves[ i ]; + this.curves.push( new Curves[ curve.type ]().fromJSON( curve ) ); - face = new Face3(); - face.a = faces[ offset ++ ]; - face.b = faces[ offset ++ ]; - face.c = faces[ offset ++ ]; + } - if ( hasMaterial ) { + return this; - materialIndex = faces[ offset ++ ]; - face.materialIndex = materialIndex; + } - } +} ); - // to get face <=> uv index correspondence +/** + * @author zz85 / http://www.lab4games.net/zz85/blog + * Creates free form 2d path using series of points, lines or curves. + **/ - fi = geometry.faces.length; +function Path( points ) { - if ( hasFaceVertexUv ) { + CurvePath.call( this ); - for ( i = 0; i < nUvLayers; i ++ ) { + this.type = 'Path'; - uvLayer = json.uvs[ i ]; + this.currentPoint = new Vector2(); - geometry.faceVertexUvs[ i ][ fi ] = []; + if ( points ) { - for ( j = 0; j < 3; j ++ ) { + this.setFromPoints( points ); - uvIndex = faces[ offset ++ ]; + } - u = uvLayer[ uvIndex * 2 ]; - v = uvLayer[ uvIndex * 2 + 1 ]; +} - uv = new Vector2( u, v ); +Path.prototype = Object.assign( Object.create( CurvePath.prototype ), { - geometry.faceVertexUvs[ i ][ fi ].push( uv ); + constructor: Path, - } + setFromPoints: function ( points ) { - } + this.moveTo( points[ 0 ].x, points[ 0 ].y ); - } + for ( var i = 1, l = points.length; i < l; i ++ ) { - if ( hasFaceNormal ) { + this.lineTo( points[ i ].x, points[ i ].y ); - normalIndex = faces[ offset ++ ] * 3; + } - face.normal.set( - normals[ normalIndex ++ ], - normals[ normalIndex ++ ], - normals[ normalIndex ] - ); + }, - } + moveTo: function ( x, y ) { - if ( hasFaceVertexNormal ) { + this.currentPoint.set( x, y ); // TODO consider referencing vectors instead of copying? - for ( i = 0; i < 3; i ++ ) { + }, - normalIndex = faces[ offset ++ ] * 3; + lineTo: function ( x, y ) { - normal = new Vector3( - normals[ normalIndex ++ ], - normals[ normalIndex ++ ], - normals[ normalIndex ] - ); + var curve = new LineCurve( this.currentPoint.clone(), new Vector2( x, y ) ); + this.curves.push( curve ); - face.vertexNormals.push( normal ); + this.currentPoint.set( x, y ); - } + }, - } + quadraticCurveTo: function ( aCPx, aCPy, aX, aY ) { + var curve = new QuadraticBezierCurve( + this.currentPoint.clone(), + new Vector2( aCPx, aCPy ), + new Vector2( aX, aY ) + ); - if ( hasFaceColor ) { + this.curves.push( curve ); - colorIndex = faces[ offset ++ ]; - face.color.setHex( colors[ colorIndex ] ); + this.currentPoint.set( aX, aY ); - } + }, + bezierCurveTo: function ( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY ) { - if ( hasFaceVertexColor ) { + var curve = new CubicBezierCurve( + this.currentPoint.clone(), + new Vector2( aCP1x, aCP1y ), + new Vector2( aCP2x, aCP2y ), + new Vector2( aX, aY ) + ); - for ( i = 0; i < 3; i ++ ) { + this.curves.push( curve ); - colorIndex = faces[ offset ++ ]; - face.vertexColors.push( new Color( colors[ colorIndex ] ) ); + this.currentPoint.set( aX, aY ); - } + }, - } + splineThru: function ( pts /*Array of Vector*/ ) { - geometry.faces.push( face ); + var npts = [ this.currentPoint.clone() ].concat( pts ); - } + var curve = new SplineCurve( npts ); + this.curves.push( curve ); - } + this.currentPoint.copy( pts[ pts.length - 1 ] ); - } + }, - function parseSkin( json, geometry ) { + arc: function ( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) { - var influencesPerVertex = ( json.influencesPerVertex !== undefined ) ? json.influencesPerVertex : 2; + var x0 = this.currentPoint.x; + var y0 = this.currentPoint.y; - if ( json.skinWeights ) { + this.absarc( aX + x0, aY + y0, aRadius, + aStartAngle, aEndAngle, aClockwise ); - for ( var i = 0, l = json.skinWeights.length; i < l; i += influencesPerVertex ) { + }, - var x = json.skinWeights[ i ]; - var y = ( influencesPerVertex > 1 ) ? json.skinWeights[ i + 1 ] : 0; - var z = ( influencesPerVertex > 2 ) ? json.skinWeights[ i + 2 ] : 0; - var w = ( influencesPerVertex > 3 ) ? json.skinWeights[ i + 3 ] : 0; + absarc: function ( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) { - geometry.skinWeights.push( new Vector4( x, y, z, w ) ); + this.absellipse( aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise ); - } + }, - } + ellipse: function ( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ) { - if ( json.skinIndices ) { + var x0 = this.currentPoint.x; + var y0 = this.currentPoint.y; - for ( var i = 0, l = json.skinIndices.length; i < l; i += influencesPerVertex ) { + this.absellipse( aX + x0, aY + y0, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ); - 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; + }, - geometry.skinIndices.push( new Vector4( a, b, c, d ) ); + absellipse: function ( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ) { - } + var curve = new EllipseCurve( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ); - } + if ( this.curves.length > 0 ) { - geometry.bones = json.bones; + // if a previous curve is present, attempt to join + var firstPoint = curve.getPoint( 0 ); - if ( geometry.bones && geometry.bones.length > 0 && ( geometry.skinWeights.length !== geometry.skinIndices.length || geometry.skinIndices.length !== geometry.vertices.length ) ) { + if ( ! firstPoint.equals( this.currentPoint ) ) { - console.warn( 'When skinning, number of vertices (' + geometry.vertices.length + '), skinIndices (' + - geometry.skinIndices.length + '), and skinWeights (' + geometry.skinWeights.length + ') should match.' ); + this.lineTo( firstPoint.x, firstPoint.y ); } } - function parseMorphing( json, geometry ) { - - var scale = json.scale; - - if ( json.morphTargets !== undefined ) { - - for ( var i = 0, l = json.morphTargets.length; i < l; i ++ ) { + this.curves.push( curve ); - geometry.morphTargets[ i ] = {}; - geometry.morphTargets[ i ].name = json.morphTargets[ i ].name; - geometry.morphTargets[ i ].vertices = []; + var lastPoint = curve.getPoint( 1 ); + this.currentPoint.copy( lastPoint ); - var dstVertices = geometry.morphTargets[ i ].vertices; - var srcVertices = json.morphTargets[ i ].vertices; + }, - for ( var v = 0, vl = srcVertices.length; v < vl; v += 3 ) { + copy: function ( source ) { - var vertex = new Vector3(); - vertex.x = srcVertices[ v ] * scale; - vertex.y = srcVertices[ v + 1 ] * scale; - vertex.z = srcVertices[ v + 2 ] * scale; + CurvePath.prototype.copy.call( this, source ); - dstVertices.push( vertex ); + this.currentPoint.copy( source.currentPoint ); - } + return this; - } + }, - } + toJSON: function () { - if ( json.morphColors !== undefined && json.morphColors.length > 0 ) { + var data = CurvePath.prototype.toJSON.call( this ); - console.warn( 'THREE.JSONLoader: "morphColors" no longer supported. Using them as face colors.' ); + data.currentPoint = this.currentPoint.toArray(); - var faces = geometry.faces; - var morphColors = json.morphColors[ 0 ].colors; + return data; - for ( var i = 0, l = faces.length; i < l; i ++ ) { + }, - faces[ i ].color.fromArray( morphColors, i * 3 ); + fromJSON: function ( json ) { - } + CurvePath.prototype.fromJSON.call( this, json ); - } + this.currentPoint.fromArray( json.currentPoint ); - } + return this; - function parseAnimations( json, geometry ) { + } - var outputAnimations = []; +} ); - // parse old style Bone/Hierarchy animations - var animations = []; +/** + * @author zz85 / http://www.lab4games.net/zz85/blog + * Defines a 2d shape plane using paths. + **/ - if ( json.animation !== undefined ) { +// 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. - animations.push( json.animation ); +function Shape( points ) { - } + Path.call( this, points ); - if ( json.animations !== undefined ) { + this.uuid = _Math.generateUUID(); - if ( json.animations.length ) { + this.type = 'Shape'; - animations = animations.concat( json.animations ); + this.holes = []; - } else { +} - animations.push( json.animations ); +Shape.prototype = Object.assign( Object.create( Path.prototype ), { - } + constructor: Shape, - } + getPointsHoles: function ( divisions ) { - for ( var i = 0; i < animations.length; i ++ ) { + var holesPts = []; - var clip = AnimationClip.parseAnimation( animations[ i ], geometry.bones ); - if ( clip ) outputAnimations.push( clip ); + for ( var i = 0, l = this.holes.length; i < l; i ++ ) { - } + holesPts[ i ] = this.holes[ i ].getPoints( divisions ); - // parse implicit morph animations - if ( geometry.morphTargets ) { + } - // TODO: Figure out what an appropraite FPS is for morph target animations -- defaulting to 10, but really it is completely arbitrary. - var morphAnimationClips = AnimationClip.CreateClipsFromMorphTargetSequences( geometry.morphTargets, 10 ); - outputAnimations = outputAnimations.concat( morphAnimationClips ); + return holesPts; - } + }, - if ( outputAnimations.length > 0 ) geometry.animations = outputAnimations; + // get points of shape and holes (keypoints based on segments parameter) - } + extractPoints: function ( divisions ) { - return function parse( json, texturePath ) { + return { - if ( json.data !== undefined ) { + shape: this.getPoints( divisions ), + holes: this.getPointsHoles( divisions ) - // Geometry 4.0 spec - json = json.data; + }; - } + }, - if ( json.scale !== undefined ) { + copy: function ( source ) { - json.scale = 1.0 / json.scale; + Path.prototype.copy.call( this, source ); - } else { + this.holes = []; - json.scale = 1.0; + for ( var i = 0, l = source.holes.length; i < l; i ++ ) { - } + var hole = source.holes[ i ]; - var geometry = new Geometry(); + this.holes.push( hole.clone() ); - parseModel( json, geometry ); - parseSkin( json, geometry ); - parseMorphing( json, geometry ); - parseAnimations( json, geometry ); + } - geometry.computeFaceNormals(); - geometry.computeBoundingSphere(); + return this; - if ( json.materials === undefined || json.materials.length === 0 ) { + }, - return { geometry: geometry }; + toJSON: function () { - } else { + var data = Path.prototype.toJSON.call( this ); - var materials = Loader.prototype.initMaterials( json.materials, texturePath, this.crossOrigin ); + data.uuid = this.uuid; + data.holes = []; - return { geometry: geometry, materials: materials }; + for ( var i = 0, l = this.holes.length; i < l; i ++ ) { - } + var hole = this.holes[ i ]; + data.holes.push( hole.toJSON() ); - }; + } - } )() + return data; -} ); + }, -/** - * @author mrdoob / http://mrdoob.com/ - */ + fromJSON: function ( json ) { -function ObjectLoader( manager ) { + Path.prototype.fromJSON.call( this, json ); - this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager; - this.texturePath = ''; + this.uuid = json.uuid; + this.holes = []; -} + for ( var i = 0, l = json.holes.length; i < l; i ++ ) { -Object.assign( ObjectLoader.prototype, { + var hole = json.holes[ i ]; + this.holes.push( new Path().fromJSON( hole ) ); - load: function ( url, onLoad, onProgress, onError ) { + } - if ( this.texturePath === '' ) { + return this; - this.texturePath = url.substring( 0, url.lastIndexOf( '/' ) + 1 ); + } - } +} ); - var scope = this; +/** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + */ - var loader = new FileLoader( scope.manager ); - loader.load( url, function ( text ) { +function Light( color, intensity ) { - var json = null; + Object3D.call( this ); - try { + this.type = 'Light'; - json = JSON.parse( text ); + this.color = new Color( color ); + this.intensity = intensity !== undefined ? intensity : 1; - } catch ( error ) { + this.receiveShadow = undefined; - if ( onError !== undefined ) onError( error ); +} - console.error( 'THREE:ObjectLoader: Can\'t parse ' + url + '.', error.message ); +Light.prototype = Object.assign( Object.create( Object3D.prototype ), { - return; + constructor: Light, - } + isLight: true, - var metadata = json.metadata; + copy: function ( source ) { - if ( metadata === undefined || metadata.type === undefined || metadata.type.toLowerCase() === 'geometry' ) { + Object3D.prototype.copy.call( this, source ); - console.error( 'THREE.ObjectLoader: Can\'t load ' + url + '. Use THREE.JSONLoader instead.' ); - return; + this.color.copy( source.color ); + this.intensity = source.intensity; - } + return this; - scope.parse( json, onLoad ); + }, - }, onProgress, onError ); + toJSON: function ( meta ) { - }, + var data = Object3D.prototype.toJSON.call( this, meta ); - setTexturePath: function ( value ) { + data.object.color = this.color.getHex(); + data.object.intensity = this.intensity; - this.texturePath = value; + if ( this.groundColor !== undefined ) data.object.groundColor = this.groundColor.getHex(); - }, + if ( this.distance !== undefined ) data.object.distance = this.distance; + if ( this.angle !== undefined ) data.object.angle = this.angle; + if ( this.decay !== undefined ) data.object.decay = this.decay; + if ( this.penumbra !== undefined ) data.object.penumbra = this.penumbra; - setCrossOrigin: function ( value ) { + if ( this.shadow !== undefined ) data.object.shadow = this.shadow.toJSON(); - this.crossOrigin = value; + return data; - }, + } - parse: function ( json, onLoad ) { +} ); - var shapes = this.parseShape( json.shapes ); - var geometries = this.parseGeometries( json.geometries, shapes ); +/** + * @author alteredq / http://alteredqualia.com/ + */ - var images = this.parseImages( json.images, function () { +function HemisphereLight( skyColor, groundColor, intensity ) { - if ( onLoad !== undefined ) onLoad( object ); + Light.call( this, skyColor, intensity ); - } ); + this.type = 'HemisphereLight'; - var textures = this.parseTextures( json.textures, images ); - var materials = this.parseMaterials( json.materials, textures ); + this.castShadow = undefined; - var object = this.parseObject( json.object, geometries, materials ); + this.position.copy( Object3D.DefaultUp ); + this.updateMatrix(); - if ( json.animations ) { + this.groundColor = new Color( groundColor ); - object.animations = this.parseAnimations( json.animations ); +} - } +HemisphereLight.prototype = Object.assign( Object.create( Light.prototype ), { - if ( json.images === undefined || json.images.length === 0 ) { + constructor: HemisphereLight, - if ( onLoad !== undefined ) onLoad( object ); + isHemisphereLight: true, - } + copy: function ( source ) { - return object; + Light.prototype.copy.call( this, source ); - }, + this.groundColor.copy( source.groundColor ); - parseShape: function ( json ) { + return this; - var shapes = {}; + } - if ( json !== undefined ) { +} ); - for ( var i = 0, l = json.length; i < l; i ++ ) { +/** + * @author mrdoob / http://mrdoob.com/ + */ - var shape = new Shape().fromJSON( json[ i ] ); +function LightShadow( camera ) { - shapes[ shape.uuid ] = shape; + this.camera = camera; - } + this.bias = 0; + this.radius = 1; - } + this.mapSize = new Vector2( 512, 512 ); - return shapes; + this.map = null; + this.matrix = new Matrix4(); - }, +} - parseGeometries: function ( json, shapes ) { +Object.assign( LightShadow.prototype, { - var geometries = {}; + copy: function ( source ) { - if ( json !== undefined ) { + this.camera = source.camera.clone(); - var geometryLoader = new JSONLoader(); - var bufferGeometryLoader = new BufferGeometryLoader(); + this.bias = source.bias; + this.radius = source.radius; - for ( var i = 0, l = json.length; i < l; i ++ ) { + this.mapSize.copy( source.mapSize ); - var geometry; - var data = json[ i ]; + return this; - switch ( data.type ) { + }, - case 'PlaneGeometry': - case 'PlaneBufferGeometry': + clone: function () { - geometry = new Geometries[ data.type ]( - data.width, - data.height, - data.widthSegments, - data.heightSegments - ); + return new this.constructor().copy( this ); - break; + }, - case 'BoxGeometry': - case 'BoxBufferGeometry': - case 'CubeGeometry': // backwards compatible + toJSON: function () { - geometry = new Geometries[ data.type ]( - data.width, - data.height, - data.depth, - data.widthSegments, - data.heightSegments, - data.depthSegments - ); + var object = {}; - break; + 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(); - case 'CircleGeometry': - case 'CircleBufferGeometry': + object.camera = this.camera.toJSON( false ).object; + delete object.camera.matrix; - geometry = new Geometries[ data.type ]( - data.radius, - data.segments, - data.thetaStart, - data.thetaLength - ); + return object; - break; + } - 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 - ); +/** + * @author mrdoob / http://mrdoob.com/ + */ - break; +function SpotLightShadow() { - case 'ConeGeometry': - case 'ConeBufferGeometry': + LightShadow.call( this, new PerspectiveCamera( 50, 1, 0.5, 500 ) ); - geometry = new Geometries[ data.type ]( - data.radius, - data.height, - data.radialSegments, - data.heightSegments, - data.openEnded, - data.thetaStart, - data.thetaLength - ); +} - break; +SpotLightShadow.prototype = Object.assign( Object.create( LightShadow.prototype ), { - case 'SphereGeometry': - case 'SphereBufferGeometry': + constructor: SpotLightShadow, - geometry = new Geometries[ data.type ]( - data.radius, - data.widthSegments, - data.heightSegments, - data.phiStart, - data.phiLength, - data.thetaStart, - data.thetaLength - ); + isSpotLightShadow: true, - break; + update: function ( light ) { - case 'DodecahedronGeometry': - case 'DodecahedronBufferGeometry': - case 'IcosahedronGeometry': - case 'IcosahedronBufferGeometry': - case 'OctahedronGeometry': - case 'OctahedronBufferGeometry': - case 'TetrahedronGeometry': - case 'TetrahedronBufferGeometry': + var camera = this.camera; - geometry = new Geometries[ data.type ]( - data.radius, - data.detail - ); + var fov = _Math.RAD2DEG * 2 * light.angle; + var aspect = this.mapSize.width / this.mapSize.height; + var far = light.distance || camera.far; - break; + if ( fov !== camera.fov || aspect !== camera.aspect || far !== camera.far ) { - case 'RingGeometry': - case 'RingBufferGeometry': + camera.fov = fov; + camera.aspect = aspect; + camera.far = far; + camera.updateProjectionMatrix(); - geometry = new Geometries[ data.type ]( - data.innerRadius, - data.outerRadius, - data.thetaSegments, - data.phiSegments, - data.thetaStart, - data.thetaLength - ); + } - break; + } - case 'TorusGeometry': - case 'TorusBufferGeometry': +} ); - geometry = new Geometries[ data.type ]( - data.radius, - data.tube, - data.radialSegments, - data.tubularSegments, - data.arc - ); +/** + * @author alteredq / http://alteredqualia.com/ + */ - break; +function SpotLight( color, intensity, distance, angle, penumbra, decay ) { - case 'TorusKnotGeometry': - case 'TorusKnotBufferGeometry': + Light.call( this, color, intensity ); - geometry = new Geometries[ data.type ]( - data.radius, - data.tube, - data.tubularSegments, - data.radialSegments, - data.p, - data.q - ); + this.type = 'SpotLight'; - break; + this.position.copy( Object3D.DefaultUp ); + this.updateMatrix(); - case 'LatheGeometry': - case 'LatheBufferGeometry': + this.target = new Object3D(); - geometry = new Geometries[ data.type ]( - data.points, - data.segments, - data.phiStart, - data.phiLength - ); + Object.defineProperty( this, 'power', { + get: function () { - break; + // 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; - case 'PolyhedronGeometry': - case 'PolyhedronBufferGeometry': + }, + set: function ( power ) { - geometry = new Geometries[ data.type ]( - data.vertices, - data.indices, - data.radius, - data.details - ); + // 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; - break; + } + } ); - case 'ShapeGeometry': - case 'ShapeBufferGeometry': + 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. - var geometryShapes = []; + this.shadow = new SpotLightShadow(); - for ( var i = 0, l = data.shapes.length; i < l; i ++ ) { +} - var shape = shapes[ data.shapes[ i ] ]; +SpotLight.prototype = Object.assign( Object.create( Light.prototype ), { - geometryShapes.push( shape ); + constructor: SpotLight, - } + isSpotLight: true, - geometry = new Geometries[ data.type ]( - geometryShapes, - data.curveSegments - ); + copy: function ( source ) { - break; + Light.prototype.copy.call( this, source ); - case 'BufferGeometry': + this.distance = source.distance; + this.angle = source.angle; + this.penumbra = source.penumbra; + this.decay = source.decay; - geometry = bufferGeometryLoader.parse( data ); + this.target = source.target.clone(); - break; + this.shadow = source.shadow.clone(); - case 'Geometry': + return this; - geometry = geometryLoader.parse( data, this.texturePath ).geometry; + } - break; +} ); - default: +/** + * @author mrdoob / http://mrdoob.com/ + */ - console.warn( 'THREE.ObjectLoader: Unsupported geometry type "' + data.type + '"' ); - continue; +function PointLight( color, intensity, distance, decay ) { - } + Light.call( this, color, intensity ); - geometry.uuid = data.uuid; + this.type = 'PointLight'; - if ( data.name !== undefined ) geometry.name = data.name; + Object.defineProperty( this, 'power', { + get: function () { - geometries[ data.uuid ] = geometry; + // 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 ); } + } ); - return geometries; + this.distance = ( distance !== undefined ) ? distance : 0; + this.decay = ( decay !== undefined ) ? decay : 1; // for physically correct lights, should be 2. - }, + this.shadow = new LightShadow( new PerspectiveCamera( 90, 1, 0.5, 500 ) ); - parseMaterials: function ( json, textures ) { +} - var materials = {}; +PointLight.prototype = Object.assign( Object.create( Light.prototype ), { - if ( json !== undefined ) { + constructor: PointLight, - var loader = new MaterialLoader(); - loader.setTextures( textures ); + isPointLight: true, - for ( var i = 0, l = json.length; i < l; i ++ ) { + copy: function ( source ) { - var data = json[ i ]; + Light.prototype.copy.call( this, source ); - if ( data.type === 'MultiMaterial' ) { + this.distance = source.distance; + this.decay = source.decay; - // Deprecated + this.shadow = source.shadow.clone(); - var array = []; + return this; - for ( var j = 0; j < data.materials.length; j ++ ) { + } - array.push( loader.parse( data.materials[ j ] ) ); +} ); - } +/** + * @author alteredq / http://alteredqualia.com/ + * @author arose / http://github.com/arose + */ - materials[ data.uuid ] = array; +function OrthographicCamera( left, right, top, bottom, near, far ) { - } else { + Camera.call( this ); - materials[ data.uuid ] = loader.parse( data ); + this.type = 'OrthographicCamera'; - } + this.zoom = 1; + this.view = null; - } + 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; - return materials; + this.updateProjectionMatrix(); - }, +} - parseAnimations: function ( json ) { +OrthographicCamera.prototype = Object.assign( Object.create( Camera.prototype ), { - var animations = []; + constructor: OrthographicCamera, - for ( var i = 0; i < json.length; i ++ ) { + isOrthographicCamera: true, - var clip = AnimationClip.parse( json[ i ] ); + copy: function ( source, recursive ) { - animations.push( clip ); + 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 animations; + this.zoom = source.zoom; + this.view = source.view === null ? null : Object.assign( {}, source.view ); + + return this; }, - parseImages: function ( json, onLoad ) { + setViewOffset: function ( fullWidth, fullHeight, x, y, width, height ) { - var scope = this; - var images = {}; + if ( this.view === null ) { - function loadImage( url ) { + this.view = { + enabled: true, + fullWidth: 1, + fullHeight: 1, + offsetX: 0, + offsetY: 0, + width: 1, + height: 1 + }; - scope.manager.itemStart( url ); + } - return loader.load( url, function () { + 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; - scope.manager.itemEnd( url ); + this.updateProjectionMatrix(); - }, undefined, function () { + }, - scope.manager.itemEnd( url ); - scope.manager.itemError( url ); + clearViewOffset: function () { - } ); + if ( this.view !== null ) { + + this.view.enabled = false; } - if ( json !== undefined && json.length > 0 ) { + this.updateProjectionMatrix(); - var manager = new LoadingManager( onLoad ); + }, - var loader = new ImageLoader( manager ); - loader.setCrossOrigin( this.crossOrigin ); + updateProjectionMatrix: function () { - for ( var i = 0, l = json.length; i < l; i ++ ) { + 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 image = json[ i ]; - var path = /^(\/\/)|([a-z]+:(\/\/)?)/i.test( image.url ) ? image.url : scope.texturePath + image.url; + var left = cx - dx; + var right = cx + dx; + var top = cy + dy; + var bottom = cy - dy; - images[ image.uuid ] = loadImage( path ); + if ( this.view !== null && this.view.enabled ) { - } + 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; + + 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 ); } - return images; + this.projectionMatrix.makeOrthographic( left, right, top, bottom, this.near, this.far ); + + this.projectionMatrixInverse.getInverse( this.projectionMatrix ); }, - parseTextures: function ( json, images ) { + toJSON: function ( meta ) { - function parseConstant( value, type ) { + var data = Object3D.prototype.toJSON.call( this, meta ); - if ( typeof value === 'number' ) return value; + 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; - console.warn( 'THREE.ObjectLoader.parseTexture: Constant should be in numeric form.', value ); + if ( this.view !== null ) data.object.view = Object.assign( {}, this.view ); - return type[ value ]; + return data; - } + } - var textures = {}; +} ); - if ( json !== undefined ) { +/** + * @author mrdoob / http://mrdoob.com/ + */ - for ( var i = 0, l = json.length; i < l; i ++ ) { +function DirectionalLightShadow( ) { - var data = json[ i ]; + LightShadow.call( this, new OrthographicCamera( - 5, 5, 5, - 5, 0.5, 500 ) ); - if ( data.image === undefined ) { +} - console.warn( 'THREE.ObjectLoader: No "image" specified for', data.uuid ); +DirectionalLightShadow.prototype = Object.assign( Object.create( LightShadow.prototype ), { - } + constructor: DirectionalLightShadow - if ( images[ data.image ] === undefined ) { +} ); - console.warn( 'THREE.ObjectLoader: Undefined image', data.image ); +/** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + */ - } +function DirectionalLight( color, intensity ) { - var texture = new Texture( images[ data.image ] ); - texture.needsUpdate = true; + Light.call( this, color, intensity ); - texture.uuid = data.uuid; + this.type = 'DirectionalLight'; - if ( data.name !== undefined ) texture.name = data.name; + this.position.copy( Object3D.DefaultUp ); + this.updateMatrix(); - if ( data.mapping !== undefined ) texture.mapping = parseConstant( data.mapping, TEXTURE_MAPPING ); + this.target = new Object3D(); - 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; + this.shadow = new DirectionalLightShadow(); - if ( data.wrap !== undefined ) { +} - texture.wrapS = parseConstant( data.wrap[ 0 ], TEXTURE_WRAPPING ); - texture.wrapT = parseConstant( data.wrap[ 1 ], TEXTURE_WRAPPING ); +DirectionalLight.prototype = Object.assign( Object.create( Light.prototype ), { - } + constructor: DirectionalLight, - 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; + isDirectionalLight: true, - if ( data.flipY !== undefined ) texture.flipY = data.flipY; + copy: function ( source ) { - textures[ data.uuid ] = texture; + Light.prototype.copy.call( this, source ); - } + this.target = source.target.clone(); - } + this.shadow = source.shadow.clone(); - return textures; + return this; - }, + } - parseObject: function ( data, geometries, materials ) { +} ); - var object; +/** + * @author mrdoob / http://mrdoob.com/ + */ - function getGeometry( name ) { +function AmbientLight( color, intensity ) { - if ( geometries[ name ] === undefined ) { + Light.call( this, color, intensity ); - console.warn( 'THREE.ObjectLoader: Undefined geometry', name ); + this.type = 'AmbientLight'; - } + this.castShadow = undefined; - return geometries[ name ]; +} - } +AmbientLight.prototype = Object.assign( Object.create( Light.prototype ), { - function getMaterial( name ) { + constructor: AmbientLight, - if ( name === undefined ) return undefined; + isAmbientLight: true - if ( Array.isArray( name ) ) { +} ); - var array = []; +/** + * @author abelnation / http://github.com/abelnation + */ - for ( var i = 0, l = name.length; i < l; i ++ ) { +function RectAreaLight( color, intensity, width, height ) { - var uuid = name[ i ]; + Light.call( this, color, intensity ); - if ( materials[ uuid ] === undefined ) { + this.type = 'RectAreaLight'; - console.warn( 'THREE.ObjectLoader: Undefined material', uuid ); + this.width = ( width !== undefined ) ? width : 10; + this.height = ( height !== undefined ) ? height : 10; - } +} - array.push( materials[ uuid ] ); +RectAreaLight.prototype = Object.assign( Object.create( Light.prototype ), { - } + constructor: RectAreaLight, - return array; + isRectAreaLight: true, - } + copy: function ( source ) { - if ( materials[ name ] === undefined ) { + Light.prototype.copy.call( this, source ); - console.warn( 'THREE.ObjectLoader: Undefined material', name ); + this.width = source.width; + this.height = source.height; - } + return this; - return materials[ name ]; + }, - } + toJSON: function ( meta ) { - switch ( data.type ) { + var data = Light.prototype.toJSON.call( this, meta ); - case 'Scene': + data.object.width = this.width; + data.object.height = this.height; - object = new Scene(); + return data; - if ( data.background !== undefined ) { + } - if ( Number.isInteger( data.background ) ) { +} ); - object.background = new Color( data.background ); +/** + * @author mrdoob / http://mrdoob.com/ + */ - } +function MaterialLoader( manager ) { - } + this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager; + this.textures = {}; - if ( data.fog !== undefined ) { +} - if ( data.fog.type === 'Fog' ) { +Object.assign( MaterialLoader.prototype, { - object.fog = new Fog( data.fog.color, data.fog.near, data.fog.far ); + load: function ( url, onLoad, onProgress, onError ) { - } else if ( data.fog.type === 'FogExp2' ) { + var scope = this; - object.fog = new FogExp2( data.fog.color, data.fog.density ); + var loader = new FileLoader( scope.manager ); + loader.setPath( scope.path ); + loader.load( url, function ( text ) { - } + onLoad( scope.parse( JSON.parse( text ) ) ); - } + }, onProgress, onError ); - break; + }, - case 'PerspectiveCamera': + parse: function ( json ) { - object = new PerspectiveCamera( data.fov, data.aspect, data.near, data.far ); + var textures = this.textures; - 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 ); + function getTexture( name ) { - break; + if ( textures[ name ] === undefined ) { - case 'OrthographicCamera': + console.warn( 'THREE.MaterialLoader: Undefined texture', name ); - object = new OrthographicCamera( data.left, data.right, data.top, data.bottom, data.near, data.far ); + } - break; + return textures[ name ]; - case 'AmbientLight': + } - object = new AmbientLight( data.color, data.intensity ); + var material = new Materials[ json.type ](); - break; + if ( json.uuid !== undefined ) material.uuid = json.uuid; + if ( json.name !== undefined ) material.name = json.name; + if ( json.color !== undefined ) material.color.setHex( json.color ); + if ( json.roughness !== undefined ) material.roughness = json.roughness; + if ( json.metalness !== undefined ) material.metalness = json.metalness; + if ( json.emissive !== undefined ) material.emissive.setHex( json.emissive ); + if ( json.specular !== undefined ) material.specular.setHex( json.specular ); + if ( json.shininess !== undefined ) material.shininess = json.shininess; + if ( json.clearCoat !== undefined ) material.clearCoat = json.clearCoat; + if ( json.clearCoatRoughness !== undefined ) material.clearCoatRoughness = json.clearCoatRoughness; + if ( json.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; - case 'DirectionalLight': + if ( json.rotation !== undefined ) material.rotation = json.rotation; - object = new DirectionalLight( data.color, data.intensity ); + 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; - break; + if ( json.polygonOffset !== undefined ) material.polygonOffset = json.polygonOffset; + if ( json.polygonOffsetFactor !== undefined ) material.polygonOffsetFactor = json.polygonOffsetFactor; + if ( json.polygonOffsetUnits !== undefined ) material.polygonOffsetUnits = json.polygonOffsetUnits; - case 'PointLight': + if ( json.skinning !== undefined ) material.skinning = json.skinning; + if ( json.morphTargets !== undefined ) material.morphTargets = json.morphTargets; + if ( json.dithering !== undefined ) material.dithering = json.dithering; - object = new PointLight( data.color, data.intensity, data.distance, data.decay ); + if ( json.visible !== undefined ) material.visible = json.visible; + if ( json.userData !== undefined ) material.userData = json.userData; - break; + // Shader Material - case 'RectAreaLight': + if ( json.uniforms !== undefined ) { - object = new RectAreaLight( data.color, data.intensity, data.width, data.height ); + for ( var name in json.uniforms ) { - break; + var uniform = json.uniforms[ name ]; - case 'SpotLight': + material.uniforms[ name ] = {}; - object = new SpotLight( data.color, data.intensity, data.distance, data.angle, data.penumbra, data.decay ); + switch ( uniform.type ) { - break; + case 't': + material.uniforms[ name ].value = getTexture( uniform.value ); + break; - case 'HemisphereLight': + case 'c': + material.uniforms[ name ].value = new Color().setHex( uniform.value ); + break; - object = new HemisphereLight( data.color, data.groundColor, data.intensity ); + case 'v2': + material.uniforms[ name ].value = new Vector2().fromArray( uniform.value ); + break; - break; + case 'v3': + material.uniforms[ name ].value = new Vector3().fromArray( uniform.value ); + break; - case 'SkinnedMesh': + case 'v4': + material.uniforms[ name ].value = new Vector4().fromArray( uniform.value ); + break; - console.warn( 'THREE.ObjectLoader.parseObject() does not support SkinnedMesh yet.' ); + case 'm4': + material.uniforms[ name ].value = new Matrix4().fromArray( uniform.value ); + break; - case 'Mesh': + default: + material.uniforms[ name ].value = uniform.value; - var geometry = getGeometry( data.geometry ); - var material = getMaterial( data.material ); + } - if ( geometry.bones && geometry.bones.length > 0 ) { + } - object = new SkinnedMesh( geometry, material ); + } - } else { + if ( json.defines !== undefined ) material.defines = json.defines; + if ( json.vertexShader !== undefined ) material.vertexShader = json.vertexShader; + if ( json.fragmentShader !== undefined ) material.fragmentShader = json.fragmentShader; - object = new Mesh( geometry, material ); + if ( json.extensions !== undefined ) { - } + for ( var key in json.extensions ) { - break; + material.extensions[ key ] = json.extensions[ key ]; - case 'LOD': + } - object = new LOD(); + } - break; + // Deprecated - case 'Line': + if ( json.shading !== undefined ) material.flatShading = json.shading === 1; // THREE.FlatShading - object = new Line( getGeometry( data.geometry ), getMaterial( data.material ), data.mode ); + // for PointsMaterial - break; + if ( json.size !== undefined ) material.size = json.size; + if ( json.sizeAttenuation !== undefined ) material.sizeAttenuation = json.sizeAttenuation; - case 'LineLoop': + // maps - object = new LineLoop( getGeometry( data.geometry ), getMaterial( data.material ) ); + if ( json.map !== undefined ) material.map = getTexture( json.map ); - break; + if ( json.alphaMap !== undefined ) { - case 'LineSegments': + material.alphaMap = getTexture( json.alphaMap ); + material.transparent = true; - object = new LineSegments( getGeometry( data.geometry ), getMaterial( data.material ) ); + } - break; + if ( json.bumpMap !== undefined ) material.bumpMap = getTexture( json.bumpMap ); + if ( json.bumpScale !== undefined ) material.bumpScale = json.bumpScale; - case 'PointCloud': - case 'Points': + if ( json.normalMap !== undefined ) material.normalMap = getTexture( json.normalMap ); + if ( json.normalMapType !== undefined ) material.normalMapType = json.normalMapType; + if ( json.normalScale !== undefined ) { - object = new Points( getGeometry( data.geometry ), getMaterial( data.material ) ); + var normalScale = json.normalScale; - break; + if ( Array.isArray( normalScale ) === false ) { - case 'Sprite': + // Blender exporter used to export a scalar. See #7459 - object = new Sprite( getMaterial( data.material ) ); + normalScale = [ normalScale, normalScale ]; - break; + } - case 'Group': + material.normalScale = new Vector2().fromArray( normalScale ); - object = new Group(); + } - break; + 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; - default: + if ( json.roughnessMap !== undefined ) material.roughnessMap = getTexture( json.roughnessMap ); + if ( json.metalnessMap !== undefined ) material.metalnessMap = getTexture( json.metalnessMap ); - object = new Object3D(); + 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 ); - object.uuid = data.uuid; + if ( json.envMap !== undefined ) material.envMap = getTexture( json.envMap ); + if ( json.envMapIntensity !== undefined ) material.envMapIntensity = json.envMapIntensity; - if ( data.name !== undefined ) object.name = data.name; - if ( data.matrix !== undefined ) { + if ( json.reflectivity !== undefined ) material.reflectivity = json.reflectivity; - object.matrix.fromArray( data.matrix ); - object.matrix.decompose( object.position, object.quaternion, object.scale ); + if ( json.lightMap !== undefined ) material.lightMap = getTexture( json.lightMap ); + if ( json.lightMapIntensity !== undefined ) material.lightMapIntensity = json.lightMapIntensity; - } else { + if ( json.aoMap !== undefined ) material.aoMap = getTexture( json.aoMap ); + if ( json.aoMapIntensity !== undefined ) material.aoMapIntensity = json.aoMapIntensity; - if ( data.position !== undefined ) object.position.fromArray( data.position ); - if ( data.rotation !== undefined ) object.rotation.fromArray( data.rotation ); - if ( data.quaternion !== undefined ) object.quaternion.fromArray( data.quaternion ); - if ( data.scale !== undefined ) object.scale.fromArray( data.scale ); + if ( json.gradientMap !== undefined ) material.gradientMap = getTexture( json.gradientMap ); - } + return material; - if ( data.castShadow !== undefined ) object.castShadow = data.castShadow; - if ( data.receiveShadow !== undefined ) object.receiveShadow = data.receiveShadow; + }, - if ( data.shadow ) { + setPath: function ( value ) { - if ( data.shadow.bias !== undefined ) object.shadow.bias = data.shadow.bias; - if ( data.shadow.radius !== undefined ) object.shadow.radius = data.shadow.radius; - if ( data.shadow.mapSize !== undefined ) object.shadow.mapSize.fromArray( data.shadow.mapSize ); - if ( data.shadow.camera !== undefined ) object.shadow.camera = this.parseObject( data.shadow.camera ); + this.path = value; + return this; - } + }, - if ( data.visible !== undefined ) object.visible = data.visible; - if ( data.userData !== undefined ) object.userData = data.userData; + setTextures: function ( value ) { - if ( data.children !== undefined ) { + this.textures = value; + return this; - var children = data.children; + } - for ( var i = 0; i < children.length; i ++ ) { +} ); - object.add( this.parseObject( children[ i ], geometries, materials ) ); +/** + * @author Don McCurdy / https://www.donmccurdy.com + */ - } +var LoaderUtils = { + + decodeText: function ( array ) { + + if ( typeof TextDecoder !== 'undefined' ) { + + return new TextDecoder().decode( array ); } - if ( data.type === 'LOD' ) { + // Avoid the String.fromCharCode.apply(null, array) shortcut, which + // throws a "maximum call stack size exceeded" error for large arrays. - var levels = data.levels; + var s = ''; - for ( var l = 0; l < levels.length; l ++ ) { + for ( var i = 0, il = array.length; i < il; i ++ ) { - var level = levels[ l ]; - var child = object.getObjectByProperty( 'uuid', level.object ); + // Implicitly assumes little-endian. + s += String.fromCharCode( array[ i ] ); - if ( child !== undefined ) { + } - object.addLevel( child, level.distance ); + // Merges multi-byte utf-8 characters. + return decodeURIComponent( escape( s ) ); - } + }, - } + extractUrlBase: function ( url ) { - } + var index = url.lastIndexOf( '/' ); - return object; + if ( index === - 1 ) return './'; - } + return url.substr( 0, index + 1 ); -} ); + } -var TEXTURE_MAPPING = { - UVMapping: UVMapping, - CubeReflectionMapping: CubeReflectionMapping, - CubeRefractionMapping: CubeRefractionMapping, - EquirectangularReflectionMapping: EquirectangularReflectionMapping, - EquirectangularRefractionMapping: EquirectangularRefractionMapping, - SphericalReflectionMapping: SphericalReflectionMapping, - CubeUVReflectionMapping: CubeUVReflectionMapping, - CubeUVRefractionMapping: CubeUVRefractionMapping }; -var TEXTURE_WRAPPING = { - RepeatWrapping: RepeatWrapping, - ClampToEdgeWrapping: ClampToEdgeWrapping, - MirroredRepeatWrapping: MirroredRepeatWrapping -}; +/** + * @author mrdoob / http://mrdoob.com/ + */ -var TEXTURE_FILTER = { - NearestFilter: NearestFilter, - NearestMipMapNearestFilter: NearestMipMapNearestFilter, - NearestMipMapLinearFilter: NearestMipMapLinearFilter, - LinearFilter: LinearFilter, - LinearMipMapNearestFilter: LinearMipMapNearestFilter, - LinearMipMapLinearFilter: LinearMipMapLinearFilter -}; - -/** - * @author thespite / http://clicktorelease.com/ - */ - -function ImageBitmapLoader( manager ) { - - if ( typeof createImageBitmap === 'undefined' ) { - - console.warn( 'THREE.ImageBitmapLoader: createImageBitmap() not supported.' ); - - } - - if ( typeof fetch === 'undefined' ) { - - console.warn( 'THREE.ImageBitmapLoader: fetch() not supported.' ); - - } +function BufferGeometryLoader( manager ) { - this.manager = manager !== undefined ? manager : DefaultLoadingManager; - this.options = undefined; + this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager; } -ImageBitmapLoader.prototype = { +Object.assign( BufferGeometryLoader.prototype, { - constructor: ImageBitmapLoader, + load: function ( url, onLoad, onProgress, onError ) { - setOptions: function setOptions( options ) { + var scope = this; - this.options = options; + var loader = new FileLoader( scope.manager ); + loader.setPath( scope.path ); + loader.load( url, function ( text ) { - return this; + onLoad( scope.parse( JSON.parse( text ) ) ); + + }, onProgress, onError ); }, - load: function load( url, onLoad, onProgress, onError ) { + parse: function ( json ) { - if ( url === undefined ) url = ''; + var geometry = new BufferGeometry(); - if ( this.path !== undefined ) url = this.path + url; + var index = json.data.index; - var scope = this; + if ( index !== undefined ) { - var cached = Cache.get( url ); + var typedArray = new TYPED_ARRAYS[ index.type ]( index.array ); + geometry.setIndex( new BufferAttribute( typedArray, 1 ) ); - if ( cached !== undefined ) { + } - scope.manager.itemStart( url ); + var attributes = json.data.attributes; - setTimeout( function () { + for ( var key in attributes ) { - if ( onLoad ) onLoad( cached ); + var attribute = attributes[ key ]; + var typedArray = new TYPED_ARRAYS[ attribute.type ]( attribute.array ); - scope.manager.itemEnd( url ); + geometry.addAttribute( key, new BufferAttribute( typedArray, attribute.itemSize, attribute.normalized ) ); - }, 0 ); + } - return cached; + var groups = json.data.groups || json.data.drawcalls || json.data.offsets; - } + if ( groups !== undefined ) { - fetch( url ).then( function ( res ) { + for ( var i = 0, n = groups.length; i !== n; ++ i ) { - return res.blob(); + var group = groups[ i ]; - } ).then( function ( blob ) { + geometry.addGroup( group.start, group.count, group.materialIndex ); - return createImageBitmap( blob, scope.options ); + } - } ).then( function ( imageBitmap ) { + } - Cache.add( url, imageBitmap ); + var boundingSphere = json.data.boundingSphere; - if ( onLoad ) onLoad( imageBitmap ); + if ( boundingSphere !== undefined ) { - scope.manager.itemEnd( url ); + var center = new Vector3(); - } ).catch( function ( e ) { + if ( boundingSphere.center !== undefined ) { - if ( onError ) onError( e ); + center.fromArray( boundingSphere.center ); - scope.manager.itemEnd( url ); - scope.manager.itemError( url ); + } - } ); + geometry.boundingSphere = new Sphere( center, boundingSphere.radius ); - }, + } - setCrossOrigin: function ( /* value */ ) { + if ( json.name ) geometry.name = json.name; + if ( json.userData ) geometry.userData = json.userData; - return this; + return geometry; }, @@ -40357,22063 +39017,15977 @@ ImageBitmapLoader.prototype = { } +} ); + +var TYPED_ARRAYS = { + Int8Array: Int8Array, + Uint8Array: Uint8Array, + // Workaround for IE11 pre KB2929437. See #11440 + Uint8ClampedArray: typeof Uint8ClampedArray !== 'undefined' ? Uint8ClampedArray : Uint8Array, + Int16Array: Int16Array, + Uint16Array: Uint16Array, + Int32Array: Int32Array, + Uint32Array: Uint32Array, + Float32Array: Float32Array, + Float64Array: Float64Array }; /** - * @author zz85 / http://www.lab4games.net/zz85/blog - * minimal class for proxing functions to Path. Replaces old "extractSubpaths()" - **/ - -function ShapePath() { + * @author mrdoob / http://mrdoob.com/ + */ - this.type = 'ShapePath'; +function ObjectLoader( manager ) { - this.subPaths = []; - this.currentPath = null; + this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager; + this.resourcePath = ''; } -Object.assign( ShapePath.prototype, { - - moveTo: function ( x, y ) { +Object.assign( ObjectLoader.prototype, { - this.currentPath = new Path(); - this.subPaths.push( this.currentPath ); - this.currentPath.moveTo( x, y ); + crossOrigin: 'anonymous', - }, + load: function ( url, onLoad, onProgress, onError ) { - lineTo: function ( x, y ) { + var scope = this; - this.currentPath.lineTo( x, y ); + var path = ( this.path === undefined ) ? LoaderUtils.extractUrlBase( url ) : this.path; + this.resourcePath = this.resourcePath || path; - }, + var loader = new FileLoader( scope.manager ); + loader.setPath( this.path ); + loader.load( url, function ( text ) { - quadraticCurveTo: function ( aCPx, aCPy, aX, aY ) { + var json = null; - this.currentPath.quadraticCurveTo( aCPx, aCPy, aX, aY ); + try { - }, + json = JSON.parse( text ); - bezierCurveTo: function ( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY ) { + } catch ( error ) { - this.currentPath.bezierCurveTo( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY ); + if ( onError !== undefined ) onError( error ); - }, + console.error( 'THREE:ObjectLoader: Can\'t parse ' + url + '.', error.message ); - splineThru: function ( pts ) { + return; - this.currentPath.splineThru( pts ); + } - }, + var metadata = json.metadata; - toShapes: function ( isCCW, noHoles ) { + if ( metadata === undefined || metadata.type === undefined || metadata.type.toLowerCase() === 'geometry' ) { - function toShapesNoHoles( inSubpaths ) { + console.error( 'THREE.ObjectLoader: Can\'t load ' + url ); + return; - var shapes = []; + } - for ( var i = 0, l = inSubpaths.length; i < l; i ++ ) { + scope.parse( json, onLoad ); - var tmpPath = inSubpaths[ i ]; + }, onProgress, onError ); - var tmpShape = new Shape(); - tmpShape.curves = tmpPath.curves; + }, - shapes.push( tmpShape ); + setPath: function ( value ) { - } + this.path = value; + return this; - return shapes; + }, - } + setResourcePath: function ( value ) { - function isPointInsidePolygon( inPt, inPolygon ) { + this.resourcePath = value; + return this; - 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 ++ ) { + setCrossOrigin: function ( value ) { - var edgeLowPt = inPolygon[ p ]; - var edgeHighPt = inPolygon[ q ]; + this.crossOrigin = value; + return this; - var edgeDx = edgeHighPt.x - edgeLowPt.x; - var edgeDy = edgeHighPt.y - edgeLowPt.y; + }, - if ( Math.abs( edgeDy ) > Number.EPSILON ) { + parse: function ( json, onLoad ) { - // not parallel - if ( edgeDy < 0 ) { + var shapes = this.parseShape( json.shapes ); + var geometries = this.parseGeometries( json.geometries, shapes ); - edgeLowPt = inPolygon[ q ]; edgeDx = - edgeDx; - edgeHighPt = inPolygon[ p ]; edgeDy = - edgeDy; + var images = this.parseImages( json.images, function () { - } - if ( ( inPt.y < edgeLowPt.y ) || ( inPt.y > edgeHighPt.y ) ) continue; + if ( onLoad !== undefined ) onLoad( object ); - if ( inPt.y === edgeLowPt.y ) { + } ); - if ( inPt.x === edgeLowPt.x ) return true; // inPt is on contour ? - // continue; // no intersection or edgeLowPt => doesn't count !!! + var textures = this.parseTextures( json.textures, images ); + var materials = this.parseMaterials( json.materials, textures ); - } else { + var object = this.parseObject( json.object, geometries, materials ); - 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 + if ( json.animations ) { - } + object.animations = this.parseAnimations( json.animations ); - } else { + } - // parallel or collinear - if ( inPt.y !== edgeLowPt.y ) continue; // parallel - // edge lies on the same horizontal line as inPt - if ( ( ( edgeHighPt.x <= inPt.x ) && ( inPt.x <= edgeLowPt.x ) ) || - ( ( edgeLowPt.x <= inPt.x ) && ( inPt.x <= edgeHighPt.x ) ) ) return true; // inPt: Point on contour ! - // continue; + if ( json.images === undefined || json.images.length === 0 ) { - } + if ( onLoad !== undefined ) onLoad( object ); - } + } - return inside; + return object; - } + }, - var isClockWise = ShapeUtils.isClockWise; + parseShape: function ( json ) { - var subPaths = this.subPaths; - if ( subPaths.length === 0 ) return []; + var shapes = {}; - if ( noHoles === true ) return toShapesNoHoles( subPaths ); + if ( json !== undefined ) { + for ( var i = 0, l = json.length; i < l; i ++ ) { - var solid, tmpPath, tmpShape, shapes = []; + var shape = new Shape().fromJSON( json[ i ] ); - if ( subPaths.length === 1 ) { + shapes[ shape.uuid ] = shape; - 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; + return shapes; - // console.log("Holes first", holesFirst); + }, - var betterShapeHoles = []; - var newShapes = []; - var newShapeHoles = []; - var mainIdx = 0; - var tmpPoints; + parseGeometries: function ( json, shapes ) { - newShapes[ mainIdx ] = undefined; - newShapeHoles[ mainIdx ] = []; + var geometries = {}; - for ( var i = 0, l = subPaths.length; i < l; i ++ ) { + if ( json !== undefined ) { - tmpPath = subPaths[ i ]; - tmpPoints = tmpPath.getPoints(); - solid = isClockWise( tmpPoints ); - solid = isCCW ? ! solid : solid; + var bufferGeometryLoader = new BufferGeometryLoader(); - if ( solid ) { + for ( var i = 0, l = json.length; i < l; i ++ ) { - if ( ( ! holesFirst ) && ( newShapes[ mainIdx ] ) ) mainIdx ++; + var geometry; + var data = json[ i ]; - newShapes[ mainIdx ] = { s: new Shape(), p: tmpPoints }; - newShapes[ mainIdx ].s.curves = tmpPath.curves; + switch ( data.type ) { - if ( holesFirst ) mainIdx ++; - newShapeHoles[ mainIdx ] = []; + case 'PlaneGeometry': + case 'PlaneBufferGeometry': - //console.log('cw', i); + geometry = new Geometries[ data.type ]( + data.width, + data.height, + data.widthSegments, + data.heightSegments + ); - } else { + break; - newShapeHoles[ mainIdx ].push( { h: tmpPath, p: tmpPoints[ 0 ] } ); + case 'BoxGeometry': + case 'BoxBufferGeometry': + case 'CubeGeometry': // backwards compatible - //console.log('ccw', i); + geometry = new Geometries[ data.type ]( + data.width, + data.height, + data.depth, + data.widthSegments, + data.heightSegments, + data.depthSegments + ); - } + break; - } + case 'CircleGeometry': + case 'CircleBufferGeometry': - // only Holes? -> probably all Shapes with wrong orientation - if ( ! newShapes[ 0 ] ) return toShapesNoHoles( subPaths ); + geometry = new Geometries[ data.type ]( + data.radius, + data.segments, + data.thetaStart, + data.thetaLength + ); + break; - if ( newShapes.length > 1 ) { + case 'CylinderGeometry': + case 'CylinderBufferGeometry': - var ambiguous = false; - var toChange = []; + geometry = new Geometries[ data.type ]( + data.radiusTop, + data.radiusBottom, + data.height, + data.radialSegments, + data.heightSegments, + data.openEnded, + data.thetaStart, + data.thetaLength + ); - for ( var sIdx = 0, sLen = newShapes.length; sIdx < sLen; sIdx ++ ) { + break; - betterShapeHoles[ sIdx ] = []; + case 'ConeGeometry': + case 'ConeBufferGeometry': - } + geometry = new Geometries[ data.type ]( + data.radius, + data.height, + data.radialSegments, + data.heightSegments, + data.openEnded, + data.thetaStart, + data.thetaLength + ); - for ( var sIdx = 0, sLen = newShapes.length; sIdx < sLen; sIdx ++ ) { + break; - var sho = newShapeHoles[ sIdx ]; + case 'SphereGeometry': + case 'SphereBufferGeometry': - for ( var hIdx = 0; hIdx < sho.length; hIdx ++ ) { + geometry = new Geometries[ data.type ]( + data.radius, + data.widthSegments, + data.heightSegments, + data.phiStart, + data.phiLength, + data.thetaStart, + data.thetaLength + ); - var ho = sho[ hIdx ]; - var hole_unassigned = true; + break; - for ( var s2Idx = 0; s2Idx < newShapes.length; s2Idx ++ ) { + case 'DodecahedronGeometry': + case 'DodecahedronBufferGeometry': + case 'IcosahedronGeometry': + case 'IcosahedronBufferGeometry': + case 'OctahedronGeometry': + case 'OctahedronBufferGeometry': + case 'TetrahedronGeometry': + case 'TetrahedronBufferGeometry': - if ( isPointInsidePolygon( ho.p, newShapes[ s2Idx ].p ) ) { + geometry = new Geometries[ data.type ]( + data.radius, + data.detail + ); - if ( sIdx !== s2Idx ) toChange.push( { froms: sIdx, tos: s2Idx, hole: hIdx } ); - if ( hole_unassigned ) { + break; - hole_unassigned = false; - betterShapeHoles[ s2Idx ].push( ho ); + case 'RingGeometry': + case 'RingBufferGeometry': - } else { + geometry = new Geometries[ data.type ]( + data.innerRadius, + data.outerRadius, + data.thetaSegments, + data.phiSegments, + data.thetaStart, + data.thetaLength + ); - ambiguous = true; + break; - } + case 'TorusGeometry': + case 'TorusBufferGeometry': - } + geometry = new Geometries[ data.type ]( + data.radius, + data.tube, + data.radialSegments, + data.tubularSegments, + data.arc + ); - } - if ( hole_unassigned ) { + break; - betterShapeHoles[ sIdx ].push( ho ); + case 'TorusKnotGeometry': + case 'TorusKnotBufferGeometry': - } + geometry = new Geometries[ data.type ]( + data.radius, + data.tube, + data.tubularSegments, + data.radialSegments, + data.p, + data.q + ); - } + break; - } - // console.log("ambiguous: ", ambiguous); - if ( toChange.length > 0 ) { + case 'LatheGeometry': + case 'LatheBufferGeometry': - // console.log("to change: ", toChange); - if ( ! ambiguous ) newShapeHoles = betterShapeHoles; + geometry = new Geometries[ data.type ]( + data.points, + data.segments, + data.phiStart, + data.phiLength + ); - } + break; - } + case 'PolyhedronGeometry': + case 'PolyhedronBufferGeometry': - var tmpHoles; + geometry = new Geometries[ data.type ]( + data.vertices, + data.indices, + data.radius, + data.details + ); - for ( var i = 0, il = newShapes.length; i < il; i ++ ) { + break; - tmpShape = newShapes[ i ].s; - shapes.push( tmpShape ); - tmpHoles = newShapeHoles[ i ]; + case 'ShapeGeometry': + case 'ShapeBufferGeometry': - for ( var j = 0, jl = tmpHoles.length; j < jl; j ++ ) { + var geometryShapes = []; - tmpShape.holes.push( tmpHoles[ j ].h ); + for ( var j = 0, jl = data.shapes.length; j < jl; j ++ ) { - } + var shape = shapes[ data.shapes[ j ] ]; - } + geometryShapes.push( shape ); - //console.log("shape", shapes); + } - return shapes; + geometry = new Geometries[ data.type ]( + geometryShapes, + data.curveSegments + ); - } + break; -} ); -/** - * @author zz85 / http://www.lab4games.net/zz85/blog - * @author mrdoob / http://mrdoob.com/ - */ + case 'ExtrudeGeometry': + case 'ExtrudeBufferGeometry': -function Font( data ) { + var geometryShapes = []; - this.type = 'Font'; + for ( var j = 0, jl = data.shapes.length; j < jl; j ++ ) { - this.data = data; + var shape = shapes[ data.shapes[ j ] ]; -} + geometryShapes.push( shape ); -Object.assign( Font.prototype, { + } - isFont: true, + var extrudePath = data.options.extrudePath; - generateShapes: function ( text, size, divisions ) { + if ( extrudePath !== undefined ) { - if ( size === undefined ) size = 100; - if ( divisions === undefined ) divisions = 4; + data.options.extrudePath = new Curves[ extrudePath.type ]().fromJSON( extrudePath ); - var shapes = []; - var paths = createPaths( text, size, divisions, this.data ); + } - for ( var p = 0, pl = paths.length; p < pl; p ++ ) { + geometry = new Geometries[ data.type ]( + geometryShapes, + data.options + ); - Array.prototype.push.apply( shapes, paths[ p ].toShapes() ); + break; - } + case 'BufferGeometry': - return shapes; + geometry = bufferGeometryLoader.parse( data ); - } - -} ); - -function createPaths( text, size, divisions, data ) { + break; - var chars = String( text ).split( '' ); - var scale = size / data.resolution; - var line_height = ( data.boundingBox.yMax - data.boundingBox.yMin + data.underlineThickness ) * scale; + case 'Geometry': - var paths = []; + if ( 'THREE' in window && 'LegacyJSONLoader' in THREE ) { - var offsetX = 0, offsetY = 0; + var geometryLoader = new THREE.LegacyJSONLoader(); + geometry = geometryLoader.parse( data, this.resourcePath ).geometry; - for ( var i = 0; i < chars.length; i ++ ) { - var char = chars[ i ]; + } else { - if ( char === '\n' ) { + console.error( 'THREE.ObjectLoader: You have to import LegacyJSONLoader in order load geometry data of type "Geometry".' ); - offsetX = 0; - offsetY -= line_height; + } - } else { + break; - var ret = createPath( char, divisions, scale, offsetX, offsetY, data ); - offsetX += ret.offsetX; - paths.push( ret.path ); + default: - } + console.warn( 'THREE.ObjectLoader: Unsupported geometry type "' + data.type + '"' ); - } + continue; - return paths; + } -} + geometry.uuid = data.uuid; -function createPath( char, divisions, scale, offsetX, offsetY, data ) { + if ( data.name !== undefined ) geometry.name = data.name; + if ( geometry.isBufferGeometry === true && data.userData !== undefined ) geometry.userData = data.userData; - var glyph = data.glyphs[ char ] || data.glyphs[ '?' ]; + geometries[ data.uuid ] = geometry; - if ( ! glyph ) return; + } - var path = new ShapePath(); + } - var x, y, cpx, cpy, cpx1, cpy1, cpx2, cpy2; + return geometries; - if ( glyph.o ) { + }, - var outline = glyph._cachedOutline || ( glyph._cachedOutline = glyph.o.split( ' ' ) ); + parseMaterials: function ( json, textures ) { - for ( var i = 0, l = outline.length; i < l; ) { + var cache = {}; // MultiMaterial + var materials = {}; - var action = outline[ i ++ ]; + if ( json !== undefined ) { - switch ( action ) { + var loader = new MaterialLoader(); + loader.setTextures( textures ); - case 'm': // moveTo + for ( var i = 0, l = json.length; i < l; i ++ ) { - x = outline[ i ++ ] * scale + offsetX; - y = outline[ i ++ ] * scale + offsetY; + var data = json[ i ]; - path.moveTo( x, y ); + if ( data.type === 'MultiMaterial' ) { - break; + // Deprecated - case 'l': // lineTo + var array = []; - x = outline[ i ++ ] * scale + offsetX; - y = outline[ i ++ ] * scale + offsetY; + for ( var j = 0; j < data.materials.length; j ++ ) { - path.lineTo( x, y ); + var material = data.materials[ j ]; - break; + if ( cache[ material.uuid ] === undefined ) { - case 'q': // quadraticCurveTo + cache[ material.uuid ] = loader.parse( material ); - cpx = outline[ i ++ ] * scale + offsetX; - cpy = outline[ i ++ ] * scale + offsetY; - cpx1 = outline[ i ++ ] * scale + offsetX; - cpy1 = outline[ i ++ ] * scale + offsetY; + } - path.quadraticCurveTo( cpx1, cpy1, cpx, cpy ); + array.push( cache[ material.uuid ] ); - break; + } - case 'b': // bezierCurveTo + materials[ data.uuid ] = array; - 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; + } else { - path.bezierCurveTo( cpx1, cpy1, cpx2, cpy2, cpx, cpy ); + materials[ data.uuid ] = loader.parse( data ); + cache[ data.uuid ] = materials[ data.uuid ]; - break; + } } } - } + return materials; - return { offsetX: glyph.ha * scale, path: path }; + }, -} + parseAnimations: function ( json ) { -/** - * @author mrdoob / http://mrdoob.com/ - */ + var animations = []; -function FontLoader( manager ) { + for ( var i = 0; i < json.length; i ++ ) { - this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager; + var data = json[ i ]; -} + var clip = AnimationClip.parse( data ); -Object.assign( FontLoader.prototype, { + if ( data.uuid !== undefined ) clip.uuid = data.uuid; - load: function ( url, onLoad, onProgress, onError ) { + animations.push( clip ); - var scope = this; + } - var loader = new FileLoader( this.manager ); - loader.setPath( this.path ); - loader.load( url, function ( text ) { + return animations; - var json; + }, - try { + parseImages: function ( json, onLoad ) { - json = JSON.parse( text ); + var scope = this; + var images = {}; - } catch ( e ) { + function loadImage( url ) { - console.warn( 'THREE.FontLoader: typeface.js support is being deprecated. Use typeface.json instead.' ); - json = JSON.parse( text.substring( 65, text.length - 2 ) ); + scope.manager.itemStart( url ); - } + return loader.load( url, function () { - var font = scope.parse( json ); + scope.manager.itemEnd( url ); - if ( onLoad ) onLoad( font ); + }, undefined, function () { - }, onProgress, onError ); + scope.manager.itemError( url ); + scope.manager.itemEnd( url ); - }, + } ); - parse: function ( json ) { + } - return new Font( json ); + if ( json !== undefined && json.length > 0 ) { - }, + var manager = new LoadingManager( onLoad ); - setPath: function ( value ) { + var loader = new ImageLoader( manager ); + loader.setCrossOrigin( this.crossOrigin ); - this.path = value; - return this; + for ( var i = 0, il = json.length; i < il; i ++ ) { - } + var image = json[ i ]; + var url = image.url; -} ); + if ( Array.isArray( url ) ) { -/** - * @author mrdoob / http://mrdoob.com/ - */ + // load array of images e.g CubeTexture -var context; + images[ image.uuid ] = []; -var AudioContext = { + for ( var j = 0, jl = url.length; j < jl; j ++ ) { - getContext: function () { + var currentUrl = url[ j ]; - if ( context === undefined ) { + var path = /^(\/\/)|([a-z]+:(\/\/)?)/i.test( currentUrl ) ? currentUrl : scope.resourcePath + currentUrl; - context = new ( window.AudioContext || window.webkitAudioContext )(); + images[ image.uuid ].push( loadImage( path ) ); - } + } - return context; + } else { - }, + // load single image - setContext: function ( value ) { + var path = /^(\/\/)|([a-z]+:(\/\/)?)/i.test( image.url ) ? image.url : scope.resourcePath + image.url; - context = value; + images[ image.uuid ] = loadImage( path ); - } + } -}; + } -/** - * @author Reece Aaron Lecrivain / http://reecenotes.com/ - */ + } -function AudioLoader( manager ) { + return images; - this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager; + }, -} + parseTextures: function ( json, images ) { -Object.assign( AudioLoader.prototype, { + function parseConstant( value, type ) { - load: function ( url, onLoad, onProgress, onError ) { + if ( typeof value === 'number' ) return value; - var loader = new FileLoader( this.manager ); - loader.setResponseType( 'arraybuffer' ); - loader.load( url, function ( buffer ) { + console.warn( 'THREE.ObjectLoader.parseTexture: Constant should be in numeric form.', value ); - var context = AudioContext.getContext(); + return type[ value ]; - context.decodeAudioData( buffer, function ( audioBuffer ) { + } - onLoad( audioBuffer ); + var textures = {}; - } ); + if ( json !== undefined ) { - }, onProgress, onError ); + for ( var i = 0, l = json.length; i < l; i ++ ) { - } + var data = json[ i ]; -} ); + if ( data.image === undefined ) { -/** - * @author mrdoob / http://mrdoob.com/ - */ + console.warn( 'THREE.ObjectLoader: No "image" specified for', data.uuid ); -function StereoCamera() { + } - this.type = 'StereoCamera'; + if ( images[ data.image ] === undefined ) { - this.aspect = 1; + console.warn( 'THREE.ObjectLoader: Undefined image', data.image ); - this.eyeSep = 0.064; + } - this.cameraL = new PerspectiveCamera(); - this.cameraL.layers.enable( 1 ); - this.cameraL.matrixAutoUpdate = false; + var texture; - this.cameraR = new PerspectiveCamera(); - this.cameraR.layers.enable( 2 ); - this.cameraR.matrixAutoUpdate = false; + if ( Array.isArray( images[ data.image ] ) ) { -} + texture = new CubeTexture( images[ data.image ] ); -Object.assign( StereoCamera.prototype, { + } else { - update: ( function () { + texture = new Texture( images[ data.image ] ); - var instance, focus, fov, aspect, near, far, zoom, eyeSep; + } - var eyeRight = new Matrix4(); - var eyeLeft = new Matrix4(); + texture.needsUpdate = true; - return function update( camera ) { + texture.uuid = data.uuid; - 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; + if ( data.name !== undefined ) texture.name = data.name; - if ( needsUpdate ) { + if ( data.mapping !== undefined ) texture.mapping = parseConstant( data.mapping, TEXTURE_MAPPING ); - instance = this; - focus = camera.focus; - fov = camera.fov; - aspect = camera.aspect * this.aspect; - near = camera.near; - far = camera.far; - zoom = camera.zoom; + 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; - // Off-axis stereoscopic effect based on - // http://paulbourke.net/stereographics/stereorender/ + if ( data.wrap !== undefined ) { - 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; + texture.wrapS = parseConstant( data.wrap[ 0 ], TEXTURE_WRAPPING ); + texture.wrapT = parseConstant( data.wrap[ 1 ], TEXTURE_WRAPPING ); - // translate xOffset + } - eyeLeft.elements[ 12 ] = - eyeSep; - eyeRight.elements[ 12 ] = eyeSep; + if ( data.format !== undefined ) texture.format = data.format; + if ( data.type !== undefined ) texture.type = data.type; + if ( data.encoding !== undefined ) texture.encoding = data.encoding; - // for left eye + 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; - xmin = - ymax * aspect + eyeSepOnProjection; - xmax = ymax * aspect + eyeSepOnProjection; + if ( data.flipY !== undefined ) texture.flipY = data.flipY; - projectionMatrix.elements[ 0 ] = 2 * near / ( xmax - xmin ); - projectionMatrix.elements[ 8 ] = ( xmax + xmin ) / ( xmax - xmin ); + if ( data.premultiplyAlpha !== undefined ) texture.premultiplyAlpha = data.premultiplyAlpha; + if ( data.unpackAlignment !== undefined ) texture.unpackAlignment = data.unpackAlignment; - this.cameraL.projectionMatrix.copy( projectionMatrix ); + textures[ data.uuid ] = texture; - // for right eye + } - xmin = - ymax * aspect - eyeSepOnProjection; - xmax = ymax * aspect - eyeSepOnProjection; + } - projectionMatrix.elements[ 0 ] = 2 * near / ( xmax - xmin ); - projectionMatrix.elements[ 8 ] = ( xmax + xmin ) / ( xmax - xmin ); + return textures; - this.cameraR.projectionMatrix.copy( projectionMatrix ); + }, - } + parseObject: function ( data, geometries, materials ) { - this.cameraL.matrixWorld.copy( camera.matrixWorld ).multiply( eyeLeft ); - this.cameraR.matrixWorld.copy( camera.matrixWorld ).multiply( eyeRight ); + var object; - }; + function getGeometry( name ) { - } )() + if ( geometries[ name ] === undefined ) { -} ); + console.warn( 'THREE.ObjectLoader: Undefined geometry', name ); -/** - * Camera for rendering cube maps - * - renders scene into axis-aligned cube - * - * @author alteredq / http://alteredqualia.com/ - */ + } -function CubeCamera( near, far, cubeResolution ) { + return geometries[ name ]; - Object3D.call( this ); + } - this.type = 'CubeCamera'; + function getMaterial( name ) { - var fov = 90, aspect = 1; + if ( name === undefined ) return undefined; - 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 ( Array.isArray( name ) ) { - var cameraNX = new PerspectiveCamera( fov, aspect, near, far ); - cameraNX.up.set( 0, - 1, 0 ); - cameraNX.lookAt( new Vector3( - 1, 0, 0 ) ); - this.add( cameraNX ); + var array = []; - var cameraPY = new PerspectiveCamera( fov, aspect, near, far ); - cameraPY.up.set( 0, 0, 1 ); - cameraPY.lookAt( new Vector3( 0, 1, 0 ) ); - this.add( cameraPY ); + for ( var i = 0, l = name.length; i < l; i ++ ) { - var cameraNY = new PerspectiveCamera( fov, aspect, near, far ); - cameraNY.up.set( 0, 0, - 1 ); - cameraNY.lookAt( new Vector3( 0, - 1, 0 ) ); - this.add( cameraNY ); + var uuid = name[ i ]; - var cameraPZ = new PerspectiveCamera( fov, aspect, near, far ); - cameraPZ.up.set( 0, - 1, 0 ); - cameraPZ.lookAt( new Vector3( 0, 0, 1 ) ); - this.add( cameraPZ ); + if ( materials[ uuid ] === undefined ) { - var cameraNZ = new PerspectiveCamera( fov, aspect, near, far ); - cameraNZ.up.set( 0, - 1, 0 ); - cameraNZ.lookAt( new Vector3( 0, 0, - 1 ) ); - this.add( cameraNZ ); + console.warn( 'THREE.ObjectLoader: Undefined material', uuid ); - var options = { format: RGBFormat, magFilter: LinearFilter, minFilter: LinearFilter }; + } - this.renderTarget = new WebGLRenderTargetCube( cubeResolution, cubeResolution, options ); - this.renderTarget.texture.name = "CubeCamera"; + array.push( materials[ uuid ] ); - this.update = function ( renderer, scene ) { + } - if ( this.parent === null ) this.updateMatrixWorld(); + return array; - var renderTarget = this.renderTarget; - var generateMipmaps = renderTarget.texture.generateMipmaps; + } - renderTarget.texture.generateMipmaps = false; + if ( materials[ name ] === undefined ) { - renderTarget.activeCubeFace = 0; - renderer.render( scene, cameraPX, renderTarget ); + console.warn( 'THREE.ObjectLoader: Undefined material', name ); - renderTarget.activeCubeFace = 1; - renderer.render( scene, cameraNX, renderTarget ); + } - renderTarget.activeCubeFace = 2; - renderer.render( scene, cameraPY, renderTarget ); + return materials[ name ]; - renderTarget.activeCubeFace = 3; - renderer.render( scene, cameraNY, renderTarget ); + } - renderTarget.activeCubeFace = 4; - renderer.render( scene, cameraPZ, renderTarget ); + switch ( data.type ) { - renderTarget.texture.generateMipmaps = generateMipmaps; + case 'Scene': - renderTarget.activeCubeFace = 5; - renderer.render( scene, cameraNZ, renderTarget ); + object = new Scene(); - renderer.setRenderTarget( null ); + if ( data.background !== undefined ) { - }; + if ( Number.isInteger( data.background ) ) { - this.clear = function ( renderer, color, depth, stencil ) { + object.background = new Color( data.background ); - var renderTarget = this.renderTarget; + } - for ( var i = 0; i < 6; i ++ ) { + } - renderTarget.activeCubeFace = i; - renderer.setRenderTarget( renderTarget ); + if ( data.fog !== undefined ) { - renderer.clear( color, depth, stencil ); + if ( data.fog.type === 'Fog' ) { - } + object.fog = new Fog( data.fog.color, data.fog.near, data.fog.far ); - renderer.setRenderTarget( null ); + } else if ( data.fog.type === 'FogExp2' ) { - }; + object.fog = new FogExp2( data.fog.color, data.fog.density ); -} + } -CubeCamera.prototype = Object.create( Object3D.prototype ); -CubeCamera.prototype.constructor = CubeCamera; + } -/** - * @author mrdoob / http://mrdoob.com/ - */ + break; -function AudioListener() { + case 'PerspectiveCamera': - Object3D.call( this ); + object = new PerspectiveCamera( data.fov, data.aspect, data.near, data.far ); - this.type = 'AudioListener'; + 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 ); - this.context = AudioContext.getContext(); + break; - this.gain = this.context.createGain(); - this.gain.connect( this.context.destination ); + case 'OrthographicCamera': - this.filter = null; + object = new OrthographicCamera( data.left, data.right, data.top, data.bottom, data.near, data.far ); -} + if ( data.zoom !== undefined ) object.zoom = data.zoom; + if ( data.view !== undefined ) object.view = Object.assign( {}, data.view ); -AudioListener.prototype = Object.assign( Object.create( Object3D.prototype ), { + break; - constructor: AudioListener, + case 'AmbientLight': - getInput: function () { + object = new AmbientLight( data.color, data.intensity ); - return this.gain; + break; - }, + case 'DirectionalLight': - removeFilter: function ( ) { + object = new DirectionalLight( data.color, data.intensity ); - if ( this.filter !== null ) { + break; - this.gain.disconnect( this.filter ); - this.filter.disconnect( this.context.destination ); - this.gain.connect( this.context.destination ); - this.filter = null; + case 'PointLight': - } + object = new PointLight( data.color, data.intensity, data.distance, data.decay ); - }, + break; - getFilter: function () { + case 'RectAreaLight': - return this.filter; + object = new RectAreaLight( data.color, data.intensity, data.width, data.height ); - }, + break; - setFilter: function ( value ) { + case 'SpotLight': - if ( this.filter !== null ) { + object = new SpotLight( data.color, data.intensity, data.distance, data.angle, data.penumbra, data.decay ); - this.gain.disconnect( this.filter ); - this.filter.disconnect( this.context.destination ); + break; - } else { + case 'HemisphereLight': - this.gain.disconnect( this.context.destination ); + object = new HemisphereLight( data.color, data.groundColor, data.intensity ); - } + break; - this.filter = value; - this.gain.connect( this.filter ); - this.filter.connect( this.context.destination ); + case 'SkinnedMesh': - }, + console.warn( 'THREE.ObjectLoader.parseObject() does not support SkinnedMesh yet.' ); - getMasterVolume: function () { + case 'Mesh': - return this.gain.gain.value; + var geometry = getGeometry( data.geometry ); + var material = getMaterial( data.material ); - }, + if ( geometry.bones && geometry.bones.length > 0 ) { - setMasterVolume: function ( value ) { + object = new SkinnedMesh( geometry, material ); - this.gain.gain.value = value; + } else { - }, + object = new Mesh( geometry, material ); - updateMatrixWorld: ( function () { + } - var position = new Vector3(); - var quaternion = new Quaternion(); - var scale = new Vector3(); + break; - var orientation = new Vector3(); + case 'LOD': - return function updateMatrixWorld( force ) { + object = new LOD(); - Object3D.prototype.updateMatrixWorld.call( this, force ); + break; - var listener = this.context.listener; - var up = this.up; + case 'Line': - this.matrixWorld.decompose( position, quaternion, scale ); + object = new Line( getGeometry( data.geometry ), getMaterial( data.material ), data.mode ); - orientation.set( 0, 0, - 1 ).applyQuaternion( quaternion ); + break; - if ( listener.positionX ) { + case 'LineLoop': - listener.positionX.setValueAtTime( position.x, this.context.currentTime ); - listener.positionY.setValueAtTime( position.y, this.context.currentTime ); - listener.positionZ.setValueAtTime( position.z, this.context.currentTime ); - listener.forwardX.setValueAtTime( orientation.x, this.context.currentTime ); - listener.forwardY.setValueAtTime( orientation.y, this.context.currentTime ); - listener.forwardZ.setValueAtTime( orientation.z, this.context.currentTime ); - listener.upX.setValueAtTime( up.x, this.context.currentTime ); - listener.upY.setValueAtTime( up.y, this.context.currentTime ); - listener.upZ.setValueAtTime( up.z, this.context.currentTime ); + object = new LineLoop( getGeometry( data.geometry ), getMaterial( data.material ) ); - } else { + break; - listener.setPosition( position.x, position.y, position.z ); - listener.setOrientation( orientation.x, orientation.y, orientation.z, up.x, up.y, up.z ); + case 'LineSegments': - } + object = new LineSegments( getGeometry( data.geometry ), getMaterial( data.material ) ); - }; + break; - } )() + case 'PointCloud': + case 'Points': -} ); - -/** - * @author mrdoob / http://mrdoob.com/ - * @author Reece Aaron Lecrivain / http://reecenotes.com/ - */ - -function Audio( listener ) { + object = new Points( getGeometry( data.geometry ), getMaterial( data.material ) ); - Object3D.call( this ); + break; - this.type = 'Audio'; + case 'Sprite': - this.context = listener.context; + object = new Sprite( getMaterial( data.material ) ); - this.gain = this.context.createGain(); - this.gain.connect( listener.getInput() ); + break; - this.autoplay = false; + case 'Group': - this.buffer = null; - this.loop = false; - this.startTime = 0; - this.offset = 0; - this.playbackRate = 1; - this.isPlaying = false; - this.hasPlaybackControl = true; - this.sourceType = 'empty'; + object = new Group(); - this.filters = []; + break; -} + default: -Audio.prototype = Object.assign( Object.create( Object3D.prototype ), { + object = new Object3D(); - constructor: Audio, + } - getOutput: function () { + object.uuid = data.uuid; - return this.gain; + if ( data.name !== undefined ) object.name = data.name; - }, + if ( data.matrix !== undefined ) { - setNodeSource: function ( audioNode ) { + object.matrix.fromArray( data.matrix ); - this.hasPlaybackControl = false; - this.sourceType = 'audioNode'; - this.source = audioNode; - this.connect(); + if ( data.matrixAutoUpdate !== undefined ) object.matrixAutoUpdate = data.matrixAutoUpdate; + if ( object.matrixAutoUpdate ) object.matrix.decompose( object.position, object.quaternion, object.scale ); - return this; + } else { - }, + if ( data.position !== undefined ) object.position.fromArray( data.position ); + if ( data.rotation !== undefined ) object.rotation.fromArray( data.rotation ); + if ( data.quaternion !== undefined ) object.quaternion.fromArray( data.quaternion ); + if ( data.scale !== undefined ) object.scale.fromArray( data.scale ); - setBuffer: function ( audioBuffer ) { + } - this.buffer = audioBuffer; - this.sourceType = 'buffer'; + if ( data.castShadow !== undefined ) object.castShadow = data.castShadow; + if ( data.receiveShadow !== undefined ) object.receiveShadow = data.receiveShadow; - if ( this.autoplay ) this.play(); + if ( data.shadow ) { - return this; + 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 ); - }, + } - play: function () { + if ( data.visible !== undefined ) object.visible = data.visible; + if ( data.frustumCulled !== undefined ) object.frustumCulled = data.frustumCulled; + if ( data.renderOrder !== undefined ) object.renderOrder = data.renderOrder; + if ( data.userData !== undefined ) object.userData = data.userData; + if ( data.layers !== undefined ) object.layers.mask = data.layers; - if ( this.isPlaying === true ) { + if ( data.children !== undefined ) { - console.warn( 'THREE.Audio: Audio is already playing.' ); - return; + var children = data.children; - } + for ( var i = 0; i < children.length; i ++ ) { - if ( this.hasPlaybackControl === false ) { + object.add( this.parseObject( children[ i ], geometries, materials ) ); - console.warn( 'THREE.Audio: this Audio has no playback control.' ); - return; + } } - var source = this.context.createBufferSource(); - - 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 ); + if ( data.type === 'LOD' ) { - this.isPlaying = true; + var levels = data.levels; - this.source = source; + for ( var l = 0; l < levels.length; l ++ ) { - return this.connect(); + var level = levels[ l ]; + var child = object.getObjectByProperty( 'uuid', level.object ); - }, + if ( child !== undefined ) { - pause: function () { + object.addLevel( child, level.distance ); - if ( this.hasPlaybackControl === false ) { + } - console.warn( 'THREE.Audio: this Audio has no playback control.' ); - return; + } } - if ( this.isPlaying === true ) { - - this.source.stop(); - this.offset += ( this.context.currentTime - this.startTime ) * this.playbackRate; - this.isPlaying = false; + return object; - } + } - return this; +} ); - }, +var TEXTURE_MAPPING = { + UVMapping: UVMapping, + CubeReflectionMapping: CubeReflectionMapping, + CubeRefractionMapping: CubeRefractionMapping, + EquirectangularReflectionMapping: EquirectangularReflectionMapping, + EquirectangularRefractionMapping: EquirectangularRefractionMapping, + SphericalReflectionMapping: SphericalReflectionMapping, + CubeUVReflectionMapping: CubeUVReflectionMapping, + CubeUVRefractionMapping: CubeUVRefractionMapping +}; - stop: function () { +var TEXTURE_WRAPPING = { + RepeatWrapping: RepeatWrapping, + ClampToEdgeWrapping: ClampToEdgeWrapping, + MirroredRepeatWrapping: MirroredRepeatWrapping +}; - if ( this.hasPlaybackControl === false ) { +var TEXTURE_FILTER = { + NearestFilter: NearestFilter, + NearestMipMapNearestFilter: NearestMipMapNearestFilter, + NearestMipMapLinearFilter: NearestMipMapLinearFilter, + LinearFilter: LinearFilter, + LinearMipMapNearestFilter: LinearMipMapNearestFilter, + LinearMipMapLinearFilter: LinearMipMapLinearFilter +}; - console.warn( 'THREE.Audio: this Audio has no playback control.' ); - return; +/** + * @author thespite / http://clicktorelease.com/ + */ - } - this.source.stop(); - this.offset = 0; - this.isPlaying = false; +function ImageBitmapLoader( manager ) { - return this; + if ( typeof createImageBitmap === 'undefined' ) { - }, + console.warn( 'THREE.ImageBitmapLoader: createImageBitmap() not supported.' ); - connect: function () { + } - if ( this.filters.length > 0 ) { + if ( typeof fetch === 'undefined' ) { - this.source.connect( this.filters[ 0 ] ); + console.warn( 'THREE.ImageBitmapLoader: fetch() not supported.' ); - for ( var i = 1, l = this.filters.length; i < l; i ++ ) { + } - this.filters[ i - 1 ].connect( this.filters[ i ] ); + this.manager = manager !== undefined ? manager : DefaultLoadingManager; + this.options = undefined; - } +} - this.filters[ this.filters.length - 1 ].connect( this.getOutput() ); +ImageBitmapLoader.prototype = { - } else { + constructor: ImageBitmapLoader, - this.source.connect( this.getOutput() ); + setOptions: function setOptions( options ) { - } + this.options = options; return this; }, - disconnect: function () { + load: function ( url, onLoad, onProgress, onError ) { - if ( this.filters.length > 0 ) { + if ( url === undefined ) url = ''; - this.source.disconnect( this.filters[ 0 ] ); + if ( this.path !== undefined ) url = this.path + url; - for ( var i = 1, l = this.filters.length; i < l; i ++ ) { + url = this.manager.resolveURL( url ); - this.filters[ i - 1 ].disconnect( this.filters[ i ] ); + var scope = this; - } + var cached = Cache.get( url ); - this.filters[ this.filters.length - 1 ].disconnect( this.getOutput() ); + if ( cached !== undefined ) { - } else { + scope.manager.itemStart( url ); - this.source.disconnect( this.getOutput() ); + setTimeout( function () { - } + if ( onLoad ) onLoad( cached ); - return this; + scope.manager.itemEnd( url ); - }, + }, 0 ); - getFilters: function () { + return cached; - return this.filters; + } - }, + fetch( url ).then( function ( res ) { - setFilters: function ( value ) { + return res.blob(); - if ( ! value ) value = []; + } ).then( function ( blob ) { - if ( this.isPlaying === true ) { + return createImageBitmap( blob, scope.options ); - this.disconnect(); - this.filters = value; - this.connect(); + } ).then( function ( imageBitmap ) { - } else { + Cache.add( url, imageBitmap ); - this.filters = value; + if ( onLoad ) onLoad( imageBitmap ); - } + scope.manager.itemEnd( url ); - return this; + } ).catch( function ( e ) { - }, + if ( onError ) onError( e ); - getFilter: function () { + scope.manager.itemError( url ); + scope.manager.itemEnd( url ); - return this.getFilters()[ 0 ]; + } ); }, - setFilter: function ( filter ) { + setCrossOrigin: function ( /* value */ ) { - return this.setFilters( filter ? [ filter ] : [] ); + return this; }, - setPlaybackRate: function ( value ) { + setPath: function ( value ) { - if ( this.hasPlaybackControl === false ) { + this.path = value; + return this; - console.warn( 'THREE.Audio: this Audio has no playback control.' ); - return; + } - } +}; - this.playbackRate = value; +/** + * @author zz85 / http://www.lab4games.net/zz85/blog + * minimal class for proxing functions to Path. Replaces old "extractSubpaths()" + **/ - if ( this.isPlaying === true ) { +function ShapePath() { - this.source.playbackRate.setValueAtTime( this.playbackRate, this.context.currentTime ); + this.type = 'ShapePath'; - } + this.color = new Color(); - return this; + this.subPaths = []; + this.currentPath = null; - }, +} - getPlaybackRate: function () { +Object.assign( ShapePath.prototype, { - return this.playbackRate; + moveTo: function ( x, y ) { + + this.currentPath = new Path(); + this.subPaths.push( this.currentPath ); + this.currentPath.moveTo( x, y ); }, - onEnded: function () { + lineTo: function ( x, y ) { - this.isPlaying = false; + this.currentPath.lineTo( x, y ); }, - getLoop: function () { + quadraticCurveTo: function ( aCPx, aCPy, aX, aY ) { - if ( this.hasPlaybackControl === false ) { + this.currentPath.quadraticCurveTo( aCPx, aCPy, aX, aY ); - console.warn( 'THREE.Audio: this Audio has no playback control.' ); - return false; + }, - } + bezierCurveTo: function ( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY ) { - return this.loop; + this.currentPath.bezierCurveTo( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY ); }, - setLoop: function ( value ) { + splineThru: function ( pts ) { - if ( this.hasPlaybackControl === false ) { + this.currentPath.splineThru( pts ); - console.warn( 'THREE.Audio: this Audio has no playback control.' ); - return; + }, - } + toShapes: function ( isCCW, noHoles ) { - this.loop = value; + function toShapesNoHoles( inSubpaths ) { - if ( this.isPlaying === true ) { + var shapes = []; - this.source.loop = this.loop; + for ( var i = 0, l = inSubpaths.length; i < l; i ++ ) { - } + var tmpPath = inSubpaths[ i ]; - return this; + var tmpShape = new Shape(); + tmpShape.curves = tmpPath.curves; - }, + shapes.push( tmpShape ); - getVolume: function () { + } - return this.gain.gain.value; + return shapes; - }, + } - setVolume: function ( value ) { + function isPointInsidePolygon( inPt, inPolygon ) { - this.gain.gain.value = value; + var polyLen = inPolygon.length; - return this; + // inPt on polygon contour => immediate success or + // toggling of inside/outside at every single! intersection point of an edge + // with the horizontal line through inPt, left of inPt + // not counting lowerY endpoints of edges and whole edges on that line + var inside = false; + for ( var p = polyLen - 1, q = 0; q < polyLen; p = q ++ ) { - } + var edgeLowPt = inPolygon[ p ]; + var edgeHighPt = inPolygon[ q ]; -} ); + var edgeDx = edgeHighPt.x - edgeLowPt.x; + var edgeDy = edgeHighPt.y - edgeLowPt.y; -/** - * @author mrdoob / http://mrdoob.com/ - */ + if ( Math.abs( edgeDy ) > Number.EPSILON ) { -function PositionalAudio( listener ) { + // not parallel + if ( edgeDy < 0 ) { - Audio.call( this, listener ); + edgeLowPt = inPolygon[ q ]; edgeDx = - edgeDx; + edgeHighPt = inPolygon[ p ]; edgeDy = - edgeDy; - this.panner = this.context.createPanner(); - this.panner.connect( this.gain ); + } + if ( ( inPt.y < edgeLowPt.y ) || ( inPt.y > edgeHighPt.y ) ) continue; -} + if ( inPt.y === edgeLowPt.y ) { -PositionalAudio.prototype = Object.assign( Object.create( Audio.prototype ), { + if ( inPt.x === edgeLowPt.x ) return true; // inPt is on contour ? + // continue; // no intersection or edgeLowPt => doesn't count !!! - constructor: PositionalAudio, + } else { - getOutput: function () { + 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 - return this.panner; + } - }, + } else { - getRefDistance: 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; - return this.panner.refDistance; + } - }, + } - setRefDistance: function ( value ) { + return inside; - this.panner.refDistance = value; + } - }, + var isClockWise = ShapeUtils.isClockWise; - getRolloffFactor: function () { + var subPaths = this.subPaths; + if ( subPaths.length === 0 ) return []; - return this.panner.rolloffFactor; + if ( noHoles === true ) return toShapesNoHoles( subPaths ); - }, - setRolloffFactor: function ( value ) { + var solid, tmpPath, tmpShape, shapes = []; - this.panner.rolloffFactor = value; + if ( subPaths.length === 1 ) { - }, + tmpPath = subPaths[ 0 ]; + tmpShape = new Shape(); + tmpShape.curves = tmpPath.curves; + shapes.push( tmpShape ); + return shapes; - getDistanceModel: function () { + } - return this.panner.distanceModel; + var holesFirst = ! isClockWise( subPaths[ 0 ].getPoints() ); + holesFirst = isCCW ? ! holesFirst : holesFirst; - }, + // console.log("Holes first", holesFirst); - setDistanceModel: function ( value ) { + var betterShapeHoles = []; + var newShapes = []; + var newShapeHoles = []; + var mainIdx = 0; + var tmpPoints; - this.panner.distanceModel = value; + newShapes[ mainIdx ] = undefined; + newShapeHoles[ mainIdx ] = []; - }, + for ( var i = 0, l = subPaths.length; i < l; i ++ ) { - getMaxDistance: function () { + tmpPath = subPaths[ i ]; + tmpPoints = tmpPath.getPoints(); + solid = isClockWise( tmpPoints ); + solid = isCCW ? ! solid : solid; - return this.panner.maxDistance; + if ( solid ) { - }, + if ( ( ! holesFirst ) && ( newShapes[ mainIdx ] ) ) mainIdx ++; - setMaxDistance: function ( value ) { + newShapes[ mainIdx ] = { s: new Shape(), p: tmpPoints }; + newShapes[ mainIdx ].s.curves = tmpPath.curves; - this.panner.maxDistance = value; + if ( holesFirst ) mainIdx ++; + newShapeHoles[ mainIdx ] = []; - }, + //console.log('cw', i); - updateMatrixWorld: ( function () { + } else { - var position = new Vector3(); + newShapeHoles[ mainIdx ].push( { h: tmpPath, p: tmpPoints[ 0 ] } ); - return function updateMatrixWorld( force ) { + //console.log('ccw', i); - Object3D.prototype.updateMatrixWorld.call( this, force ); + } - position.setFromMatrixPosition( this.matrixWorld ); + } - this.panner.setPosition( position.x, position.y, position.z ); + // only Holes? -> probably all Shapes with wrong orientation + if ( ! newShapes[ 0 ] ) return toShapesNoHoles( subPaths ); - }; - } )() + if ( newShapes.length > 1 ) { + var ambiguous = false; + var toChange = []; -} ); + for ( var sIdx = 0, sLen = newShapes.length; sIdx < sLen; sIdx ++ ) { -/** - * @author mrdoob / http://mrdoob.com/ - */ + betterShapeHoles[ sIdx ] = []; -function AudioAnalyser( audio, fftSize ) { + } - this.analyser = audio.context.createAnalyser(); - this.analyser.fftSize = fftSize !== undefined ? fftSize : 2048; + for ( var sIdx = 0, sLen = newShapes.length; sIdx < sLen; sIdx ++ ) { - this.data = new Uint8Array( this.analyser.frequencyBinCount ); + var sho = newShapeHoles[ sIdx ]; - audio.getOutput().connect( this.analyser ); + for ( var hIdx = 0; hIdx < sho.length; hIdx ++ ) { -} + var ho = sho[ hIdx ]; + var hole_unassigned = true; -Object.assign( AudioAnalyser.prototype, { + for ( var s2Idx = 0; s2Idx < newShapes.length; s2Idx ++ ) { - getFrequencyData: function () { + if ( isPointInsidePolygon( ho.p, newShapes[ s2Idx ].p ) ) { - this.analyser.getByteFrequencyData( this.data ); + if ( sIdx !== s2Idx ) toChange.push( { froms: sIdx, tos: s2Idx, hole: hIdx } ); + if ( hole_unassigned ) { - return this.data; + hole_unassigned = false; + betterShapeHoles[ s2Idx ].push( ho ); - }, + } else { - getAverageFrequency: function () { + ambiguous = true; - var value = 0, data = this.getFrequencyData(); + } - for ( var i = 0; i < data.length; i ++ ) { + } - value += data[ i ]; + } + if ( hole_unassigned ) { - } + betterShapeHoles[ sIdx ].push( ho ); - return value / data.length; + } - } + } -} ); + } + // console.log("ambiguous: ", ambiguous); + if ( toChange.length > 0 ) { -/** - * - * Buffered scene graph property that allows weighted accumulation. - * - * - * @author Ben Houston / http://clara.io/ - * @author David Sarno / http://lighthaus.us/ - * @author tschw - */ + // console.log("to change: ", toChange); + if ( ! ambiguous ) newShapeHoles = betterShapeHoles; -function PropertyMixer( binding, typeName, valueSize ) { + } - this.binding = binding; - this.valueSize = valueSize; + } - var bufferType = Float64Array, - mixFunction; - - switch ( typeName ) { + var tmpHoles; - case 'quaternion': - mixFunction = this._slerp; - break; + for ( var i = 0, il = newShapes.length; i < il; i ++ ) { - case 'string': - case 'bool': - bufferType = Array; - mixFunction = this._select; - break; + tmpShape = newShapes[ i ].s; + shapes.push( tmpShape ); + tmpHoles = newShapeHoles[ i ]; - default: - mixFunction = this._lerp; + for ( var j = 0, jl = tmpHoles.length; j < jl; j ++ ) { - } + tmpShape.holes.push( tmpHoles[ j ].h ); - 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 + } - this._mixBufferRegion = mixFunction; + } - this.cumulativeWeight = 0; + //console.log("shape", shapes); - this.useCount = 0; - this.referenceCount = 0; + return shapes; -} + } -Object.assign( PropertyMixer.prototype, { +} ); - // accumulate data in the 'incoming' region into 'accu' - accumulate: function ( accuIndex, weight ) { +/** + * @author zz85 / http://www.lab4games.net/zz85/blog + * @author mrdoob / http://mrdoob.com/ + */ - // note: happily accumulating nothing when weight = 0, the caller knows - // the weight and shouldn't have made the call in the first place - var buffer = this.buffer, - stride = this.valueSize, - offset = accuIndex * stride + stride, +function Font( data ) { - currentWeight = this.cumulativeWeight; + this.type = 'Font'; - if ( currentWeight === 0 ) { + this.data = data; - // accuN := incoming * weight +} - for ( var i = 0; i !== stride; ++ i ) { +Object.assign( Font.prototype, { - buffer[ offset + i ] = buffer[ i ]; + isFont: true, - } + generateShapes: function ( text, size ) { - currentWeight = weight; + if ( size === undefined ) size = 100; - } else { + var shapes = []; + var paths = createPaths( text, size, this.data ); - // accuN := accuN + incoming * weight + for ( var p = 0, pl = paths.length; p < pl; p ++ ) { - currentWeight += weight; - var mix = weight / currentWeight; - this._mixBufferRegion( buffer, offset, 0, mix, stride ); + Array.prototype.push.apply( shapes, paths[ p ].toShapes() ); } - this.cumulativeWeight = currentWeight; - - }, - - // apply the state of 'accu' to the binding when accus differ - apply: function ( accuIndex ) { - - var stride = this.valueSize, - buffer = this.buffer, - offset = accuIndex * stride + stride, - - weight = this.cumulativeWeight, + return shapes; - binding = this.binding; + } - this.cumulativeWeight = 0; +} ); - if ( weight < 1 ) { +function createPaths( text, size, data ) { - // accuN := accuN + original * ( 1 - cumulativeWeight ) + 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; - var originalValueOffset = stride * 3; + var paths = []; - this._mixBufferRegion( - buffer, offset, originalValueOffset, 1 - weight, stride ); + var offsetX = 0, offsetY = 0; - } + for ( var i = 0; i < chars.length; i ++ ) { - for ( var i = stride, e = stride + stride; i !== e; ++ i ) { + var char = chars[ i ]; - if ( buffer[ i ] !== buffer[ i + stride ] ) { + if ( char === '\n' ) { - // value has changed -> update scene graph + offsetX = 0; + offsetY -= line_height; - binding.setValue( buffer, offset ); - break; + } else { - } + var ret = createPath( char, scale, offsetX, offsetY, data ); + offsetX += ret.offsetX; + paths.push( ret.path ); } - }, - - // remember the state of the bound property and copy it to both accus - saveOriginalState: function () { + } - var binding = this.binding; + return paths; - var buffer = this.buffer, - stride = this.valueSize, +} - originalValueOffset = stride * 3; +function createPath( char, scale, offsetX, offsetY, data ) { - binding.getValue( buffer, originalValueOffset ); + var glyph = data.glyphs[ char ] || data.glyphs[ '?' ]; - // accu[0..1] := orig -- initially detect changes against the original - for ( var i = stride, e = originalValueOffset; i !== e; ++ i ) { + if ( ! glyph ) return; - buffer[ i ] = buffer[ originalValueOffset + ( i % stride ) ]; + var path = new ShapePath(); - } + var x, y, cpx, cpy, cpx1, cpy1, cpx2, cpy2; - this.cumulativeWeight = 0; + if ( glyph.o ) { - }, + var outline = glyph._cachedOutline || ( glyph._cachedOutline = glyph.o.split( ' ' ) ); - // apply the state previously taken via 'saveOriginalState' to the binding - restoreOriginalState: function () { + for ( var i = 0, l = outline.length; i < l; ) { - var originalValueOffset = this.valueSize * 3; - this.binding.setValue( this.buffer, originalValueOffset ); + var action = outline[ i ++ ]; - }, + switch ( action ) { + case 'm': // moveTo - // mix functions + x = outline[ i ++ ] * scale + offsetX; + y = outline[ i ++ ] * scale + offsetY; - _select: function ( buffer, dstOffset, srcOffset, t, stride ) { + path.moveTo( x, y ); - if ( t >= 0.5 ) { + break; - for ( var i = 0; i !== stride; ++ i ) { + case 'l': // lineTo - buffer[ dstOffset + i ] = buffer[ srcOffset + i ]; + x = outline[ i ++ ] * scale + offsetX; + y = outline[ i ++ ] * scale + offsetY; - } + path.lineTo( x, y ); - } + break; - }, + case 'q': // quadraticCurveTo - _slerp: function ( buffer, dstOffset, srcOffset, t ) { + cpx = outline[ i ++ ] * scale + offsetX; + cpy = outline[ i ++ ] * scale + offsetY; + cpx1 = outline[ i ++ ] * scale + offsetX; + cpy1 = outline[ i ++ ] * scale + offsetY; - Quaternion.slerpFlat( buffer, dstOffset, buffer, dstOffset, buffer, srcOffset, t ); + path.quadraticCurveTo( cpx1, cpy1, cpx, cpy ); - }, + break; - _lerp: function ( buffer, dstOffset, srcOffset, t, stride ) { + case 'b': // bezierCurveTo - var s = 1 - t; + 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 i = 0; i !== stride; ++ i ) { + path.bezierCurveTo( cpx1, cpy1, cpx2, cpy2, cpx, cpy ); - var j = dstOffset + i; + break; - buffer[ j ] = buffer[ j ] * s + buffer[ srcOffset + i ] * t; + } } } -} ); + return { offsetX: glyph.ha * scale, path: path }; + +} /** - * - * A reference to a real property in the scene graph. - * - * - * @author Ben Houston / http://clara.io/ - * @author David Sarno / http://lighthaus.us/ - * @author tschw + * @author mrdoob / http://mrdoob.com/ */ -// Characters [].:/ are reserved for track binding syntax. -var RESERVED_CHARS_RE = '\\[\\]\\.:\\/'; - -function Composite( targetGroup, path, optionalParsedPath ) { - - var parsedPath = optionalParsedPath || PropertyBinding.parseTrackName( path ); +function FontLoader( manager ) { - this._targetGroup = targetGroup; - this._bindings = targetGroup.subscribe_( path, parsedPath ); + this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager; } -Object.assign( Composite.prototype, { - - getValue: function ( array, offset ) { - - 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 ); +Object.assign( FontLoader.prototype, { - }, + load: function ( url, onLoad, onProgress, onError ) { - setValue: function ( array, offset ) { + var scope = this; - var bindings = this._bindings; + var loader = new FileLoader( this.manager ); + loader.setPath( this.path ); + loader.load( url, function ( text ) { - for ( var i = this._targetGroup.nCachedObjects_, - n = bindings.length; i !== n; ++ i ) { + var json; - bindings[ i ].setValue( array, offset ); + try { - } + json = JSON.parse( text ); - }, + } catch ( e ) { - bind: function () { + console.warn( 'THREE.FontLoader: typeface.js support is being deprecated. Use typeface.json instead.' ); + json = JSON.parse( text.substring( 65, text.length - 2 ) ); - var bindings = this._bindings; + } - for ( var i = this._targetGroup.nCachedObjects_, - n = bindings.length; i !== n; ++ i ) { + var font = scope.parse( json ); - bindings[ i ].bind(); + if ( onLoad ) onLoad( font ); - } + }, onProgress, onError ); }, - unbind: function () { + parse: function ( json ) { - var bindings = this._bindings; + return new Font( json ); - for ( var i = this._targetGroup.nCachedObjects_, - n = bindings.length; i !== n; ++ i ) { + }, - bindings[ i ].unbind(); + setPath: function ( value ) { - } + this.path = value; + return this; } } ); +/** + * @author alteredq / http://alteredqualia.com/ + */ -function PropertyBinding( rootNode, path, parsedPath ) { - - this.path = path; - this.parsedPath = parsedPath || PropertyBinding.parseTrackName( path ); - - this.node = PropertyBinding.findNode( rootNode, this.parsedPath.nodeName ) || rootNode; - - this.rootNode = rootNode; - -} - -Object.assign( PropertyBinding, { - - Composite: Composite, - - create: function ( root, path, parsedPath ) { - - if ( ! ( root && root.isAnimationObjectGroup ) ) { +function Loader() {} - return new PropertyBinding( root, path, parsedPath ); +Loader.Handlers = { - } else { + handlers: [], - return new PropertyBinding.Composite( root, path, parsedPath ); + add: function ( regex, loader ) { - } + this.handlers.push( regex, loader ); }, - /** - * 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 () { - - var reservedRe = new RegExp( '[' + RESERVED_CHARS_RE + ']', 'g' ); - - return function sanitizeNodeName( name ) { - - return name.replace( /\s/g, '_' ).replace( reservedRe, '' ); - - }; - - }() ), - - parseTrackName: function () { - - // 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 ); - - // 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 ); - - // Property and accessor. May not contain reserved characters. Accessor may - // contain any non-bracket characters. - var propertyRe = /\.(WC+)(?:\[(.+)\])?/.source.replace( 'WC', wordChar ); - - var trackRe = new RegExp( '' - + '^' - + directoryRe - + nodeRe - + objectRe - + propertyRe - + '$' - ); + get: function ( file ) { - var supportedObjectNames = [ 'material', 'materials', 'bones' ]; + var handlers = this.handlers; - return function parseTrackName( trackName ) { + for ( var i = 0, l = handlers.length; i < l; i += 2 ) { - var matches = trackRe.exec( trackName ); + var regex = handlers[ i ]; + var loader = handlers[ i + 1 ]; - if ( ! matches ) { + if ( regex.test( file ) ) { - throw new Error( 'PropertyBinding: Cannot parse trackName: ' + trackName ); + return loader; } - var results = { - // directoryName: matches[ 1 ], // (tschw) currently unused - nodeName: matches[ 2 ], - objectName: matches[ 3 ], - objectIndex: matches[ 4 ], - propertyName: matches[ 5 ], // required - propertyIndex: matches[ 6 ] - }; - - var lastDot = results.nodeName && results.nodeName.lastIndexOf( '.' ); - - if ( lastDot !== undefined && lastDot !== - 1 ) { - - var objectName = results.nodeName.substring( lastDot + 1 ); - - // 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 ) { + } - results.nodeName = results.nodeName.substring( 0, lastDot ); - results.objectName = objectName; + return null; - } + } - } +}; - if ( results.propertyName === null || results.propertyName.length === 0 ) { +Object.assign( Loader.prototype, { - throw new Error( 'PropertyBinding: can not parse propertyName from trackName: ' + trackName ); + crossOrigin: 'anonymous', - } + onLoadStart: function () {}, - return results; + onLoadProgress: function () {}, - }; + onLoadComplete: function () {}, - }(), + initMaterials: function ( materials, texturePath, crossOrigin ) { - findNode: function ( root, nodeName ) { + var array = []; - if ( ! nodeName || nodeName === "" || nodeName === "root" || nodeName === "." || nodeName === - 1 || nodeName === root.name || nodeName === root.uuid ) { + for ( var i = 0; i < materials.length; ++ i ) { - return root; + array[ i ] = this.createMaterial( materials[ i ], texturePath, crossOrigin ); } - // search into skeleton bones. - if ( root.skeleton ) { + return array; - var bone = root.skeleton.getBoneByName( nodeName ); + }, - if ( bone !== undefined ) { + createMaterial: ( function () { - return bone; + var BlendingMode = { + NoBlending: NoBlending, + NormalBlending: NormalBlending, + AdditiveBlending: AdditiveBlending, + SubtractiveBlending: SubtractiveBlending, + MultiplyBlending: MultiplyBlending, + CustomBlending: CustomBlending + }; - } + var color = new Color(); + var textureLoader = new TextureLoader(); + var materialLoader = new MaterialLoader(); - } + return function createMaterial( m, texturePath, crossOrigin ) { - // search into node subtree. - if ( root.children ) { + // convert from old material format - var searchNodeSubtree = function ( children ) { + var textures = {}; - for ( var i = 0; i < children.length; i ++ ) { + function loadTexture( path, repeat, offset, wrap, anisotropy ) { - var childNode = children[ i ]; + var fullPath = texturePath + path; + var loader = Loader.Handlers.get( fullPath ); - if ( childNode.name === nodeName || childNode.uuid === nodeName ) { + var texture; - return childNode; + if ( loader !== null ) { - } + texture = loader.load( fullPath ); - var result = searchNodeSubtree( childNode.children ); + } else { - if ( result ) return result; + textureLoader.setCrossOrigin( crossOrigin ); + texture = textureLoader.load( fullPath ); } - return null; - - }; - - var subTreeNode = searchNodeSubtree( root.children ); - - if ( subTreeNode ) { - - return subTreeNode; - - } + if ( repeat !== undefined ) { - } + texture.repeat.fromArray( repeat ); - return null; + if ( repeat[ 0 ] !== 1 ) texture.wrapS = RepeatWrapping; + if ( repeat[ 1 ] !== 1 ) texture.wrapT = RepeatWrapping; - } + } -} ); + if ( offset !== undefined ) { -Object.assign( PropertyBinding.prototype, { // prototype, continued + texture.offset.fromArray( offset ); - // these are used to "bind" a nonexistent property - _getValue_unavailable: function () {}, - _setValue_unavailable: function () {}, + } - BindingType: { - Direct: 0, - EntireArray: 1, - ArrayElement: 2, - HasFromToArray: 3 - }, + if ( wrap !== undefined ) { - Versioning: { - None: 0, - NeedsUpdate: 1, - MatrixWorldNeedsUpdate: 2 - }, + if ( wrap[ 0 ] === 'repeat' ) texture.wrapS = RepeatWrapping; + if ( wrap[ 0 ] === 'mirror' ) texture.wrapS = MirroredRepeatWrapping; - GetterByBindingType: [ + if ( wrap[ 1 ] === 'repeat' ) texture.wrapT = RepeatWrapping; + if ( wrap[ 1 ] === 'mirror' ) texture.wrapT = MirroredRepeatWrapping; - function getValue_direct( buffer, offset ) { + } - buffer[ offset ] = this.node[ this.propertyName ]; + if ( anisotropy !== undefined ) { - }, + texture.anisotropy = anisotropy; - function getValue_array( buffer, offset ) { + } - var source = this.resolvedProperty; + var uuid = _Math.generateUUID(); - for ( var i = 0, n = source.length; i !== n; ++ i ) { + textures[ uuid ] = texture; - buffer[ offset ++ ] = source[ i ]; + return uuid; } - }, - - function getValue_arrayElement( buffer, offset ) { + // - buffer[ offset ] = this.resolvedProperty[ this.propertyIndex ]; + var json = { + uuid: _Math.generateUUID(), + type: 'MeshLambertMaterial' + }; - }, + for ( var name in m ) { - function getValue_toArray( buffer, offset ) { + var value = m[ name ]; - this.resolvedProperty.toArray( buffer, offset ); + 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; - ], + } - SetterByBindingTypeAndVersioning: [ + } - [ - // Direct + if ( json.type === 'MeshBasicMaterial' ) delete json.emissive; + if ( json.type !== 'MeshPhongMaterial' ) delete json.specular; - function setValue_direct( buffer, offset ) { + if ( json.opacity < 1 ) json.transparent = true; - this.targetObject[ this.propertyName ] = buffer[ offset ]; + materialLoader.setTextures( textures ); - }, + return materialLoader.parse( json ); - function setValue_direct_setNeedsUpdate( buffer, offset ) { + }; - this.targetObject[ this.propertyName ] = buffer[ offset ]; - this.targetObject.needsUpdate = true; + } )() - }, +} ); - function setValue_direct_setMatrixWorldNeedsUpdate( buffer, offset ) { +/** + * @author mrdoob / http://mrdoob.com/ + */ - this.targetObject[ this.propertyName ] = buffer[ offset ]; - this.targetObject.matrixWorldNeedsUpdate = true; +var context; - } +var AudioContext = { - ], [ + getContext: function () { - // EntireArray + if ( context === undefined ) { - function setValue_array( buffer, offset ) { + context = new ( window.AudioContext || window.webkitAudioContext )(); - var dest = this.resolvedProperty; + } - for ( var i = 0, n = dest.length; i !== n; ++ i ) { + return context; - dest[ i ] = buffer[ offset ++ ]; + }, - } + setContext: function ( value ) { - }, + context = value; - function setValue_array_setNeedsUpdate( buffer, offset ) { + } - var dest = this.resolvedProperty; +}; - for ( var i = 0, n = dest.length; i !== n; ++ i ) { +/** + * @author Reece Aaron Lecrivain / http://reecenotes.com/ + */ - dest[ i ] = buffer[ offset ++ ]; +function AudioLoader( manager ) { - } + this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager; - this.targetObject.needsUpdate = true; +} - }, +Object.assign( AudioLoader.prototype, { - function setValue_array_setMatrixWorldNeedsUpdate( buffer, offset ) { + load: function ( url, onLoad, onProgress, onError ) { - var dest = this.resolvedProperty; + var loader = new FileLoader( this.manager ); + loader.setResponseType( 'arraybuffer' ); + loader.setPath( this.path ); + loader.load( url, function ( buffer ) { - for ( var i = 0, n = dest.length; i !== n; ++ i ) { + // Create a copy of the buffer. The `decodeAudioData` method + // detaches the buffer when complete, preventing reuse. + var bufferCopy = buffer.slice( 0 ); - dest[ i ] = buffer[ offset ++ ]; + var context = AudioContext.getContext(); + context.decodeAudioData( bufferCopy, function ( audioBuffer ) { - } + onLoad( audioBuffer ); - this.targetObject.matrixWorldNeedsUpdate = true; + } ); - } + }, onProgress, onError ); - ], [ + }, - // ArrayElement + setPath: function ( value ) { - function setValue_arrayElement( buffer, offset ) { + this.path = value; + return this; - this.resolvedProperty[ this.propertyIndex ] = buffer[ offset ]; + } - }, +} ); - function setValue_arrayElement_setNeedsUpdate( buffer, offset ) { +/** + * @author mrdoob / http://mrdoob.com/ + */ - this.resolvedProperty[ this.propertyIndex ] = buffer[ offset ]; - this.targetObject.needsUpdate = true; +function StereoCamera() { - }, + this.type = 'StereoCamera'; - function setValue_arrayElement_setMatrixWorldNeedsUpdate( buffer, offset ) { + this.aspect = 1; - this.resolvedProperty[ this.propertyIndex ] = buffer[ offset ]; - this.targetObject.matrixWorldNeedsUpdate = true; + this.eyeSep = 0.064; - } + this.cameraL = new PerspectiveCamera(); + this.cameraL.layers.enable( 1 ); + this.cameraL.matrixAutoUpdate = false; - ], [ + this.cameraR = new PerspectiveCamera(); + this.cameraR.layers.enable( 2 ); + this.cameraR.matrixAutoUpdate = false; - // HasToFromArray +} - function setValue_fromArray( buffer, offset ) { +Object.assign( StereoCamera.prototype, { - this.resolvedProperty.fromArray( buffer, offset ); + update: ( function () { - }, + var instance, focus, fov, aspect, near, far, zoom, eyeSep; - function setValue_fromArray_setNeedsUpdate( buffer, offset ) { + var eyeRight = new Matrix4(); + var eyeLeft = new Matrix4(); - this.resolvedProperty.fromArray( buffer, offset ); - this.targetObject.needsUpdate = true; + return function update( camera ) { - }, + 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; - function setValue_fromArray_setMatrixWorldNeedsUpdate( buffer, offset ) { + if ( needsUpdate ) { - this.resolvedProperty.fromArray( buffer, offset ); - this.targetObject.matrixWorldNeedsUpdate = true; + instance = this; + focus = camera.focus; + fov = camera.fov; + aspect = camera.aspect * this.aspect; + near = camera.near; + far = camera.far; + zoom = camera.zoom; - } + // Off-axis stereoscopic effect based on + // http://paulbourke.net/stereographics/stereorender/ - ] + 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; - ], + // translate xOffset - getValue: function getValue_unbound( targetArray, offset ) { + eyeLeft.elements[ 12 ] = - eyeSep; + eyeRight.elements[ 12 ] = eyeSep; - this.bind(); - this.getValue( targetArray, offset ); + // for left eye - // 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. + xmin = - ymax * aspect + eyeSepOnProjection; + xmax = ymax * aspect + eyeSepOnProjection; - }, + projectionMatrix.elements[ 0 ] = 2 * near / ( xmax - xmin ); + projectionMatrix.elements[ 8 ] = ( xmax + xmin ) / ( xmax - xmin ); - setValue: function getValue_unbound( sourceArray, offset ) { + this.cameraL.projectionMatrix.copy( projectionMatrix ); - this.bind(); - this.setValue( sourceArray, offset ); + // for right eye - }, + xmin = - ymax * aspect - eyeSepOnProjection; + xmax = ymax * aspect - eyeSepOnProjection; - // create getter / setter pair for a property in the scene graph - bind: function () { + projectionMatrix.elements[ 0 ] = 2 * near / ( xmax - xmin ); + projectionMatrix.elements[ 8 ] = ( xmax + xmin ) / ( xmax - xmin ); - var targetObject = this.node, - parsedPath = this.parsedPath, + this.cameraR.projectionMatrix.copy( projectionMatrix ); - objectName = parsedPath.objectName, - propertyName = parsedPath.propertyName, - propertyIndex = parsedPath.propertyIndex; + } - if ( ! targetObject ) { + this.cameraL.matrixWorld.copy( camera.matrixWorld ).multiply( eyeLeft ); + this.cameraR.matrixWorld.copy( camera.matrixWorld ).multiply( eyeRight ); - targetObject = PropertyBinding.findNode( this.rootNode, parsedPath.nodeName ) || this.rootNode; + }; - this.node = targetObject; + } )() - } +} ); - // set fail state so we can just 'return' on error - this.getValue = this._getValue_unavailable; - this.setValue = this._setValue_unavailable; +/** + * Camera for rendering cube maps + * - renders scene into axis-aligned cube + * + * @author alteredq / http://alteredqualia.com/ + */ - // ensure there is a value node - if ( ! targetObject ) { +function CubeCamera( near, far, cubeResolution, options ) { - console.error( 'THREE.PropertyBinding: Trying to update node for track: ' + this.path + ' but it wasn\'t found.' ); - return; + Object3D.call( this ); - } + this.type = 'CubeCamera'; - if ( objectName ) { + var fov = 90, aspect = 1; - var objectIndex = parsedPath.objectIndex; + var cameraPX = new PerspectiveCamera( fov, aspect, near, far ); + cameraPX.up.set( 0, - 1, 0 ); + cameraPX.lookAt( new Vector3( 1, 0, 0 ) ); + this.add( cameraPX ); - // special cases were we need to reach deeper into the hierarchy to get the face materials.... - switch ( objectName ) { + var cameraNX = new PerspectiveCamera( fov, aspect, near, far ); + cameraNX.up.set( 0, - 1, 0 ); + cameraNX.lookAt( new Vector3( - 1, 0, 0 ) ); + this.add( cameraNX ); - case 'materials': + var cameraPY = new PerspectiveCamera( fov, aspect, near, far ); + cameraPY.up.set( 0, 0, 1 ); + cameraPY.lookAt( new Vector3( 0, 1, 0 ) ); + this.add( cameraPY ); - if ( ! targetObject.material ) { + var cameraNY = new PerspectiveCamera( fov, aspect, near, far ); + cameraNY.up.set( 0, 0, - 1 ); + cameraNY.lookAt( new Vector3( 0, - 1, 0 ) ); + this.add( cameraNY ); - console.error( 'THREE.PropertyBinding: Can not bind to material as node does not have a material.', this ); - return; + var cameraPZ = new PerspectiveCamera( fov, aspect, near, far ); + 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.up.set( 0, - 1, 0 ); + cameraNZ.lookAt( new Vector3( 0, 0, - 1 ) ); + this.add( cameraNZ ); - if ( ! targetObject.material.materials ) { + options = options || { format: RGBFormat, magFilter: LinearFilter, minFilter: LinearFilter }; - console.error( 'THREE.PropertyBinding: Can not bind to material.materials as node.material does not have a materials array.', this ); - return; + this.renderTarget = new WebGLRenderTargetCube( cubeResolution, cubeResolution, options ); + this.renderTarget.texture.name = "CubeCamera"; - } + this.update = function ( renderer, scene ) { - targetObject = targetObject.material.materials; + if ( this.parent === null ) this.updateMatrixWorld(); - break; + var renderTarget = this.renderTarget; + var generateMipmaps = renderTarget.texture.generateMipmaps; - case 'bones': + renderTarget.texture.generateMipmaps = false; - if ( ! targetObject.skeleton ) { + renderTarget.activeCubeFace = 0; + renderer.render( scene, cameraPX, renderTarget ); - console.error( 'THREE.PropertyBinding: Can not bind to bones as node does not have a skeleton.', this ); - return; + renderTarget.activeCubeFace = 1; + renderer.render( scene, cameraNX, renderTarget ); - } + renderTarget.activeCubeFace = 2; + renderer.render( scene, cameraPY, renderTarget ); - // potential future optimization: skip this if propertyIndex is already an integer - // and convert the integer string to a true integer. + renderTarget.activeCubeFace = 3; + renderer.render( scene, cameraNY, renderTarget ); - targetObject = targetObject.skeleton.bones; + renderTarget.activeCubeFace = 4; + renderer.render( scene, cameraPZ, renderTarget ); - // support resolving morphTarget names into indices. - for ( var i = 0; i < targetObject.length; i ++ ) { + renderTarget.texture.generateMipmaps = generateMipmaps; - if ( targetObject[ i ].name === objectIndex ) { + renderTarget.activeCubeFace = 5; + renderer.render( scene, cameraNZ, renderTarget ); - objectIndex = i; - break; + renderer.setRenderTarget( null ); - } + }; - } + this.clear = function ( renderer, color, depth, stencil ) { - break; + var renderTarget = this.renderTarget; - default: + for ( var i = 0; i < 6; i ++ ) { - if ( targetObject[ objectName ] === undefined ) { + renderTarget.activeCubeFace = i; + renderer.setRenderTarget( renderTarget ); - console.error( 'THREE.PropertyBinding: Can not bind to objectName of node undefined.', this ); - return; + renderer.clear( color, depth, stencil ); - } + } - targetObject = targetObject[ objectName ]; + renderer.setRenderTarget( null ); - } + }; +} - if ( objectIndex !== undefined ) { +CubeCamera.prototype = Object.create( Object3D.prototype ); +CubeCamera.prototype.constructor = CubeCamera; - if ( targetObject[ objectIndex ] === undefined ) { +/** + * @author alteredq / http://alteredqualia.com/ + */ - console.error( 'THREE.PropertyBinding: Trying to bind to objectIndex of objectName, but is undefined.', this, targetObject ); - return; +function Clock( autoStart ) { - } + this.autoStart = ( autoStart !== undefined ) ? autoStart : true; - targetObject = targetObject[ objectIndex ]; + this.startTime = 0; + this.oldTime = 0; + this.elapsedTime = 0; - } + this.running = false; - } +} - // resolve property - var nodeProperty = targetObject[ propertyName ]; +Object.assign( Clock.prototype, { - if ( nodeProperty === undefined ) { + start: function () { - var nodeName = parsedPath.nodeName; + this.startTime = ( typeof performance === 'undefined' ? Date : performance ).now(); // see #10732 - console.error( 'THREE.PropertyBinding: Trying to update property for track: ' + nodeName + - '.' + propertyName + ' but it wasn\'t found.', targetObject ); - return; + this.oldTime = this.startTime; + this.elapsedTime = 0; + this.running = true; - } + }, - // determine versioning scheme - var versioning = this.Versioning.None; + stop: function () { - if ( targetObject.needsUpdate !== undefined ) { // material + this.getElapsedTime(); + this.running = false; + this.autoStart = false; - versioning = this.Versioning.NeedsUpdate; - this.targetObject = targetObject; + }, - } else if ( targetObject.matrixWorldNeedsUpdate !== undefined ) { // node transform + getElapsedTime: function () { - versioning = this.Versioning.MatrixWorldNeedsUpdate; - this.targetObject = targetObject; + this.getDelta(); + return this.elapsedTime; - } + }, - // determine how the property gets bound - var bindingType = this.BindingType.Direct; + getDelta: function () { - if ( propertyIndex !== undefined ) { + var diff = 0; - // access a sub element of the property array (only primitives are supported right now) + if ( this.autoStart && ! this.running ) { - if ( propertyName === "morphTargetInfluences" ) { + this.start(); + return 0; - // 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 ) { + if ( this.running ) { - console.error( 'THREE.PropertyBinding: Can not bind to morphTargetInfluences because node does not have a geometry.', this ); - return; + var newTime = ( typeof performance === 'undefined' ? Date : performance ).now(); - } + diff = ( newTime - this.oldTime ) / 1000; + this.oldTime = newTime; - if ( targetObject.geometry.isBufferGeometry ) { + this.elapsedTime += diff; - if ( ! targetObject.geometry.morphAttributes ) { + } - console.error( 'THREE.PropertyBinding: Can not bind to morphTargetInfluences because node does not have a geometry.morphAttributes.', this ); - return; + return diff; - } + } - for ( var i = 0; i < this.node.geometry.morphAttributes.position.length; i ++ ) { +} ); - if ( targetObject.geometry.morphAttributes.position[ i ].name === propertyIndex ) { +/** + * @author mrdoob / http://mrdoob.com/ + */ - propertyIndex = i; - break; +function AudioListener() { - } + Object3D.call( this ); - } + this.type = 'AudioListener'; + this.context = AudioContext.getContext(); - } else { + this.gain = this.context.createGain(); + this.gain.connect( this.context.destination ); - if ( ! targetObject.geometry.morphTargets ) { + this.filter = null; - console.error( 'THREE.PropertyBinding: Can not bind to morphTargetInfluences because node does not have a geometry.morphTargets.', this ); - return; + this.timeDelta = 0; - } +} - for ( var i = 0; i < this.node.geometry.morphTargets.length; i ++ ) { +AudioListener.prototype = Object.assign( Object.create( Object3D.prototype ), { - if ( targetObject.geometry.morphTargets[ i ].name === propertyIndex ) { + constructor: AudioListener, - propertyIndex = i; - break; + getInput: function () { - } + return this.gain; - } + }, - } + removeFilter: function ( ) { - } + if ( this.filter !== null ) { - bindingType = this.BindingType.ArrayElement; + this.gain.disconnect( this.filter ); + this.filter.disconnect( this.context.destination ); + this.gain.connect( this.context.destination ); + this.filter = null; - this.resolvedProperty = nodeProperty; - this.propertyIndex = propertyIndex; + } - } else if ( nodeProperty.fromArray !== undefined && nodeProperty.toArray !== undefined ) { + return this; - // must use copy for Object3D.Euler/Quaternion + }, - bindingType = this.BindingType.HasFromToArray; + getFilter: function () { - this.resolvedProperty = nodeProperty; + return this.filter; - } else if ( Array.isArray( nodeProperty ) ) { + }, - bindingType = this.BindingType.EntireArray; + setFilter: function ( value ) { - this.resolvedProperty = nodeProperty; + if ( this.filter !== null ) { + + this.gain.disconnect( this.filter ); + this.filter.disconnect( this.context.destination ); } else { - this.propertyName = propertyName; + this.gain.disconnect( this.context.destination ); } - // select getter / setter - this.getValue = this.GetterByBindingType[ bindingType ]; - this.setValue = this.SetterByBindingTypeAndVersioning[ bindingType ][ versioning ]; - - }, + this.filter = value; + this.gain.connect( this.filter ); + this.filter.connect( this.context.destination ); - unbind: function () { + return this; - this.node = null; + }, - // back to the prototype version of getValue / setValue - // note: avoiding to mutate the shape of 'this' via 'delete' - this.getValue = this._getValue_unbound; - this.setValue = this._setValue_unbound; + getMasterVolume: function () { - } + return this.gain.gain.value; -} ); + }, -//!\ DECLARE ALIAS AFTER assign prototype ! -Object.assign( PropertyBinding.prototype, { + setMasterVolume: function ( value ) { - // initial state of these methods that calls 'bind' - _getValue_unbound: PropertyBinding.prototype.getValue, - _setValue_unbound: PropertyBinding.prototype.setValue, + this.gain.gain.setTargetAtTime( value, this.context.currentTime, 0.01 ); -} ); + return this; -/** - * - * 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 - */ + }, -function AnimationObjectGroup() { + updateMatrixWorld: ( function () { - this.uuid = _Math.generateUUID(); + var position = new Vector3(); + var quaternion = new Quaternion(); + var scale = new Vector3(); - // cached objects followed by the active ones - this._objects = Array.prototype.slice.call( arguments ); + var orientation = new Vector3(); + var clock = new Clock(); - this.nCachedObjects_ = 0; // threshold - // note: read by PropertyBinding.Composite + return function updateMatrixWorld( force ) { - var indices = {}; - this._indicesByUUID = indices; // for bookkeeping + Object3D.prototype.updateMatrixWorld.call( this, force ); - for ( var i = 0, n = arguments.length; i !== n; ++ i ) { + var listener = this.context.listener; + var up = this.up; - indices[ arguments[ i ].uuid ] = i; + this.timeDelta = clock.getDelta(); - } + this.matrixWorld.decompose( position, quaternion, scale ); - this._paths = []; // inside: string - this._parsedPaths = []; // inside: { we don't care, here } - this._bindings = []; // inside: Array< PropertyBinding > - this._bindingsIndicesByPath = {}; // inside: indices in these arrays + orientation.set( 0, 0, - 1 ).applyQuaternion( quaternion ); - var scope = this; + if ( listener.positionX ) { - this.stats = { + // code path for Chrome (see #14393) - objects: { - get total() { + var endTime = this.context.currentTime + this.timeDelta; - return scope._objects.length; + 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 ); - }, - get inUse() { + } else { - return this.total - scope.nCachedObjects_; + listener.setPosition( position.x, position.y, position.z ); + listener.setOrientation( orientation.x, orientation.y, orientation.z, up.x, up.y, up.z ); } - }, - get bindingsPerObject() { - return scope._bindings.length; + }; - } + } )() - }; +} ); -} +/** + * @author mrdoob / http://mrdoob.com/ + * @author Reece Aaron Lecrivain / http://reecenotes.com/ + */ -Object.assign( AnimationObjectGroup.prototype, { +function Audio( listener ) { - isAnimationObjectGroup: true, + Object3D.call( this ); - add: function () { + this.type = 'Audio'; - 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; + this.listener = listener; + this.context = listener.context; - for ( var i = 0, n = arguments.length; i !== n; ++ i ) { + this.gain = this.context.createGain(); + this.gain.connect( listener.getInput() ); - var object = arguments[ i ], - uuid = object.uuid, - index = indicesByUUID[ uuid ]; + this.autoplay = false; - if ( index === undefined ) { + this.buffer = null; + this.detune = 0; + this.loop = false; + this.startTime = 0; + this.offset = 0; + this.playbackRate = 1; + this.isPlaying = false; + this.hasPlaybackControl = true; + this.sourceType = 'empty'; - // unknown object -> add it to the ACTIVE region + this.filters = []; - index = nObjects ++; - indicesByUUID[ uuid ] = index; - objects.push( object ); +} - // accounting is done, now do the same for all bindings +Audio.prototype = Object.assign( Object.create( Object3D.prototype ), { - for ( var j = 0, m = nBindings; j !== m; ++ j ) { + constructor: Audio, - bindings[ j ].push( new PropertyBinding( object, paths[ j ], parsedPaths[ j ] ) ); + getOutput: function () { - } + return this.gain; - } else if ( index < nCachedObjects ) { + }, - knownObject = objects[ index ]; + setNodeSource: function ( audioNode ) { - // move existing object to the ACTIVE region + this.hasPlaybackControl = false; + this.sourceType = 'audioNode'; + this.source = audioNode; + this.connect(); - var firstActiveIndex = -- nCachedObjects, - lastCachedObject = objects[ firstActiveIndex ]; + return this; - indicesByUUID[ lastCachedObject.uuid ] = index; - objects[ index ] = lastCachedObject; + }, - indicesByUUID[ uuid ] = firstActiveIndex; - objects[ firstActiveIndex ] = object; + setMediaElementSource: function ( mediaElement ) { - // accounting is done, now do the same for all bindings + this.hasPlaybackControl = false; + this.sourceType = 'mediaNode'; + this.source = this.context.createMediaElementSource( mediaElement ); + this.connect(); - for ( var j = 0, m = nBindings; j !== m; ++ j ) { + return this; - var bindingsForPath = bindings[ j ], - lastCached = bindingsForPath[ firstActiveIndex ], - binding = bindingsForPath[ index ]; + }, - bindingsForPath[ index ] = lastCached; + setBuffer: function ( audioBuffer ) { - if ( binding === undefined ) { + this.buffer = audioBuffer; + this.sourceType = 'buffer'; - // since we do not bother to create new bindings - // for objects that are cached, the binding may - // or may not exist + if ( this.autoplay ) this.play(); - binding = new PropertyBinding( object, paths[ j ], parsedPaths[ j ] ); + return this; - } + }, - bindingsForPath[ firstActiveIndex ] = binding; + play: function () { - } + if ( this.isPlaying === true ) { - } else if ( objects[ index ] !== knownObject ) { + console.warn( 'THREE.Audio: Audio is already playing.' ); + return; - 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 + if ( this.hasPlaybackControl === false ) { - } // for arguments + console.warn( 'THREE.Audio: this Audio has no playback control.' ); + return; - this.nCachedObjects_ = nCachedObjects; + } - }, + var source = this.context.createBufferSource(); - remove: function () { + source.buffer = this.buffer; + source.detune.value = this.detune; + 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 ); - var objects = this._objects, - nCachedObjects = this.nCachedObjects_, - indicesByUUID = this._indicesByUUID, - bindings = this._bindings, - nBindings = bindings.length; + this.isPlaying = true; - for ( var i = 0, n = arguments.length; i !== n; ++ i ) { + this.source = source; - var object = arguments[ i ], - uuid = object.uuid, - index = indicesByUUID[ uuid ]; + return this.connect(); - if ( index !== undefined && index >= nCachedObjects ) { + }, - // move existing object into the CACHED region + pause: function () { - var lastCachedIndex = nCachedObjects ++, - firstActiveObject = objects[ lastCachedIndex ]; + if ( this.hasPlaybackControl === false ) { - indicesByUUID[ firstActiveObject.uuid ] = index; - objects[ index ] = firstActiveObject; + console.warn( 'THREE.Audio: this Audio has no playback control.' ); + return; - indicesByUUID[ uuid ] = lastCachedIndex; - objects[ lastCachedIndex ] = object; + } - // accounting is done, now do the same for all bindings + if ( this.isPlaying === true ) { - for ( var j = 0, m = nBindings; j !== m; ++ j ) { + this.source.stop(); + this.source.onended = null; + this.offset += ( this.context.currentTime - this.startTime ) * this.playbackRate; + this.isPlaying = false; - var bindingsForPath = bindings[ j ], - firstActive = bindingsForPath[ lastCachedIndex ], - binding = bindingsForPath[ index ]; + } - bindingsForPath[ index ] = firstActive; - bindingsForPath[ lastCachedIndex ] = binding; + return this; - } + }, - } + stop: function () { - } // for arguments + if ( this.hasPlaybackControl === false ) { - this.nCachedObjects_ = nCachedObjects; + console.warn( 'THREE.Audio: this Audio has no playback control.' ); + return; - }, + } - // remove & forget - uncache: function () { + this.source.stop(); + this.source.onended = null; + this.offset = 0; + this.isPlaying = false; - var objects = this._objects, - nObjects = objects.length, - nCachedObjects = this.nCachedObjects_, - indicesByUUID = this._indicesByUUID, - bindings = this._bindings, - nBindings = bindings.length; + return this; - for ( var i = 0, n = arguments.length; i !== n; ++ i ) { + }, - var object = arguments[ i ], - uuid = object.uuid, - index = indicesByUUID[ uuid ]; + connect: function () { - if ( index !== undefined ) { + if ( this.filters.length > 0 ) { - delete indicesByUUID[ uuid ]; + this.source.connect( this.filters[ 0 ] ); - if ( index < nCachedObjects ) { + for ( var i = 1, l = this.filters.length; i < l; i ++ ) { - // object is cached, shrink the CACHED region + this.filters[ i - 1 ].connect( this.filters[ i ] ); - 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; + this.filters[ this.filters.length - 1 ].connect( this.getOutput() ); - // last object goes to the activated slot and pop - indicesByUUID[ lastObject.uuid ] = firstActiveIndex; - objects[ firstActiveIndex ] = lastObject; - objects.pop(); + } else { - // accounting is done, now do the same for all bindings + this.source.connect( this.getOutput() ); - for ( var j = 0, m = nBindings; j !== m; ++ j ) { + } - var bindingsForPath = bindings[ j ], - lastCached = bindingsForPath[ firstActiveIndex ], - last = bindingsForPath[ lastIndex ]; + return this; - bindingsForPath[ index ] = lastCached; - bindingsForPath[ firstActiveIndex ] = last; - bindingsForPath.pop(); + }, - } + disconnect: function () { - } else { + if ( this.filters.length > 0 ) { - // object is active, just swap with the last and pop + this.source.disconnect( this.filters[ 0 ] ); - var lastIndex = -- nObjects, - lastObject = objects[ lastIndex ]; + for ( var i = 1, l = this.filters.length; i < l; i ++ ) { - indicesByUUID[ lastObject.uuid ] = index; - objects[ index ] = lastObject; - objects.pop(); + this.filters[ i - 1 ].disconnect( this.filters[ i ] ); - // accounting is done, now do the same for all bindings + } - for ( var j = 0, m = nBindings; j !== m; ++ j ) { + this.filters[ this.filters.length - 1 ].disconnect( this.getOutput() ); - var bindingsForPath = bindings[ j ]; + } else { - bindingsForPath[ index ] = bindingsForPath[ lastIndex ]; - bindingsForPath.pop(); + this.source.disconnect( this.getOutput() ); - } + } - } // cached or active + return this; - } // if object is known + }, - } // for arguments + getFilters: function () { - this.nCachedObjects_ = nCachedObjects; + return this.filters; }, - // Internal interface used by befriended PropertyBinding.Composite: + setFilters: function ( value ) { - subscribe_: function ( path, parsedPath ) { + if ( ! value ) value = []; - // returns an array of bindings for the given path that is changed - // according to the contained objects in the group + if ( this.isPlaying === true ) { - var indicesByPath = this._bindingsIndicesByPath, - index = indicesByPath[ path ], - bindings = this._bindings; + this.disconnect(); + this.filters = value; + this.connect(); - if ( index !== undefined ) return bindings[ index ]; + } else { - var paths = this._paths, - parsedPaths = this._parsedPaths, - objects = this._objects, - nObjects = objects.length, - nCachedObjects = this.nCachedObjects_, - bindingsForPath = new Array( nObjects ); + this.filters = value; - index = bindings.length; + } - indicesByPath[ path ] = index; + return this; - paths.push( path ); - parsedPaths.push( parsedPath ); - bindings.push( bindingsForPath ); + }, - for ( var i = nCachedObjects, n = objects.length; i !== n; ++ i ) { + setDetune: function ( value ) { - var object = objects[ i ]; - bindingsForPath[ i ] = new PropertyBinding( object, path, parsedPath ); + this.detune = value; + + if ( this.isPlaying === true ) { + + this.source.detune.setTargetAtTime( this.detune, this.context.currentTime, 0.01 ); } - return bindingsForPath; + return this; }, - unsubscribe_: function ( path ) { + getDetune: function () { - // tells the group to forget about a property path and no longer - // update the array previously obtained with 'subscribe_' + return this.detune; - var indicesByPath = this._bindingsIndicesByPath, - index = indicesByPath[ path ]; + }, - if ( index !== undefined ) { + getFilter: function () { - var paths = this._paths, - parsedPaths = this._parsedPaths, - bindings = this._bindings, - lastBindingsIndex = bindings.length - 1, - lastBindings = bindings[ lastBindingsIndex ], - lastBindingsPath = path[ lastBindingsIndex ]; + return this.getFilters()[ 0 ]; - indicesByPath[ lastBindingsPath ] = index; + }, - bindings[ index ] = lastBindings; - bindings.pop(); + setFilter: function ( filter ) { - parsedPaths[ index ] = parsedPaths[ lastBindingsIndex ]; - parsedPaths.pop(); + return this.setFilters( filter ? [ filter ] : [] ); - paths[ index ] = paths[ lastBindingsIndex ]; - paths.pop(); + }, - } + setPlaybackRate: function ( value ) { - } + if ( this.hasPlaybackControl === false ) { -} ); + console.warn( 'THREE.Audio: this Audio has no playback control.' ); + return; -/** - * - * 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 - * - */ + } -function AnimationAction( mixer, clip, localRoot ) { + this.playbackRate = value; - this._mixer = mixer; - this._clip = clip; - this._localRoot = localRoot || null; + if ( this.isPlaying === true ) { - var tracks = clip.tracks, - nTracks = tracks.length, - interpolants = new Array( nTracks ); + this.source.playbackRate.setTargetAtTime( this.playbackRate, this.context.currentTime, 0.01 ); - var interpolantSettings = { - endingStart: ZeroCurvatureEnding, - endingEnd: ZeroCurvatureEnding - }; + } - for ( var i = 0; i !== nTracks; ++ i ) { + return this; - var interpolant = tracks[ i ].createInterpolant( null ); - interpolants[ i ] = interpolant; - interpolant.settings = interpolantSettings; + }, - } + getPlaybackRate: function () { - this._interpolantSettings = interpolantSettings; + return this.playbackRate; - this._interpolants = interpolants; // bound by the mixer + }, - // inside: PropertyMixer (managed by the mixer) - this._propertyBindings = new Array( nTracks ); + onEnded: function () { - this._cacheIndex = null; // for the memory manager - this._byClipCacheIndex = null; // for the memory manager + this.isPlaying = false; - this._timeScaleInterpolant = null; - this._weightInterpolant = null; + }, - this.loop = LoopRepeat; - this._loopCount = - 1; + getLoop: function () { - // global mixer time when the action is to be started - // it's set back to 'null' upon start of the action - this._startTime = null; + if ( this.hasPlaybackControl === false ) { - // scaled local time of the action - // gets clamped or wrapped to 0..clip.duration according to loop - this.time = 0; + console.warn( 'THREE.Audio: this Audio has no playback control.' ); + return false; - this.timeScale = 1; - this._effectiveTimeScale = 1; + } - this.weight = 1; - this._effectiveWeight = 1; + return this.loop; - this.repetitions = Infinity; // no. of repetitions when looping + }, - this.paused = false; // true -> zero effective time scale - this.enabled = true; // false -> zero effective weight + setLoop: function ( value ) { - this.clampWhenFinished = false; // keep feeding the last frame? + if ( this.hasPlaybackControl === false ) { - this.zeroSlopeAtStart = true; // for smooth interpolation w/o separate - this.zeroSlopeAtEnd = true; // clips for start, loop and end + console.warn( 'THREE.Audio: this Audio has no playback control.' ); + return; -} + } -Object.assign( AnimationAction.prototype, { + this.loop = value; - // State & Scheduling + if ( this.isPlaying === true ) { - play: function () { + this.source.loop = this.loop; - this._mixer._activateAction( this ); + } return this; }, - stop: function () { - - this._mixer._deactivateAction( this ); + getVolume: function () { - return this.reset(); + return this.gain.gain.value; }, - reset: function () { + setVolume: function ( value ) { - this.paused = false; - this.enabled = true; + this.gain.gain.setTargetAtTime( value, this.context.currentTime, 0.01 ); - this.time = 0; // restart clip - this._loopCount = - 1; // forget previous loops - this._startTime = null; // forget scheduling + return this; - return this.stopFading().stopWarping(); + } - }, +} ); - isRunning: function () { +/** + * @author mrdoob / http://mrdoob.com/ + */ - return this.enabled && ! this.paused && this.timeScale !== 0 && - this._startTime === null && this._mixer._isActiveAction( this ); +function PositionalAudio( listener ) { - }, + Audio.call( this, listener ); - // return true when play has been called - isScheduled: function () { + this.panner = this.context.createPanner(); + this.panner.connect( this.gain ); - return this._mixer._isActiveAction( this ); +} - }, +PositionalAudio.prototype = Object.assign( Object.create( Audio.prototype ), { - startAt: function ( time ) { + constructor: PositionalAudio, - this._startTime = time; + getOutput: function () { - return this; + return this.panner; }, - setLoop: function ( mode, repetitions ) { - - this.loop = mode; - this.repetitions = repetitions; + getRefDistance: function () { - return this; + return this.panner.refDistance; }, - // Weight - - // set the weight stopping any scheduled fading - // although .enabled = false yields an effective weight of zero, this - // method does *not* change .enabled, because it would be confusing - setEffectiveWeight: function ( weight ) { - - this.weight = weight; + setRefDistance: function ( value ) { - // note: same logic as when updated at runtime - this._effectiveWeight = this.enabled ? weight : 0; + this.panner.refDistance = value; - return this.stopFading(); + return this; }, - // return the weight considering fading and .enabled - getEffectiveWeight: function () { + getRolloffFactor: function () { - return this._effectiveWeight; + return this.panner.rolloffFactor; }, - fadeIn: function ( duration ) { - - return this._scheduleFading( duration, 0, 1 ); - - }, + setRolloffFactor: function ( value ) { - fadeOut: function ( duration ) { + this.panner.rolloffFactor = value; - return this._scheduleFading( duration, 1, 0 ); + return this; }, - crossFadeFrom: function ( fadeOutAction, duration, warp ) { - - fadeOutAction.fadeOut( duration ); - this.fadeIn( duration ); - - if ( warp ) { + getDistanceModel: function () { - var fadeInDuration = this._clip.duration, - fadeOutDuration = fadeOutAction._clip.duration, + return this.panner.distanceModel; - startEndRatio = fadeOutDuration / fadeInDuration, - endStartRatio = fadeInDuration / fadeOutDuration; + }, - fadeOutAction.warp( 1.0, startEndRatio, duration ); - this.warp( endStartRatio, 1.0, duration ); + setDistanceModel: function ( value ) { - } + this.panner.distanceModel = value; return this; }, - crossFadeTo: function ( fadeInAction, duration, warp ) { + getMaxDistance: function () { - return fadeInAction.crossFadeFrom( this, duration, warp ); + return this.panner.maxDistance; }, - stopFading: function () { - - var weightInterpolant = this._weightInterpolant; - - if ( weightInterpolant !== null ) { - - this._weightInterpolant = null; - this._mixer._takeBackControlInterpolant( weightInterpolant ); + setMaxDistance: function ( value ) { - } + this.panner.maxDistance = value; return this; }, - // Time Scale Control - - // set the time scale stopping any scheduled warping - // although .paused = true yields an effective time scale of zero, this - // method does *not* change .paused, because it would be confusing - setEffectiveTimeScale: function ( timeScale ) { + setDirectionalCone: function ( coneInnerAngle, coneOuterAngle, coneOuterGain ) { - this.timeScale = timeScale; - this._effectiveTimeScale = this.paused ? 0 : timeScale; + this.panner.coneInnerAngle = coneInnerAngle; + this.panner.coneOuterAngle = coneOuterAngle; + this.panner.coneOuterGain = coneOuterGain; - return this.stopWarping(); + return this; }, - // return the time scale considering warping and .paused - getEffectiveTimeScale: function () { - - return this._effectiveTimeScale; + updateMatrixWorld: ( function () { - }, + var position = new Vector3(); + var quaternion = new Quaternion(); + var scale = new Vector3(); - setDuration: function ( duration ) { + var orientation = new Vector3(); - this.timeScale = this._clip.duration / duration; + return function updateMatrixWorld( force ) { - return this.stopWarping(); + Object3D.prototype.updateMatrixWorld.call( this, force ); - }, + if ( this.isPlaying === false ) return; - syncWith: function ( action ) { + this.matrixWorld.decompose( position, quaternion, scale ); - this.time = action.time; - this.timeScale = action.timeScale; + orientation.set( 0, 0, 1 ).applyQuaternion( quaternion ); - return this.stopWarping(); + var panner = this.panner; - }, + if ( panner.positionX ) { - halt: function ( duration ) { + // code path for Chrome and Firefox (see #14393) - return this.warp( this._effectiveTimeScale, 0, duration ); + var endTime = this.context.currentTime + this.listener.timeDelta; - }, + panner.positionX.linearRampToValueAtTime( position.x, endTime ); + panner.positionY.linearRampToValueAtTime( position.y, endTime ); + panner.positionZ.linearRampToValueAtTime( position.z, endTime ); + panner.orientationX.linearRampToValueAtTime( orientation.x, endTime ); + panner.orientationY.linearRampToValueAtTime( orientation.y, endTime ); + panner.orientationZ.linearRampToValueAtTime( orientation.z, endTime ); - warp: function ( startTimeScale, endTimeScale, duration ) { + } else { - var mixer = this._mixer, now = mixer.time, - interpolant = this._timeScaleInterpolant, + panner.setPosition( position.x, position.y, position.z ); + panner.setOrientation( orientation.x, orientation.y, orientation.z ); - timeScale = this.timeScale; + } - if ( interpolant === null ) { + }; - interpolant = mixer._lendControlInterpolant(); - this._timeScaleInterpolant = interpolant; + } )() - } - var times = interpolant.parameterPositions, - values = interpolant.sampleValues; +} ); - times[ 0 ] = now; - times[ 1 ] = now + duration; +/** + * @author mrdoob / http://mrdoob.com/ + */ - values[ 0 ] = startTimeScale / timeScale; - values[ 1 ] = endTimeScale / timeScale; +function AudioAnalyser( audio, fftSize ) { - return this; + this.analyser = audio.context.createAnalyser(); + this.analyser.fftSize = fftSize !== undefined ? fftSize : 2048; - }, + this.data = new Uint8Array( this.analyser.frequencyBinCount ); - stopWarping: function () { + audio.getOutput().connect( this.analyser ); - var timeScaleInterpolant = this._timeScaleInterpolant; +} - if ( timeScaleInterpolant !== null ) { +Object.assign( AudioAnalyser.prototype, { - this._timeScaleInterpolant = null; - this._mixer._takeBackControlInterpolant( timeScaleInterpolant ); + getFrequencyData: function () { - } + this.analyser.getByteFrequencyData( this.data ); - return this; + return this.data; }, - // Object Accessors + getAverageFrequency: function () { - getMixer: function () { + var value = 0, data = this.getFrequencyData(); - return this._mixer; + for ( var i = 0; i < data.length; i ++ ) { - }, + value += data[ i ]; - getClip: function () { + } - return this._clip; + return value / data.length; - }, + } - getRoot: function () { +} ); - return this._localRoot || this._mixer._root; +/** + * + * Buffered scene graph property that allows weighted accumulation. + * + * + * @author Ben Houston / http://clara.io/ + * @author David Sarno / http://lighthaus.us/ + * @author tschw + */ - }, +function PropertyMixer( binding, typeName, valueSize ) { - // Interna + this.binding = binding; + this.valueSize = valueSize; - _update: function ( time, deltaTime, timeDirection, accuIndex ) { + var bufferType = Float64Array, + mixFunction; - // called by the mixer + switch ( typeName ) { - if ( ! this.enabled ) { + case 'quaternion': + mixFunction = this._slerp; + break; - // call ._updateWeight() to update ._effectiveWeight + case 'string': + case 'bool': + bufferType = Array; + mixFunction = this._select; + break; - this._updateWeight( time ); - return; + default: + mixFunction = this._lerp; - } + } - var startTime = this._startTime; + 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 ( startTime !== null ) { + this._mixBufferRegion = mixFunction; - // check for scheduled start of action + this.cumulativeWeight = 0; - var timeRunning = ( time - startTime ) * timeDirection; - if ( timeRunning < 0 || timeDirection === 0 ) { + this.useCount = 0; + this.referenceCount = 0; - return; // yet to come / don't decide when delta = 0 +} - } +Object.assign( PropertyMixer.prototype, { - // start + // accumulate data in the 'incoming' region into 'accu' + accumulate: function ( accuIndex, weight ) { - this._startTime = null; // unschedule - deltaTime = timeDirection * timeRunning; + // note: happily accumulating nothing when weight = 0, the caller knows + // the weight and shouldn't have made the call in the first place - } + var buffer = this.buffer, + stride = this.valueSize, + offset = accuIndex * stride + stride, - // apply time scale and advance time + currentWeight = this.cumulativeWeight; - deltaTime *= this._updateTimeScale( time ); - var clipTime = this._updateTime( deltaTime ); + if ( currentWeight === 0 ) { - // note: _updateTime may disable the action resulting in - // an effective weight of 0 + // accuN := incoming * weight - var weight = this._updateWeight( time ); + for ( var i = 0; i !== stride; ++ i ) { - if ( weight > 0 ) { + buffer[ offset + i ] = buffer[ i ]; - var interpolants = this._interpolants; - var propertyMixers = this._propertyBindings; + } - for ( var j = 0, m = interpolants.length; j !== m; ++ j ) { + currentWeight = weight; - interpolants[ j ].evaluate( clipTime ); - propertyMixers[ j ].accumulate( accuIndex, weight ); + } else { - } + // accuN := accuN + incoming * weight + + currentWeight += weight; + var mix = weight / currentWeight; + this._mixBufferRegion( buffer, offset, 0, mix, stride ); } + this.cumulativeWeight = currentWeight; + }, - _updateWeight: function ( time ) { + // apply the state of 'accu' to the binding when accus differ + apply: function ( accuIndex ) { - var weight = 0; + var stride = this.valueSize, + buffer = this.buffer, + offset = accuIndex * stride + stride, - if ( this.enabled ) { + weight = this.cumulativeWeight, - weight = this.weight; - var interpolant = this._weightInterpolant; + binding = this.binding; - if ( interpolant !== null ) { + this.cumulativeWeight = 0; - var interpolantValue = interpolant.evaluate( time )[ 0 ]; + if ( weight < 1 ) { - weight *= interpolantValue; + // accuN := accuN + original * ( 1 - cumulativeWeight ) - if ( time > interpolant.parameterPositions[ 1 ] ) { + var originalValueOffset = stride * 3; - this.stopFading(); + this._mixBufferRegion( + buffer, offset, originalValueOffset, 1 - weight, stride ); - if ( interpolantValue === 0 ) { + } - // faded out, disable - this.enabled = false; + for ( var i = stride, e = stride + stride; i !== e; ++ i ) { - } + if ( buffer[ i ] !== buffer[ i + stride ] ) { - } + // value has changed -> update scene graph + + binding.setValue( buffer, offset ); + break; } } - this._effectiveWeight = weight; - return weight; - }, - _updateTimeScale: function ( time ) { + // remember the state of the bound property and copy it to both accus + saveOriginalState: function () { - var timeScale = 0; + var binding = this.binding; - if ( ! this.paused ) { + var buffer = this.buffer, + stride = this.valueSize, - timeScale = this.timeScale; + originalValueOffset = stride * 3; - var interpolant = this._timeScaleInterpolant; + binding.getValue( buffer, originalValueOffset ); - if ( interpolant !== null ) { + // accu[0..1] := orig -- initially detect changes against the original + for ( var i = stride, e = originalValueOffset; i !== e; ++ i ) { - var interpolantValue = interpolant.evaluate( time )[ 0 ]; + buffer[ i ] = buffer[ originalValueOffset + ( i % stride ) ]; - timeScale *= interpolantValue; + } - if ( time > interpolant.parameterPositions[ 1 ] ) { + this.cumulativeWeight = 0; - this.stopWarping(); + }, - if ( timeScale === 0 ) { + // apply the state previously taken via 'saveOriginalState' to the binding + restoreOriginalState: function () { - // motion has halted, pause - this.paused = true; + var originalValueOffset = this.valueSize * 3; + this.binding.setValue( this.buffer, originalValueOffset ); - } else { + }, - // warp done - apply final time scale - this.timeScale = timeScale; - } + // mix functions - } + _select: function ( buffer, dstOffset, srcOffset, t, stride ) { + + if ( t >= 0.5 ) { + + for ( var i = 0; i !== stride; ++ i ) { + + buffer[ dstOffset + i ] = buffer[ srcOffset + i ]; } } - this._effectiveTimeScale = timeScale; - return timeScale; - }, - _updateTime: function ( deltaTime ) { + _slerp: function ( buffer, dstOffset, srcOffset, t ) { - var time = this.time + deltaTime; + Quaternion.slerpFlat( buffer, dstOffset, buffer, dstOffset, buffer, srcOffset, t ); - if ( deltaTime === 0 ) return time; + }, - var duration = this._clip.duration, + _lerp: function ( buffer, dstOffset, srcOffset, t, stride ) { - loop = this.loop, - loopCount = this._loopCount; + var s = 1 - t; - if ( loop === LoopOnce ) { + for ( var i = 0; i !== stride; ++ i ) { - if ( loopCount === - 1 ) { + var j = dstOffset + i; - // just started + buffer[ j ] = buffer[ j ] * s + buffer[ srcOffset + i ] * t; - this._loopCount = 0; - this._setEndings( true, true, false ); + } - } + } - handle_stop: { +} ); - if ( time >= duration ) { +/** + * + * A reference to a real property in the scene graph. + * + * + * @author Ben Houston / http://clara.io/ + * @author David Sarno / http://lighthaus.us/ + * @author tschw + */ - time = duration; +// Characters [].:/ are reserved for track binding syntax. +var RESERVED_CHARS_RE = '\\[\\]\\.:\\/'; - } else if ( time < 0 ) { +function Composite( targetGroup, path, optionalParsedPath ) { - time = 0; + var parsedPath = optionalParsedPath || PropertyBinding.parseTrackName( path ); - } else break handle_stop; + this._targetGroup = targetGroup; + this._bindings = targetGroup.subscribe_( path, parsedPath ); - if ( this.clampWhenFinished ) this.paused = true; - else this.enabled = false; +} - this._mixer.dispatchEvent( { - type: 'finished', action: this, - direction: deltaTime < 0 ? - 1 : 1 - } ); +Object.assign( Composite.prototype, { - } + getValue: function ( array, offset ) { - } else { // repetitive Repeat or PingPong + this.bind(); // bind all binding - var pingPong = ( loop === LoopPingPong ); + var firstValidIndex = this._targetGroup.nCachedObjects_, + binding = this._bindings[ firstValidIndex ]; - if ( loopCount === - 1 ) { + // and only call .getValue on the first + if ( binding !== undefined ) binding.getValue( array, offset ); - // just started + }, - if ( deltaTime >= 0 ) { + setValue: function ( array, offset ) { - loopCount = 0; + var bindings = this._bindings; - this._setEndings( true, this.repetitions === 0, pingPong ); + for ( var i = this._targetGroup.nCachedObjects_, n = bindings.length; i !== n; ++ i ) { - } else { + bindings[ i ].setValue( array, offset ); - // when looping in reverse direction, the initial - // transition through zero counts as a repetition, - // so leave loopCount at -1 + } - this._setEndings( this.repetitions === 0, true, pingPong ); + }, - } + bind: function () { - } - - if ( time >= duration || time < 0 ) { - - // wrap around + var bindings = this._bindings; - var loopDelta = Math.floor( time / duration ); // signed - time -= duration * loopDelta; + for ( var i = this._targetGroup.nCachedObjects_, n = bindings.length; i !== n; ++ i ) { - loopCount += Math.abs( loopDelta ); + bindings[ i ].bind(); - var pending = this.repetitions - loopCount; + } - if ( pending < 0 ) { + }, - // have to stop (switch state, clamp time, fire event) + unbind: function () { - if ( this.clampWhenFinished ) this.paused = true; - else this.enabled = false; + var bindings = this._bindings; - time = deltaTime > 0 ? duration : 0; + for ( var i = this._targetGroup.nCachedObjects_, n = bindings.length; i !== n; ++ i ) { - this._mixer.dispatchEvent( { - type: 'finished', action: this, - direction: deltaTime > 0 ? 1 : - 1 - } ); + bindings[ i ].unbind(); - } else { + } - // keep running + } - if ( pending === 0 ) { +} ); - // entering the last round - var atStart = deltaTime < 0; - this._setEndings( atStart, ! atStart, pingPong ); +function PropertyBinding( rootNode, path, parsedPath ) { - } else { + this.path = path; + this.parsedPath = parsedPath || PropertyBinding.parseTrackName( path ); - this._setEndings( false, false, pingPong ); + this.node = PropertyBinding.findNode( rootNode, this.parsedPath.nodeName ) || rootNode; - } + this.rootNode = rootNode; - this._loopCount = loopCount; +} - this._mixer.dispatchEvent( { - type: 'loop', action: this, loopDelta: loopDelta - } ); +Object.assign( PropertyBinding, { - } + Composite: Composite, - } + create: function ( root, path, parsedPath ) { - if ( pingPong && ( loopCount & 1 ) === 1 ) { + if ( ! ( root && root.isAnimationObjectGroup ) ) { - // invert time for the "pong round" + return new PropertyBinding( root, path, parsedPath ); - this.time = time; - return duration - time; + } else { - } + return new PropertyBinding.Composite( root, path, parsedPath ); } - this.time = time; - return time; - }, - _setEndings: function ( atStart, atEnd, pingPong ) { - - var settings = this._interpolantSettings; - - if ( pingPong ) { + /** + * 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 () { - settings.endingStart = ZeroSlopeEnding; - settings.endingEnd = ZeroSlopeEnding; + var reservedRe = new RegExp( '[' + RESERVED_CHARS_RE + ']', 'g' ); - } else { + return function sanitizeNodeName( name ) { - // assuming for LoopOnce atStart == atEnd == true + return name.replace( /\s/g, '_' ).replace( reservedRe, '' ); - if ( atStart ) { + }; - settings.endingStart = this.zeroSlopeAtStart ? ZeroSlopeEnding : ZeroCurvatureEnding; + }() ), - } else { + parseTrackName: function () { - settings.endingStart = WrapAroundEnding; + // 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 ); - if ( atEnd ) { + // Target node. May contain word characters (a-zA-Z0-9_) and '.' or '-'. + var nodeRe = /(WCOD+)?/.source.replace( 'WCOD', wordCharOrDot ); - settings.endingEnd = this.zeroSlopeAtEnd ? ZeroSlopeEnding : ZeroCurvatureEnding; + // 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 ); - } else { + // Property and accessor. May not contain reserved characters. Accessor may + // contain any non-bracket characters. + var propertyRe = /\.(WC+)(?:\[(.+)\])?/.source.replace( 'WC', wordChar ); - settings.endingEnd = WrapAroundEnding; + var trackRe = new RegExp( '' + + '^' + + directoryRe + + nodeRe + + objectRe + + propertyRe + + '$' + ); - } + var supportedObjectNames = [ 'material', 'materials', 'bones' ]; - } + return function parseTrackName( trackName ) { - }, + var matches = trackRe.exec( trackName ); - _scheduleFading: function ( duration, weightNow, weightThen ) { + if ( ! matches ) { - var mixer = this._mixer, now = mixer.time, - interpolant = this._weightInterpolant; + throw new Error( 'PropertyBinding: Cannot parse trackName: ' + trackName ); - if ( interpolant === null ) { + } - interpolant = mixer._lendControlInterpolant(); - this._weightInterpolant = interpolant; + var results = { + // directoryName: matches[ 1 ], // (tschw) currently unused + nodeName: matches[ 2 ], + objectName: matches[ 3 ], + objectIndex: matches[ 4 ], + propertyName: matches[ 5 ], // required + propertyIndex: matches[ 6 ] + }; - } + var lastDot = results.nodeName && results.nodeName.lastIndexOf( '.' ); - var times = interpolant.parameterPositions, - values = interpolant.sampleValues; + if ( lastDot !== undefined && lastDot !== - 1 ) { - times[ 0 ] = now; values[ 0 ] = weightNow; - times[ 1 ] = now + duration; values[ 1 ] = weightThen; + var objectName = results.nodeName.substring( lastDot + 1 ); - return this; + // 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 ) { - } + results.nodeName = results.nodeName.substring( 0, lastDot ); + results.objectName = objectName; -} ); + } -/** - * - * Player for AnimationClips. - * - * - * @author Ben Houston / http://clara.io/ - * @author David Sarno / http://lighthaus.us/ - * @author tschw - */ + } -function AnimationMixer( root ) { + if ( results.propertyName === null || results.propertyName.length === 0 ) { - this._root = root; - this._initMemoryManager(); - this._accuIndex = 0; + throw new Error( 'PropertyBinding: can not parse propertyName from trackName: ' + trackName ); - this.time = 0; + } - this.timeScale = 1.0; + return results; -} + }; -AnimationMixer.prototype = Object.assign( Object.create( EventDispatcher.prototype ), { + }(), - constructor: AnimationMixer, + findNode: function ( root, nodeName ) { - _bindAction: function ( action, prototypeAction ) { + if ( ! nodeName || nodeName === "" || nodeName === "root" || nodeName === "." || nodeName === - 1 || nodeName === root.name || nodeName === root.uuid ) { - 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 ]; + return root; - if ( bindingsByName === undefined ) { + } - bindingsByName = {}; - bindingsByRoot[ rootUuid ] = bindingsByName; + // search into skeleton bones. + if ( root.skeleton ) { - } + var bone = root.skeleton.getBoneByName( nodeName ); - for ( var i = 0; i !== nTracks; ++ i ) { + if ( bone !== undefined ) { - var track = tracks[ i ], - trackName = track.name, - binding = bindingsByName[ trackName ]; + return bone; - if ( binding !== undefined ) { + } - bindings[ i ] = binding; + } - } else { + // search into node subtree. + if ( root.children ) { - binding = bindings[ i ]; + var searchNodeSubtree = function ( children ) { - if ( binding !== undefined ) { + for ( var i = 0; i < children.length; i ++ ) { - // existing binding, make sure the cache knows + var childNode = children[ i ]; - if ( binding._cacheIndex === null ) { + if ( childNode.name === nodeName || childNode.uuid === nodeName ) { - ++ binding.referenceCount; - this._addInactiveBinding( binding, rootUuid, trackName ); + return childNode; } - continue; + var result = searchNodeSubtree( childNode.children ); + + if ( result ) return result; } - var path = prototypeAction && prototypeAction. - _propertyBindings[ i ].binding.parsedPath; + return null; - binding = new PropertyMixer( - PropertyBinding.create( root, trackName, path ), - track.ValueTypeName, track.getValueSize() ); + }; - ++ binding.referenceCount; - this._addInactiveBinding( binding, rootUuid, trackName ); + var subTreeNode = searchNodeSubtree( root.children ); - bindings[ i ] = binding; + if ( subTreeNode ) { - } + return subTreeNode; - interpolants[ i ].resultBuffer = binding.buffer; + } } - }, + return null; - _activateAction: function ( action ) { + } - if ( ! this._isActiveAction( action ) ) { +} ); - if ( action._cacheIndex === null ) { +Object.assign( PropertyBinding.prototype, { // prototype, continued - // this action has been forgotten by the cache, but the user - // appears to be still using it -> rebind + // these are used to "bind" a nonexistent property + _getValue_unavailable: function () {}, + _setValue_unavailable: function () {}, - var rootUuid = ( action._localRoot || this._root ).uuid, - clipUuid = action._clip.uuid, - actionsForClip = this._actionsByClip[ clipUuid ]; + BindingType: { + Direct: 0, + EntireArray: 1, + ArrayElement: 2, + HasFromToArray: 3 + }, - this._bindAction( action, - actionsForClip && actionsForClip.knownActions[ 0 ] ); + Versioning: { + None: 0, + NeedsUpdate: 1, + MatrixWorldNeedsUpdate: 2 + }, - this._addInactiveAction( action, clipUuid, rootUuid ); + GetterByBindingType: [ - } + function getValue_direct( buffer, offset ) { - var bindings = action._propertyBindings; + buffer[ offset ] = this.node[ this.propertyName ]; - // increment reference counts / sort out state - for ( var i = 0, n = bindings.length; i !== n; ++ i ) { + }, - var binding = bindings[ i ]; + function getValue_array( buffer, offset ) { - if ( binding.useCount ++ === 0 ) { + var source = this.resolvedProperty; - this._lendBinding( binding ); - binding.saveOriginalState(); + for ( var i = 0, n = source.length; i !== n; ++ i ) { - } + buffer[ offset ++ ] = source[ i ]; } - this._lendAction( action ); - - } + }, - }, + function getValue_arrayElement( buffer, offset ) { - _deactivateAction: function ( action ) { + buffer[ offset ] = this.resolvedProperty[ this.propertyIndex ]; - if ( this._isActiveAction( action ) ) { + }, - var bindings = action._propertyBindings; + function getValue_toArray( buffer, offset ) { - // decrement reference counts / sort out state - for ( var i = 0, n = bindings.length; i !== n; ++ i ) { + this.resolvedProperty.toArray( buffer, offset ); - var binding = bindings[ i ]; + } - if ( -- binding.useCount === 0 ) { + ], - binding.restoreOriginalState(); - this._takeBackBinding( binding ); + SetterByBindingTypeAndVersioning: [ - } + [ + // Direct - } + function setValue_direct( buffer, offset ) { - this._takeBackAction( action ); + this.targetObject[ this.propertyName ] = buffer[ offset ]; - } + }, - }, + function setValue_direct_setNeedsUpdate( buffer, offset ) { - // Memory manager + this.targetObject[ this.propertyName ] = buffer[ offset ]; + this.targetObject.needsUpdate = true; - _initMemoryManager: function () { + }, - this._actions = []; // 'nActiveActions' followed by inactive ones - this._nActiveActions = 0; + function setValue_direct_setMatrixWorldNeedsUpdate( buffer, offset ) { - this._actionsByClip = {}; - // inside: - // { - // knownActions: Array< AnimationAction > - used as prototypes - // actionByRoot: AnimationAction - lookup - // } + this.targetObject[ this.propertyName ] = buffer[ offset ]; + this.targetObject.matrixWorldNeedsUpdate = true; + } - this._bindings = []; // 'nActiveBindings' followed by inactive ones - this._nActiveBindings = 0; + ], [ - this._bindingsByRootAndName = {}; // inside: Map< name, PropertyMixer > + // EntireArray + function setValue_array( buffer, offset ) { - this._controlInterpolants = []; // same game as above - this._nActiveControlInterpolants = 0; + var dest = this.resolvedProperty; - var scope = this; + for ( var i = 0, n = dest.length; i !== n; ++ i ) { - this.stats = { + dest[ i ] = buffer[ offset ++ ]; - actions: { - get total() { + } - return scope._actions.length; + }, - }, - get inUse() { + function setValue_array_setNeedsUpdate( buffer, offset ) { - return scope._nActiveActions; + var dest = this.resolvedProperty; - } - }, - bindings: { - get total() { + for ( var i = 0, n = dest.length; i !== n; ++ i ) { - return scope._bindings.length; + dest[ i ] = buffer[ offset ++ ]; - }, - get inUse() { + } - return scope._nActiveBindings; + this.targetObject.needsUpdate = true; - } }, - controlInterpolants: { - get total() { - - return scope._controlInterpolants.length; - }, - get inUse() { + function setValue_array_setMatrixWorldNeedsUpdate( buffer, offset ) { - return scope._nActiveControlInterpolants; + var dest = this.resolvedProperty; - } - } + for ( var i = 0, n = dest.length; i !== n; ++ i ) { - }; + dest[ i ] = buffer[ offset ++ ]; - }, + } - // Memory management for AnimationAction objects + this.targetObject.matrixWorldNeedsUpdate = true; - _isActiveAction: function ( action ) { + } - var index = action._cacheIndex; - return index !== null && index < this._nActiveActions; + ], [ - }, + // ArrayElement - _addInactiveAction: function ( action, clipUuid, rootUuid ) { + function setValue_arrayElement( buffer, offset ) { - var actions = this._actions, - actionsByClip = this._actionsByClip, - actionsForClip = actionsByClip[ clipUuid ]; + this.resolvedProperty[ this.propertyIndex ] = buffer[ offset ]; - if ( actionsForClip === undefined ) { + }, - actionsForClip = { + function setValue_arrayElement_setNeedsUpdate( buffer, offset ) { - knownActions: [ action ], - actionByRoot: {} + this.resolvedProperty[ this.propertyIndex ] = buffer[ offset ]; + this.targetObject.needsUpdate = true; - }; + }, - action._byClipCacheIndex = 0; + function setValue_arrayElement_setMatrixWorldNeedsUpdate( buffer, offset ) { - actionsByClip[ clipUuid ] = actionsForClip; + this.resolvedProperty[ this.propertyIndex ] = buffer[ offset ]; + this.targetObject.matrixWorldNeedsUpdate = true; - } else { + } - var knownActions = actionsForClip.knownActions; + ], [ - action._byClipCacheIndex = knownActions.length; - knownActions.push( action ); + // HasToFromArray - } + function setValue_fromArray( buffer, offset ) { - action._cacheIndex = actions.length; - actions.push( action ); + this.resolvedProperty.fromArray( buffer, offset ); - actionsForClip.actionByRoot[ rootUuid ] = action; + }, - }, + function setValue_fromArray_setNeedsUpdate( buffer, offset ) { - _removeInactiveAction: function ( action ) { + this.resolvedProperty.fromArray( buffer, offset ); + this.targetObject.needsUpdate = true; - var actions = this._actions, - lastInactiveAction = actions[ actions.length - 1 ], - cacheIndex = action._cacheIndex; + }, - lastInactiveAction._cacheIndex = cacheIndex; - actions[ cacheIndex ] = lastInactiveAction; - actions.pop(); + function setValue_fromArray_setMatrixWorldNeedsUpdate( buffer, offset ) { - action._cacheIndex = null; + this.resolvedProperty.fromArray( buffer, offset ); + this.targetObject.matrixWorldNeedsUpdate = true; + } - var clipUuid = action._clip.uuid, - actionsByClip = this._actionsByClip, - actionsForClip = actionsByClip[ clipUuid ], - knownActionsForClip = actionsForClip.knownActions, + ] - lastKnownAction = - knownActionsForClip[ knownActionsForClip.length - 1 ], + ], - byClipCacheIndex = action._byClipCacheIndex; + getValue: function getValue_unbound( targetArray, offset ) { - lastKnownAction._byClipCacheIndex = byClipCacheIndex; - knownActionsForClip[ byClipCacheIndex ] = lastKnownAction; - knownActionsForClip.pop(); + this.bind(); + this.getValue( targetArray, offset ); - action._byClipCacheIndex = null; + // 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. + }, - var actionByRoot = actionsForClip.actionByRoot, - rootUuid = ( action._localRoot || this._root ).uuid; + setValue: function getValue_unbound( sourceArray, offset ) { - delete actionByRoot[ rootUuid ]; + this.bind(); + this.setValue( sourceArray, offset ); - if ( knownActionsForClip.length === 0 ) { + }, - delete actionsByClip[ clipUuid ]; + // create getter / setter pair for a property in the scene graph + bind: function () { - } + var targetObject = this.node, + parsedPath = this.parsedPath, - this._removeInactiveBindingsForAction( action ); + objectName = parsedPath.objectName, + propertyName = parsedPath.propertyName, + propertyIndex = parsedPath.propertyIndex; - }, + if ( ! targetObject ) { - _removeInactiveBindingsForAction: function ( action ) { + targetObject = PropertyBinding.findNode( this.rootNode, parsedPath.nodeName ) || this.rootNode; - var bindings = action._propertyBindings; - for ( var i = 0, n = bindings.length; i !== n; ++ i ) { + this.node = targetObject; - var binding = bindings[ i ]; + } - if ( -- binding.referenceCount === 0 ) { + // set fail state so we can just 'return' on error + this.getValue = this._getValue_unavailable; + this.setValue = this._setValue_unavailable; - this._removeInactiveBinding( binding ); + // ensure there is a value node + if ( ! targetObject ) { - } + console.error( 'THREE.PropertyBinding: Trying to update node for track: ' + this.path + ' but it wasn\'t found.' ); + return; } - }, + if ( objectName ) { - _lendAction: function ( action ) { + var objectIndex = parsedPath.objectIndex; - // [ active actions | inactive actions ] - // [ active actions >| inactive actions ] - // s a - // <-swap-> - // a s + // special cases were we need to reach deeper into the hierarchy to get the face materials.... + switch ( objectName ) { - var actions = this._actions, - prevIndex = action._cacheIndex, + case 'materials': - lastActiveIndex = this._nActiveActions ++, + if ( ! targetObject.material ) { - firstInactiveAction = actions[ lastActiveIndex ]; + console.error( 'THREE.PropertyBinding: Can not bind to material as node does not have a material.', this ); + return; - action._cacheIndex = lastActiveIndex; - actions[ lastActiveIndex ] = action; + } - firstInactiveAction._cacheIndex = prevIndex; - actions[ prevIndex ] = firstInactiveAction; + 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; - _takeBackAction: function ( action ) { + } - // [ active actions | inactive actions ] - // [ active actions |< inactive actions ] - // a s - // <-swap-> - // s a + targetObject = targetObject.material.materials; - var actions = this._actions, - prevIndex = action._cacheIndex, + break; - firstInactiveIndex = -- this._nActiveActions, + case 'bones': - lastActiveAction = actions[ firstInactiveIndex ]; + if ( ! targetObject.skeleton ) { - action._cacheIndex = firstInactiveIndex; - actions[ firstInactiveIndex ] = action; + console.error( 'THREE.PropertyBinding: Can not bind to bones as node does not have a skeleton.', this ); + return; - lastActiveAction._cacheIndex = prevIndex; - actions[ prevIndex ] = lastActiveAction; + } - }, + // potential future optimization: skip this if propertyIndex is already an integer + // and convert the integer string to a true integer. - // Memory management for PropertyMixer objects + targetObject = targetObject.skeleton.bones; - _addInactiveBinding: function ( binding, rootUuid, trackName ) { + // support resolving morphTarget names into indices. + for ( var i = 0; i < targetObject.length; i ++ ) { - var bindingsByRoot = this._bindingsByRootAndName, - bindingByName = bindingsByRoot[ rootUuid ], + if ( targetObject[ i ].name === objectIndex ) { - bindings = this._bindings; + objectIndex = i; + break; - if ( bindingByName === undefined ) { + } - bindingByName = {}; - bindingsByRoot[ rootUuid ] = bindingByName; + } - } + break; - bindingByName[ trackName ] = binding; + default: - binding._cacheIndex = bindings.length; - bindings.push( binding ); + if ( targetObject[ objectName ] === undefined ) { - }, + console.error( 'THREE.PropertyBinding: Can not bind to objectName of node undefined.', this ); + return; - _removeInactiveBinding: function ( binding ) { + } - var bindings = this._bindings, - propBinding = binding.binding, - rootUuid = propBinding.rootNode.uuid, - trackName = propBinding.path, - bindingsByRoot = this._bindingsByRootAndName, - bindingByName = bindingsByRoot[ rootUuid ], + targetObject = targetObject[ objectName ]; - lastInactiveBinding = bindings[ bindings.length - 1 ], - cacheIndex = binding._cacheIndex; + } - lastInactiveBinding._cacheIndex = cacheIndex; - bindings[ cacheIndex ] = lastInactiveBinding; - bindings.pop(); - delete bindingByName[ trackName ]; + if ( objectIndex !== undefined ) { - remove_empty_map: { + if ( targetObject[ objectIndex ] === undefined ) { - for ( var _ in bindingByName ) break remove_empty_map; // eslint-disable-line no-unused-vars + console.error( 'THREE.PropertyBinding: Trying to bind to objectIndex of objectName, but is undefined.', this, targetObject ); + return; - delete bindingsByRoot[ rootUuid ]; + } - } + targetObject = targetObject[ objectIndex ]; - }, + } - _lendBinding: function ( binding ) { + } - var bindings = this._bindings, - prevIndex = binding._cacheIndex, + // resolve property + var nodeProperty = targetObject[ propertyName ]; - lastActiveIndex = this._nActiveBindings ++, + if ( nodeProperty === undefined ) { - firstInactiveBinding = bindings[ lastActiveIndex ]; + var nodeName = parsedPath.nodeName; - binding._cacheIndex = lastActiveIndex; - bindings[ lastActiveIndex ] = binding; + console.error( 'THREE.PropertyBinding: Trying to update property for track: ' + nodeName + + '.' + propertyName + ' but it wasn\'t found.', targetObject ); + return; - firstInactiveBinding._cacheIndex = prevIndex; - bindings[ prevIndex ] = firstInactiveBinding; + } - }, + // determine versioning scheme + var versioning = this.Versioning.None; - _takeBackBinding: function ( binding ) { + this.targetObject = targetObject; - var bindings = this._bindings, - prevIndex = binding._cacheIndex, + if ( targetObject.needsUpdate !== undefined ) { // material - firstInactiveIndex = -- this._nActiveBindings, + versioning = this.Versioning.NeedsUpdate; - lastActiveBinding = bindings[ firstInactiveIndex ]; + } else if ( targetObject.matrixWorldNeedsUpdate !== undefined ) { // node transform - binding._cacheIndex = firstInactiveIndex; - bindings[ firstInactiveIndex ] = binding; + versioning = this.Versioning.MatrixWorldNeedsUpdate; - lastActiveBinding._cacheIndex = prevIndex; - bindings[ prevIndex ] = lastActiveBinding; + } - }, + // determine how the property gets bound + var bindingType = this.BindingType.Direct; + if ( propertyIndex !== undefined ) { - // Memory management of Interpolants for weight and time scale + // access a sub element of the property array (only primitives are supported right now) - _lendControlInterpolant: function () { + if ( propertyName === "morphTargetInfluences" ) { - var interpolants = this._controlInterpolants, - lastActiveIndex = this._nActiveControlInterpolants ++, - interpolant = interpolants[ lastActiveIndex ]; + // potential optimization, skip this if propertyIndex is already an integer, and convert the integer string to a true integer. - if ( interpolant === undefined ) { + // support resolving morphTarget names into indices. + if ( ! targetObject.geometry ) { - interpolant = new LinearInterpolant( - new Float32Array( 2 ), new Float32Array( 2 ), - 1, this._controlInterpolantsResultBuffer ); + console.error( 'THREE.PropertyBinding: Can not bind to morphTargetInfluences because node does not have a geometry.', this ); + return; - interpolant.__cacheIndex = lastActiveIndex; - interpolants[ lastActiveIndex ] = interpolant; + } - } + if ( targetObject.geometry.isBufferGeometry ) { - return interpolant; + if ( ! targetObject.geometry.morphAttributes ) { - }, + console.error( 'THREE.PropertyBinding: Can not bind to morphTargetInfluences because node does not have a geometry.morphAttributes.', this ); + return; - _takeBackControlInterpolant: function ( interpolant ) { + } - var interpolants = this._controlInterpolants, - prevIndex = interpolant.__cacheIndex, + for ( var i = 0; i < this.node.geometry.morphAttributes.position.length; i ++ ) { - firstInactiveIndex = -- this._nActiveControlInterpolants, + if ( targetObject.geometry.morphAttributes.position[ i ].name === propertyIndex ) { - lastActiveInterpolant = interpolants[ firstInactiveIndex ]; + propertyIndex = i; + break; - interpolant.__cacheIndex = firstInactiveIndex; - interpolants[ firstInactiveIndex ] = interpolant; + } - lastActiveInterpolant.__cacheIndex = prevIndex; - interpolants[ prevIndex ] = lastActiveInterpolant; + } - }, - _controlInterpolantsResultBuffer: new Float32Array( 1 ), + } else { - // 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 ) { + if ( ! targetObject.geometry.morphTargets ) { - var root = optionalRoot || this._root, - rootUuid = root.uuid, + console.error( 'THREE.PropertyBinding: Can not bind to morphTargetInfluences because node does not have a geometry.morphTargets.', this ); + return; - clipObject = typeof clip === 'string' ? - AnimationClip.findByName( root, clip ) : clip, + } - clipUuid = clipObject !== null ? clipObject.uuid : clip, + for ( var i = 0; i < this.node.geometry.morphTargets.length; i ++ ) { - actionsForClip = this._actionsByClip[ clipUuid ], - prototypeAction = null; + if ( targetObject.geometry.morphTargets[ i ].name === propertyIndex ) { - if ( actionsForClip !== undefined ) { + propertyIndex = i; + break; - var existingAction = - actionsForClip.actionByRoot[ rootUuid ]; + } - if ( existingAction !== undefined ) { + } - return existingAction; + } } - // we know the clip, so we don't have to parse all - // the bindings again but can just copy - prototypeAction = actionsForClip.knownActions[ 0 ]; - - // also, take the clip from the prototype action - if ( clipObject === null ) - clipObject = prototypeAction._clip; - - } - - // clip must be known when specified via string - if ( clipObject === null ) return null; - - // allocate all resources required to run it - var newAction = new AnimationAction( this, clipObject, optionalRoot ); - - this._bindAction( newAction, prototypeAction ); + bindingType = this.BindingType.ArrayElement; - // and make the action known to the memory manager - this._addInactiveAction( newAction, clipUuid, rootUuid ); + this.resolvedProperty = nodeProperty; + this.propertyIndex = propertyIndex; - return newAction; + } else if ( nodeProperty.fromArray !== undefined && nodeProperty.toArray !== undefined ) { - }, + // must use copy for Object3D.Euler/Quaternion - // get an existing action - existingAction: function ( clip, optionalRoot ) { + bindingType = this.BindingType.HasFromToArray; - var root = optionalRoot || this._root, - rootUuid = root.uuid, + this.resolvedProperty = nodeProperty; - clipObject = typeof clip === 'string' ? - AnimationClip.findByName( root, clip ) : clip, + } else if ( Array.isArray( nodeProperty ) ) { - clipUuid = clipObject ? clipObject.uuid : clip, + bindingType = this.BindingType.EntireArray; - actionsForClip = this._actionsByClip[ clipUuid ]; + this.resolvedProperty = nodeProperty; - if ( actionsForClip !== undefined ) { + } else { - return actionsForClip.actionByRoot[ rootUuid ] || null; + this.propertyName = propertyName; } - return null; + // select getter / setter + this.getValue = this.GetterByBindingType[ bindingType ]; + this.setValue = this.SetterByBindingTypeAndVersioning[ bindingType ][ versioning ]; }, - // deactivates all previously scheduled actions - stopAllAction: function () { + unbind: function () { - var actions = this._actions, - nActions = this._nActiveActions, - bindings = this._bindings, - nBindings = this._nActiveBindings; + this.node = null; - this._nActiveActions = 0; - this._nActiveBindings = 0; + // 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 i = 0; i !== nActions; ++ i ) { + } - actions[ i ].reset(); +} ); - } +//!\ DECLARE ALIAS AFTER assign prototype ! +Object.assign( PropertyBinding.prototype, { - for ( var i = 0; i !== nBindings; ++ i ) { + // initial state of these methods that calls 'bind' + _getValue_unbound: PropertyBinding.prototype.getValue, + _setValue_unbound: PropertyBinding.prototype.setValue, - bindings[ i ].useCount = 0; +} ); - } +/** + * + * 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 + */ - return this; +function AnimationObjectGroup() { - }, + this.uuid = _Math.generateUUID(); - // advance the time and update apply the animation - update: function ( deltaTime ) { + // cached objects followed by the active ones + this._objects = Array.prototype.slice.call( arguments ); - deltaTime *= this.timeScale; + this.nCachedObjects_ = 0; // threshold + // note: read by PropertyBinding.Composite - var actions = this._actions, - nActions = this._nActiveActions, + var indices = {}; + this._indicesByUUID = indices; // for bookkeeping - time = this.time += deltaTime, - timeDirection = Math.sign( deltaTime ), + for ( var i = 0, n = arguments.length; i !== n; ++ i ) { - accuIndex = this._accuIndex ^= 1; + indices[ arguments[ i ].uuid ] = i; - // run active actions + } - for ( var i = 0; i !== nActions; ++ 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 action = actions[ i ]; + var scope = this; - action._update( time, deltaTime, timeDirection, accuIndex ); + this.stats = { - } + objects: { + get total() { - // update scene graph + return scope._objects.length; - var bindings = this._bindings, - nBindings = this._nActiveBindings; + }, + get inUse() { - for ( var i = 0; i !== nBindings; ++ i ) { + return this.total - scope.nCachedObjects_; - bindings[ i ].apply( accuIndex ); + } + }, + get bindingsPerObject() { + + return scope._bindings.length; } - return this; + }; - }, +} - // return this mixer's root target object - getRoot: function () { +Object.assign( AnimationObjectGroup.prototype, { - return this._root; + isAnimationObjectGroup: true, - }, + add: function () { - // free all resources specific to a particular clip - uncacheClip: function ( clip ) { + 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; - var actions = this._actions, - clipUuid = clip.uuid, - actionsByClip = this._actionsByClip, - actionsForClip = actionsByClip[ clipUuid ]; + for ( var i = 0, n = arguments.length; i !== n; ++ i ) { - if ( actionsForClip !== undefined ) { + var object = arguments[ i ], + uuid = object.uuid, + index = indicesByUUID[ uuid ]; - // note: just calling _removeInactiveAction would mess up the - // iteration state and also require updating the state we can - // just throw away + if ( index === undefined ) { - var actionsToRemove = actionsForClip.knownActions; + // unknown object -> add it to the ACTIVE region - for ( var i = 0, n = actionsToRemove.length; i !== n; ++ i ) { + index = nObjects ++; + indicesByUUID[ uuid ] = index; + objects.push( object ); - var action = actionsToRemove[ i ]; + // accounting is done, now do the same for all bindings - this._deactivateAction( action ); + for ( var j = 0, m = nBindings; j !== m; ++ j ) { - var cacheIndex = action._cacheIndex, - lastInactiveAction = actions[ actions.length - 1 ]; + bindings[ j ].push( new PropertyBinding( object, paths[ j ], parsedPaths[ j ] ) ); - action._cacheIndex = null; - action._byClipCacheIndex = null; + } - lastInactiveAction._cacheIndex = cacheIndex; - actions[ cacheIndex ] = lastInactiveAction; - actions.pop(); + } else if ( index < nCachedObjects ) { - this._removeInactiveBindingsForAction( action ); + knownObject = objects[ index ]; - } + // move existing object to the ACTIVE region - delete actionsByClip[ clipUuid ]; + var firstActiveIndex = -- nCachedObjects, + lastCachedObject = objects[ firstActiveIndex ]; - } + indicesByUUID[ lastCachedObject.uuid ] = index; + objects[ index ] = lastCachedObject; - }, + indicesByUUID[ uuid ] = firstActiveIndex; + objects[ firstActiveIndex ] = object; - // free all resources specific to a particular root target object - uncacheRoot: function ( root ) { + // accounting is done, now do the same for all bindings - var rootUuid = root.uuid, - actionsByClip = this._actionsByClip; + for ( var j = 0, m = nBindings; j !== m; ++ j ) { - for ( var clipUuid in actionsByClip ) { + var bindingsForPath = bindings[ j ], + lastCached = bindingsForPath[ firstActiveIndex ], + binding = bindingsForPath[ index ]; - var actionByRoot = actionsByClip[ clipUuid ].actionByRoot, - action = actionByRoot[ rootUuid ]; + bindingsForPath[ index ] = lastCached; - if ( action !== undefined ) { + if ( binding === undefined ) { - this._deactivateAction( action ); - this._removeInactiveAction( action ); + // since we do not bother to create new bindings + // for objects that are cached, the binding may + // or may not exist - } + binding = new PropertyBinding( object, paths[ j ], parsedPaths[ j ] ); - } + } - var bindingsByRoot = this._bindingsByRootAndName, - bindingByName = bindingsByRoot[ rootUuid ]; + bindingsForPath[ firstActiveIndex ] = binding; - if ( bindingByName !== undefined ) { + } - for ( var trackName in bindingByName ) { + } else if ( objects[ index ] !== knownObject ) { - var binding = bindingByName[ trackName ]; - binding.restoreOriginalState(); - this._removeInactiveBinding( binding ); + console.error( 'THREE.AnimationObjectGroup: Different objects with the same UUID ' + + 'detected. Clean the caches or recreate your infrastructure when reloading scenes.' ); - } + } // else the object is already where we want it to be - } + } // for arguments + + this.nCachedObjects_ = nCachedObjects; }, - // remove a targeted clip from the cache - uncacheAction: function ( clip, optionalRoot ) { + remove: function () { - var action = this.existingAction( clip, optionalRoot ); + var objects = this._objects, + nCachedObjects = this.nCachedObjects_, + indicesByUUID = this._indicesByUUID, + bindings = this._bindings, + nBindings = bindings.length; - if ( action !== null ) { + for ( var i = 0, n = arguments.length; i !== n; ++ i ) { - this._deactivateAction( action ); - this._removeInactiveAction( action ); + var object = arguments[ i ], + uuid = object.uuid, + index = indicesByUUID[ uuid ]; - } + if ( index !== undefined && index >= nCachedObjects ) { - } + // move existing object into the CACHED region -} ); + var lastCachedIndex = nCachedObjects ++, + firstActiveObject = objects[ lastCachedIndex ]; -/** - * @author mrdoob / http://mrdoob.com/ - */ + indicesByUUID[ firstActiveObject.uuid ] = index; + objects[ index ] = firstActiveObject; -function Uniform( value ) { + indicesByUUID[ uuid ] = lastCachedIndex; + objects[ lastCachedIndex ] = object; - if ( typeof value === 'string' ) { + // accounting is done, now do the same for all bindings - console.warn( 'THREE.Uniform: Type parameter is no longer needed.' ); - value = arguments[ 1 ]; + for ( var j = 0, m = nBindings; j !== m; ++ j ) { - } + var bindingsForPath = bindings[ j ], + firstActive = bindingsForPath[ lastCachedIndex ], + binding = bindingsForPath[ index ]; - this.value = value; + bindingsForPath[ index ] = firstActive; + bindingsForPath[ lastCachedIndex ] = binding; -} + } -Uniform.prototype.clone = function () { + } - return new Uniform( this.value.clone === undefined ? this.value : this.value.clone() ); + } // for arguments -}; + this.nCachedObjects_ = nCachedObjects; -/** - * @author benaadams / https://twitter.com/ben_a_adams - */ + }, -function InstancedBufferGeometry() { + // remove & forget + uncache: function () { - BufferGeometry.call( this ); + var objects = this._objects, + nObjects = objects.length, + nCachedObjects = this.nCachedObjects_, + indicesByUUID = this._indicesByUUID, + bindings = this._bindings, + nBindings = bindings.length; - this.type = 'InstancedBufferGeometry'; - this.maxInstancedCount = undefined; + for ( var i = 0, n = arguments.length; i !== n; ++ i ) { -} + var object = arguments[ i ], + uuid = object.uuid, + index = indicesByUUID[ uuid ]; -InstancedBufferGeometry.prototype = Object.assign( Object.create( BufferGeometry.prototype ), { + if ( index !== undefined ) { - constructor: InstancedBufferGeometry, + delete indicesByUUID[ uuid ]; - isInstancedBufferGeometry: true, + if ( index < nCachedObjects ) { - copy: function ( source ) { + // object is cached, shrink the CACHED region - BufferGeometry.prototype.copy.call( this, source ); + var firstActiveIndex = -- nCachedObjects, + lastCachedObject = objects[ firstActiveIndex ], + lastIndex = -- nObjects, + lastObject = objects[ lastIndex ]; - this.maxInstancedCount = source.maxInstancedCount; + // last cached object takes this object's place + indicesByUUID[ lastCachedObject.uuid ] = index; + objects[ index ] = lastCachedObject; - return this; + // last object goes to the activated slot and pop + indicesByUUID[ lastObject.uuid ] = firstActiveIndex; + objects[ firstActiveIndex ] = lastObject; + objects.pop(); - }, + // accounting is done, now do the same for all bindings - clone: function () { + for ( var j = 0, m = nBindings; j !== m; ++ j ) { - return new this.constructor().copy( this ); + var bindingsForPath = bindings[ j ], + lastCached = bindingsForPath[ firstActiveIndex ], + last = bindingsForPath[ lastIndex ]; - } + bindingsForPath[ index ] = lastCached; + bindingsForPath[ firstActiveIndex ] = last; + bindingsForPath.pop(); -} ); + } -/** - * @author benaadams / https://twitter.com/ben_a_adams - */ + } else { -function InterleavedBufferAttribute( interleavedBuffer, itemSize, offset, normalized ) { + // object is active, just swap with the last and pop - this.uuid = _Math.generateUUID(); + var lastIndex = -- nObjects, + lastObject = objects[ lastIndex ]; - this.data = interleavedBuffer; - this.itemSize = itemSize; - this.offset = offset; + indicesByUUID[ lastObject.uuid ] = index; + objects[ index ] = lastObject; + objects.pop(); - this.normalized = normalized === true; + // accounting is done, now do the same for all bindings -} + for ( var j = 0, m = nBindings; j !== m; ++ j ) { -Object.defineProperties( InterleavedBufferAttribute.prototype, { + var bindingsForPath = bindings[ j ]; - count: { + bindingsForPath[ index ] = bindingsForPath[ lastIndex ]; + bindingsForPath.pop(); - get: function () { + } - return this.data.count; + } // cached or active - } + } // if object is known - }, + } // for arguments - array: { + this.nCachedObjects_ = nCachedObjects; - get: function () { + }, - return this.data.array; + // Internal interface used by befriended PropertyBinding.Composite: - } + subscribe_: function ( path, parsedPath ) { - } + // 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; -Object.assign( InterleavedBufferAttribute.prototype, { + if ( index !== undefined ) return bindings[ index ]; - isInterleavedBufferAttribute: true, + var paths = this._paths, + parsedPaths = this._parsedPaths, + objects = this._objects, + nObjects = objects.length, + nCachedObjects = this.nCachedObjects_, + bindingsForPath = new Array( nObjects ); - setX: function ( index, x ) { + index = bindings.length; - this.data.array[ index * this.data.stride + this.offset ] = x; + indicesByPath[ path ] = index; - return this; + paths.push( path ); + parsedPaths.push( parsedPath ); + bindings.push( bindingsForPath ); - }, + for ( var i = nCachedObjects, n = objects.length; i !== n; ++ i ) { - setY: function ( index, y ) { + var object = objects[ i ]; + bindingsForPath[ i ] = new PropertyBinding( object, path, parsedPath ); - this.data.array[ index * this.data.stride + this.offset + 1 ] = y; + } - return this; + return bindingsForPath; }, - setZ: function ( index, z ) { - - this.data.array[ index * this.data.stride + this.offset + 2 ] = z; + unsubscribe_: function ( path ) { - return this; + // tells the group to forget about a property path and no longer + // update the array previously obtained with 'subscribe_' - }, + var indicesByPath = this._bindingsIndicesByPath, + index = indicesByPath[ path ]; - setW: function ( index, w ) { + if ( index !== undefined ) { - this.data.array[ index * this.data.stride + this.offset + 3 ] = w; + var paths = this._paths, + parsedPaths = this._parsedPaths, + bindings = this._bindings, + lastBindingsIndex = bindings.length - 1, + lastBindings = bindings[ lastBindingsIndex ], + lastBindingsPath = path[ lastBindingsIndex ]; - return this; + indicesByPath[ lastBindingsPath ] = index; - }, + bindings[ index ] = lastBindings; + bindings.pop(); - getX: function ( index ) { + parsedPaths[ index ] = parsedPaths[ lastBindingsIndex ]; + parsedPaths.pop(); - return this.data.array[ index * this.data.stride + this.offset ]; + paths[ index ] = paths[ lastBindingsIndex ]; + paths.pop(); - }, + } - getY: function ( index ) { + } - return this.data.array[ index * this.data.stride + this.offset + 1 ]; +} ); - }, +/** + * + * 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 + * + */ - getZ: function ( index ) { +function AnimationAction( mixer, clip, localRoot ) { - return this.data.array[ index * this.data.stride + this.offset + 2 ]; + this._mixer = mixer; + this._clip = clip; + this._localRoot = localRoot || null; - }, + var tracks = clip.tracks, + nTracks = tracks.length, + interpolants = new Array( nTracks ); - getW: function ( index ) { + var interpolantSettings = { + endingStart: ZeroCurvatureEnding, + endingEnd: ZeroCurvatureEnding + }; - return this.data.array[ index * this.data.stride + this.offset + 3 ]; + for ( var i = 0; i !== nTracks; ++ i ) { - }, + var interpolant = tracks[ i ].createInterpolant( null ); + interpolants[ i ] = interpolant; + interpolant.settings = interpolantSettings; - setXY: function ( index, x, y ) { + } - index = index * this.data.stride + this.offset; + this._interpolantSettings = interpolantSettings; - this.data.array[ index + 0 ] = x; - this.data.array[ index + 1 ] = y; + this._interpolants = interpolants; // bound by the mixer - return this; + // 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 - setXYZ: function ( index, x, y, z ) { + this._timeScaleInterpolant = null; + this._weightInterpolant = null; - index = index * this.data.stride + this.offset; + this.loop = LoopRepeat; + this._loopCount = - 1; - this.data.array[ index + 0 ] = x; - this.data.array[ index + 1 ] = y; - this.data.array[ index + 2 ] = z; + // global mixer time when the action is to be started + // it's set back to 'null' upon start of the action + this._startTime = null; - return this; + // 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; - setXYZW: function ( index, x, y, z, w ) { + this.weight = 1; + this._effectiveWeight = 1; - index = index * this.data.stride + this.offset; + this.repetitions = Infinity; // no. of repetitions when looping - 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.paused = false; // true -> zero effective time scale + this.enabled = true; // false -> zero effective weight - return this; + this.clampWhenFinished = false;// keep feeding the last frame? - } + this.zeroSlopeAtStart = true;// for smooth interpolation w/o separate + this.zeroSlopeAtEnd = true;// clips for start, loop and end -} ); +} -/** - * @author benaadams / https://twitter.com/ben_a_adams - */ +Object.assign( AnimationAction.prototype, { -function InterleavedBuffer( array, stride ) { + // State & Scheduling - this.uuid = _Math.generateUUID(); + play: function () { - this.array = array; - this.stride = stride; - this.count = array !== undefined ? array.length / stride : 0; + this._mixer._activateAction( this ); - this.dynamic = false; - this.updateRange = { offset: 0, count: - 1 }; + return this; - this.onUploadCallback = function () {}; + }, - this.version = 0; + stop: function () { -} + this._mixer._deactivateAction( this ); -Object.defineProperty( InterleavedBuffer.prototype, 'needsUpdate', { + return this.reset(); - set: function ( value ) { + }, - if ( value === true ) this.version ++; + reset: function () { - } + this.paused = false; + this.enabled = true; -} ); + this.time = 0; // restart clip + this._loopCount = - 1;// forget previous loops + this._startTime = null;// forget scheduling -Object.assign( InterleavedBuffer.prototype, { + return this.stopFading().stopWarping(); - isInterleavedBuffer: true, + }, - setArray: function ( array ) { + isRunning: function () { - if ( Array.isArray( array ) ) { + return this.enabled && ! this.paused && this.timeScale !== 0 && + this._startTime === null && this._mixer._isActiveAction( this ); - throw new TypeError( 'THREE.BufferAttribute: array should be a Typed Array.' ); + }, - } + // return true when play has been called + isScheduled: function () { - this.count = array !== undefined ? array.length / this.stride : 0; - this.array = array; + return this._mixer._isActiveAction( this ); }, - setDynamic: function ( value ) { + startAt: function ( time ) { - this.dynamic = value; + this._startTime = time; return this; }, - copy: function ( source ) { + setLoop: function ( mode, repetitions ) { - this.array = new source.array.constructor( source.array ); - this.count = source.count; - this.stride = source.stride; - this.dynamic = source.dynamic; + this.loop = mode; + this.repetitions = repetitions; return this; }, - copyAt: function ( index1, attribute, index2 ) { - - index1 *= this.stride; - index2 *= attribute.stride; + // Weight - for ( var i = 0, l = this.stride; i < l; i ++ ) { + // 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.array[ index1 + i ] = attribute.array[ index2 + i ]; + this.weight = weight; - } + // note: same logic as when updated at runtime + this._effectiveWeight = this.enabled ? weight : 0; - return this; + return this.stopFading(); }, - set: function ( value, offset ) { + // return the weight considering fading and .enabled + getEffectiveWeight: function () { - if ( offset === undefined ) offset = 0; + return this._effectiveWeight; - this.array.set( value, offset ); + }, - return this; + fadeIn: function ( duration ) { + + return this._scheduleFading( duration, 0, 1 ); }, - clone: function () { + fadeOut: function ( duration ) { - return new this.constructor().copy( this ); + return this._scheduleFading( duration, 1, 0 ); }, - onUpload: function ( callback ) { + crossFadeFrom: function ( fadeOutAction, duration, warp ) { - this.onUploadCallback = callback; + fadeOutAction.fadeOut( duration ); + this.fadeIn( duration ); - return this; + if ( warp ) { - } + var fadeInDuration = this._clip.duration, + fadeOutDuration = fadeOutAction._clip.duration, -} ); + startEndRatio = fadeOutDuration / fadeInDuration, + endStartRatio = fadeInDuration / fadeOutDuration; -/** - * @author benaadams / https://twitter.com/ben_a_adams - */ + fadeOutAction.warp( 1.0, startEndRatio, duration ); + this.warp( endStartRatio, 1.0, duration ); -function InstancedInterleavedBuffer( array, stride, meshPerAttribute ) { + } - InterleavedBuffer.call( this, array, stride ); + return this; - this.meshPerAttribute = meshPerAttribute || 1; + }, -} + crossFadeTo: function ( fadeInAction, duration, warp ) { -InstancedInterleavedBuffer.prototype = Object.assign( Object.create( InterleavedBuffer.prototype ), { + return fadeInAction.crossFadeFrom( this, duration, warp ); - constructor: InstancedInterleavedBuffer, + }, - isInstancedInterleavedBuffer: true, + stopFading: function () { - copy: function ( source ) { + var weightInterpolant = this._weightInterpolant; - InterleavedBuffer.prototype.copy.call( this, source ); + if ( weightInterpolant !== null ) { - this.meshPerAttribute = source.meshPerAttribute; + this._weightInterpolant = null; + this._mixer._takeBackControlInterpolant( weightInterpolant ); + + } return this; - } + }, -} ); + // Time Scale Control -/** - * @author benaadams / https://twitter.com/ben_a_adams - */ + // 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 ) { -function InstancedBufferAttribute( array, itemSize, meshPerAttribute ) { + this.timeScale = timeScale; + this._effectiveTimeScale = this.paused ? 0 : timeScale; - BufferAttribute.call( this, array, itemSize ); + return this.stopWarping(); - this.meshPerAttribute = meshPerAttribute || 1; + }, -} + // return the time scale considering warping and .paused + getEffectiveTimeScale: function () { -InstancedBufferAttribute.prototype = Object.assign( Object.create( BufferAttribute.prototype ), { + return this._effectiveTimeScale; - constructor: InstancedBufferAttribute, + }, - isInstancedBufferAttribute: true, + setDuration: function ( duration ) { - copy: function ( source ) { + this.timeScale = this._clip.duration / duration; - BufferAttribute.prototype.copy.call( this, source ); + return this.stopWarping(); - this.meshPerAttribute = source.meshPerAttribute; + }, - return this; + syncWith: function ( action ) { - } + this.time = action.time; + this.timeScale = action.timeScale; -} ); + return this.stopWarping(); -/** - * @author mrdoob / http://mrdoob.com/ - * @author bhouston / http://clara.io/ - * @author stephomi / http://stephaneginier.com/ - */ + }, -function Raycaster( origin, direction, near, far ) { + halt: function ( duration ) { - this.ray = new Ray( origin, direction ); - // direction is assumed to be normalized (for accurate distance calculations) + return this.warp( this._effectiveTimeScale, 0, duration ); - this.near = near || 0; - this.far = far || Infinity; + }, - this.params = { - Mesh: {}, - Line: {}, - LOD: {}, - Points: { threshold: 1 }, - Sprite: {} - }; + warp: function ( startTimeScale, endTimeScale, duration ) { - Object.defineProperties( this.params, { - PointCloud: { - get: function () { + var mixer = this._mixer, now = mixer.time, + interpolant = this._timeScaleInterpolant, - console.warn( 'THREE.Raycaster: params.PointCloud has been renamed to params.Points.' ); - return this.Points; + timeScale = this.timeScale; - } - } - } ); + if ( interpolant === null ) { -} + interpolant = mixer._lendControlInterpolant(); + this._timeScaleInterpolant = interpolant; -function ascSort( a, b ) { + } - return a.distance - b.distance; + var times = interpolant.parameterPositions, + values = interpolant.sampleValues; -} + times[ 0 ] = now; + times[ 1 ] = now + duration; -function intersectObject( object, raycaster, intersects, recursive ) { + values[ 0 ] = startTimeScale / timeScale; + values[ 1 ] = endTimeScale / timeScale; - if ( object.visible === false ) return; + return this; - object.raycast( raycaster, intersects ); + }, - if ( recursive === true ) { + stopWarping: function () { - var children = object.children; + var timeScaleInterpolant = this._timeScaleInterpolant; - for ( var i = 0, l = children.length; i < l; i ++ ) { + if ( timeScaleInterpolant !== null ) { - intersectObject( children[ i ], raycaster, intersects, true ); + this._timeScaleInterpolant = null; + this._mixer._takeBackControlInterpolant( timeScaleInterpolant ); } - } + return this; -} + }, -Object.assign( Raycaster.prototype, { + // Object Accessors - linePrecision: 1, + getMixer: function () { - set: function ( origin, direction ) { + return this._mixer; - // direction is assumed to be normalized (for accurate distance calculations) + }, - this.ray.set( origin, direction ); + getClip: function () { + + return this._clip; }, - setFromCamera: function ( coords, camera ) { + getRoot: function () { - if ( ( camera && camera.isPerspectiveCamera ) ) { + return this._localRoot || this._mixer._root; - 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 ) ) { + // Interna - 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 ); + _update: function ( time, deltaTime, timeDirection, accuIndex ) { - } else { + // called by the mixer - console.error( 'THREE.Raycaster: Unsupported camera type.' ); + if ( ! this.enabled ) { - } + // call ._updateWeight() to update ._effectiveWeight - }, + this._updateWeight( time ); + return; - intersectObject: function ( object, recursive ) { + } - var intersects = []; + var startTime = this._startTime; - intersectObject( object, this, intersects, recursive ); + if ( startTime !== null ) { - intersects.sort( ascSort ); - - return intersects; + // check for scheduled start of action - }, + var timeRunning = ( time - startTime ) * timeDirection; + if ( timeRunning < 0 || timeDirection === 0 ) { - intersectObjects: function ( objects, recursive ) { + return; // yet to come / don't decide when delta = 0 - var intersects = []; + } - if ( Array.isArray( objects ) === false ) { + // start - console.warn( 'THREE.Raycaster.intersectObjects: objects is not an Array.' ); - return intersects; + this._startTime = null; // unschedule + deltaTime = timeDirection * timeRunning; } - for ( var i = 0, l = objects.length; i < l; i ++ ) { + // apply time scale and advance time - intersectObject( objects[ i ], this, intersects, recursive ); + deltaTime *= this._updateTimeScale( time ); + var clipTime = this._updateTime( deltaTime ); - } + // note: _updateTime may disable the action resulting in + // an effective weight of 0 - intersects.sort( ascSort ); + var weight = this._updateWeight( time ); - return intersects; + if ( weight > 0 ) { - } + var interpolants = this._interpolants; + var propertyMixers = this._propertyBindings; -} ); + for ( var j = 0, m = interpolants.length; j !== m; ++ j ) { -/** - * @author alteredq / http://alteredqualia.com/ - */ + interpolants[ j ].evaluate( clipTime ); + propertyMixers[ j ].accumulate( accuIndex, weight ); -function Clock( autoStart ) { + } - this.autoStart = ( autoStart !== undefined ) ? autoStart : true; + } - this.startTime = 0; - this.oldTime = 0; - this.elapsedTime = 0; + }, - this.running = false; + _updateWeight: function ( time ) { -} + var weight = 0; -Object.assign( Clock.prototype, { + if ( this.enabled ) { - start: function () { + weight = this.weight; + var interpolant = this._weightInterpolant; - this.startTime = ( typeof performance === 'undefined' ? Date : performance ).now(); // see #10732 + if ( interpolant !== null ) { - this.oldTime = this.startTime; - this.elapsedTime = 0; - this.running = true; + var interpolantValue = interpolant.evaluate( time )[ 0 ]; - }, + weight *= interpolantValue; - stop: function () { + if ( time > interpolant.parameterPositions[ 1 ] ) { - this.getElapsedTime(); - this.running = false; - this.autoStart = false; + this.stopFading(); - }, + if ( interpolantValue === 0 ) { - getElapsedTime: function () { + // faded out, disable + this.enabled = false; - this.getDelta(); - return this.elapsedTime; + } - }, + } - getDelta: function () { + } - var diff = 0; + } - if ( this.autoStart && ! this.running ) { + this._effectiveWeight = weight; + return weight; - this.start(); - return 0; + }, - } + _updateTimeScale: function ( time ) { - if ( this.running ) { + var timeScale = 0; - var newTime = ( typeof performance === 'undefined' ? Date : performance ).now(); + if ( ! this.paused ) { - diff = ( newTime - this.oldTime ) / 1000; - this.oldTime = newTime; + timeScale = this.timeScale; - this.elapsedTime += diff; + var interpolant = this._timeScaleInterpolant; - } + if ( interpolant !== null ) { - return diff; + var interpolantValue = interpolant.evaluate( time )[ 0 ]; - } + timeScale *= interpolantValue; -} ); + if ( time > interpolant.parameterPositions[ 1 ] ) { -/** - * @author bhouston / http://clara.io - * @author WestLangley / http://github.com/WestLangley - * - * Ref: https://en.wikipedia.org/wiki/Spherical_coordinate_system - * - * The poles (phi) are at the positive and negative y axis. - * The equator starts at positive z. - */ + this.stopWarping(); -function Spherical( radius, phi, theta ) { + if ( timeScale === 0 ) { - this.radius = ( radius !== undefined ) ? radius : 1.0; - this.phi = ( phi !== undefined ) ? phi : 0; // up / down towards top and bottom pole - this.theta = ( theta !== undefined ) ? theta : 0; // around the equator of the sphere + // motion has halted, pause + this.paused = true; - return this; + } else { -} + // warp done - apply final time scale + this.timeScale = timeScale; -Object.assign( Spherical.prototype, { + } - set: function ( radius, phi, theta ) { + } - this.radius = radius; - this.phi = phi; - this.theta = theta; + } - return this; + } + + this._effectiveTimeScale = timeScale; + return timeScale; }, - clone: function () { + _updateTime: function ( deltaTime ) { - return new this.constructor().copy( this ); + var time = this.time + deltaTime; + var duration = this._clip.duration; + var loop = this.loop; + var loopCount = this._loopCount; - }, + var pingPong = ( loop === LoopPingPong ); - copy: function ( other ) { + if ( deltaTime === 0 ) { - this.radius = other.radius; - this.phi = other.phi; - this.theta = other.theta; + if ( loopCount === - 1 ) return time; - return this; + return ( pingPong && ( loopCount & 1 ) === 1 ) ? duration - time : time; - }, + } - // restrict phi to be betwee EPS and PI-EPS - makeSafe: function () { + if ( loop === LoopOnce ) { - var EPS = 0.000001; - this.phi = Math.max( EPS, Math.min( Math.PI - EPS, this.phi ) ); + if ( loopCount === - 1 ) { - return this; + // just started - }, + this._loopCount = 0; + this._setEndings( true, true, false ); - setFromVector3: function ( vec3 ) { + } - this.radius = vec3.length(); + handle_stop: { - if ( this.radius === 0 ) { + if ( time >= duration ) { - this.theta = 0; - this.phi = 0; + time = duration; - } else { + } else if ( time < 0 ) { - this.theta = Math.atan2( vec3.x, vec3.z ); // equator angle around y-up axis - this.phi = Math.acos( _Math.clamp( vec3.y / this.radius, - 1, 1 ) ); // polar angle + time = 0; - } + } else break handle_stop; - return this; + if ( this.clampWhenFinished ) this.paused = true; + else this.enabled = false; - } + this._mixer.dispatchEvent( { + type: 'finished', action: this, + direction: deltaTime < 0 ? - 1 : 1 + } ); -} ); + } -/** - * @author Mugen87 / https://github.com/Mugen87 - * - * Ref: https://en.wikipedia.org/wiki/Cylindrical_coordinate_system - * - */ + } else { // repetitive Repeat or PingPong -function Cylindrical( radius, theta, y ) { + if ( loopCount === - 1 ) { - 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 + // just started - return this; + if ( deltaTime >= 0 ) { -} + loopCount = 0; -Object.assign( Cylindrical.prototype, { + this._setEndings( true, this.repetitions === 0, pingPong ); - set: function ( radius, theta, y ) { + } else { - this.radius = radius; - this.theta = theta; - this.y = y; + // when looping in reverse direction, the initial + // transition through zero counts as a repetition, + // so leave loopCount at -1 - return this; + this._setEndings( this.repetitions === 0, true, pingPong ); - }, + } - clone: function () { + } - return new this.constructor().copy( this ); + if ( time >= duration || time < 0 ) { - }, + // wrap around - copy: function ( other ) { + var loopDelta = Math.floor( time / duration ); // signed + time -= duration * loopDelta; - this.radius = other.radius; - this.theta = other.theta; - this.y = other.y; + loopCount += Math.abs( loopDelta ); - return this; + var pending = this.repetitions - loopCount; - }, + if ( pending <= 0 ) { - setFromVector3: function ( vec3 ) { + // have to stop (switch state, clamp time, fire event) - this.radius = Math.sqrt( vec3.x * vec3.x + vec3.z * vec3.z ); - this.theta = Math.atan2( vec3.x, vec3.z ); - this.y = vec3.y; + if ( this.clampWhenFinished ) this.paused = true; + else this.enabled = false; - return this; + time = deltaTime > 0 ? duration : 0; - } + this._mixer.dispatchEvent( { + type: 'finished', action: this, + direction: deltaTime > 0 ? 1 : - 1 + } ); -} ); + } else { -/** - * @author bhouston / http://clara.io - */ + // keep running -function Box2( min, max ) { + if ( pending === 1 ) { - this.min = ( min !== undefined ) ? min : new Vector2( + Infinity, + Infinity ); - this.max = ( max !== undefined ) ? max : new Vector2( - Infinity, - Infinity ); + // entering the last round -} + var atStart = deltaTime < 0; + this._setEndings( atStart, ! atStart, pingPong ); -Object.assign( Box2.prototype, { + } else { - set: function ( min, max ) { + this._setEndings( false, false, pingPong ); - this.min.copy( min ); - this.max.copy( max ); + } - return this; + this._loopCount = loopCount; - }, + this._mixer.dispatchEvent( { + type: 'loop', action: this, loopDelta: loopDelta + } ); - setFromPoints: function ( points ) { + } - this.makeEmpty(); + } - for ( var i = 0, il = points.length; i < il; i ++ ) { + if ( pingPong && ( loopCount & 1 ) === 1 ) { - this.expandByPoint( points[ i ] ); + // invert time for the "pong round" + + this.time = time; + return duration - time; + + } } - return this; + this.time = time; + return time; }, - setFromCenterAndSize: function () { + _setEndings: function ( atStart, atEnd, pingPong ) { - var v1 = new Vector2(); + var settings = this._interpolantSettings; - return function setFromCenterAndSize( center, size ) { + if ( pingPong ) { - var halfSize = v1.copy( size ).multiplyScalar( 0.5 ); - this.min.copy( center ).sub( halfSize ); - this.max.copy( center ).add( halfSize ); + settings.endingStart = ZeroSlopeEnding; + settings.endingEnd = ZeroSlopeEnding; - return this; + } else { - }; + // assuming for LoopOnce atStart == atEnd == true - }(), + if ( atStart ) { - clone: function () { + settings.endingStart = this.zeroSlopeAtStart ? ZeroSlopeEnding : ZeroCurvatureEnding; - return new this.constructor().copy( this ); + } else { - }, + settings.endingStart = WrapAroundEnding; - copy: function ( box ) { + } - this.min.copy( box.min ); - this.max.copy( box.max ); + if ( atEnd ) { - return this; + settings.endingEnd = this.zeroSlopeAtEnd ? ZeroSlopeEnding : ZeroCurvatureEnding; - }, + } else { - makeEmpty: function () { + settings.endingEnd = WrapAroundEnding; - this.min.x = this.min.y = + Infinity; - this.max.x = this.max.y = - Infinity; + } - return this; + } }, - isEmpty: function () { + _scheduleFading: function ( duration, weightNow, weightThen ) { - // this is a more robust check for empty than ( volume <= 0 ) because volume can get positive with two negative axes + var mixer = this._mixer, now = mixer.time, + interpolant = this._weightInterpolant; - return ( this.max.x < this.min.x ) || ( this.max.y < this.min.y ); + if ( interpolant === null ) { - }, + interpolant = mixer._lendControlInterpolant(); + this._weightInterpolant = interpolant; - getCenter: function ( optionalTarget ) { + } - var result = optionalTarget || new Vector2(); - return this.isEmpty() ? result.set( 0, 0 ) : result.addVectors( this.min, this.max ).multiplyScalar( 0.5 ); + var times = interpolant.parameterPositions, + values = interpolant.sampleValues; - }, + times[ 0 ] = now; + values[ 0 ] = weightNow; + times[ 1 ] = now + duration; + values[ 1 ] = weightThen; - getSize: function ( optionalTarget ) { + return this; - var result = optionalTarget || new Vector2(); - return this.isEmpty() ? result.set( 0, 0 ) : result.subVectors( this.max, this.min ); + } - }, +} ); - expandByPoint: function ( point ) { +/** + * + * Player for AnimationClips. + * + * + * @author Ben Houston / http://clara.io/ + * @author David Sarno / http://lighthaus.us/ + * @author tschw + */ - this.min.min( point ); - this.max.max( point ); +function AnimationMixer( root ) { - return this; + this._root = root; + this._initMemoryManager(); + this._accuIndex = 0; - }, + this.time = 0; - expandByVector: function ( vector ) { + this.timeScale = 1.0; - this.min.sub( vector ); - this.max.add( vector ); +} - return this; +AnimationMixer.prototype = Object.assign( Object.create( EventDispatcher.prototype ), { - }, + constructor: AnimationMixer, - expandByScalar: function ( scalar ) { + _bindAction: function ( action, prototypeAction ) { - this.min.addScalar( - scalar ); - this.max.addScalar( scalar ); + 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 ]; - return this; + if ( bindingsByName === undefined ) { - }, + bindingsByName = {}; + bindingsByRoot[ rootUuid ] = bindingsByName; - 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; + for ( var i = 0; i !== nTracks; ++ i ) { - }, + var track = tracks[ i ], + trackName = track.name, + binding = bindingsByName[ trackName ]; - containsBox: function ( box ) { + if ( binding !== undefined ) { - 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; + bindings[ i ] = binding; - }, + } else { - getParameter: function ( point, optionalTarget ) { + binding = bindings[ i ]; - // This can potentially have a divide by zero if the box - // has a size dimension of 0. + if ( binding !== undefined ) { - var result = optionalTarget || new Vector2(); + // existing binding, make sure the cache knows - return result.set( - ( point.x - this.min.x ) / ( this.max.x - this.min.x ), - ( point.y - this.min.y ) / ( this.max.y - this.min.y ) - ); + if ( binding._cacheIndex === null ) { - }, + ++ binding.referenceCount; + this._addInactiveBinding( binding, rootUuid, trackName ); - intersectsBox: function ( box ) { + } - // using 4 splitting planes to rule out intersections + continue; - 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; + } - }, + var path = prototypeAction && prototypeAction. + _propertyBindings[ i ].binding.parsedPath; - clampPoint: function ( point, optionalTarget ) { + binding = new PropertyMixer( + PropertyBinding.create( root, trackName, path ), + track.ValueTypeName, track.getValueSize() ); - var result = optionalTarget || new Vector2(); - return result.copy( point ).clamp( this.min, this.max ); + ++ binding.referenceCount; + this._addInactiveBinding( binding, rootUuid, trackName ); - }, + bindings[ i ] = binding; - distanceToPoint: function () { + } - var v1 = new Vector2(); + interpolants[ i ].resultBuffer = binding.buffer; - return function distanceToPoint( point ) { + } - var clampedPoint = v1.copy( point ).clamp( this.min, this.max ); - return clampedPoint.sub( point ).length(); + }, - }; + _activateAction: function ( action ) { - }(), + if ( ! this._isActiveAction( action ) ) { - intersect: function ( box ) { + if ( action._cacheIndex === null ) { - this.min.max( box.min ); - this.max.min( box.max ); + // this action has been forgotten by the cache, but the user + // appears to be still using it -> rebind - return this; + var rootUuid = ( action._localRoot || this._root ).uuid, + clipUuid = action._clip.uuid, + actionsForClip = this._actionsByClip[ clipUuid ]; - }, + this._bindAction( action, + actionsForClip && actionsForClip.knownActions[ 0 ] ); - union: function ( box ) { + this._addInactiveAction( action, clipUuid, rootUuid ); - this.min.min( box.min ); - this.max.max( box.max ); + } - return this; + var bindings = action._propertyBindings; - }, + // increment reference counts / sort out state + for ( var i = 0, n = bindings.length; i !== n; ++ i ) { - translate: function ( offset ) { + var binding = bindings[ i ]; - this.min.add( offset ); - this.max.add( offset ); + if ( binding.useCount ++ === 0 ) { - return this; + this._lendBinding( binding ); + binding.saveOriginalState(); - }, + } - equals: function ( box ) { + } - return box.min.equals( this.min ) && box.max.equals( this.max ); + this._lendAction( action ); - } + } -} ); + }, -/** - * @author alteredq / http://alteredqualia.com/ - */ + _deactivateAction: function ( action ) { -function ImmediateRenderObject( material ) { + if ( this._isActiveAction( action ) ) { - Object3D.call( this ); + var bindings = action._propertyBindings; - this.material = material; - this.render = function ( /* renderCallback */ ) {}; + // decrement reference counts / sort out state + for ( var i = 0, n = bindings.length; i !== n; ++ i ) { -} + var binding = bindings[ i ]; -ImmediateRenderObject.prototype = Object.create( Object3D.prototype ); -ImmediateRenderObject.prototype.constructor = ImmediateRenderObject; + if ( -- binding.useCount === 0 ) { -ImmediateRenderObject.prototype.isImmediateRenderObject = true; + binding.restoreOriginalState(); + this._takeBackBinding( binding ); -/** - * @author mrdoob / http://mrdoob.com/ - * @author WestLangley / http://github.com/WestLangley - */ + } -function VertexNormalsHelper( object, size, hex, linewidth ) { + } - this.object = object; + this._takeBackAction( action ); - this.size = ( size !== undefined ) ? size : 1; + } - var color = ( hex !== undefined ) ? hex : 0xff0000; + }, - var width = ( linewidth !== undefined ) ? linewidth : 1; + // Memory manager - // + _initMemoryManager: function () { - var nNormals = 0; + this._actions = []; // 'nActiveActions' followed by inactive ones + this._nActiveActions = 0; - var objGeometry = this.object.geometry; + this._actionsByClip = {}; + // inside: + // { + // knownActions: Array< AnimationAction > - used as prototypes + // actionByRoot: AnimationAction - lookup + // } - if ( objGeometry && objGeometry.isGeometry ) { - nNormals = objGeometry.faces.length * 3; + this._bindings = []; // 'nActiveBindings' followed by inactive ones + this._nActiveBindings = 0; - } else if ( objGeometry && objGeometry.isBufferGeometry ) { + this._bindingsByRootAndName = {}; // inside: Map< name, PropertyMixer > - nNormals = objGeometry.attributes.normal.count; - } + this._controlInterpolants = []; // same game as above + this._nActiveControlInterpolants = 0; - // + var scope = this; - var geometry = new BufferGeometry(); + this.stats = { - var positions = new Float32BufferAttribute( nNormals * 2 * 3, 3 ); + actions: { + get total() { - geometry.addAttribute( 'position', positions ); + return scope._actions.length; - LineSegments.call( this, geometry, new LineBasicMaterial( { color: color, linewidth: width } ) ); + }, + get inUse() { - // + return scope._nActiveActions; - this.matrixAutoUpdate = false; + } + }, + bindings: { + get total() { - this.update(); + return scope._bindings.length; -} + }, + get inUse() { -VertexNormalsHelper.prototype = Object.create( LineSegments.prototype ); -VertexNormalsHelper.prototype.constructor = VertexNormalsHelper; + return scope._nActiveBindings; -VertexNormalsHelper.prototype.update = ( function () { + } + }, + controlInterpolants: { + get total() { - var v1 = new Vector3(); - var v2 = new Vector3(); - var normalMatrix = new Matrix3(); + return scope._controlInterpolants.length; - return function update() { + }, + get inUse() { - var keys = [ 'a', 'b', 'c' ]; + return scope._nActiveControlInterpolants; - this.object.updateMatrixWorld( true ); + } + } - normalMatrix.getNormalMatrix( this.object.matrixWorld ); + }; - var matrixWorld = this.object.matrixWorld; + }, - var position = this.geometry.attributes.position; + // Memory management for AnimationAction objects - // + _isActiveAction: function ( action ) { - var objGeometry = this.object.geometry; + var index = action._cacheIndex; + return index !== null && index < this._nActiveActions; - if ( objGeometry && objGeometry.isGeometry ) { + }, - var vertices = objGeometry.vertices; + _addInactiveAction: function ( action, clipUuid, rootUuid ) { - var faces = objGeometry.faces; + var actions = this._actions, + actionsByClip = this._actionsByClip, + actionsForClip = actionsByClip[ clipUuid ]; - var idx = 0; + if ( actionsForClip === undefined ) { - for ( var i = 0, l = faces.length; i < l; i ++ ) { + actionsForClip = { - var face = faces[ i ]; + knownActions: [ action ], + actionByRoot: {} - for ( var j = 0, jl = face.vertexNormals.length; j < jl; j ++ ) { + }; - var vertex = vertices[ face[ keys[ j ] ] ]; + action._byClipCacheIndex = 0; - var normal = face.vertexNormals[ j ]; + actionsByClip[ clipUuid ] = actionsForClip; - v1.copy( vertex ).applyMatrix4( matrixWorld ); + } else { - v2.copy( normal ).applyMatrix3( normalMatrix ).normalize().multiplyScalar( this.size ).add( v1 ); + var knownActions = actionsForClip.knownActions; - position.setXYZ( idx, v1.x, v1.y, v1.z ); + action._byClipCacheIndex = knownActions.length; + knownActions.push( action ); - idx = idx + 1; + } - position.setXYZ( idx, v2.x, v2.y, v2.z ); + action._cacheIndex = actions.length; + actions.push( action ); - idx = idx + 1; + actionsForClip.actionByRoot[ rootUuid ] = action; - } + }, - } + _removeInactiveAction: function ( action ) { - } else if ( objGeometry && objGeometry.isBufferGeometry ) { + var actions = this._actions, + lastInactiveAction = actions[ actions.length - 1 ], + cacheIndex = action._cacheIndex; - var objPos = objGeometry.attributes.position; + lastInactiveAction._cacheIndex = cacheIndex; + actions[ cacheIndex ] = lastInactiveAction; + actions.pop(); - var objNorm = objGeometry.attributes.normal; + action._cacheIndex = null; - var idx = 0; - // for simplicity, ignore index and drawcalls, and render every normal + var clipUuid = action._clip.uuid, + actionsByClip = this._actionsByClip, + actionsForClip = actionsByClip[ clipUuid ], + knownActionsForClip = actionsForClip.knownActions, - for ( var j = 0, jl = objPos.count; j < jl; j ++ ) { + lastKnownAction = + knownActionsForClip[ knownActionsForClip.length - 1 ], - v1.set( objPos.getX( j ), objPos.getY( j ), objPos.getZ( j ) ).applyMatrix4( matrixWorld ); + byClipCacheIndex = action._byClipCacheIndex; - v2.set( objNorm.getX( j ), objNorm.getY( j ), objNorm.getZ( j ) ); + lastKnownAction._byClipCacheIndex = byClipCacheIndex; + knownActionsForClip[ byClipCacheIndex ] = lastKnownAction; + knownActionsForClip.pop(); - v2.applyMatrix3( normalMatrix ).normalize().multiplyScalar( this.size ).add( v1 ); + action._byClipCacheIndex = null; - position.setXYZ( idx, v1.x, v1.y, v1.z ); - idx = idx + 1; + var actionByRoot = actionsForClip.actionByRoot, + rootUuid = ( action._localRoot || this._root ).uuid; - position.setXYZ( idx, v2.x, v2.y, v2.z ); + delete actionByRoot[ rootUuid ]; - idx = idx + 1; + if ( knownActionsForClip.length === 0 ) { - } + delete actionsByClip[ clipUuid ]; } - position.needsUpdate = true; + this._removeInactiveBindingsForAction( action ); - }; + }, -}() ); + _removeInactiveBindingsForAction: function ( action ) { -/** - * @author alteredq / http://alteredqualia.com/ - * @author mrdoob / http://mrdoob.com/ - * @author WestLangley / http://github.com/WestLangley - */ + var bindings = action._propertyBindings; + for ( var i = 0, n = bindings.length; i !== n; ++ i ) { -function SpotLightHelper( light, color ) { + var binding = bindings[ i ]; - Object3D.call( this ); + if ( -- binding.referenceCount === 0 ) { - this.light = light; - this.light.updateMatrixWorld(); + this._removeInactiveBinding( binding ); - this.matrix = light.matrixWorld; - this.matrixAutoUpdate = false; + } - this.color = color; + } - var geometry = new BufferGeometry(); + }, - 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 - ]; + _lendAction: function ( action ) { - for ( var i = 0, j = 1, l = 32; i < l; i ++, j ++ ) { + // [ active actions | inactive actions ] + // [ active actions >| inactive actions ] + // s a + // <-swap-> + // a s - var p1 = ( i / l ) * Math.PI * 2; - var p2 = ( j / l ) * Math.PI * 2; + var actions = this._actions, + prevIndex = action._cacheIndex, - positions.push( - Math.cos( p1 ), Math.sin( p1 ), 1, - Math.cos( p2 ), Math.sin( p2 ), 1 - ); + lastActiveIndex = this._nActiveActions ++, - } + firstInactiveAction = actions[ lastActiveIndex ]; - geometry.addAttribute( 'position', new Float32BufferAttribute( positions, 3 ) ); + action._cacheIndex = lastActiveIndex; + actions[ lastActiveIndex ] = action; - var material = new LineBasicMaterial( { fog: false } ); + firstInactiveAction._cacheIndex = prevIndex; + actions[ prevIndex ] = firstInactiveAction; - this.cone = new LineSegments( geometry, material ); - this.add( this.cone ); + }, - this.update(); + _takeBackAction: function ( action ) { -} + // [ active actions | inactive actions ] + // [ active actions |< inactive actions ] + // a s + // <-swap-> + // s a -SpotLightHelper.prototype = Object.create( Object3D.prototype ); -SpotLightHelper.prototype.constructor = SpotLightHelper; + var actions = this._actions, + prevIndex = action._cacheIndex, -SpotLightHelper.prototype.dispose = function () { + firstInactiveIndex = -- this._nActiveActions, - this.cone.geometry.dispose(); - this.cone.material.dispose(); + lastActiveAction = actions[ firstInactiveIndex ]; -}; + action._cacheIndex = firstInactiveIndex; + actions[ firstInactiveIndex ] = action; -SpotLightHelper.prototype.update = function () { + lastActiveAction._cacheIndex = prevIndex; + actions[ prevIndex ] = lastActiveAction; - var vector = new Vector3(); - var vector2 = new Vector3(); + }, - return function update() { + // Memory management for PropertyMixer objects - this.light.updateMatrixWorld(); + _addInactiveBinding: function ( binding, rootUuid, trackName ) { - var coneLength = this.light.distance ? this.light.distance : 1000; - var coneWidth = coneLength * Math.tan( this.light.angle ); + var bindingsByRoot = this._bindingsByRootAndName, + bindingByName = bindingsByRoot[ rootUuid ], - this.cone.scale.set( coneWidth, coneWidth, coneLength ); + bindings = this._bindings; - vector.setFromMatrixPosition( this.light.matrixWorld ); - vector2.setFromMatrixPosition( this.light.target.matrixWorld ); + if ( bindingByName === undefined ) { - this.cone.lookAt( vector2.sub( vector ) ); + bindingByName = {}; + bindingsByRoot[ rootUuid ] = bindingByName; - if ( this.color !== undefined ) { + } - this.cone.material.color.set( this.color ); + bindingByName[ trackName ] = binding; - } else { + binding._cacheIndex = bindings.length; + bindings.push( binding ); - this.cone.material.color.copy( this.light.color ); + }, - } + _removeInactiveBinding: function ( binding ) { - }; + 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; -/** - * @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 - */ + lastInactiveBinding._cacheIndex = cacheIndex; + bindings[ cacheIndex ] = lastInactiveBinding; + bindings.pop(); -function getBoneList( object ) { + delete bindingByName[ trackName ]; - var boneList = []; + remove_empty_map: { - if ( object && object.isBone ) { + for ( var _ in bindingByName ) break remove_empty_map; // eslint-disable-line no-unused-vars - boneList.push( object ); + delete bindingsByRoot[ rootUuid ]; - } + } - for ( var i = 0; i < object.children.length; i ++ ) { + }, - boneList.push.apply( boneList, getBoneList( object.children[ i ] ) ); + _lendBinding: function ( binding ) { - } + var bindings = this._bindings, + prevIndex = binding._cacheIndex, - return boneList; + lastActiveIndex = this._nActiveBindings ++, -} + firstInactiveBinding = bindings[ lastActiveIndex ]; -function SkeletonHelper( object ) { + binding._cacheIndex = lastActiveIndex; + bindings[ lastActiveIndex ] = binding; - var bones = getBoneList( object ); + firstInactiveBinding._cacheIndex = prevIndex; + bindings[ prevIndex ] = firstInactiveBinding; - var geometry = new BufferGeometry(); + }, - var vertices = []; - var colors = []; + _takeBackBinding: function ( binding ) { - var color1 = new Color( 0, 0, 1 ); - var color2 = new Color( 0, 1, 0 ); + var bindings = this._bindings, + prevIndex = binding._cacheIndex, - for ( var i = 0; i < bones.length; i ++ ) { + firstInactiveIndex = -- this._nActiveBindings, - var bone = bones[ i ]; + lastActiveBinding = bindings[ firstInactiveIndex ]; - if ( bone.parent && bone.parent.isBone ) { + binding._cacheIndex = firstInactiveIndex; + bindings[ firstInactiveIndex ] = binding; - 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 ); + lastActiveBinding._cacheIndex = prevIndex; + bindings[ prevIndex ] = lastActiveBinding; - } + }, - } - geometry.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - geometry.addAttribute( 'color', new Float32BufferAttribute( colors, 3 ) ); + // Memory management of Interpolants for weight and time scale - var material = new LineBasicMaterial( { vertexColors: VertexColors, depthTest: false, depthWrite: false, transparent: true } ); + _lendControlInterpolant: function () { - LineSegments.call( this, geometry, material ); + var interpolants = this._controlInterpolants, + lastActiveIndex = this._nActiveControlInterpolants ++, + interpolant = interpolants[ lastActiveIndex ]; - this.root = object; - this.bones = bones; + if ( interpolant === undefined ) { - this.matrix = object.matrixWorld; - this.matrixAutoUpdate = false; + interpolant = new LinearInterpolant( + new Float32Array( 2 ), new Float32Array( 2 ), + 1, this._controlInterpolantsResultBuffer ); -} + interpolant.__cacheIndex = lastActiveIndex; + interpolants[ lastActiveIndex ] = interpolant; -SkeletonHelper.prototype = Object.create( LineSegments.prototype ); -SkeletonHelper.prototype.constructor = SkeletonHelper; + } -SkeletonHelper.prototype.updateMatrixWorld = function () { + return interpolant; - var vector = new Vector3(); + }, - var boneMatrix = new Matrix4(); - var matrixWorldInv = new Matrix4(); + _takeBackControlInterpolant: function ( interpolant ) { - return function updateMatrixWorld( force ) { + var interpolants = this._controlInterpolants, + prevIndex = interpolant.__cacheIndex, - var bones = this.bones; + firstInactiveIndex = -- this._nActiveControlInterpolants, - var geometry = this.geometry; - var position = geometry.getAttribute( 'position' ); + lastActiveInterpolant = interpolants[ firstInactiveIndex ]; - matrixWorldInv.getInverse( this.root.matrixWorld ); + interpolant.__cacheIndex = firstInactiveIndex; + interpolants[ firstInactiveIndex ] = interpolant; - for ( var i = 0, j = 0; i < bones.length; i ++ ) { + lastActiveInterpolant.__cacheIndex = prevIndex; + interpolants[ prevIndex ] = lastActiveInterpolant; - var bone = bones[ i ]; + }, - if ( bone.parent && bone.parent.isBone ) { + _controlInterpolantsResultBuffer: new Float32Array( 1 ), - boneMatrix.multiplyMatrices( matrixWorldInv, bone.matrixWorld ); - vector.setFromMatrixPosition( boneMatrix ); - position.setXYZ( j, vector.x, vector.y, vector.z ); + // 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 ) { - boneMatrix.multiplyMatrices( matrixWorldInv, bone.parent.matrixWorld ); - vector.setFromMatrixPosition( boneMatrix ); - position.setXYZ( j + 1, vector.x, vector.y, vector.z ); + var root = optionalRoot || this._root, + rootUuid = root.uuid, - j += 2; + clipObject = typeof clip === 'string' ? + AnimationClip.findByName( root, clip ) : clip, - } + clipUuid = clipObject !== null ? clipObject.uuid : clip, - } + actionsForClip = this._actionsByClip[ clipUuid ], + prototypeAction = null; - geometry.getAttribute( 'position' ).needsUpdate = true; + if ( actionsForClip !== undefined ) { - Object3D.prototype.updateMatrixWorld.call( this, force ); + var existingAction = + actionsForClip.actionByRoot[ rootUuid ]; - }; + if ( existingAction !== undefined ) { -}(); + return existingAction; -/** - * @author alteredq / http://alteredqualia.com/ - * @author mrdoob / http://mrdoob.com/ - */ + } -function PointLightHelper( light, sphereSize, color ) { + // we know the clip, so we don't have to parse all + // the bindings again but can just copy + prototypeAction = actionsForClip.knownActions[ 0 ]; - this.light = light; - this.light.updateMatrixWorld(); + // also, take the clip from the prototype action + if ( clipObject === null ) + clipObject = prototypeAction._clip; - this.color = color; + } - var geometry = new SphereBufferGeometry( sphereSize, 4, 2 ); - var material = new MeshBasicMaterial( { wireframe: true, fog: false } ); + // clip must be known when specified via string + if ( clipObject === null ) return null; - Mesh.call( this, geometry, material ); + // allocate all resources required to run it + var newAction = new AnimationAction( this, clipObject, optionalRoot ); - this.matrix = this.light.matrixWorld; - this.matrixAutoUpdate = false; + this._bindAction( newAction, prototypeAction ); - this.update(); + // and make the action known to the memory manager + this._addInactiveAction( newAction, clipUuid, rootUuid ); + return newAction; - /* - var distanceGeometry = new THREE.IcosahedronGeometry( 1, 2 ); - var distanceMaterial = new THREE.MeshBasicMaterial( { color: hexColor, fog: false, wireframe: true, opacity: 0.1, transparent: true } ); + }, - this.lightSphere = new THREE.Mesh( bulbGeometry, bulbMaterial ); - this.lightDistance = new THREE.Mesh( distanceGeometry, distanceMaterial ); + // get an existing action + existingAction: function ( clip, optionalRoot ) { - var d = light.distance; + var root = optionalRoot || this._root, + rootUuid = root.uuid, - if ( d === 0.0 ) { + clipObject = typeof clip === 'string' ? + AnimationClip.findByName( root, clip ) : clip, - this.lightDistance.visible = false; + clipUuid = clipObject ? clipObject.uuid : clip, - } else { + actionsForClip = this._actionsByClip[ clipUuid ]; - this.lightDistance.scale.set( d, d, d ); + if ( actionsForClip !== undefined ) { - } + return actionsForClip.actionByRoot[ rootUuid ] || null; - this.add( this.lightDistance ); - */ + } -} + return null; -PointLightHelper.prototype = Object.create( Mesh.prototype ); -PointLightHelper.prototype.constructor = PointLightHelper; + }, -PointLightHelper.prototype.dispose = function () { + // deactivates all previously scheduled actions + stopAllAction: function () { - this.geometry.dispose(); - this.material.dispose(); + var actions = this._actions, + nActions = this._nActiveActions, + bindings = this._bindings, + nBindings = this._nActiveBindings; -}; + this._nActiveActions = 0; + this._nActiveBindings = 0; -PointLightHelper.prototype.update = function () { + for ( var i = 0; i !== nActions; ++ i ) { - if ( this.color !== undefined ) { + actions[ i ].reset(); - this.material.color.set( this.color ); + } - } else { + for ( var i = 0; i !== nBindings; ++ i ) { - this.material.color.copy( this.light.color ); + bindings[ i ].useCount = 0; - } + } - /* - var d = this.light.distance; + return this; - if ( d === 0.0 ) { + }, - this.lightDistance.visible = false; + // advance the time and update apply the animation + update: function ( deltaTime ) { - } else { + deltaTime *= this.timeScale; - this.lightDistance.visible = true; - this.lightDistance.scale.set( d, d, d ); + var actions = this._actions, + nActions = this._nActiveActions, - } - */ - -}; - -/** - * @author abelnation / http://github.com/abelnation - * @author Mugen87 / http://github.com/Mugen87 - * @author WestLangley / http://github.com/WestLangley - */ - -function RectAreaLightHelper( light, color ) { + time = this.time += deltaTime, + timeDirection = Math.sign( deltaTime ), - Object3D.call( this ); + accuIndex = this._accuIndex ^= 1; - this.light = light; - this.light.updateMatrixWorld(); + // run active actions - this.matrix = light.matrixWorld; - this.matrixAutoUpdate = false; + for ( var i = 0; i !== nActions; ++ i ) { - this.color = color; + var action = actions[ i ]; - var material = new LineBasicMaterial( { fog: false } ); + action._update( time, deltaTime, timeDirection, accuIndex ); - var geometry = new BufferGeometry(); + } - geometry.addAttribute( 'position', new BufferAttribute( new Float32Array( 5 * 3 ), 3 ) ); + // update scene graph - this.line = new Line( geometry, material ); - this.add( this.line ); + var bindings = this._bindings, + nBindings = this._nActiveBindings; + for ( var i = 0; i !== nBindings; ++ i ) { - this.update(); + bindings[ i ].apply( accuIndex ); -} + } -RectAreaLightHelper.prototype = Object.create( Object3D.prototype ); -RectAreaLightHelper.prototype.constructor = RectAreaLightHelper; + return this; -RectAreaLightHelper.prototype.dispose = function () { + }, - this.children[ 0 ].geometry.dispose(); - this.children[ 0 ].material.dispose(); + // return this mixer's root target object + getRoot: function () { -}; + return this._root; -RectAreaLightHelper.prototype.update = function () { + }, - // calculate new dimensions of the helper + // free all resources specific to a particular clip + uncacheClip: function ( clip ) { - var hx = this.light.width * 0.5; - var hy = this.light.height * 0.5; + var actions = this._actions, + clipUuid = clip.uuid, + actionsByClip = this._actionsByClip, + actionsForClip = actionsByClip[ clipUuid ]; - var position = this.line.geometry.attributes.position; - var array = position.array; + if ( actionsForClip !== undefined ) { - // update vertices + // note: just calling _removeInactiveAction would mess up the + // iteration state and also require updating the state we can + // just throw away - 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; + var actionsToRemove = actionsForClip.knownActions; - position.needsUpdate = true; + for ( var i = 0, n = actionsToRemove.length; i !== n; ++ i ) { - if ( this.color !== undefined ) { + var action = actionsToRemove[ i ]; - this.line.material.color.set( this.color ); + this._deactivateAction( action ); - } else { + var cacheIndex = action._cacheIndex, + lastInactiveAction = actions[ actions.length - 1 ]; - this.line.material.color.copy( this.light.color ); + action._cacheIndex = null; + action._byClipCacheIndex = null; - } + lastInactiveAction._cacheIndex = cacheIndex; + actions[ cacheIndex ] = lastInactiveAction; + actions.pop(); -}; + this._removeInactiveBindingsForAction( action ); -/** - * @author alteredq / http://alteredqualia.com/ - * @author mrdoob / http://mrdoob.com/ - * @author Mugen87 / https://github.com/Mugen87 - */ + } -function HemisphereLightHelper( light, size, color ) { + delete actionsByClip[ clipUuid ]; - Object3D.call( this ); + } - this.light = light; - this.light.updateMatrixWorld(); + }, - this.matrix = light.matrixWorld; - this.matrixAutoUpdate = false; + // free all resources specific to a particular root target object + uncacheRoot: function ( root ) { - this.color = color; + var rootUuid = root.uuid, + actionsByClip = this._actionsByClip; - var geometry = new OctahedronBufferGeometry( size ); - geometry.rotateY( Math.PI * 0.5 ); + for ( var clipUuid in actionsByClip ) { - this.material = new MeshBasicMaterial( { wireframe: true, fog: false } ); - if ( this.color === undefined ) this.material.vertexColors = VertexColors; + var actionByRoot = actionsByClip[ clipUuid ].actionByRoot, + action = actionByRoot[ rootUuid ]; - var position = geometry.getAttribute( 'position' ); - var colors = new Float32Array( position.count * 3 ); + if ( action !== undefined ) { - geometry.addAttribute( 'color', new BufferAttribute( colors, 3 ) ); + this._deactivateAction( action ); + this._removeInactiveAction( action ); - this.add( new Mesh( geometry, this.material ) ); + } - this.update(); + } -} + var bindingsByRoot = this._bindingsByRootAndName, + bindingByName = bindingsByRoot[ rootUuid ]; -HemisphereLightHelper.prototype = Object.create( Object3D.prototype ); -HemisphereLightHelper.prototype.constructor = HemisphereLightHelper; + if ( bindingByName !== undefined ) { -HemisphereLightHelper.prototype.dispose = function () { + for ( var trackName in bindingByName ) { - this.children[ 0 ].geometry.dispose(); - this.children[ 0 ].material.dispose(); + var binding = bindingByName[ trackName ]; + binding.restoreOriginalState(); + this._removeInactiveBinding( binding ); -}; + } -HemisphereLightHelper.prototype.update = function () { + } - var vector = new Vector3(); + }, - var color1 = new Color(); - var color2 = new Color(); + // remove a targeted clip from the cache + uncacheAction: function ( clip, optionalRoot ) { - return function update() { + var action = this.existingAction( clip, optionalRoot ); - var mesh = this.children[ 0 ]; + if ( action !== null ) { - if ( this.color !== undefined ) { + this._deactivateAction( action ); + this._removeInactiveAction( action ); - this.material.color.set( this.color ); + } - } else { + } - var colors = mesh.geometry.getAttribute( 'color' ); +} ); - color1.copy( this.light.color ); - color2.copy( this.light.groundColor ); +/** + * @author mrdoob / http://mrdoob.com/ + */ - for ( var i = 0, l = colors.count; i < l; i ++ ) { +function Uniform( value ) { - var color = ( i < ( l / 2 ) ) ? color1 : color2; + if ( typeof value === 'string' ) { - colors.setXYZ( i, color.r, color.g, color.b ); + console.warn( 'THREE.Uniform: Type parameter is no longer needed.' ); + value = arguments[ 1 ]; - } + } - colors.needsUpdate = true; + this.value = value; - } +} - mesh.lookAt( vector.setFromMatrixPosition( this.light.matrixWorld ).negate() ); +Uniform.prototype.clone = function () { - }; + return new Uniform( this.value.clone === undefined ? this.value : this.value.clone() ); -}(); +}; /** - * @author mrdoob / http://mrdoob.com/ + * @author benaadams / https://twitter.com/ben_a_adams */ -function GridHelper( size, divisions, color1, color2 ) { +function InstancedBufferGeometry() { - size = size || 10; - divisions = divisions || 10; - color1 = new Color( color1 !== undefined ? color1 : 0x444444 ); - color2 = new Color( color2 !== undefined ? color2 : 0x888888 ); + BufferGeometry.call( this ); - var center = divisions / 2; - var step = size / divisions; - var halfSize = size / 2; + this.type = 'InstancedBufferGeometry'; + this.maxInstancedCount = undefined; - var vertices = [], colors = []; +} - for ( var i = 0, j = 0, k = - halfSize; i <= divisions; i ++, k += step ) { +InstancedBufferGeometry.prototype = Object.assign( Object.create( BufferGeometry.prototype ), { - vertices.push( - halfSize, 0, k, halfSize, 0, k ); - vertices.push( k, 0, - halfSize, k, 0, halfSize ); + constructor: InstancedBufferGeometry, - var color = i === center ? color1 : color2; + isInstancedBufferGeometry: true, - color.toArray( colors, j ); j += 3; - color.toArray( colors, j ); j += 3; - color.toArray( colors, j ); j += 3; - color.toArray( colors, j ); j += 3; + copy: function ( source ) { - } + BufferGeometry.prototype.copy.call( this, source ); - var geometry = new BufferGeometry(); - geometry.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - geometry.addAttribute( 'color', new Float32BufferAttribute( colors, 3 ) ); + this.maxInstancedCount = source.maxInstancedCount; - var material = new LineBasicMaterial( { vertexColors: VertexColors } ); + return this; - LineSegments.call( this, geometry, material ); + }, -} + clone: function () { -GridHelper.prototype = Object.create( LineSegments.prototype ); -GridHelper.prototype.constructor = GridHelper; + return new this.constructor().copy( this ); + + } + +} ); /** - * @author mrdoob / http://mrdoob.com/ - * @author Mugen87 / http://github.com/Mugen87 - * @author Hectate / http://www.github.com/Hectate + * @author benaadams / https://twitter.com/ben_a_adams */ -function PolarGridHelper( radius, radials, circles, divisions, color1, color2 ) { +function InstancedInterleavedBuffer( array, stride, meshPerAttribute ) { - 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 ); + InterleavedBuffer.call( this, array, stride ); - var vertices = []; - var colors = []; + this.meshPerAttribute = meshPerAttribute || 1; - var x, z; - var v, i, j, r, color; +} - // create the radials +InstancedInterleavedBuffer.prototype = Object.assign( Object.create( InterleavedBuffer.prototype ), { - for ( i = 0; i <= radials; i ++ ) { + constructor: InstancedInterleavedBuffer, - v = ( i / radials ) * ( Math.PI * 2 ); + isInstancedInterleavedBuffer: true, - x = Math.sin( v ) * radius; - z = Math.cos( v ) * radius; + copy: function ( source ) { - vertices.push( 0, 0, 0 ); - vertices.push( x, 0, z ); + InterleavedBuffer.prototype.copy.call( this, source ); - color = ( i & 1 ) ? color1 : color2; + this.meshPerAttribute = source.meshPerAttribute; - colors.push( color.r, color.g, color.b ); - colors.push( color.r, color.g, color.b ); + return this; } - // create the circles +} ); - for ( i = 0; i <= circles; i ++ ) { +/** + * @author benaadams / https://twitter.com/ben_a_adams + */ - color = ( i & 1 ) ? color1 : color2; +function InstancedBufferAttribute( array, itemSize, normalized, meshPerAttribute ) { - r = radius - ( radius / circles * i ); + if ( typeof ( normalized ) === 'number' ) { - for ( j = 0; j < divisions; j ++ ) { + meshPerAttribute = normalized; - // first vertex + normalized = false; - v = ( j / divisions ) * ( Math.PI * 2 ); + console.error( 'THREE.InstancedBufferAttribute: The constructor now expects normalized as the third argument.' ); - x = Math.sin( v ) * r; - z = Math.cos( v ) * r; + } - vertices.push( x, 0, z ); - colors.push( color.r, color.g, color.b ); + BufferAttribute.call( this, array, itemSize, normalized ); - // second vertex + this.meshPerAttribute = meshPerAttribute || 1; - v = ( ( j + 1 ) / divisions ) * ( Math.PI * 2 ); +} - x = Math.sin( v ) * r; - z = Math.cos( v ) * r; +InstancedBufferAttribute.prototype = Object.assign( Object.create( BufferAttribute.prototype ), { - vertices.push( x, 0, z ); - colors.push( color.r, color.g, color.b ); + constructor: InstancedBufferAttribute, - } + isInstancedBufferAttribute: true, - } + copy: function ( source ) { - var geometry = new BufferGeometry(); - geometry.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - geometry.addAttribute( 'color', new Float32BufferAttribute( colors, 3 ) ); + BufferAttribute.prototype.copy.call( this, source ); - var material = new LineBasicMaterial( { vertexColors: VertexColors } ); + this.meshPerAttribute = source.meshPerAttribute; - LineSegments.call( this, geometry, material ); + return this; -} + } -PolarGridHelper.prototype = Object.create( LineSegments.prototype ); -PolarGridHelper.prototype.constructor = PolarGridHelper; +} ); /** * @author mrdoob / http://mrdoob.com/ - * @author WestLangley / http://github.com/WestLangley + * @author bhouston / http://clara.io/ + * @author stephomi / http://stephaneginier.com/ */ -function FaceNormalsHelper( object, size, hex, linewidth ) { - - // FaceNormalsHelper only supports THREE.Geometry +function Raycaster( origin, direction, near, far ) { - this.object = object; + this.ray = new Ray( origin, direction ); + // direction is assumed to be normalized (for accurate distance calculations) - this.size = ( size !== undefined ) ? size : 1; + this.near = near || 0; + this.far = far || Infinity; - var color = ( hex !== undefined ) ? hex : 0xffff00; + this.params = { + Mesh: {}, + Line: {}, + LOD: {}, + Points: { threshold: 1 }, + Sprite: {} + }; - var width = ( linewidth !== undefined ) ? linewidth : 1; + Object.defineProperties( this.params, { + PointCloud: { + get: function () { - // + console.warn( 'THREE.Raycaster: params.PointCloud has been renamed to params.Points.' ); + return this.Points; - var nNormals = 0; + } + } + } ); - var objGeometry = this.object.geometry; +} - if ( objGeometry && objGeometry.isGeometry ) { +function ascSort( a, b ) { - nNormals = objGeometry.faces.length; + return a.distance - b.distance; - } else { +} - console.warn( 'THREE.FaceNormalsHelper: only THREE.Geometry is supported. Use THREE.VertexNormalsHelper, instead.' ); +function intersectObject( object, raycaster, intersects, recursive ) { - } + if ( object.visible === false ) return; - // + object.raycast( raycaster, intersects ); - var geometry = new BufferGeometry(); + if ( recursive === true ) { - var positions = new Float32BufferAttribute( nNormals * 2 * 3, 3 ); + var children = object.children; - geometry.addAttribute( 'position', positions ); + for ( var i = 0, l = children.length; i < l; i ++ ) { - LineSegments.call( this, geometry, new LineBasicMaterial( { color: color, linewidth: width } ) ); + intersectObject( children[ i ], raycaster, intersects, true ); - // + } - this.matrixAutoUpdate = false; - this.update(); + } } -FaceNormalsHelper.prototype = Object.create( LineSegments.prototype ); -FaceNormalsHelper.prototype.constructor = FaceNormalsHelper; +Object.assign( Raycaster.prototype, { -FaceNormalsHelper.prototype.update = ( function () { + linePrecision: 1, - var v1 = new Vector3(); - var v2 = new Vector3(); - var normalMatrix = new Matrix3(); + set: function ( origin, direction ) { - return function update() { + // direction is assumed to be normalized (for accurate distance calculations) - this.object.updateMatrixWorld( true ); + this.ray.set( origin, direction ); - normalMatrix.getNormalMatrix( this.object.matrixWorld ); + }, - var matrixWorld = this.object.matrixWorld; + setFromCamera: function ( coords, camera ) { - var position = this.geometry.attributes.position; + 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(); - var objGeometry = this.object.geometry; + } else if ( ( camera && camera.isOrthographicCamera ) ) { - var vertices = objGeometry.vertices; + 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 ); - var faces = objGeometry.faces; + } else { - var idx = 0; + console.error( 'THREE.Raycaster: Unsupported camera type.' ); - for ( var i = 0, l = faces.length; i < l; i ++ ) { + } - var face = faces[ i ]; + }, - var normal = face.normal; + intersectObject: function ( object, recursive, optionalTarget ) { - v1.copy( vertices[ face.a ] ) - .add( vertices[ face.b ] ) - .add( vertices[ face.c ] ) - .divideScalar( 3 ) - .applyMatrix4( matrixWorld ); + var intersects = optionalTarget || []; - v2.copy( normal ).applyMatrix3( normalMatrix ).normalize().multiplyScalar( this.size ).add( v1 ); + intersectObject( object, this, intersects, recursive ); - position.setXYZ( idx, v1.x, v1.y, v1.z ); + intersects.sort( ascSort ); - idx = idx + 1; + return intersects; - position.setXYZ( idx, v2.x, v2.y, v2.z ); + }, - idx = idx + 1; + intersectObjects: function ( objects, recursive, optionalTarget ) { + + var intersects = optionalTarget || []; + + if ( Array.isArray( objects ) === false ) { + + console.warn( 'THREE.Raycaster.intersectObjects: objects is not an Array.' ); + return intersects; } - position.needsUpdate = true; + for ( var i = 0, l = objects.length; i < l; i ++ ) { - }; + intersectObject( objects[ i ], this, intersects, recursive ); -}() ); + } + + intersects.sort( ascSort ); + + return intersects; + + } + +} ); /** - * @author alteredq / http://alteredqualia.com/ - * @author mrdoob / http://mrdoob.com/ + * @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 DirectionalLightHelper( light, size, color ) { +function Spherical( radius, phi, theta ) { - Object3D.call( this ); + this.radius = ( radius !== undefined ) ? radius : 1.0; + this.phi = ( phi !== undefined ) ? phi : 0; // polar angle + this.theta = ( theta !== undefined ) ? theta : 0; // azimuthal angle - this.light = light; - this.light.updateMatrixWorld(); + return this; - this.matrix = light.matrixWorld; - this.matrixAutoUpdate = false; +} - this.color = color; +Object.assign( Spherical.prototype, { - if ( size === undefined ) size = 1; + set: function ( radius, phi, theta ) { - 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 ) ); + this.radius = radius; + this.phi = phi; + this.theta = theta; - var material = new LineBasicMaterial( { fog: false } ); + return this; - this.lightPlane = new Line( geometry, material ); - this.add( this.lightPlane ); + }, - geometry = new BufferGeometry(); - geometry.addAttribute( 'position', new Float32BufferAttribute( [ 0, 0, 0, 0, 0, 1 ], 3 ) ); + clone: function () { - this.targetLine = new Line( geometry, material ); - this.add( this.targetLine ); + return new this.constructor().copy( this ); - this.update(); + }, -} + copy: function ( other ) { -DirectionalLightHelper.prototype = Object.create( Object3D.prototype ); -DirectionalLightHelper.prototype.constructor = DirectionalLightHelper; + this.radius = other.radius; + this.phi = other.phi; + this.theta = other.theta; -DirectionalLightHelper.prototype.dispose = function () { + return this; - this.lightPlane.geometry.dispose(); - this.lightPlane.material.dispose(); - this.targetLine.geometry.dispose(); - this.targetLine.material.dispose(); + }, -}; + // restrict phi to be betwee EPS and PI-EPS + makeSafe: function () { -DirectionalLightHelper.prototype.update = function () { + var EPS = 0.000001; + this.phi = Math.max( EPS, Math.min( Math.PI - EPS, this.phi ) ); - var v1 = new Vector3(); - var v2 = new Vector3(); - var v3 = new Vector3(); + return this; - return function update() { + }, - v1.setFromMatrixPosition( this.light.matrixWorld ); - v2.setFromMatrixPosition( this.light.target.matrixWorld ); - v3.subVectors( v2, v1 ); + setFromVector3: function ( v ) { - this.lightPlane.lookAt( v3 ); + return this.setFromCartesianCoords( v.x, v.y, v.z ); - if ( this.color !== undefined ) { + }, - this.lightPlane.material.color.set( this.color ); - this.targetLine.material.color.set( this.color ); + setFromCartesianCoords: function ( x, y, z ) { + + this.radius = Math.sqrt( x * x + y * y + z * z ); + + if ( this.radius === 0 ) { + + this.theta = 0; + this.phi = 0; } else { - this.lightPlane.material.color.copy( this.light.color ); - this.targetLine.material.color.copy( this.light.color ); + this.theta = Math.atan2( x, z ); + this.phi = Math.acos( _Math.clamp( y / this.radius, - 1, 1 ) ); } - this.targetLine.lookAt( v3 ); - this.targetLine.scale.z = v3.length(); + return this; - }; + } -}(); +} ); /** - * @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 + * Ref: https://en.wikipedia.org/wiki/Cylindrical_coordinate_system + * */ -function CameraHelper( camera ) { - - var geometry = new BufferGeometry(); - var material = new LineBasicMaterial( { color: 0xffffff, vertexColors: FaceColors } ); +function Cylindrical( radius, theta, y ) { - var vertices = []; - var colors = []; + 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 - var pointMap = {}; + return this; - // 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 ); +Object.assign( Cylindrical.prototype, { - // near + set: function ( radius, theta, y ) { - addLine( 'n1', 'n2', colorFrustum ); - addLine( 'n2', 'n4', colorFrustum ); - addLine( 'n4', 'n3', colorFrustum ); - addLine( 'n3', 'n1', colorFrustum ); + this.radius = radius; + this.theta = theta; + this.y = y; - // far + return this; - addLine( 'f1', 'f2', colorFrustum ); - addLine( 'f2', 'f4', colorFrustum ); - addLine( 'f4', 'f3', colorFrustum ); - addLine( 'f3', 'f1', colorFrustum ); + }, - // sides + clone: function () { - addLine( 'n1', 'f1', colorFrustum ); - addLine( 'n2', 'f2', colorFrustum ); - addLine( 'n3', 'f3', colorFrustum ); - addLine( 'n4', 'f4', colorFrustum ); + return new this.constructor().copy( this ); - // cone + }, - addLine( 'p', 'n1', colorCone ); - addLine( 'p', 'n2', colorCone ); - addLine( 'p', 'n3', colorCone ); - addLine( 'p', 'n4', colorCone ); + copy: function ( other ) { - // up + this.radius = other.radius; + this.theta = other.theta; + this.y = other.y; - addLine( 'u1', 'u2', colorUp ); - addLine( 'u2', 'u3', colorUp ); - addLine( 'u3', 'u1', colorUp ); + return this; - // target + }, - addLine( 'c', 't', colorTarget ); - addLine( 'p', 'c', colorCross ); + setFromVector3: function ( v ) { - // cross + return this.setFromCartesianCoords( v.x, v.y, v.z ); - addLine( 'cn1', 'cn2', colorCross ); - addLine( 'cn3', 'cn4', colorCross ); + }, - addLine( 'cf1', 'cf2', colorCross ); - addLine( 'cf3', 'cf4', colorCross ); + setFromCartesianCoords: function ( x, y, z ) { - function addLine( a, b, color ) { + this.radius = Math.sqrt( x * x + z * z ); + this.theta = Math.atan2( x, z ); + this.y = y; - addPoint( a, color ); - addPoint( b, color ); + return this; } - function addPoint( id, color ) { +} ); - vertices.push( 0, 0, 0 ); - colors.push( color.r, color.g, color.b ); +/** + * @author bhouston / http://clara.io + */ - if ( pointMap[ id ] === undefined ) { +function Box2( min, max ) { - pointMap[ id ] = []; + this.min = ( min !== undefined ) ? min : new Vector2( + Infinity, + Infinity ); + this.max = ( max !== undefined ) ? max : new Vector2( - Infinity, - Infinity ); - } +} - pointMap[ id ].push( ( vertices.length / 3 ) - 1 ); +Object.assign( Box2.prototype, { - } + set: function ( min, max ) { - geometry.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - geometry.addAttribute( 'color', new Float32BufferAttribute( colors, 3 ) ); + this.min.copy( min ); + this.max.copy( max ); - LineSegments.call( this, geometry, material ); + return this; - this.camera = camera; - if ( this.camera.updateProjectionMatrix ) this.camera.updateProjectionMatrix(); + }, - this.matrix = camera.matrixWorld; - this.matrixAutoUpdate = false; + setFromPoints: function ( points ) { - this.pointMap = pointMap; + this.makeEmpty(); - this.update(); + for ( var i = 0, il = points.length; i < il; i ++ ) { -} + this.expandByPoint( points[ i ] ); -CameraHelper.prototype = Object.create( LineSegments.prototype ); -CameraHelper.prototype.constructor = CameraHelper; + } -CameraHelper.prototype.update = function () { + return this; - var geometry, pointMap; + }, - var vector = new Vector3(); - var camera = new Camera(); + setFromCenterAndSize: function () { - function setPoint( point, x, y, z ) { + var v1 = new Vector2(); - vector.set( x, y, z ).unproject( camera ); + return function setFromCenterAndSize( center, size ) { - var points = pointMap[ point ]; + var halfSize = v1.copy( size ).multiplyScalar( 0.5 ); + this.min.copy( center ).sub( halfSize ); + this.max.copy( center ).add( halfSize ); - if ( points !== undefined ) { + return this; - var position = geometry.getAttribute( 'position' ); + }; - for ( var i = 0, l = points.length; i < l; i ++ ) { + }(), - position.setXYZ( points[ i ], vector.x, vector.y, vector.z ); + clone: function () { - } + return new this.constructor().copy( this ); - } + }, - } + copy: function ( box ) { - return function update() { + this.min.copy( box.min ); + this.max.copy( box.max ); - geometry = this.geometry; - pointMap = this.pointMap; + return this; - var w = 1, h = 1; + }, - // we need just camera projection matrix - // world matrix must be identity + makeEmpty: function () { - camera.projectionMatrix.copy( this.camera.projectionMatrix ); + this.min.x = this.min.y = + Infinity; + this.max.x = this.max.y = - Infinity; - // center / target + return this; - setPoint( 'c', 0, 0, - 1 ); - setPoint( 't', 0, 0, 1 ); + }, - // near + isEmpty: function () { - setPoint( 'n1', - w, - h, - 1 ); - setPoint( 'n2', w, - h, - 1 ); - setPoint( 'n3', - w, h, - 1 ); - setPoint( 'n4', w, h, - 1 ); + // this is a more robust check for empty than ( volume <= 0 ) because volume can get positive with two negative axes - // far + return ( this.max.x < this.min.x ) || ( this.max.y < this.min.y ); - setPoint( 'f1', - w, - h, 1 ); - setPoint( 'f2', w, - h, 1 ); - setPoint( 'f3', - w, h, 1 ); - setPoint( 'f4', w, h, 1 ); + }, - // up + getCenter: function ( target ) { - setPoint( 'u1', w * 0.7, h * 1.1, - 1 ); - setPoint( 'u2', - w * 0.7, h * 1.1, - 1 ); - setPoint( 'u3', 0, h * 2, - 1 ); + if ( target === undefined ) { - // cross + console.warn( 'THREE.Box2: .getCenter() target is now required' ); + target = new Vector2(); - setPoint( 'cf1', - w, 0, 1 ); - setPoint( 'cf2', w, 0, 1 ); - setPoint( 'cf3', 0, - h, 1 ); - setPoint( 'cf4', 0, h, 1 ); + } - setPoint( 'cn1', - w, 0, - 1 ); - setPoint( 'cn2', w, 0, - 1 ); - setPoint( 'cn3', 0, - h, - 1 ); - setPoint( 'cn4', 0, h, - 1 ); + return this.isEmpty() ? target.set( 0, 0 ) : target.addVectors( this.min, this.max ).multiplyScalar( 0.5 ); - geometry.getAttribute( 'position' ).needsUpdate = true; + }, - }; + getSize: function ( target ) { -}(); + if ( target === undefined ) { -/** - * @author mrdoob / http://mrdoob.com/ - * @author Mugen87 / http://github.com/Mugen87 - */ + console.warn( 'THREE.Box2: .getSize() target is now required' ); + target = new Vector2(); -function BoxHelper( object, color ) { + } - this.object = object; + return this.isEmpty() ? target.set( 0, 0 ) : target.subVectors( this.max, this.min ); - 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 = new Float32Array( 8 * 3 ); + expandByPoint: function ( point ) { - var geometry = new BufferGeometry(); - geometry.setIndex( new BufferAttribute( indices, 1 ) ); - geometry.addAttribute( 'position', new BufferAttribute( positions, 3 ) ); + this.min.min( point ); + this.max.max( point ); - LineSegments.call( this, geometry, new LineBasicMaterial( { color: color } ) ); + return this; - this.matrixAutoUpdate = false; + }, - this.update(); + expandByVector: function ( vector ) { -} + this.min.sub( vector ); + this.max.add( vector ); -BoxHelper.prototype = Object.create( LineSegments.prototype ); -BoxHelper.prototype.constructor = BoxHelper; + return this; -BoxHelper.prototype.update = ( function () { + }, - var box = new Box3(); + expandByScalar: function ( scalar ) { - return function update( object ) { + this.min.addScalar( - scalar ); + this.max.addScalar( scalar ); - if ( object !== undefined ) { + return this; - console.warn( 'THREE.BoxHelper: .update() has no longer arguments.' ); + }, - } + containsPoint: function ( point ) { - if ( this.object !== undefined ) { + return point.x < this.min.x || point.x > this.max.x || + point.y < this.min.y || point.y > this.max.y ? false : true; - box.setFromObject( this.object ); + }, - } + containsBox: function ( box ) { - if ( box.isEmpty() ) return; + 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; - var min = box.min; - var max = box.max; + }, - /* - 5____4 - 1/___0/| - | 6__|_7 - 2/___3/ + getParameter: function ( point, target ) { - 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 - */ + // This can potentially have a divide by zero if the box + // has a size dimension of 0. - var position = this.geometry.attributes.position; - var array = position.array; + if ( target === undefined ) { - 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; + console.warn( 'THREE.Box2: .getParameter() target is now required' ); + target = new Vector2(); - position.needsUpdate = true; + } - this.geometry.computeBoundingSphere(); + return target.set( + ( point.x - this.min.x ) / ( this.max.x - this.min.x ), + ( point.y - this.min.y ) / ( this.max.y - this.min.y ) + ); - }; + }, -} )(); + intersectsBox: function ( box ) { -BoxHelper.prototype.setFromObject = function ( object ) { + // using 4 splitting planes to rule out intersections - this.object = object; - this.update(); + 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; - return this; + }, -}; + clampPoint: function ( point, target ) { -/** - * @author WestLangley / http://github.com/WestLangley - */ + if ( target === undefined ) { -function Box3Helper( box, hex ) { + console.warn( 'THREE.Box2: .clampPoint() target is now required' ); + target = new Vector2(); - this.type = 'Box3Helper'; + } - this.box = box; + return target.copy( point ).clamp( this.min, this.max ); - 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 ] ); + distanceToPoint: function () { - 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 v1 = new Vector2(); - var geometry = new BufferGeometry(); + return function distanceToPoint( point ) { - geometry.setIndex( new BufferAttribute( indices, 1 ) ); + var clampedPoint = v1.copy( point ).clamp( this.min, this.max ); + return clampedPoint.sub( point ).length(); - geometry.addAttribute( 'position', new Float32BufferAttribute( positions, 3 ) ); + }; - LineSegments.call( this, geometry, new LineBasicMaterial( { color: color } ) ); + }(), - this.geometry.computeBoundingSphere(); + intersect: function ( box ) { -} + this.min.max( box.min ); + this.max.min( box.max ); -Box3Helper.prototype = Object.create( LineSegments.prototype ); -Box3Helper.prototype.constructor = Box3Helper; + return this; -Box3Helper.prototype.updateMatrixWorld = function ( force ) { + }, - var box = this.box; + union: function ( box ) { - if ( box.isEmpty() ) return; + this.min.min( box.min ); + this.max.max( box.max ); - box.getCenter( this.position ); + return this; - box.getSize( this.scale ); + }, - this.scale.multiplyScalar( 0.5 ); + translate: function ( offset ) { - Object3D.prototype.updateMatrixWorld.call( this, force ); + this.min.add( offset ); + this.max.add( offset ); -}; + return this; -/** - * @author WestLangley / http://github.com/WestLangley - */ + }, -function PlaneHelper( plane, size, hex ) { + equals: function ( box ) { - this.type = 'PlaneHelper'; + return box.min.equals( this.min ) && box.max.equals( this.max ); - this.plane = plane; + } - this.size = ( size === undefined ) ? 1 : size; +} ); - var color = ( hex !== undefined ) ? hex : 0xffff00; +/** + * @author bhouston / http://clara.io + */ - 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 ]; +function Line3( start, end ) { - var geometry = new BufferGeometry(); - geometry.addAttribute( 'position', new Float32BufferAttribute( positions, 3 ) ); - geometry.computeBoundingSphere(); + this.start = ( start !== undefined ) ? start : new Vector3(); + this.end = ( end !== undefined ) ? end : new Vector3(); - Line.call( this, geometry, new LineBasicMaterial( { color: color } ) ); +} - // +Object.assign( Line3.prototype, { - var positions2 = [ 1, 1, 1, - 1, 1, 1, - 1, - 1, 1, 1, 1, 1, - 1, - 1, 1, 1, - 1, 1 ]; + set: function ( start, end ) { - var geometry2 = new BufferGeometry(); - geometry2.addAttribute( 'position', new Float32BufferAttribute( positions2, 3 ) ); - geometry2.computeBoundingSphere(); + this.start.copy( start ); + this.end.copy( end ); - this.add( new Mesh( geometry2, new MeshBasicMaterial( { color: color, opacity: 0.2, transparent: true, depthWrite: false } ) ) ); + return this; -} + }, -PlaneHelper.prototype = Object.create( Line.prototype ); -PlaneHelper.prototype.constructor = PlaneHelper; + clone: function () { -PlaneHelper.prototype.updateMatrixWorld = function ( force ) { + return new this.constructor().copy( this ); - var scale = - this.plane.constant; + }, - if ( Math.abs( scale ) < 1e-8 ) scale = 1e-8; // sign does not matter + copy: function ( line ) { - this.scale.set( 0.5 * this.size, 0.5 * this.size, scale ); + this.start.copy( line.start ); + this.end.copy( line.end ); - this.lookAt( this.plane.normal ); + return this; - Object3D.prototype.updateMatrixWorld.call( this, force ); + }, -}; + getCenter: function ( target ) { -/** - * @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 - */ + if ( target === undefined ) { -var lineGeometry; -var coneGeometry; + console.warn( 'THREE.Line3: .getCenter() target is now required' ); + target = new Vector3(); -function ArrowHelper( dir, origin, length, color, headLength, headWidth ) { + } - // dir is assumed to be normalized + return target.addVectors( this.start, this.end ).multiplyScalar( 0.5 ); - Object3D.call( this ); + }, - if ( color === undefined ) color = 0xffff00; - if ( length === undefined ) length = 1; - if ( headLength === undefined ) headLength = 0.2 * length; - if ( headWidth === undefined ) headWidth = 0.2 * headLength; + delta: function ( target ) { - if ( lineGeometry === undefined ) { + if ( target === undefined ) { - lineGeometry = new BufferGeometry(); - lineGeometry.addAttribute( 'position', new Float32BufferAttribute( [ 0, 0, 0, 0, 1, 0 ], 3 ) ); + console.warn( 'THREE.Line3: .delta() target is now required' ); + target = new Vector3(); - coneGeometry = new CylinderBufferGeometry( 0, 0.5, 1, 5, 1 ); - coneGeometry.translate( 0, - 0.5, 0 ); + } - } + return target.subVectors( this.end, this.start ); - this.position.copy( origin ); + }, - this.line = new Line( lineGeometry, new LineBasicMaterial( { color: color } ) ); - this.line.matrixAutoUpdate = false; - this.add( this.line ); + distanceSq: function () { - this.cone = new Mesh( coneGeometry, new MeshBasicMaterial( { color: color } ) ); - this.cone.matrixAutoUpdate = false; - this.add( this.cone ); + return this.start.distanceToSquared( this.end ); - this.setDirection( dir ); - this.setLength( length, headLength, headWidth ); + }, -} + distance: function () { -ArrowHelper.prototype = Object.create( Object3D.prototype ); -ArrowHelper.prototype.constructor = ArrowHelper; + return this.start.distanceTo( this.end ); -ArrowHelper.prototype.setDirection = ( function () { + }, - var axis = new Vector3(); - var radians; + at: function ( t, target ) { - return function setDirection( dir ) { + if ( target === undefined ) { - // dir is assumed to be normalized + console.warn( 'THREE.Line3: .at() target is now required' ); + target = new Vector3(); - if ( dir.y > 0.99999 ) { + } - this.quaternion.set( 0, 0, 0, 1 ); + return this.delta( target ).multiplyScalar( t ).add( this.start ); - } else if ( dir.y < - 0.99999 ) { + }, - this.quaternion.set( 1, 0, 0, 0 ); + closestPointToPointParameter: function () { - } else { + var startP = new Vector3(); + var startEnd = new Vector3(); - axis.set( dir.z, 0, - dir.x ).normalize(); + return function closestPointToPointParameter( point, clampToLine ) { - radians = Math.acos( dir.y ); + startP.subVectors( point, this.start ); + startEnd.subVectors( this.end, this.start ); - this.quaternion.setFromAxisAngle( axis, radians ); + var startEnd2 = startEnd.dot( startEnd ); + var startEnd_startP = startEnd.dot( startP ); - } + var t = startEnd_startP / startEnd2; - }; + if ( clampToLine ) { -}() ); + t = _Math.clamp( t, 0, 1 ); -ArrowHelper.prototype.setLength = function ( length, headLength, headWidth ) { + } - if ( headLength === undefined ) headLength = 0.2 * length; - if ( headWidth === undefined ) headWidth = 0.2 * headLength; + return t; - this.line.scale.set( 1, Math.max( 0, length - headLength ), 1 ); - this.line.updateMatrix(); + }; - this.cone.scale.set( headWidth, headLength, headWidth ); - this.cone.position.y = length; - this.cone.updateMatrix(); + }(), -}; + closestPointToPoint: function ( point, clampToLine, target ) { -ArrowHelper.prototype.setColor = function ( color ) { + var t = this.closestPointToPointParameter( point, clampToLine ); - this.line.material.color.copy( color ); - this.cone.material.color.copy( color ); + if ( target === undefined ) { -}; + console.warn( 'THREE.Line3: .closestPointToPoint() target is now required' ); + target = new Vector3(); -/** - * @author sroucheray / http://sroucheray.org/ - * @author mrdoob / http://mrdoob.com/ - */ + } -function AxesHelper( size ) { + return this.delta( target ).multiplyScalar( t ).add( this.start ); - size = size || 1; + }, - var vertices = [ - 0, 0, 0, size, 0, 0, - 0, 0, 0, 0, size, 0, - 0, 0, 0, 0, 0, size - ]; + applyMatrix4: function ( matrix ) { - var colors = [ - 1, 0, 0, 1, 0.6, 0, - 0, 1, 0, 0.6, 1, 0, - 0, 0, 1, 0, 0.6, 1 - ]; + this.start.applyMatrix4( matrix ); + this.end.applyMatrix4( matrix ); - var geometry = new BufferGeometry(); - geometry.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - geometry.addAttribute( 'color', new Float32BufferAttribute( colors, 3 ) ); + return this; - var material = new LineBasicMaterial( { vertexColors: VertexColors } ); + }, - LineSegments.call( this, geometry, material ); + equals: function ( line ) { -} + return line.start.equals( this.start ) && line.end.equals( this.end ); -AxesHelper.prototype = Object.create( LineSegments.prototype ); -AxesHelper.prototype.constructor = AxesHelper; + } + +} ); /** - * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ */ -function Face4( a, b, c, d, normal, color, materialIndex ) { +function ImmediateRenderObject( material ) { - console.warn( 'THREE.Face4 has been removed. A THREE.Face3 will be created instead.' ); - return new Face3( a, b, c, normal, color, materialIndex ); + Object3D.call( this ); + + this.material = material; + this.render = function ( /* renderCallback */ ) {}; } -var LineStrip = 0; +ImmediateRenderObject.prototype = Object.create( Object3D.prototype ); +ImmediateRenderObject.prototype.constructor = ImmediateRenderObject; -var LinePieces = 1; +ImmediateRenderObject.prototype.isImmediateRenderObject = true; -function MeshFaceMaterial( materials ) { +/** + * @author mrdoob / http://mrdoob.com/ + * @author WestLangley / http://github.com/WestLangley + */ - console.warn( 'THREE.MeshFaceMaterial has been removed. Use an Array instead.' ); - return materials; +function VertexNormalsHelper( object, size, hex, linewidth ) { -} + this.object = object; -function MultiMaterial( materials ) { + this.size = ( size !== undefined ) ? size : 1; - if ( materials === undefined ) materials = []; + var color = ( hex !== undefined ) ? hex : 0xff0000; - console.warn( 'THREE.MultiMaterial has been removed. Use an Array instead.' ); - materials.isMultiMaterial = true; - materials.materials = materials; - materials.clone = function () { + var width = ( linewidth !== undefined ) ? linewidth : 1; - return materials.slice(); + // - }; - return materials; + var nNormals = 0; -} + var objGeometry = this.object.geometry; -function PointCloud( geometry, material ) { + if ( objGeometry && objGeometry.isGeometry ) { - console.warn( 'THREE.PointCloud has been renamed to THREE.Points.' ); - return new Points( geometry, material ); + nNormals = objGeometry.faces.length * 3; -} + } else if ( objGeometry && objGeometry.isBufferGeometry ) { -function Particle( material ) { + nNormals = objGeometry.attributes.normal.count; - console.warn( 'THREE.Particle has been renamed to THREE.Sprite.' ); - return new Sprite( material ); + } -} + // -function ParticleSystem( geometry, material ) { + var geometry = new BufferGeometry(); - console.warn( 'THREE.ParticleSystem has been renamed to THREE.Points.' ); - return new Points( geometry, material ); + var positions = new Float32BufferAttribute( nNormals * 2 * 3, 3 ); -} + geometry.addAttribute( 'position', positions ); -function PointCloudMaterial( parameters ) { + LineSegments.call( this, geometry, new LineBasicMaterial( { color: color, linewidth: width } ) ); - console.warn( 'THREE.PointCloudMaterial has been renamed to THREE.PointsMaterial.' ); - return new PointsMaterial( parameters ); + // + + this.matrixAutoUpdate = false; + + this.update(); } -function ParticleBasicMaterial( parameters ) { +VertexNormalsHelper.prototype = Object.create( LineSegments.prototype ); +VertexNormalsHelper.prototype.constructor = VertexNormalsHelper; - console.warn( 'THREE.ParticleBasicMaterial has been renamed to THREE.PointsMaterial.' ); - return new PointsMaterial( parameters ); +VertexNormalsHelper.prototype.update = ( function () { -} + var v1 = new Vector3(); + var v2 = new Vector3(); + var normalMatrix = new Matrix3(); -function ParticleSystemMaterial( parameters ) { + return function update() { - console.warn( 'THREE.ParticleSystemMaterial has been renamed to THREE.PointsMaterial.' ); - return new PointsMaterial( parameters ); + var keys = [ 'a', 'b', 'c' ]; -} + this.object.updateMatrixWorld( true ); -function Vertex( x, y, z ) { + normalMatrix.getNormalMatrix( this.object.matrixWorld ); - console.warn( 'THREE.Vertex has been removed. Use THREE.Vector3 instead.' ); - return new Vector3( x, y, z ); + var matrixWorld = this.object.matrixWorld; -} + var position = this.geometry.attributes.position; -// + // -function DynamicBufferAttribute( array, itemSize ) { + var objGeometry = this.object.geometry; - console.warn( 'THREE.DynamicBufferAttribute has been removed. Use new THREE.BufferAttribute().setDynamic( true ) instead.' ); - return new BufferAttribute( array, itemSize ).setDynamic( true ); + if ( objGeometry && objGeometry.isGeometry ) { -} + var vertices = objGeometry.vertices; -function Int8Attribute( array, itemSize ) { + var faces = objGeometry.faces; - console.warn( 'THREE.Int8Attribute has been removed. Use new THREE.Int8BufferAttribute() instead.' ); - return new Int8BufferAttribute( array, itemSize ); + var idx = 0; -} + for ( var i = 0, l = faces.length; i < l; i ++ ) { -function Uint8Attribute( array, itemSize ) { + var face = faces[ i ]; - console.warn( 'THREE.Uint8Attribute has been removed. Use new THREE.Uint8BufferAttribute() instead.' ); - return new Uint8BufferAttribute( array, itemSize ); + for ( var j = 0, jl = face.vertexNormals.length; j < jl; j ++ ) { -} + var vertex = vertices[ face[ keys[ j ] ] ]; -function Uint8ClampedAttribute( array, itemSize ) { + var normal = face.vertexNormals[ j ]; - console.warn( 'THREE.Uint8ClampedAttribute has been removed. Use new THREE.Uint8ClampedBufferAttribute() instead.' ); - return new Uint8ClampedBufferAttribute( array, itemSize ); + v1.copy( vertex ).applyMatrix4( matrixWorld ); -} + v2.copy( normal ).applyMatrix3( normalMatrix ).normalize().multiplyScalar( this.size ).add( v1 ); -function Int16Attribute( array, itemSize ) { + position.setXYZ( idx, v1.x, v1.y, v1.z ); - console.warn( 'THREE.Int16Attribute has been removed. Use new THREE.Int16BufferAttribute() instead.' ); - return new Int16BufferAttribute( array, itemSize ); + idx = idx + 1; -} + position.setXYZ( idx, v2.x, v2.y, v2.z ); -function Uint16Attribute( array, itemSize ) { + idx = idx + 1; - console.warn( 'THREE.Uint16Attribute has been removed. Use new THREE.Uint16BufferAttribute() instead.' ); - return new Uint16BufferAttribute( array, itemSize ); + } -} + } -function Int32Attribute( array, itemSize ) { + } else if ( objGeometry && objGeometry.isBufferGeometry ) { - console.warn( 'THREE.Int32Attribute has been removed. Use new THREE.Int32BufferAttribute() instead.' ); - return new Int32BufferAttribute( array, itemSize ); + var objPos = objGeometry.attributes.position; -} + var objNorm = objGeometry.attributes.normal; -function Uint32Attribute( array, itemSize ) { + var idx = 0; - console.warn( 'THREE.Uint32Attribute has been removed. Use new THREE.Uint32BufferAttribute() instead.' ); - return new Uint32BufferAttribute( array, itemSize ); + // for simplicity, ignore index and drawcalls, and render every normal -} + for ( var j = 0, jl = objPos.count; j < jl; j ++ ) { -function Float32Attribute( array, itemSize ) { + v1.set( objPos.getX( j ), objPos.getY( j ), objPos.getZ( j ) ).applyMatrix4( matrixWorld ); - console.warn( 'THREE.Float32Attribute has been removed. Use new THREE.Float32BufferAttribute() instead.' ); - return new Float32BufferAttribute( array, itemSize ); + v2.set( objNorm.getX( j ), objNorm.getY( j ), objNorm.getZ( j ) ); -} + v2.applyMatrix3( normalMatrix ).normalize().multiplyScalar( this.size ).add( v1 ); -function Float64Attribute( array, itemSize ) { + position.setXYZ( idx, v1.x, v1.y, v1.z ); - console.warn( 'THREE.Float64Attribute has been removed. Use new THREE.Float64BufferAttribute() instead.' ); - return new Float64BufferAttribute( array, itemSize ); + idx = idx + 1; -} + position.setXYZ( idx, v2.x, v2.y, v2.z ); -// + idx = idx + 1; -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; + position.needsUpdate = true; - return construct; + }; -}; +}() ); -// +/** + * @author alteredq / http://alteredqualia.com/ + * @author mrdoob / http://mrdoob.com/ + * @author WestLangley / http://github.com/WestLangley + */ -Object.assign( CurvePath.prototype, { +function SpotLightHelper( light, color ) { - createPointsGeometry: function ( divisions ) { + Object3D.call( this ); - console.warn( 'THREE.CurvePath: .createPointsGeometry() has been removed. Use new THREE.Geometry().setFromPoints( points ) instead.' ); + this.light = light; + this.light.updateMatrixWorld(); - // generate geometry from path points (for Line or Points objects) + this.matrix = light.matrixWorld; + this.matrixAutoUpdate = false; - var pts = this.getPoints( divisions ); - return this.createGeometry( pts ); + this.color = color; - }, + var geometry = new BufferGeometry(); - createSpacedPointsGeometry: function ( divisions ) { + 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.CurvePath: .createSpacedPointsGeometry() has been removed. Use new THREE.Geometry().setFromPoints( points ) instead.' ); + for ( var i = 0, j = 1, l = 32; i < l; i ++, j ++ ) { - // generate geometry from equidistant sampling along the path + var p1 = ( i / l ) * Math.PI * 2; + var p2 = ( j / l ) * Math.PI * 2; - var pts = this.getSpacedPoints( divisions ); - return this.createGeometry( pts ); + positions.push( + Math.cos( p1 ), Math.sin( p1 ), 1, + Math.cos( p2 ), Math.sin( p2 ), 1 + ); - }, + } - createGeometry: function ( points ) { + geometry.addAttribute( 'position', new Float32BufferAttribute( positions, 3 ) ); - console.warn( 'THREE.CurvePath: .createGeometry() has been removed. Use new THREE.Geometry().setFromPoints( points ) instead.' ); + var material = new LineBasicMaterial( { fog: false } ); - var geometry = new Geometry(); + this.cone = new LineSegments( geometry, material ); + this.add( this.cone ); - for ( var i = 0, l = points.length; i < l; i ++ ) { + this.update(); - var point = points[ i ]; - geometry.vertices.push( new Vector3( point.x, point.y, point.z || 0 ) ); +} - } +SpotLightHelper.prototype = Object.create( Object3D.prototype ); +SpotLightHelper.prototype.constructor = SpotLightHelper; - return geometry; +SpotLightHelper.prototype.dispose = function () { - } + this.cone.geometry.dispose(); + this.cone.material.dispose(); -} ); +}; -// +SpotLightHelper.prototype.update = function () { -Object.assign( Path.prototype, { + var vector = new Vector3(); - fromPoints: function ( points ) { + return function update() { - console.warn( 'THREE.Path: .fromPoints() has been renamed to .setFromPoints().' ); - this.setFromPoints( points ); + 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 ); -// + vector.setFromMatrixPosition( this.light.target.matrixWorld ); -function ClosedSplineCurve3( points ) { + this.cone.lookAt( vector ); - console.warn( 'THREE.ClosedSplineCurve3 has been deprecated. Use THREE.CatmullRomCurve3 instead.' ); + if ( this.color !== undefined ) { - CatmullRomCurve3.call( this, points ); - this.type = 'catmullrom'; - this.closed = true; + this.cone.material.color.set( this.color ); -} + } else { -ClosedSplineCurve3.prototype = Object.create( CatmullRomCurve3.prototype ); + this.cone.material.color.copy( this.light.color ); -// + } -function SplineCurve3( points ) { + }; - console.warn( 'THREE.SplineCurve3 has been deprecated. Use THREE.CatmullRomCurve3 instead.' ); +}(); - CatmullRomCurve3.call( this, points ); - this.type = 'catmullrom'; +/** + * @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 + */ -} +function getBoneList( object ) { -SplineCurve3.prototype = Object.create( CatmullRomCurve3.prototype ); + var boneList = []; -// + if ( object && object.isBone ) { -function Spline( points ) { + boneList.push( object ); - console.warn( 'THREE.Spline has been removed. Use THREE.CatmullRomCurve3 instead.' ); + } - CatmullRomCurve3.call( this, points ); - this.type = 'catmullrom'; + for ( var i = 0; i < object.children.length; i ++ ) { + + boneList.push.apply( boneList, getBoneList( object.children[ i ] ) ); + + } + + return boneList; } -Spline.prototype = Object.create( CatmullRomCurve3.prototype ); +function SkeletonHelper( object ) { -Object.assign( Spline.prototype, { + var bones = getBoneList( object ); - initFromArray: function ( /* a */ ) { + var geometry = new BufferGeometry(); - console.error( 'THREE.Spline: .initFromArray() has been removed.' ); + var vertices = []; + var colors = []; - }, - getControlPointsArray: function ( /* optionalTarget */ ) { + var color1 = new Color( 0, 0, 1 ); + var color2 = new Color( 0, 1, 0 ); - console.error( 'THREE.Spline: .getControlPointsArray() has been removed.' ); + for ( var i = 0; i < bones.length; i ++ ) { - }, - reparametrizeByArcLength: function ( /* samplingCoef */ ) { + var bone = bones[ i ]; - console.error( 'THREE.Spline: .reparametrizeByArcLength() has been removed.' ); + if ( bone.parent && bone.parent.isBone ) { - } + vertices.push( 0, 0, 0 ); + vertices.push( 0, 0, 0 ); + colors.push( color1.r, color1.g, color1.b ); + colors.push( color2.r, color2.g, color2.b ); -} ); + } -// + } -function AxisHelper( size ) { + geometry.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); + geometry.addAttribute( 'color', new Float32BufferAttribute( colors, 3 ) ); - console.warn( 'THREE.AxisHelper has been renamed to THREE.AxesHelper.' ); - return new AxesHelper( size ); + var material = new LineBasicMaterial( { vertexColors: VertexColors, depthTest: false, depthWrite: false, transparent: true } ); -} + LineSegments.call( this, geometry, material ); -function BoundingBoxHelper( object, color ) { + this.root = object; + this.bones = bones; - console.warn( 'THREE.BoundingBoxHelper has been deprecated. Creating a THREE.BoxHelper instead.' ); - return new BoxHelper( object, color ); + this.matrix = object.matrixWorld; + this.matrixAutoUpdate = false; } -function EdgesHelper( object, hex ) { +SkeletonHelper.prototype = Object.create( LineSegments.prototype ); +SkeletonHelper.prototype.constructor = SkeletonHelper; - 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 } ) ); +SkeletonHelper.prototype.updateMatrixWorld = function () { -} + var vector = new Vector3(); -GridHelper.prototype.setColors = function () { + var boneMatrix = new Matrix4(); + var matrixWorldInv = new Matrix4(); - console.error( 'THREE.GridHelper: setColors() has been deprecated, pass them in the constructor instead.' ); + return function updateMatrixWorld( force ) { -}; + var bones = this.bones; -SkeletonHelper.prototype.update = function () { + var geometry = this.geometry; + var position = geometry.getAttribute( 'position' ); - console.error( 'THREE.SkeletonHelper: update() no longer needs to be called.' ); + matrixWorldInv.getInverse( this.root.matrixWorld ); -}; + for ( var i = 0, j = 0; i < bones.length; i ++ ) { -function WireframeHelper( object, hex ) { + var bone = bones[ i ]; - 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 } ) ); + if ( bone.parent && bone.parent.isBone ) { -} + 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 ); -Object.assign( Loader.prototype, { + j += 2; - extractUrlBase: function ( url ) { + } - console.warn( 'THREE.Loader: .extractUrlBase() has been deprecated. Use THREE.LoaderUtils.extractUrlBase() instead.' ); - return LoaderUtils.extractUrlBase( url ); + } - } + geometry.getAttribute( 'position' ).needsUpdate = true; -} ); + Object3D.prototype.updateMatrixWorld.call( this, force ); -function XHRLoader( manager ) { + }; - console.warn( 'THREE.XHRLoader has been renamed to THREE.FileLoader.' ); - return new FileLoader( manager ); +}(); -} +/** + * @author alteredq / http://alteredqualia.com/ + * @author mrdoob / http://mrdoob.com/ + */ -function BinaryTextureLoader( manager ) { +function PointLightHelper( light, sphereSize, color ) { - console.warn( 'THREE.BinaryTextureLoader has been renamed to THREE.DataTextureLoader.' ); - return new DataTextureLoader( manager ); + this.light = light; + this.light.updateMatrixWorld(); -} + this.color = color; -// + var geometry = new SphereBufferGeometry( sphereSize, 4, 2 ); + var material = new MeshBasicMaterial( { wireframe: true, fog: false } ); -Object.assign( Box2.prototype, { + Mesh.call( this, geometry, material ); - center: function ( optionalTarget ) { + this.matrix = this.light.matrixWorld; + this.matrixAutoUpdate = false; - console.warn( 'THREE.Box2: .center() has been renamed to .getCenter().' ); - return this.getCenter( optionalTarget ); + this.update(); - }, - empty: function () { - console.warn( 'THREE.Box2: .empty() has been renamed to .isEmpty().' ); - return this.isEmpty(); + /* + var distanceGeometry = new THREE.IcosahedronBufferGeometry( 1, 2 ); + var distanceMaterial = new THREE.MeshBasicMaterial( { color: hexColor, fog: false, wireframe: true, opacity: 0.1, transparent: true } ); - }, - isIntersectionBox: function ( box ) { + this.lightSphere = new THREE.Mesh( bulbGeometry, bulbMaterial ); + this.lightDistance = new THREE.Mesh( distanceGeometry, distanceMaterial ); - console.warn( 'THREE.Box2: .isIntersectionBox() has been renamed to .intersectsBox().' ); - return this.intersectsBox( box ); + var d = light.distance; - }, - size: function ( optionalTarget ) { + if ( d === 0.0 ) { - console.warn( 'THREE.Box2: .size() has been renamed to .getSize().' ); - return this.getSize( optionalTarget ); + this.lightDistance.visible = false; + + } else { + + this.lightDistance.scale.set( d, d, d ); } -} ); -Object.assign( Box3.prototype, { + this.add( this.lightDistance ); + */ - center: function ( optionalTarget ) { +} - console.warn( 'THREE.Box3: .center() has been renamed to .getCenter().' ); - return this.getCenter( optionalTarget ); +PointLightHelper.prototype = Object.create( Mesh.prototype ); +PointLightHelper.prototype.constructor = PointLightHelper; - }, - empty: function () { +PointLightHelper.prototype.dispose = function () { - console.warn( 'THREE.Box3: .empty() has been renamed to .isEmpty().' ); - return this.isEmpty(); + this.geometry.dispose(); + this.material.dispose(); - }, - isIntersectionBox: function ( box ) { +}; - console.warn( 'THREE.Box3: .isIntersectionBox() has been renamed to .intersectsBox().' ); - return this.intersectsBox( box ); +PointLightHelper.prototype.update = function () { - }, - isIntersectionSphere: function ( sphere ) { + if ( this.color !== undefined ) { - console.warn( 'THREE.Box3: .isIntersectionSphere() has been renamed to .intersectsSphere().' ); - return this.intersectsSphere( sphere ); + this.material.color.set( this.color ); - }, - size: function ( optionalTarget ) { + } else { - console.warn( 'THREE.Box3: .size() has been renamed to .getSize().' ); - return this.getSize( optionalTarget ); + this.material.color.copy( this.light.color ); } -} ); -Line3.prototype.center = function ( optionalTarget ) { - - console.warn( 'THREE.Line3: .center() has been renamed to .getCenter().' ); - return this.getCenter( optionalTarget ); + /* + var d = this.light.distance; -}; + if ( d === 0.0 ) { -Object.assign( _Math, { + this.lightDistance.visible = false; - random16: function () { + } else { - console.warn( 'THREE.Math: .random16() has been deprecated. Use Math.random() instead.' ); - return Math.random(); + this.lightDistance.visible = true; + this.lightDistance.scale.set( d, d, d ); - }, + } + */ - nearestPowerOfTwo: function ( value ) { +}; - console.warn( 'THREE.Math: .nearestPowerOfTwo() has been renamed to .floorPowerOfTwo().' ); - return _Math.floorPowerOfTwo( value ); +/** + * @author abelnation / http://github.com/abelnation + * @author Mugen87 / http://github.com/Mugen87 + * @author WestLangley / http://github.com/WestLangley + * + * This helper must be added as a child of the light + */ - }, +function RectAreaLightHelper( light, color ) { - nextPowerOfTwo: function ( value ) { + this.type = 'RectAreaLightHelper'; - console.warn( 'THREE.Math: .nextPowerOfTwo() has been renamed to .ceilPowerOfTwo().' ); - return _Math.ceilPowerOfTwo( value ); + this.light = light; - } + this.color = color; // optional hardwired color for the helper -} ); + var positions = [ 1, 1, 0, - 1, 1, 0, - 1, - 1, 0, 1, - 1, 0, 1, 1, 0 ]; -Object.assign( Matrix3.prototype, { + var geometry = new BufferGeometry(); + geometry.addAttribute( 'position', new Float32BufferAttribute( positions, 3 ) ); + geometry.computeBoundingSphere(); - flattenToArrayOffset: function ( array, offset ) { + var material = new LineBasicMaterial( { fog: false } ); - console.warn( "THREE.Matrix3: .flattenToArrayOffset() has been deprecated. Use .toArray() instead." ); - return this.toArray( array, offset ); + Line.call( this, geometry, material ); - }, - multiplyVector3: function ( vector ) { + // - console.warn( 'THREE.Matrix3: .multiplyVector3() has been removed. Use vector.applyMatrix3( matrix ) instead.' ); - return vector.applyMatrix3( this ); + var positions2 = [ 1, 1, 0, - 1, 1, 0, - 1, - 1, 0, 1, 1, 0, - 1, - 1, 0, 1, - 1, 0 ]; - }, - multiplyVector3Array: function ( /* a */ ) { + var geometry2 = new BufferGeometry(); + geometry2.addAttribute( 'position', new Float32BufferAttribute( positions2, 3 ) ); + geometry2.computeBoundingSphere(); - console.error( 'THREE.Matrix3: .multiplyVector3Array() has been removed.' ); + this.add( new Mesh( geometry2, new MeshBasicMaterial( { side: THREE.BackSide, fog: false } ) ) ); - }, - applyToBuffer: function ( buffer /*, offset, length */ ) { + this.update(); - console.warn( 'THREE.Matrix3: .applyToBuffer() has been removed. Use matrix.applyToBufferAttribute( attribute ) instead.' ); - return this.applyToBufferAttribute( buffer ); +} - }, - applyToVector3Array: function ( /* array, offset, length */ ) { +RectAreaLightHelper.prototype = Object.create( Line.prototype ); +RectAreaLightHelper.prototype.constructor = RectAreaLightHelper; - console.error( 'THREE.Matrix3: .applyToVector3Array() has been removed.' ); +RectAreaLightHelper.prototype.update = function () { - } + this.scale.set( 0.5 * this.light.width, 0.5 * this.light.height, 1 ); -} ); + if ( this.color !== undefined ) { -Object.assign( Matrix4.prototype, { + this.material.color.set( this.color ); + this.children[ 0 ].material.color.set( this.color ); - extractPosition: function ( m ) { + } else { - console.warn( 'THREE.Matrix4: .extractPosition() has been renamed to .copyPosition().' ); - return this.copyPosition( m ); + this.material.color.copy( this.light.color ).multiplyScalar( this.light.intensity ); - }, - flattenToArrayOffset: function ( array, offset ) { + // prevent hue shift + var c = this.material.color; + var max = Math.max( c.r, c.g, c.b ); + if ( max > 1 ) c.multiplyScalar( 1 / max ); - console.warn( "THREE.Matrix4: .flattenToArrayOffset() has been deprecated. Use .toArray() instead." ); - return this.toArray( array, offset ); + this.children[ 0 ].material.color.copy( this.material.color ); - }, - getPosition: function () { + } - var v1; +}; - return function getPosition() { +RectAreaLightHelper.prototype.dispose = function () { - if ( v1 === undefined ) v1 = new Vector3(); - console.warn( 'THREE.Matrix4: .getPosition() has been removed. Use Vector3.setFromMatrixPosition( matrix ) instead.' ); - return v1.setFromMatrixColumn( this, 3 ); + this.geometry.dispose(); + this.material.dispose(); + this.children[ 0 ].geometry.dispose(); + this.children[ 0 ].material.dispose(); - }; +}; - }(), - setRotationFromQuaternion: function ( q ) { +/** + * @author alteredq / http://alteredqualia.com/ + * @author mrdoob / http://mrdoob.com/ + * @author Mugen87 / https://github.com/Mugen87 + */ - console.warn( 'THREE.Matrix4: .setRotationFromQuaternion() has been renamed to .makeRotationFromQuaternion().' ); - return this.makeRotationFromQuaternion( q ); +function HemisphereLightHelper( light, size, color ) { - }, - multiplyToArray: function () { + Object3D.call( this ); - console.warn( 'THREE.Matrix4: .multiplyToArray() has been removed.' ); + this.light = light; + this.light.updateMatrixWorld(); - }, - multiplyVector3: function ( vector ) { + this.matrix = light.matrixWorld; + this.matrixAutoUpdate = false; - console.warn( 'THREE.Matrix4: .multiplyVector3() has been removed. Use vector.applyMatrix4( matrix ) instead.' ); - return vector.applyMatrix4( this ); + this.color = color; - }, - multiplyVector4: function ( vector ) { + var geometry = new OctahedronBufferGeometry( size ); + geometry.rotateY( Math.PI * 0.5 ); - console.warn( 'THREE.Matrix4: .multiplyVector4() has been removed. Use vector.applyMatrix4( matrix ) instead.' ); - return vector.applyMatrix4( this ); + this.material = new MeshBasicMaterial( { wireframe: true, fog: false } ); + if ( this.color === undefined ) this.material.vertexColors = VertexColors; - }, - multiplyVector3Array: function ( /* a */ ) { + var position = geometry.getAttribute( 'position' ); + var colors = new Float32Array( position.count * 3 ); - console.error( 'THREE.Matrix4: .multiplyVector3Array() has been removed.' ); + geometry.addAttribute( 'color', new BufferAttribute( colors, 3 ) ); - }, - rotateAxis: function ( v ) { + this.add( new Mesh( geometry, this.material ) ); - console.warn( 'THREE.Matrix4: .rotateAxis() has been removed. Use Vector3.transformDirection( matrix ) instead.' ); - v.transformDirection( this ); + this.update(); - }, - crossVector: function ( vector ) { +} - console.warn( 'THREE.Matrix4: .crossVector() has been removed. Use vector.applyMatrix4( matrix ) instead.' ); - return vector.applyMatrix4( this ); +HemisphereLightHelper.prototype = Object.create( Object3D.prototype ); +HemisphereLightHelper.prototype.constructor = HemisphereLightHelper; - }, - translate: function () { +HemisphereLightHelper.prototype.dispose = function () { - console.error( 'THREE.Matrix4: .translate() has been removed.' ); + this.children[ 0 ].geometry.dispose(); + this.children[ 0 ].material.dispose(); - }, - rotateX: function () { +}; - console.error( 'THREE.Matrix4: .rotateX() has been removed.' ); +HemisphereLightHelper.prototype.update = function () { - }, - rotateY: function () { + var vector = new Vector3(); - console.error( 'THREE.Matrix4: .rotateY() has been removed.' ); + var color1 = new Color(); + var color2 = new Color(); - }, - rotateZ: function () { + return function update() { - console.error( 'THREE.Matrix4: .rotateZ() has been removed.' ); + var mesh = this.children[ 0 ]; - }, - rotateByAxis: function () { + if ( this.color !== undefined ) { - console.error( 'THREE.Matrix4: .rotateByAxis() has been removed.' ); + this.material.color.set( this.color ); - }, - applyToBuffer: function ( buffer /*, offset, length */ ) { + } else { - console.warn( 'THREE.Matrix4: .applyToBuffer() has been removed. Use matrix.applyToBufferAttribute( attribute ) instead.' ); - return this.applyToBufferAttribute( buffer ); + var colors = mesh.geometry.getAttribute( 'color' ); - }, - applyToVector3Array: function ( /* array, offset, length */ ) { + color1.copy( this.light.color ); + color2.copy( this.light.groundColor ); - console.error( 'THREE.Matrix4: .applyToVector3Array() has been removed.' ); + for ( var i = 0, l = colors.count; i < l; i ++ ) { - }, - makeFrustum: function ( left, right, bottom, top, near, far ) { + var color = ( i < ( l / 2 ) ) ? color1 : color2; - 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 ); + colors.setXYZ( i, color.r, color.g, color.b ); - } + } -} ); + colors.needsUpdate = true; -Plane.prototype.isIntersectionLine = function ( line ) { + } - console.warn( 'THREE.Plane: .isIntersectionLine() has been renamed to .intersectsLine().' ); - return this.intersectsLine( line ); + mesh.lookAt( vector.setFromMatrixPosition( this.light.matrixWorld ).negate() ); -}; + }; -Quaternion.prototype.multiplyVector3 = function ( vector ) { +}(); - console.warn( 'THREE.Quaternion: .multiplyVector3() has been removed. Use is now vector.applyQuaternion( quaternion ) instead.' ); - return vector.applyQuaternion( this ); +/** + * @author mrdoob / http://mrdoob.com/ + */ -}; +function GridHelper( size, divisions, color1, color2 ) { -Object.assign( Ray.prototype, { + size = size || 10; + divisions = divisions || 10; + color1 = new Color( color1 !== undefined ? color1 : 0x444444 ); + color2 = new Color( color2 !== undefined ? color2 : 0x888888 ); - isIntersectionBox: function ( box ) { + var center = divisions / 2; + var step = size / divisions; + var halfSize = size / 2; - console.warn( 'THREE.Ray: .isIntersectionBox() has been renamed to .intersectsBox().' ); - return this.intersectsBox( box ); + var vertices = [], colors = []; - }, - isIntersectionPlane: function ( plane ) { + for ( var i = 0, j = 0, k = - halfSize; i <= divisions; i ++, k += step ) { - console.warn( 'THREE.Ray: .isIntersectionPlane() has been renamed to .intersectsPlane().' ); - return this.intersectsPlane( plane ); + vertices.push( - halfSize, 0, k, halfSize, 0, k ); + vertices.push( k, 0, - halfSize, k, 0, halfSize ); - }, - isIntersectionSphere: function ( sphere ) { + var color = i === center ? color1 : color2; - console.warn( 'THREE.Ray: .isIntersectionSphere() has been renamed to .intersectsSphere().' ); - return this.intersectsSphere( sphere ); + color.toArray( colors, j ); j += 3; + color.toArray( colors, j ); j += 3; + color.toArray( colors, j ); j += 3; + color.toArray( colors, j ); j += 3; } -} ); + var geometry = new BufferGeometry(); + geometry.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); + geometry.addAttribute( 'color', new Float32BufferAttribute( colors, 3 ) ); -Object.assign( Shape.prototype, { + var material = new LineBasicMaterial( { vertexColors: VertexColors } ); - extractAllPoints: function ( divisions ) { + LineSegments.call( this, geometry, material ); - console.warn( 'THREE.Shape: .extractAllPoints() has been removed. Use .extractPoints() instead.' ); - return this.extractPoints( divisions ); +} - }, - extrude: function ( options ) { +GridHelper.prototype = Object.create( LineSegments.prototype ); +GridHelper.prototype.constructor = GridHelper; - console.warn( 'THREE.Shape: .extrude() has been removed. Use ExtrudeGeometry() instead.' ); - return new ExtrudeGeometry( this, options ); +/** + * @author mrdoob / http://mrdoob.com/ + * @author Mugen87 / http://github.com/Mugen87 + * @author Hectate / http://www.github.com/Hectate + */ - }, - makeGeometry: function ( options ) { +function PolarGridHelper( radius, radials, circles, divisions, color1, color2 ) { - console.warn( 'THREE.Shape: .makeGeometry() has been removed. Use ShapeGeometry() instead.' ); - return new ShapeGeometry( this, options ); + 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 = []; -} ); + var x, z; + var v, i, j, r, color; -Object.assign( Vector2.prototype, { + // create the radials - fromAttribute: function ( attribute, index, offset ) { + for ( i = 0; i <= radials; i ++ ) { - console.warn( 'THREE.Vector2: .fromAttribute() has been renamed to .fromBufferAttribute().' ); - return this.fromBufferAttribute( attribute, index, offset ); + v = ( i / radials ) * ( Math.PI * 2 ); - }, - distanceToManhattan: function ( v ) { + x = Math.sin( v ) * radius; + z = Math.cos( v ) * radius; - console.warn( 'THREE.Vector2: .distanceToManhattan() has been renamed to .manhattanDistanceTo().' ); - return this.manhattanDistanceTo( v ); + vertices.push( 0, 0, 0 ); + vertices.push( x, 0, z ); - }, - lengthManhattan: function () { + color = ( i & 1 ) ? color1 : color2; - console.warn( 'THREE.Vector2: .lengthManhattan() has been renamed to .manhattanLength().' ); - return this.manhattanLength(); + colors.push( color.r, color.g, color.b ); + colors.push( color.r, color.g, color.b ); } -} ); - -Object.assign( Vector3.prototype, { + // create the circles - setEulerFromRotationMatrix: function () { + for ( i = 0; i <= circles; i ++ ) { - console.error( 'THREE.Vector3: .setEulerFromRotationMatrix() has been removed. Use Euler.setFromRotationMatrix() instead.' ); + color = ( i & 1 ) ? color1 : color2; - }, - setEulerFromQuaternion: function () { + r = radius - ( radius / circles * i ); - console.error( 'THREE.Vector3: .setEulerFromQuaternion() has been removed. Use Euler.setFromQuaternion() instead.' ); + for ( j = 0; j < divisions; j ++ ) { - }, - getPositionFromMatrix: function ( m ) { + // first vertex - console.warn( 'THREE.Vector3: .getPositionFromMatrix() has been renamed to .setFromMatrixPosition().' ); - return this.setFromMatrixPosition( m ); + v = ( j / divisions ) * ( Math.PI * 2 ); - }, - getScaleFromMatrix: function ( m ) { + x = Math.sin( v ) * r; + z = Math.cos( v ) * r; - console.warn( 'THREE.Vector3: .getScaleFromMatrix() has been renamed to .setFromMatrixScale().' ); - return this.setFromMatrixScale( m ); + vertices.push( x, 0, z ); + colors.push( color.r, color.g, color.b ); - }, - getColumnFromMatrix: function ( index, matrix ) { + // second vertex - console.warn( 'THREE.Vector3: .getColumnFromMatrix() has been renamed to .setFromMatrixColumn().' ); - return this.setFromMatrixColumn( matrix, index ); + v = ( ( j + 1 ) / divisions ) * ( Math.PI * 2 ); - }, - applyProjection: function ( m ) { + x = Math.sin( v ) * r; + z = Math.cos( v ) * r; - console.warn( 'THREE.Vector3: .applyProjection() has been removed. Use .applyMatrix4( m ) instead.' ); - return this.applyMatrix4( m ); + vertices.push( x, 0, z ); + colors.push( color.r, color.g, color.b ); - }, - fromAttribute: function ( attribute, index, offset ) { + } - console.warn( 'THREE.Vector3: .fromAttribute() has been renamed to .fromBufferAttribute().' ); - return this.fromBufferAttribute( attribute, index, offset ); + } - }, - distanceToManhattan: function ( v ) { + var geometry = new BufferGeometry(); + geometry.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); + geometry.addAttribute( 'color', new Float32BufferAttribute( colors, 3 ) ); - console.warn( 'THREE.Vector3: .distanceToManhattan() has been renamed to .manhattanDistanceTo().' ); - return this.manhattanDistanceTo( v ); + var material = new LineBasicMaterial( { vertexColors: VertexColors } ); - }, - lengthManhattan: function () { + LineSegments.call( this, geometry, material ); - console.warn( 'THREE.Vector3: .lengthManhattan() has been renamed to .manhattanLength().' ); - return this.manhattanLength(); +} - } +PolarGridHelper.prototype = Object.create( LineSegments.prototype ); +PolarGridHelper.prototype.constructor = PolarGridHelper; -} ); +/** + * @author mrdoob / http://mrdoob.com/ + * @author WestLangley / http://github.com/WestLangley + */ -Object.assign( Vector4.prototype, { +function FaceNormalsHelper( object, size, hex, linewidth ) { - fromAttribute: function ( attribute, index, offset ) { + // FaceNormalsHelper only supports THREE.Geometry - console.warn( 'THREE.Vector4: .fromAttribute() has been renamed to .fromBufferAttribute().' ); - return this.fromBufferAttribute( attribute, index, offset ); + this.object = object; - }, - lengthManhattan: function () { + this.size = ( size !== undefined ) ? size : 1; - console.warn( 'THREE.Vector4: .lengthManhattan() has been renamed to .manhattanLength().' ); - return this.manhattanLength(); + var color = ( hex !== undefined ) ? hex : 0xffff00; - } + var width = ( linewidth !== undefined ) ? linewidth : 1; -} ); + // -// + var nNormals = 0; -Object.assign( Geometry.prototype, { + var objGeometry = this.object.geometry; - computeTangents: function () { + if ( objGeometry && objGeometry.isGeometry ) { - console.error( 'THREE.Geometry: .computeTangents() has been removed.' ); + nNormals = objGeometry.faces.length; - }, - computeLineDistances: function () { + } else { - console.error( 'THREE.Geometry: .computeLineDistances() has been removed. Use THREE.Line.computeLineDistances() instead.' ); + console.warn( 'THREE.FaceNormalsHelper: only THREE.Geometry is supported. Use THREE.VertexNormalsHelper, instead.' ); } -} ); + // -Object.assign( Object3D.prototype, { + var geometry = new BufferGeometry(); - getChildByName: function ( name ) { + var positions = new Float32BufferAttribute( nNormals * 2 * 3, 3 ); - console.warn( 'THREE.Object3D: .getChildByName() has been renamed to .getObjectByName().' ); - return this.getObjectByName( name ); + geometry.addAttribute( 'position', positions ); - }, - renderDepth: function () { + LineSegments.call( this, geometry, new LineBasicMaterial( { color: color, linewidth: width } ) ); - console.warn( 'THREE.Object3D: .renderDepth has been removed. Use .renderOrder, instead.' ); + // - }, - translate: function ( distance, axis ) { + this.matrixAutoUpdate = false; + this.update(); - console.warn( 'THREE.Object3D: .translate() has been removed. Use .translateOnAxis( axis, distance ) instead.' ); - return this.translateOnAxis( axis, distance ); +} - } +FaceNormalsHelper.prototype = Object.create( LineSegments.prototype ); +FaceNormalsHelper.prototype.constructor = FaceNormalsHelper; -} ); +FaceNormalsHelper.prototype.update = ( function () { -Object.defineProperties( Object3D.prototype, { + var v1 = new Vector3(); + var v2 = new Vector3(); + var normalMatrix = new Matrix3(); - eulerOrder: { - get: function () { + return function update() { - console.warn( 'THREE.Object3D: .eulerOrder is now .rotation.order.' ); - return this.rotation.order; + this.object.updateMatrixWorld( true ); - }, - set: function ( value ) { + normalMatrix.getNormalMatrix( this.object.matrixWorld ); - console.warn( 'THREE.Object3D: .eulerOrder is now .rotation.order.' ); - this.rotation.order = value; + var matrixWorld = this.object.matrixWorld; - } - }, - useQuaternion: { - get: function () { + var position = this.geometry.attributes.position; - console.warn( 'THREE.Object3D: .useQuaternion has been removed. The library now uses quaternions by default.' ); + // - }, - set: function () { + var objGeometry = this.object.geometry; - console.warn( 'THREE.Object3D: .useQuaternion has been removed. The library now uses quaternions by default.' ); + var vertices = objGeometry.vertices; - } - } + var faces = objGeometry.faces; -} ); + var idx = 0; -Object.defineProperties( LOD.prototype, { + for ( var i = 0, l = faces.length; i < l; i ++ ) { - objects: { - get: function () { + var face = faces[ i ]; - console.warn( 'THREE.LOD: .objects has been renamed to .levels.' ); - return this.levels; + var normal = face.normal; - } - } + v1.copy( vertices[ face.a ] ) + .add( vertices[ face.b ] ) + .add( vertices[ face.c ] ) + .divideScalar( 3 ) + .applyMatrix4( matrixWorld ); -} ); + v2.copy( normal ).applyMatrix3( normalMatrix ).normalize().multiplyScalar( this.size ).add( v1 ); -Object.defineProperty( Skeleton.prototype, 'useVertexTexture', { + position.setXYZ( idx, v1.x, v1.y, v1.z ); - get: function () { + idx = idx + 1; - console.warn( 'THREE.Skeleton: useVertexTexture has been removed.' ); + position.setXYZ( idx, v2.x, v2.y, v2.z ); - }, - set: function () { + idx = idx + 1; - console.warn( 'THREE.Skeleton: useVertexTexture has been removed.' ); + } - } + position.needsUpdate = true; -} ); + }; -Object.defineProperty( Curve.prototype, '__arcLengthDivisions', { +}() ); - get: function () { +/** + * @author alteredq / http://alteredqualia.com/ + * @author mrdoob / http://mrdoob.com/ + * @author WestLangley / http://github.com/WestLangley + */ - console.warn( 'THREE.Curve: .__arcLengthDivisions is now .arcLengthDivisions.' ); - return this.arcLengthDivisions; +function DirectionalLightHelper( light, size, color ) { - }, - set: function ( value ) { + Object3D.call( this ); - console.warn( 'THREE.Curve: .__arcLengthDivisions is now .arcLengthDivisions.' ); - this.arcLengthDivisions = value; + this.light = light; + this.light.updateMatrixWorld(); - } + this.matrix = light.matrixWorld; + this.matrixAutoUpdate = false; -} ); - -// - -PerspectiveCamera.prototype.setLens = function ( focalLength, filmGauge ) { - - console.warn( "THREE.PerspectiveCamera.setLens is deprecated. " + - "Use .setFocalLength and .filmGauge for a photographic setup." ); + this.color = color; - if ( filmGauge !== undefined ) this.filmGauge = filmGauge; - this.setFocalLength( focalLength ); + if ( size === undefined ) size = 1; -}; + 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 ) ); -// + var material = new LineBasicMaterial( { fog: false } ); -Object.defineProperties( Light.prototype, { - onlyShadow: { - set: function () { + this.lightPlane = new Line( geometry, material ); + this.add( this.lightPlane ); - console.warn( 'THREE.Light: .onlyShadow has been removed.' ); + geometry = new BufferGeometry(); + geometry.addAttribute( 'position', new Float32BufferAttribute( [ 0, 0, 0, 0, 0, 1 ], 3 ) ); - } - }, - shadowCameraFov: { - set: function ( value ) { + this.targetLine = new Line( geometry, material ); + this.add( this.targetLine ); - console.warn( 'THREE.Light: .shadowCameraFov is now .shadow.camera.fov.' ); - this.shadow.camera.fov = value; + this.update(); - } - }, - shadowCameraLeft: { - set: function ( value ) { +} - console.warn( 'THREE.Light: .shadowCameraLeft is now .shadow.camera.left.' ); - this.shadow.camera.left = value; +DirectionalLightHelper.prototype = Object.create( Object3D.prototype ); +DirectionalLightHelper.prototype.constructor = DirectionalLightHelper; - } - }, - shadowCameraRight: { - set: function ( value ) { +DirectionalLightHelper.prototype.dispose = function () { - console.warn( 'THREE.Light: .shadowCameraRight is now .shadow.camera.right.' ); - this.shadow.camera.right = value; + this.lightPlane.geometry.dispose(); + this.lightPlane.material.dispose(); + this.targetLine.geometry.dispose(); + this.targetLine.material.dispose(); - } - }, - shadowCameraTop: { - set: function ( value ) { +}; - console.warn( 'THREE.Light: .shadowCameraTop is now .shadow.camera.top.' ); - this.shadow.camera.top = value; +DirectionalLightHelper.prototype.update = function () { - } - }, - shadowCameraBottom: { - set: function ( value ) { + var v1 = new Vector3(); + var v2 = new Vector3(); + var v3 = new Vector3(); - console.warn( 'THREE.Light: .shadowCameraBottom is now .shadow.camera.bottom.' ); - this.shadow.camera.bottom = value; + return function update() { - } - }, - shadowCameraNear: { - set: function ( value ) { + v1.setFromMatrixPosition( this.light.matrixWorld ); + v2.setFromMatrixPosition( this.light.target.matrixWorld ); + v3.subVectors( v2, v1 ); - console.warn( 'THREE.Light: .shadowCameraNear is now .shadow.camera.near.' ); - this.shadow.camera.near = value; + this.lightPlane.lookAt( v2 ); - } - }, - shadowCameraFar: { - set: function ( value ) { + if ( this.color !== undefined ) { - console.warn( 'THREE.Light: .shadowCameraFar is now .shadow.camera.far.' ); - this.shadow.camera.far = value; + this.lightPlane.material.color.set( this.color ); + this.targetLine.material.color.set( this.color ); - } - }, - shadowCameraVisible: { - set: function () { + } else { - console.warn( 'THREE.Light: .shadowCameraVisible has been removed. Use new THREE.CameraHelper( light.shadow.camera ) instead.' ); + this.lightPlane.material.color.copy( this.light.color ); + this.targetLine.material.color.copy( this.light.color ); } - }, - shadowBias: { - set: function ( value ) { - console.warn( 'THREE.Light: .shadowBias is now .shadow.bias.' ); - this.shadow.bias = value; + this.targetLine.lookAt( v2 ); + this.targetLine.scale.z = v3.length(); - } - }, - shadowDarkness: { - set: function () { + }; - console.warn( 'THREE.Light: .shadowDarkness has been removed.' ); +}(); - } - }, - shadowMapWidth: { - set: function ( value ) { +/** + * @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 + */ - console.warn( 'THREE.Light: .shadowMapWidth is now .shadow.mapSize.width.' ); - this.shadow.mapSize.width = value; +function CameraHelper( camera ) { - } - }, - shadowMapHeight: { - set: function ( value ) { + var geometry = new BufferGeometry(); + var material = new LineBasicMaterial( { color: 0xffffff, vertexColors: FaceColors } ); - console.warn( 'THREE.Light: .shadowMapHeight is now .shadow.mapSize.height.' ); - this.shadow.mapSize.height = value; + var vertices = []; + var colors = []; - } - } -} ); + var pointMap = {}; -// + // colors -Object.defineProperties( BufferAttribute.prototype, { + 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 ); - length: { - get: function () { + // near - console.warn( 'THREE.BufferAttribute: .length has been deprecated. Use .count instead.' ); - return this.array.length; + addLine( 'n1', 'n2', colorFrustum ); + addLine( 'n2', 'n4', colorFrustum ); + addLine( 'n4', 'n3', colorFrustum ); + addLine( 'n3', 'n1', colorFrustum ); - } - } + // far -} ); + addLine( 'f1', 'f2', colorFrustum ); + addLine( 'f2', 'f4', colorFrustum ); + addLine( 'f4', 'f3', colorFrustum ); + addLine( 'f3', 'f1', colorFrustum ); -Object.assign( BufferGeometry.prototype, { + // sides - addIndex: function ( index ) { + addLine( 'n1', 'f1', colorFrustum ); + addLine( 'n2', 'f2', colorFrustum ); + addLine( 'n3', 'f3', colorFrustum ); + addLine( 'n4', 'f4', colorFrustum ); - console.warn( 'THREE.BufferGeometry: .addIndex() has been renamed to .setIndex().' ); - this.setIndex( index ); + // cone - }, - addDrawCall: function ( start, count, indexOffset ) { + addLine( 'p', 'n1', colorCone ); + addLine( 'p', 'n2', colorCone ); + addLine( 'p', 'n3', colorCone ); + addLine( 'p', 'n4', colorCone ); - if ( indexOffset !== undefined ) { + // up - console.warn( 'THREE.BufferGeometry: .addDrawCall() no longer supports indexOffset.' ); + addLine( 'u1', 'u2', colorUp ); + addLine( 'u2', 'u3', colorUp ); + addLine( 'u3', 'u1', colorUp ); - } - console.warn( 'THREE.BufferGeometry: .addDrawCall() is now .addGroup().' ); - this.addGroup( start, count ); + // target - }, - clearDrawCalls: function () { + addLine( 'c', 't', colorTarget ); + addLine( 'p', 'c', colorCross ); - console.warn( 'THREE.BufferGeometry: .clearDrawCalls() is now .clearGroups().' ); - this.clearGroups(); + // cross - }, - computeTangents: function () { + addLine( 'cn1', 'cn2', colorCross ); + addLine( 'cn3', 'cn4', colorCross ); - console.warn( 'THREE.BufferGeometry: .computeTangents() has been removed.' ); + addLine( 'cf1', 'cf2', colorCross ); + addLine( 'cf3', 'cf4', colorCross ); - }, - computeOffsets: function () { + function addLine( a, b, color ) { - console.warn( 'THREE.BufferGeometry: .computeOffsets() has been removed.' ); + addPoint( a, color ); + addPoint( b, color ); } -} ); + function addPoint( id, color ) { -Object.defineProperties( BufferGeometry.prototype, { + vertices.push( 0, 0, 0 ); + colors.push( color.r, color.g, color.b ); - drawcalls: { - get: function () { + if ( pointMap[ id ] === undefined ) { - console.error( 'THREE.BufferGeometry: .drawcalls has been renamed to .groups.' ); - return this.groups; + pointMap[ id ] = []; } - }, - offsets: { - get: function () { - console.warn( 'THREE.BufferGeometry: .offsets has been renamed to .groups.' ); - return this.groups; + pointMap[ id ].push( ( vertices.length / 3 ) - 1 ); - } } -} ); + geometry.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); + geometry.addAttribute( 'color', new Float32BufferAttribute( colors, 3 ) ); -// + LineSegments.call( this, geometry, material ); -Object.defineProperties( Uniform.prototype, { + this.camera = camera; + if ( this.camera.updateProjectionMatrix ) this.camera.updateProjectionMatrix(); - dynamic: { - set: function () { + this.matrix = camera.matrixWorld; + this.matrixAutoUpdate = false; - console.warn( 'THREE.Uniform: .dynamic has been removed. Use object.onBeforeRender() instead.' ); + this.pointMap = pointMap; - } - }, - onUpdate: { - value: function () { + this.update(); - console.warn( 'THREE.Uniform: .onUpdate() has been removed. Use object.onBeforeRender() instead.' ); - return this; +} - } - } +CameraHelper.prototype = Object.create( LineSegments.prototype ); +CameraHelper.prototype.constructor = CameraHelper; -} ); +CameraHelper.prototype.update = function () { -// + var geometry, pointMap; -Object.defineProperties( Material.prototype, { + var vector = new Vector3(); + var camera = new Camera(); - wrapAround: { - get: function () { + function setPoint( point, x, y, z ) { - console.warn( 'THREE.Material: .wrapAround has been removed.' ); + vector.set( x, y, z ).unproject( camera ); - }, - set: function () { + var points = pointMap[ point ]; - console.warn( 'THREE.Material: .wrapAround has been removed.' ); + if ( points !== undefined ) { - } - }, - wrapRGB: { - get: function () { + var position = geometry.getAttribute( 'position' ); - console.warn( 'THREE.Material: .wrapRGB has been removed.' ); - return new Color(); + for ( var i = 0, l = points.length; i < l; i ++ ) { + + position.setXYZ( points[ i ], vector.x, vector.y, vector.z ); + + } } - }, - shading: { - get: function () { + } - console.error( 'THREE.' + this.type + ': .shading has been removed. Use the boolean .flatShading instead.' ); + return function update() { - }, - set: function ( value ) { + geometry = this.geometry; + pointMap = this.pointMap; - console.warn( 'THREE.' + this.type + ': .shading has been removed. Use the boolean .flatShading instead.' ); - this.flatShading = ( value === FlatShading ); + var w = 1, h = 1; - } - } + // we need just camera projection matrix + // world matrix must be identity -} ); + camera.projectionMatrix.copy( this.camera.projectionMatrix ); -Object.defineProperties( MeshPhongMaterial.prototype, { + // center / target - metal: { - get: function () { + setPoint( 'c', 0, 0, - 1 ); + setPoint( 't', 0, 0, 1 ); - console.warn( 'THREE.MeshPhongMaterial: .metal has been removed. Use THREE.MeshStandardMaterial instead.' ); - return false; + // near - }, - set: function () { + setPoint( 'n1', - w, - h, - 1 ); + setPoint( 'n2', w, - h, - 1 ); + setPoint( 'n3', - w, h, - 1 ); + setPoint( 'n4', w, h, - 1 ); - console.warn( 'THREE.MeshPhongMaterial: .metal has been removed. Use THREE.MeshStandardMaterial instead' ); + // far - } - } + setPoint( 'f1', - w, - h, 1 ); + setPoint( 'f2', w, - h, 1 ); + setPoint( 'f3', - w, h, 1 ); + setPoint( 'f4', w, h, 1 ); -} ); + // up -Object.defineProperties( ShaderMaterial.prototype, { + setPoint( 'u1', w * 0.7, h * 1.1, - 1 ); + setPoint( 'u2', - w * 0.7, h * 1.1, - 1 ); + setPoint( 'u3', 0, h * 2, - 1 ); - derivatives: { - get: function () { + // cross - console.warn( 'THREE.ShaderMaterial: .derivatives has been moved to .extensions.derivatives.' ); - return this.extensions.derivatives; + setPoint( 'cf1', - w, 0, 1 ); + setPoint( 'cf2', w, 0, 1 ); + setPoint( 'cf3', 0, - h, 1 ); + setPoint( 'cf4', 0, h, 1 ); - }, - set: function ( value ) { + setPoint( 'cn1', - w, 0, - 1 ); + setPoint( 'cn2', w, 0, - 1 ); + setPoint( 'cn3', 0, - h, - 1 ); + setPoint( 'cn4', 0, h, - 1 ); - console.warn( 'THREE. ShaderMaterial: .derivatives has been moved to .extensions.derivatives.' ); - this.extensions.derivatives = value; + geometry.getAttribute( 'position' ).needsUpdate = true; - } - } + }; -} ); +}(); -// +/** + * @author mrdoob / http://mrdoob.com/ + * @author Mugen87 / http://github.com/Mugen87 + */ -Object.assign( WebGLRenderer.prototype, { +function BoxHelper( object, color ) { - getCurrentRenderTarget: function () { + this.object = object; - console.warn( 'THREE.WebGLRenderer: .getCurrentRenderTarget() is now .getRenderTarget().' ); - return this.getRenderTarget(); + 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 = new Float32Array( 8 * 3 ); - getMaxAnisotropy: function () { + var geometry = new BufferGeometry(); + geometry.setIndex( new BufferAttribute( indices, 1 ) ); + geometry.addAttribute( 'position', new BufferAttribute( positions, 3 ) ); - console.warn( 'THREE.WebGLRenderer: .getMaxAnisotropy() is now .capabilities.getMaxAnisotropy().' ); - return this.capabilities.getMaxAnisotropy(); + LineSegments.call( this, geometry, new LineBasicMaterial( { color: color } ) ); - }, + this.matrixAutoUpdate = false; - getPrecision: function () { + this.update(); - console.warn( 'THREE.WebGLRenderer: .getPrecision() is now .capabilities.precision.' ); - return this.capabilities.precision; +} - }, +BoxHelper.prototype = Object.create( LineSegments.prototype ); +BoxHelper.prototype.constructor = BoxHelper; - resetGLState: function () { +BoxHelper.prototype.update = ( function () { - console.warn( 'THREE.WebGLRenderer: .resetGLState() is now .state.reset().' ); - return this.state.reset(); + var box = new Box3(); - }, + return function update( object ) { - supportsFloatTextures: function () { + if ( object !== undefined ) { - console.warn( 'THREE.WebGLRenderer: .supportsFloatTextures() is now .extensions.get( \'OES_texture_float\' ).' ); - return this.extensions.get( 'OES_texture_float' ); + console.warn( 'THREE.BoxHelper: .update() has no longer arguments.' ); - }, - supportsHalfFloatTextures: function () { + } - console.warn( 'THREE.WebGLRenderer: .supportsHalfFloatTextures() is now .extensions.get( \'OES_texture_half_float\' ).' ); - return this.extensions.get( 'OES_texture_half_float' ); + if ( this.object !== undefined ) { - }, - supportsStandardDerivatives: function () { + box.setFromObject( this.object ); - console.warn( 'THREE.WebGLRenderer: .supportsStandardDerivatives() is now .extensions.get( \'OES_standard_derivatives\' ).' ); - return this.extensions.get( 'OES_standard_derivatives' ); + } - }, - supportsCompressedTextureS3TC: function () { + if ( box.isEmpty() ) return; - console.warn( 'THREE.WebGLRenderer: .supportsCompressedTextureS3TC() is now .extensions.get( \'WEBGL_compressed_texture_s3tc\' ).' ); - return this.extensions.get( 'WEBGL_compressed_texture_s3tc' ); + var min = box.min; + var max = box.max; - }, - supportsCompressedTexturePVRTC: function () { + /* + 5____4 + 1/___0/| + | 6__|_7 + 2/___3/ - console.warn( 'THREE.WebGLRenderer: .supportsCompressedTexturePVRTC() is now .extensions.get( \'WEBGL_compressed_texture_pvrtc\' ).' ); - return this.extensions.get( 'WEBGL_compressed_texture_pvrtc' ); + 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 + */ - }, - supportsBlendMinMax: function () { + var position = this.geometry.attributes.position; + var array = position.array; - console.warn( 'THREE.WebGLRenderer: .supportsBlendMinMax() is now .extensions.get( \'EXT_blend_minmax\' ).' ); - return this.extensions.get( 'EXT_blend_minmax' ); + 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; - }, - supportsVertexTextures: function () { + position.needsUpdate = true; - console.warn( 'THREE.WebGLRenderer: .supportsVertexTextures() is now .capabilities.vertexTextures.' ); - return this.capabilities.vertexTextures; + this.geometry.computeBoundingSphere(); - }, - supportsInstancedArrays: function () { + }; - console.warn( 'THREE.WebGLRenderer: .supportsInstancedArrays() is now .extensions.get( \'ANGLE_instanced_arrays\' ).' ); - return this.extensions.get( 'ANGLE_instanced_arrays' ); +} )(); - }, - enableScissorTest: function ( boolean ) { +BoxHelper.prototype.setFromObject = function ( object ) { - console.warn( 'THREE.WebGLRenderer: .enableScissorTest() is now .setScissorTest().' ); - this.setScissorTest( boolean ); + this.object = object; + this.update(); - }, - initMaterial: function () { + return this; - console.warn( 'THREE.WebGLRenderer: .initMaterial() has been removed.' ); +}; - }, - addPrePlugin: function () { +BoxHelper.prototype.copy = function ( source ) { - console.warn( 'THREE.WebGLRenderer: .addPrePlugin() has been removed.' ); + LineSegments.prototype.copy.call( this, source ); - }, - addPostPlugin: function () { + this.object = source.object; - console.warn( 'THREE.WebGLRenderer: .addPostPlugin() has been removed.' ); + return this; - }, - updateShadowMap: function () { +}; - console.warn( 'THREE.WebGLRenderer: .updateShadowMap() has been removed.' ); +BoxHelper.prototype.clone = function () { - }, - setFaceCulling: function () { + return new this.constructor().copy( this ); - console.warn( 'THREE.WebGLRenderer: .setFaceCulling() has been removed.' ); +}; - } +/** + * @author WestLangley / http://github.com/WestLangley + */ -} ); +function Box3Helper( box, hex ) { -Object.defineProperties( WebGLRenderer.prototype, { + this.type = 'Box3Helper'; - shadowMapEnabled: { - get: function () { + this.box = box; - return this.shadowMap.enabled; + var color = ( hex !== undefined ) ? hex : 0xffff00; - }, - set: function ( value ) { + 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 ] ); - console.warn( 'THREE.WebGLRenderer: .shadowMapEnabled is now .shadowMap.enabled.' ); - this.shadowMap.enabled = value; + 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 ]; - } - }, - shadowMapType: { - get: function () { + var geometry = new BufferGeometry(); - return this.shadowMap.type; + geometry.setIndex( new BufferAttribute( indices, 1 ) ); - }, - set: function ( value ) { + geometry.addAttribute( 'position', new Float32BufferAttribute( positions, 3 ) ); - console.warn( 'THREE.WebGLRenderer: .shadowMapType is now .shadowMap.type.' ); - this.shadowMap.type = value; + LineSegments.call( this, geometry, new LineBasicMaterial( { color: color } ) ); - } - }, - shadowMapCullFace: { - get: function () { + this.geometry.computeBoundingSphere(); - console.warn( 'THREE.WebGLRenderer: .shadowMapCullFace has been removed. Set Material.shadowSide instead.' ); - return undefined; +} - }, - set: function ( /* value */ ) { +Box3Helper.prototype = Object.create( LineSegments.prototype ); +Box3Helper.prototype.constructor = Box3Helper; - console.warn( 'THREE.WebGLRenderer: .shadowMapCullFace has been removed. Set Material.shadowSide instead.' ); +Box3Helper.prototype.updateMatrixWorld = function ( force ) { - } - } -} ); + var box = this.box; -Object.defineProperties( WebGLShadowMap.prototype, { + if ( box.isEmpty() ) return; - cullFace: { - get: function () { + box.getCenter( this.position ); - console.warn( 'THREE.WebGLRenderer: .shadowMap.cullFace has been removed. Set Material.shadowSide instead.' ); - return undefined; + box.getSize( this.scale ); - }, - set: function ( /* cullFace */ ) { + this.scale.multiplyScalar( 0.5 ); - console.warn( 'THREE.WebGLRenderer: .shadowMap.cullFace has been removed. Set Material.shadowSide instead.' ); + Object3D.prototype.updateMatrixWorld.call( this, force ); - } - }, - renderReverseSided: { - get: function () { +}; - console.warn( 'THREE.WebGLRenderer: .shadowMap.renderReverseSided has been removed. Set Material.shadowSide instead.' ); - return undefined; +/** + * @author WestLangley / http://github.com/WestLangley + */ - }, - set: function () { +function PlaneHelper( plane, size, hex ) { - console.warn( 'THREE.WebGLRenderer: .shadowMap.renderReverseSided has been removed. Set Material.shadowSide instead.' ); + this.type = 'PlaneHelper'; - } - }, - renderSingleSided: { - get: function () { + this.plane = plane; - console.warn( 'THREE.WebGLRenderer: .shadowMap.renderSingleSided has been removed. Set Material.shadowSide instead.' ); - return undefined; + this.size = ( size === undefined ) ? 1 : size; - }, - set: function () { + var color = ( hex !== undefined ) ? hex : 0xffff00; - console.warn( 'THREE.WebGLRenderer: .shadowMap.renderSingleSided has been removed. Set Material.shadowSide instead.' ); + 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.addAttribute( 'position', new Float32BufferAttribute( positions, 3 ) ); + geometry.computeBoundingSphere(); -} ); + Line.call( this, geometry, new LineBasicMaterial( { color: color } ) ); -// + // -Object.defineProperties( WebGLRenderTarget.prototype, { + var positions2 = [ 1, 1, 1, - 1, 1, 1, - 1, - 1, 1, 1, 1, 1, - 1, - 1, 1, 1, - 1, 1 ]; - wrapS: { - get: function () { + var geometry2 = new BufferGeometry(); + geometry2.addAttribute( 'position', new Float32BufferAttribute( positions2, 3 ) ); + geometry2.computeBoundingSphere(); - console.warn( 'THREE.WebGLRenderTarget: .wrapS is now .texture.wrapS.' ); - return this.texture.wrapS; + this.add( new Mesh( geometry2, new MeshBasicMaterial( { color: color, opacity: 0.2, transparent: true, depthWrite: false } ) ) ); - }, - set: function ( value ) { +} - console.warn( 'THREE.WebGLRenderTarget: .wrapS is now .texture.wrapS.' ); - this.texture.wrapS = value; +PlaneHelper.prototype = Object.create( Line.prototype ); +PlaneHelper.prototype.constructor = PlaneHelper; - } - }, - wrapT: { - get: function () { +PlaneHelper.prototype.updateMatrixWorld = function ( force ) { - console.warn( 'THREE.WebGLRenderTarget: .wrapT is now .texture.wrapT.' ); - return this.texture.wrapT; + var scale = - this.plane.constant; - }, - set: function ( value ) { + if ( Math.abs( scale ) < 1e-8 ) scale = 1e-8; // sign does not matter - console.warn( 'THREE.WebGLRenderTarget: .wrapT is now .texture.wrapT.' ); - this.texture.wrapT = value; + this.scale.set( 0.5 * this.size, 0.5 * this.size, scale ); - } - }, - magFilter: { - get: function () { + this.children[ 0 ].material.side = ( scale < 0 ) ? BackSide : FrontSide; // renderer flips side when determinant < 0; flipping not wanted here - console.warn( 'THREE.WebGLRenderTarget: .magFilter is now .texture.magFilter.' ); - return this.texture.magFilter; + this.lookAt( this.plane.normal ); - }, - set: function ( value ) { + Object3D.prototype.updateMatrixWorld.call( this, force ); - console.warn( 'THREE.WebGLRenderTarget: .magFilter is now .texture.magFilter.' ); - this.texture.magFilter = value; +}; - } - }, - minFilter: { - get: function () { +/** + * @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 + */ - console.warn( 'THREE.WebGLRenderTarget: .minFilter is now .texture.minFilter.' ); - return this.texture.minFilter; +var lineGeometry, coneGeometry; - }, - set: function ( value ) { +function ArrowHelper( dir, origin, length, color, headLength, headWidth ) { - console.warn( 'THREE.WebGLRenderTarget: .minFilter is now .texture.minFilter.' ); - this.texture.minFilter = value; + // dir is assumed to be normalized - } - }, - anisotropy: { - get: function () { + Object3D.call( this ); - console.warn( 'THREE.WebGLRenderTarget: .anisotropy is now .texture.anisotropy.' ); - return this.texture.anisotropy; + 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; - }, - set: function ( value ) { + if ( lineGeometry === undefined ) { - console.warn( 'THREE.WebGLRenderTarget: .anisotropy is now .texture.anisotropy.' ); - this.texture.anisotropy = value; + lineGeometry = new BufferGeometry(); + lineGeometry.addAttribute( 'position', new Float32BufferAttribute( [ 0, 0, 0, 0, 1, 0 ], 3 ) ); - } - }, - offset: { - get: function () { + coneGeometry = new CylinderBufferGeometry( 0, 0.5, 1, 5, 1 ); + coneGeometry.translate( 0, - 0.5, 0 ); - console.warn( 'THREE.WebGLRenderTarget: .offset is now .texture.offset.' ); - return this.texture.offset; + } - }, - set: function ( value ) { + this.position.copy( origin ); - console.warn( 'THREE.WebGLRenderTarget: .offset is now .texture.offset.' ); - this.texture.offset = value; + this.line = new Line( lineGeometry, new LineBasicMaterial( { color: color } ) ); + this.line.matrixAutoUpdate = false; + this.add( this.line ); - } - }, - repeat: { - get: function () { + this.cone = new Mesh( coneGeometry, new MeshBasicMaterial( { color: color } ) ); + this.cone.matrixAutoUpdate = false; + this.add( this.cone ); - console.warn( 'THREE.WebGLRenderTarget: .repeat is now .texture.repeat.' ); - return this.texture.repeat; + this.setDirection( dir ); + this.setLength( length, headLength, headWidth ); - }, - set: function ( value ) { +} - console.warn( 'THREE.WebGLRenderTarget: .repeat is now .texture.repeat.' ); - this.texture.repeat = value; +ArrowHelper.prototype = Object.create( Object3D.prototype ); +ArrowHelper.prototype.constructor = ArrowHelper; - } - }, - format: { - get: function () { +ArrowHelper.prototype.setDirection = ( function () { - console.warn( 'THREE.WebGLRenderTarget: .format is now .texture.format.' ); - return this.texture.format; + var axis = new Vector3(); + var radians; - }, - set: function ( value ) { + return function setDirection( dir ) { - console.warn( 'THREE.WebGLRenderTarget: .format is now .texture.format.' ); - this.texture.format = value; + // dir is assumed to be normalized - } - }, - type: { - get: function () { + if ( dir.y > 0.99999 ) { - console.warn( 'THREE.WebGLRenderTarget: .type is now .texture.type.' ); - return this.texture.type; + this.quaternion.set( 0, 0, 0, 1 ); - }, - set: function ( value ) { + } else if ( dir.y < - 0.99999 ) { - console.warn( 'THREE.WebGLRenderTarget: .type is now .texture.type.' ); - this.texture.type = value; + this.quaternion.set( 1, 0, 0, 0 ); - } - }, - generateMipmaps: { - get: function () { + } else { - console.warn( 'THREE.WebGLRenderTarget: .generateMipmaps is now .texture.generateMipmaps.' ); - return this.texture.generateMipmaps; + axis.set( dir.z, 0, - dir.x ).normalize(); - }, - set: function ( value ) { + radians = Math.acos( dir.y ); - console.warn( 'THREE.WebGLRenderTarget: .generateMipmaps is now .texture.generateMipmaps.' ); - this.texture.generateMipmaps = value; + this.quaternion.setFromAxisAngle( axis, radians ); } - } -} ); + }; -// +}() ); -Object.defineProperties( WebVRManager.prototype, { +ArrowHelper.prototype.setLength = function ( length, headLength, headWidth ) { - standing: { - set: function ( /* value */ ) { + if ( headLength === undefined ) headLength = 0.2 * length; + if ( headWidth === undefined ) headWidth = 0.2 * headLength; - console.warn( 'THREE.WebVRManager: .standing has been removed.' ); + this.line.scale.set( 1, Math.max( 0, length - headLength ), 1 ); + this.line.updateMatrix(); - } - } + this.cone.scale.set( headWidth, headLength, headWidth ); + this.cone.position.y = length; + this.cone.updateMatrix(); -} ); +}; -// +ArrowHelper.prototype.setColor = function ( color ) { -Audio.prototype.load = function ( file ) { + this.line.material.color.copy( color ); + this.cone.material.color.copy( color ); - 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 ); +ArrowHelper.prototype.copy = function ( source ) { + + Object3D.prototype.copy.call( this, source, false ); + + this.line.copy( source.line ); + this.cone.copy( source.cone ); - } ); return this; }; -AudioAnalyser.prototype.getData = function () { +ArrowHelper.prototype.clone = function () { - console.warn( 'THREE.AudioAnalyser: .getData() is now .getFrequencyData().' ); - return this.getFrequencyData(); + return new this.constructor().copy( this ); }; -// +/** + * @author sroucheray / http://sroucheray.org/ + * @author mrdoob / http://mrdoob.com/ + */ -CubeCamera.prototype.updateCubeMap = function ( renderer, scene ) { +function AxesHelper( size ) { - console.warn( 'THREE.CubeCamera: .updateCubeMap() is now .update().' ); - return this.update( renderer, scene ); + 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 GeometryUtils = { + var geometry = new BufferGeometry(); + geometry.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); + geometry.addAttribute( 'color', new Float32BufferAttribute( colors, 3 ) ); - merge: function ( geometry1, geometry2, materialIndexOffset ) { + var material = new LineBasicMaterial( { vertexColors: VertexColors } ); - console.warn( 'THREE.GeometryUtils: .merge() has been moved to Geometry. Use geometry.merge( geometry2, matrix, materialIndexOffset ) instead.' ); - var matrix; + LineSegments.call( this, geometry, material ); - if ( geometry2.isMesh ) { +} - geometry2.matrixAutoUpdate && geometry2.updateMatrix(); +AxesHelper.prototype = Object.create( LineSegments.prototype ); +AxesHelper.prototype.constructor = AxesHelper; - matrix = geometry2.matrix; - geometry2 = geometry2.geometry; +/** + * @author mrdoob / http://mrdoob.com/ + */ - } +function Face4( a, b, c, d, normal, color, materialIndex ) { - geometry1.merge( geometry2, matrix, materialIndexOffset ); + console.warn( 'THREE.Face4 has been removed. A THREE.Face3 will be created instead.' ); + return new Face3( a, b, c, normal, color, materialIndex ); - }, +} - center: function ( geometry ) { +var LineStrip = 0; - console.warn( 'THREE.GeometryUtils: .center() has been moved to Geometry. Use geometry.center() instead.' ); - return geometry.center(); +var LinePieces = 1; - } +function MeshFaceMaterial( materials ) { -}; + console.warn( 'THREE.MeshFaceMaterial has been removed. Use an Array instead.' ); + return materials; -var ImageUtils = { +} + +function MultiMaterial( materials ) { - crossOrigin: undefined, + if ( materials === undefined ) materials = []; - loadTexture: function ( url, mapping, onLoad, onError ) { + console.warn( 'THREE.MultiMaterial has been removed. Use an Array instead.' ); + materials.isMultiMaterial = true; + materials.materials = materials; + materials.clone = function () { - console.warn( 'THREE.ImageUtils.loadTexture has been deprecated. Use THREE.TextureLoader() instead.' ); + return materials.slice(); - var loader = new TextureLoader(); - loader.setCrossOrigin( this.crossOrigin ); + }; + return materials; - var texture = loader.load( url, onLoad, undefined, onError ); +} - if ( mapping ) texture.mapping = mapping; +function PointCloud( geometry, material ) { - return texture; + console.warn( 'THREE.PointCloud has been renamed to THREE.Points.' ); + return new Points( geometry, material ); - }, +} - loadTextureCube: function ( urls, mapping, onLoad, onError ) { +function Particle( material ) { - console.warn( 'THREE.ImageUtils.loadTextureCube has been deprecated. Use THREE.CubeTextureLoader() instead.' ); + console.warn( 'THREE.Particle has been renamed to THREE.Sprite.' ); + return new Sprite( material ); - var loader = new CubeTextureLoader(); - loader.setCrossOrigin( this.crossOrigin ); +} - var texture = loader.load( urls, onLoad, undefined, onError ); +function ParticleSystem( geometry, material ) { - if ( mapping ) texture.mapping = mapping; + console.warn( 'THREE.ParticleSystem has been renamed to THREE.Points.' ); + return new Points( geometry, material ); - return texture; +} - }, +function PointCloudMaterial( parameters ) { - loadCompressedTexture: function () { + console.warn( 'THREE.PointCloudMaterial has been renamed to THREE.PointsMaterial.' ); + return new PointsMaterial( parameters ); - console.error( 'THREE.ImageUtils.loadCompressedTexture has been removed. Use THREE.DDSLoader instead.' ); +} - }, +function ParticleBasicMaterial( parameters ) { - loadCompressedTextureCube: function () { + console.warn( 'THREE.ParticleBasicMaterial has been renamed to THREE.PointsMaterial.' ); + return new PointsMaterial( parameters ); - console.error( 'THREE.ImageUtils.loadCompressedTextureCube has been removed. Use THREE.DDSLoader instead.' ); +} - } +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 Projector() { +function DynamicBufferAttribute( array, itemSize ) { - console.error( 'THREE.Projector has been moved to /examples/js/renderers/Projector.js.' ); + console.warn( 'THREE.DynamicBufferAttribute has been removed. Use new THREE.BufferAttribute().setDynamic( true ) instead.' ); + return new BufferAttribute( array, itemSize ).setDynamic( true ); - this.projectVector = function ( vector, camera ) { +} - console.warn( 'THREE.Projector: .projectVector() is now vector.project().' ); - vector.project( camera ); +function Int8Attribute( array, itemSize ) { - }; + console.warn( 'THREE.Int8Attribute has been removed. Use new THREE.Int8BufferAttribute() instead.' ); + return new Int8BufferAttribute( array, itemSize ); - this.unprojectVector = function ( vector, camera ) { +} - console.warn( 'THREE.Projector: .unprojectVector() is now vector.unproject().' ); - vector.unproject( camera ); +function Uint8Attribute( array, itemSize ) { - }; + console.warn( 'THREE.Uint8Attribute has been removed. Use new THREE.Uint8BufferAttribute() instead.' ); + return new Uint8BufferAttribute( array, itemSize ); - this.pickingRay = function () { +} - console.error( 'THREE.Projector: .pickingRay() is now raycaster.setFromCamera().' ); +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 ) { -function CanvasRenderer() { + console.warn( 'THREE.Int16Attribute has been removed. Use new THREE.Int16BufferAttribute() instead.' ); + return new Int16BufferAttribute( array, itemSize ); + +} - console.error( 'THREE.CanvasRenderer has been moved to /examples/js/renderers/CanvasRenderer.js' ); +function Uint16Attribute( array, itemSize ) { - this.domElement = document.createElementNS( 'http://www.w3.org/1999/xhtml', 'canvas' ); - this.clear = function () {}; - this.render = function () {}; - this.setClearColor = function () {}; - this.setSize = function () {}; + console.warn( 'THREE.Uint16Attribute has been removed. Use new THREE.Uint16BufferAttribute() instead.' ); + return new Uint16BufferAttribute( array, itemSize ); } -// +function Int32Attribute( array, itemSize ) { -var SceneUtils = { + console.warn( 'THREE.Int32Attribute has been removed. Use new THREE.Int32BufferAttribute() instead.' ); + return new Int32BufferAttribute( array, itemSize ); - createMultiMaterialObject: function ( /* geometry, materials */ ) { +} - console.error( 'THREE.SceneUtils has been moved to /examples/js/utils/SceneUtils.js' ); +function Uint32Attribute( array, itemSize ) { - }, + console.warn( 'THREE.Uint32Attribute has been removed. Use new THREE.Uint32BufferAttribute() instead.' ); + return new Uint32BufferAttribute( array, itemSize ); - detach: function ( /* child, parent, scene */ ) { +} - console.error( 'THREE.SceneUtils has been moved to /examples/js/utils/SceneUtils.js' ); +function Float32Attribute( array, itemSize ) { - }, + console.warn( 'THREE.Float32Attribute has been removed. Use new THREE.Float32BufferAttribute() instead.' ); + return new Float32BufferAttribute( array, itemSize ); - attach: function ( /* child, scene, parent */ ) { +} - console.error( 'THREE.SceneUtils has been moved to /examples/js/utils/SceneUtils.js' ); +function Float64Attribute( array, itemSize ) { - } + console.warn( 'THREE.Float64Attribute has been removed. Use new THREE.Float64BufferAttribute() instead.' ); + return new Float64BufferAttribute( array, itemSize ); -}; +} // -function LensFlare() { +Curve.create = function ( construct, getPoint ) { - console.error( 'THREE.LensFlare has been moved to /examples/js/objects/Lensflare.js' ); + console.log( 'THREE.Curve.create() has been deprecated' ); -} + construct.prototype = Object.create( Curve.prototype ); + construct.prototype.constructor = construct; + construct.prototype.getPoint = getPoint; + return construct; +}; +// -/***/ }), -/* 20 */ -/***/ (function(module, exports) { +Object.assign( CurvePath.prototype, { -module.exports = function(THREE) { - var MOUSE = THREE.MOUSE - if (!MOUSE) - MOUSE = { LEFT: 0, MIDDLE: 1, RIGHT: 2 }; + createPointsGeometry: function ( divisions ) { - /** - * @author qiao / https://github.com/qiao - * @author mrdoob / http://mrdoob.com - * @author alteredq / http://alteredqualia.com/ - * @author WestLangley / http://github.com/WestLangley - * @author erich666 / http://erichaines.com - */ - /*global THREE, console */ + console.warn( 'THREE.CurvePath: .createPointsGeometry() has been removed. Use new THREE.Geometry().setFromPoints( points ) instead.' ); - function OrbitConstraint ( object ) { + // generate geometry from path points (for Line or Points objects) - this.object = object; + var pts = this.getPoints( divisions ); + return this.createGeometry( pts ); - // "target" sets the location of focus, where the object orbits around - // and where it pans with respect to. - this.target = new THREE.Vector3(); + }, - // Limits to how far you can dolly in and out ( PerspectiveCamera only ) - this.minDistance = 0; - this.maxDistance = Infinity; + createSpacedPointsGeometry: function ( divisions ) { - // Limits to how far you can zoom in and out ( OrthographicCamera only ) - this.minZoom = 0; - this.maxZoom = Infinity; + console.warn( 'THREE.CurvePath: .createSpacedPointsGeometry() has been removed. Use new THREE.Geometry().setFromPoints( points ) instead.' ); - // How far you can orbit vertically, upper and lower limits. - // Range is 0 to Math.PI radians. - this.minPolarAngle = 0; // radians - this.maxPolarAngle = Math.PI; // radians + // generate geometry from equidistant sampling along the path - // How far you can orbit horizontally, upper and lower limits. - // If set, must be a sub-interval of the interval [ - Math.PI, Math.PI ]. - this.minAzimuthAngle = - Infinity; // radians - this.maxAzimuthAngle = Infinity; // radians + var pts = this.getSpacedPoints( divisions ); + return this.createGeometry( pts ); - // Set to true to enable damping (inertia) - // If damping is enabled, you must call controls.update() in your animation loop - this.enableDamping = false; - this.dampingFactor = 0.25; + }, - //////////// - // internals + createGeometry: function ( points ) { - var scope = this; + console.warn( 'THREE.CurvePath: .createGeometry() has been removed. Use new THREE.Geometry().setFromPoints( points ) instead.' ); - var EPS = 0.000001; + var geometry = new Geometry(); - // Current position in spherical coordinate system. - var theta; - var phi; + for ( var i = 0, l = points.length; i < l; i ++ ) { - // Pending changes - var phiDelta = 0; - var thetaDelta = 0; - var scale = 1; - var panOffset = new THREE.Vector3(); - var zoomChanged = false; + var point = points[ i ]; + geometry.vertices.push( new Vector3( point.x, point.y, point.z || 0 ) ); - // API + } - this.getPolarAngle = function () { + return geometry; - return phi; + } - }; +} ); - this.getAzimuthalAngle = function () { +// - return theta; +Object.assign( Path.prototype, { - }; + fromPoints: function ( points ) { - this.rotateLeft = function ( angle ) { + console.warn( 'THREE.Path: .fromPoints() has been renamed to .setFromPoints().' ); + this.setFromPoints( points ); - thetaDelta -= angle; + } - }; +} ); - this.rotateUp = function ( angle ) { +// - phiDelta -= angle; +function ClosedSplineCurve3( points ) { - }; + console.warn( 'THREE.ClosedSplineCurve3 has been deprecated. Use THREE.CatmullRomCurve3 instead.' ); - // pass in distance in world space to move left - this.panLeft = function() { + CatmullRomCurve3.call( this, points ); + this.type = 'catmullrom'; + this.closed = true; - var v = new THREE.Vector3(); +} - return function panLeft ( distance ) { +ClosedSplineCurve3.prototype = Object.create( CatmullRomCurve3.prototype ); - var te = this.object.matrix.elements; +// - // get X column of matrix - v.set( te[ 0 ], te[ 1 ], te[ 2 ] ); - v.multiplyScalar( - distance ); +function SplineCurve3( points ) { - panOffset.add( v ); + console.warn( 'THREE.SplineCurve3 has been deprecated. Use THREE.CatmullRomCurve3 instead.' ); - }; + CatmullRomCurve3.call( this, points ); + this.type = 'catmullrom'; - }(); +} - // pass in distance in world space to move up - this.panUp = function() { +SplineCurve3.prototype = Object.create( CatmullRomCurve3.prototype ); - var v = new THREE.Vector3(); +// - return function panUp ( distance ) { +function Spline( points ) { - var te = this.object.matrix.elements; + console.warn( 'THREE.Spline has been removed. Use THREE.CatmullRomCurve3 instead.' ); - // get Y column of matrix - v.set( te[ 4 ], te[ 5 ], te[ 6 ] ); - v.multiplyScalar( distance ); + CatmullRomCurve3.call( this, points ); + this.type = 'catmullrom'; - panOffset.add( v ); +} - }; +Spline.prototype = Object.create( CatmullRomCurve3.prototype ); - }(); +Object.assign( Spline.prototype, { - // pass in x,y of change desired in pixel space, - // right and down are positive - this.pan = function ( deltaX, deltaY, screenWidth, screenHeight ) { + initFromArray: function ( /* a */ ) { - if ( scope.object instanceof THREE.PerspectiveCamera ) { + console.error( 'THREE.Spline: .initFromArray() has been removed.' ); - // perspective - var position = scope.object.position; - var offset = position.clone().sub( scope.target ); - var targetDistance = offset.length(); + }, + getControlPointsArray: function ( /* optionalTarget */ ) { - // half of the fov is center to top of screen - targetDistance *= Math.tan( ( scope.object.fov / 2 ) * Math.PI / 180.0 ); + console.error( 'THREE.Spline: .getControlPointsArray() has been removed.' ); - // we actually don't use screenWidth, since perspective camera is fixed to screen height - scope.panLeft( 2 * deltaX * targetDistance / screenHeight ); - scope.panUp( 2 * deltaY * targetDistance / screenHeight ); + }, + reparametrizeByArcLength: function ( /* samplingCoef */ ) { - } else if ( scope.object instanceof THREE.OrthographicCamera ) { + console.error( 'THREE.Spline: .reparametrizeByArcLength() has been removed.' ); - // orthographic - scope.panLeft( deltaX * ( scope.object.right - scope.object.left ) / screenWidth ); - scope.panUp( deltaY * ( scope.object.top - scope.object.bottom ) / screenHeight ); + } - } else { +} ); - // camera neither orthographic or perspective - console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - pan disabled.' ); +// - } +function AxisHelper( size ) { - }; + console.warn( 'THREE.AxisHelper has been renamed to THREE.AxesHelper.' ); + return new AxesHelper( size ); - this.dollyIn = function ( dollyScale ) { +} - if ( scope.object instanceof THREE.PerspectiveCamera ) { +function BoundingBoxHelper( object, color ) { - scale /= dollyScale; + console.warn( 'THREE.BoundingBoxHelper has been deprecated. Creating a THREE.BoxHelper instead.' ); + return new BoxHelper( object, color ); - } else if ( scope.object instanceof THREE.OrthographicCamera ) { +} - scope.object.zoom = Math.max( this.minZoom, Math.min( this.maxZoom, this.object.zoom * dollyScale ) ); - scope.object.updateProjectionMatrix(); - zoomChanged = true; +function EdgesHelper( object, hex ) { - } else { + 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 } ) ); - console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.' ); +} - } +GridHelper.prototype.setColors = function () { - }; + console.error( 'THREE.GridHelper: setColors() has been deprecated, pass them in the constructor instead.' ); - this.dollyOut = function ( dollyScale ) { +}; - if ( scope.object instanceof THREE.PerspectiveCamera ) { +SkeletonHelper.prototype.update = function () { - scale *= dollyScale; + console.error( 'THREE.SkeletonHelper: update() no longer needs to be called.' ); - } else if ( scope.object instanceof THREE.OrthographicCamera ) { +}; - scope.object.zoom = Math.max( this.minZoom, Math.min( this.maxZoom, this.object.zoom / dollyScale ) ); - scope.object.updateProjectionMatrix(); - zoomChanged = true; +function WireframeHelper( object, hex ) { - } else { + 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 } ) ); - console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.' ); +} - } +// - }; +Object.assign( Loader.prototype, { - this.update = function() { + extractUrlBase: function ( url ) { - var offset = new THREE.Vector3(); + console.warn( 'THREE.Loader: .extractUrlBase() has been deprecated. Use THREE.LoaderUtils.extractUrlBase() instead.' ); + return LoaderUtils.extractUrlBase( url ); - // so camera.up is the orbit axis - var quat = new THREE.Quaternion().setFromUnitVectors( object.up, new THREE.Vector3( 0, 1, 0 ) ); - var quatInverse = quat.clone().inverse(); + } - var lastPosition = new THREE.Vector3(); - var lastQuaternion = new THREE.Quaternion(); +} ); - return function () { +function XHRLoader( manager ) { - var position = this.object.position; + console.warn( 'THREE.XHRLoader has been renamed to THREE.FileLoader.' ); + return new FileLoader( manager ); - offset.copy( position ).sub( this.target ); +} - // rotate offset to "y-axis-is-up" space - offset.applyQuaternion( quat ); +function BinaryTextureLoader( manager ) { - // angle from z-axis around y-axis + console.warn( 'THREE.BinaryTextureLoader has been renamed to THREE.DataTextureLoader.' ); + return new DataTextureLoader( manager ); - theta = Math.atan2( offset.x, offset.z ); +} - // angle from y-axis +Object.assign( ObjectLoader.prototype, { - phi = Math.atan2( Math.sqrt( offset.x * offset.x + offset.z * offset.z ), offset.y ); + setTexturePath: function ( value ) { - theta += thetaDelta; - phi += phiDelta; + console.warn( 'THREE.ObjectLoader: .setTexturePath() has been renamed to .setResourcePath().' ); + return this.setResourcePath( value ); - // restrict theta to be between desired limits - theta = Math.max( this.minAzimuthAngle, Math.min( this.maxAzimuthAngle, theta ) ); + } - // restrict phi to be between desired limits - phi = Math.max( this.minPolarAngle, Math.min( this.maxPolarAngle, phi ) ); +} ); - // restrict phi to be betwee EPS and PI-EPS - phi = Math.max( EPS, Math.min( Math.PI - EPS, phi ) ); +// - var radius = offset.length() * scale; +Object.assign( Box2.prototype, { - // restrict radius to be between desired limits - radius = Math.max( this.minDistance, Math.min( this.maxDistance, radius ) ); + center: function ( optionalTarget ) { - // move target to panned location - this.target.add( panOffset ); + console.warn( 'THREE.Box2: .center() has been renamed to .getCenter().' ); + return this.getCenter( optionalTarget ); - offset.x = radius * Math.sin( phi ) * Math.sin( theta ); - offset.y = radius * Math.cos( phi ); - offset.z = radius * Math.sin( phi ) * Math.cos( theta ); + }, + empty: function () { - // rotate offset back to "camera-up-vector-is-up" space - offset.applyQuaternion( quatInverse ); + console.warn( 'THREE.Box2: .empty() has been renamed to .isEmpty().' ); + return this.isEmpty(); - position.copy( this.target ).add( offset ); + }, + isIntersectionBox: function ( box ) { - this.object.lookAt( this.target ); + console.warn( 'THREE.Box2: .isIntersectionBox() has been renamed to .intersectsBox().' ); + return this.intersectsBox( box ); - if ( this.enableDamping === true ) { + }, + size: function ( optionalTarget ) { - thetaDelta *= ( 1 - this.dampingFactor ); - phiDelta *= ( 1 - this.dampingFactor ); + console.warn( 'THREE.Box2: .size() has been renamed to .getSize().' ); + return this.getSize( optionalTarget ); - } else { + } +} ); - thetaDelta = 0; - phiDelta = 0; +Object.assign( Box3.prototype, { - } + center: function ( optionalTarget ) { - scale = 1; - panOffset.set( 0, 0, 0 ); + console.warn( 'THREE.Box3: .center() has been renamed to .getCenter().' ); + return this.getCenter( optionalTarget ); - // update condition is: - // min(camera displacement, camera rotation in radians)^2 > EPS - // using small-angle approximation cos(x/2) = 1 - x^2 / 8 + }, + empty: function () { - if ( zoomChanged || - lastPosition.distanceToSquared( this.object.position ) > EPS || - 8 * ( 1 - lastQuaternion.dot( this.object.quaternion ) ) > EPS ) { + console.warn( 'THREE.Box3: .empty() has been renamed to .isEmpty().' ); + return this.isEmpty(); - lastPosition.copy( this.object.position ); - lastQuaternion.copy( this.object.quaternion ); - zoomChanged = false; + }, + isIntersectionBox: function ( box ) { - return true; + console.warn( 'THREE.Box3: .isIntersectionBox() has been renamed to .intersectsBox().' ); + return this.intersectsBox( box ); - } + }, + isIntersectionSphere: function ( sphere ) { - return false; + 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 ); - }; + } +} ); +Line3.prototype.center = function ( optionalTarget ) { - // This set of controls performs orbiting, dollying (zooming), and panning. It maintains - // the "up" direction as +Y, unlike the TrackballControls. Touch on tablet and phones is - // supported. - // - // Orbit - left mouse / touch: one finger move - // Zoom - middle mouse, or mousewheel / touch: two finger spread or squish - // Pan - right mouse, or arrow keys / touch: three finter swipe + console.warn( 'THREE.Line3: .center() has been renamed to .getCenter().' ); + return this.getCenter( optionalTarget ); - function OrbitControls ( object, domElement ) { +}; - var constraint = new OrbitConstraint( object ); +Object.assign( _Math, { - this.domElement = ( domElement !== undefined ) ? domElement : document; + random16: function () { - // API + console.warn( 'THREE.Math: .random16() has been deprecated. Use Math.random() instead.' ); + return Math.random(); - Object.defineProperty( this, 'constraint', { + }, - get: function() { + nearestPowerOfTwo: function ( value ) { - return constraint; + console.warn( 'THREE.Math: .nearestPowerOfTwo() has been renamed to .floorPowerOfTwo().' ); + return _Math.floorPowerOfTwo( value ); - } + }, - } ); + nextPowerOfTwo: function ( value ) { - this.getPolarAngle = function () { + console.warn( 'THREE.Math: .nextPowerOfTwo() has been renamed to .ceilPowerOfTwo().' ); + return _Math.ceilPowerOfTwo( value ); - return constraint.getPolarAngle(); + } - }; +} ); - this.getAzimuthalAngle = function () { +Object.assign( Matrix3.prototype, { - return constraint.getAzimuthalAngle(); + flattenToArrayOffset: function ( array, offset ) { - }; + console.warn( "THREE.Matrix3: .flattenToArrayOffset() has been deprecated. Use .toArray() instead." ); + return this.toArray( array, offset ); - // Set to false to disable this control - this.enabled = true; + }, + multiplyVector3: function ( vector ) { - // center is old, deprecated; use "target" instead - this.center = this.target; + console.warn( 'THREE.Matrix3: .multiplyVector3() has been removed. Use vector.applyMatrix3( matrix ) instead.' ); + return vector.applyMatrix3( this ); - // This option actually enables dollying in and out; left as "zoom" for - // backwards compatibility. - // Set to false to disable zooming - this.enableZoom = true; - this.zoomSpeed = 1.0; + }, + multiplyVector3Array: function ( /* a */ ) { - // Set to false to disable rotating - this.enableRotate = true; - this.rotateSpeed = 1.0; + console.error( 'THREE.Matrix3: .multiplyVector3Array() has been removed.' ); - // Set to false to disable panning - this.enablePan = true; - this.keyPanSpeed = 7.0; // pixels moved per arrow key push + }, + applyToBuffer: function ( buffer /*, offset, length */ ) { - // Set to true to automatically rotate around the target - // If auto-rotate is enabled, you must call controls.update() in your animation loop - this.autoRotate = false; - this.autoRotateSpeed = 2.0; // 30 seconds per round when fps is 60 + console.warn( 'THREE.Matrix3: .applyToBuffer() has been removed. Use matrix.applyToBufferAttribute( attribute ) instead.' ); + return this.applyToBufferAttribute( buffer ); - // Set to false to disable use of the keys - this.enableKeys = true; + }, + applyToVector3Array: function ( /* array, offset, length */ ) { - // The four arrow keys - this.keys = { LEFT: 37, UP: 38, RIGHT: 39, BOTTOM: 40 }; + console.error( 'THREE.Matrix3: .applyToVector3Array() has been removed.' ); - // Mouse buttons - this.mouseButtons = { ORBIT: THREE.MOUSE.LEFT, ZOOM: THREE.MOUSE.MIDDLE, PAN: THREE.MOUSE.RIGHT }; + } - //////////// - // internals +} ); - var scope = this; +Object.assign( Matrix4.prototype, { - var rotateStart = new THREE.Vector2(); - var rotateEnd = new THREE.Vector2(); - var rotateDelta = new THREE.Vector2(); + extractPosition: function ( m ) { - var panStart = new THREE.Vector2(); - var panEnd = new THREE.Vector2(); - var panDelta = new THREE.Vector2(); + console.warn( 'THREE.Matrix4: .extractPosition() has been renamed to .copyPosition().' ); + return this.copyPosition( m ); - var dollyStart = new THREE.Vector2(); - var dollyEnd = new THREE.Vector2(); - var dollyDelta = new THREE.Vector2(); + }, + flattenToArrayOffset: function ( array, offset ) { - var STATE = { NONE : - 1, ROTATE : 0, DOLLY : 1, PAN : 2, TOUCH_ROTATE : 3, TOUCH_DOLLY : 4, TOUCH_PAN : 5 }; + console.warn( "THREE.Matrix4: .flattenToArrayOffset() has been deprecated. Use .toArray() instead." ); + return this.toArray( array, offset ); - var state = STATE.NONE; + }, + getPosition: function () { - // for reset + var v1; - this.target0 = this.target.clone(); - this.position0 = this.object.position.clone(); - this.zoom0 = this.object.zoom; + return function getPosition() { - // events + if ( v1 === undefined ) v1 = new Vector3(); + console.warn( 'THREE.Matrix4: .getPosition() has been removed. Use Vector3.setFromMatrixPosition( matrix ) instead.' ); + return v1.setFromMatrixColumn( this, 3 ); - var changeEvent = { type: 'change' }; - var startEvent = { type: 'start' }; - var endEvent = { type: 'end' }; + }; - // pass in x,y of change desired in pixel space, - // right and down are positive - function pan( deltaX, deltaY ) { + }(), + setRotationFromQuaternion: function ( q ) { - var element = scope.domElement === document ? scope.domElement.body : scope.domElement; + console.warn( 'THREE.Matrix4: .setRotationFromQuaternion() has been renamed to .makeRotationFromQuaternion().' ); + return this.makeRotationFromQuaternion( q ); - constraint.pan( deltaX, deltaY, element.clientWidth, element.clientHeight ); + }, + multiplyToArray: function () { - } + console.warn( 'THREE.Matrix4: .multiplyToArray() has been removed.' ); - this.update = function () { + }, + multiplyVector3: function ( vector ) { - if ( this.autoRotate && state === STATE.NONE ) { + console.warn( 'THREE.Matrix4: .multiplyVector3() has been removed. Use vector.applyMatrix4( matrix ) instead.' ); + return vector.applyMatrix4( this ); - constraint.rotateLeft( getAutoRotationAngle() ); + }, + multiplyVector4: function ( vector ) { - } + console.warn( 'THREE.Matrix4: .multiplyVector4() has been removed. Use vector.applyMatrix4( matrix ) instead.' ); + return vector.applyMatrix4( this ); - if ( constraint.update() === true ) { + }, + multiplyVector3Array: function ( /* a */ ) { - this.dispatchEvent( changeEvent ); + 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 ); - this.reset = function () { + }, + crossVector: function ( vector ) { - state = STATE.NONE; + console.warn( 'THREE.Matrix4: .crossVector() has been removed. Use vector.applyMatrix4( matrix ) instead.' ); + return vector.applyMatrix4( this ); - this.target.copy( this.target0 ); - this.object.position.copy( this.position0 ); - this.object.zoom = this.zoom0; + }, + translate: function () { - this.object.updateProjectionMatrix(); - this.dispatchEvent( changeEvent ); + console.error( 'THREE.Matrix4: .translate() has been removed.' ); - this.update(); + }, + rotateX: function () { - }; + console.error( 'THREE.Matrix4: .rotateX() has been removed.' ); - function getAutoRotationAngle() { + }, + rotateY: function () { - return 2 * Math.PI / 60 / 60 * scope.autoRotateSpeed; + console.error( 'THREE.Matrix4: .rotateY() has been removed.' ); - } + }, + rotateZ: function () { - function getZoomScale() { + console.error( 'THREE.Matrix4: .rotateZ() has been removed.' ); - return Math.pow( 0.95, scope.zoomSpeed ); + }, + rotateByAxis: function () { - } + console.error( 'THREE.Matrix4: .rotateByAxis() has been removed.' ); - function onMouseDown( event ) { + }, + applyToBuffer: function ( buffer /*, offset, length */ ) { - if ( scope.enabled === false ) return; + console.warn( 'THREE.Matrix4: .applyToBuffer() has been removed. Use matrix.applyToBufferAttribute( attribute ) instead.' ); + return this.applyToBufferAttribute( buffer ); - event.preventDefault(); + }, + applyToVector3Array: function ( /* array, offset, length */ ) { - if ( event.button === scope.mouseButtons.ORBIT ) { + console.error( 'THREE.Matrix4: .applyToVector3Array() has been removed.' ); - if ( scope.enableRotate === false ) return; + }, + makeFrustum: function ( left, right, bottom, top, near, far ) { - state = STATE.ROTATE; + 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 ); - rotateStart.set( event.clientX, event.clientY ); + } - } else if ( event.button === scope.mouseButtons.ZOOM ) { +} ); - if ( scope.enableZoom === false ) return; +Plane.prototype.isIntersectionLine = function ( line ) { - state = STATE.DOLLY; + console.warn( 'THREE.Plane: .isIntersectionLine() has been renamed to .intersectsLine().' ); + return this.intersectsLine( line ); - dollyStart.set( event.clientX, event.clientY ); +}; - } else if ( event.button === scope.mouseButtons.PAN ) { +Quaternion.prototype.multiplyVector3 = function ( vector ) { - if ( scope.enablePan === false ) return; + console.warn( 'THREE.Quaternion: .multiplyVector3() has been removed. Use is now vector.applyQuaternion( quaternion ) instead.' ); + return vector.applyQuaternion( this ); - state = STATE.PAN; +}; - panStart.set( event.clientX, event.clientY ); +Object.assign( Ray.prototype, { - } + isIntersectionBox: function ( box ) { - if ( state !== STATE.NONE ) { + console.warn( 'THREE.Ray: .isIntersectionBox() has been renamed to .intersectsBox().' ); + return this.intersectsBox( box ); - document.addEventListener( 'mousemove', onMouseMove, false ); - document.addEventListener( 'mouseup', onMouseUp, false ); - scope.dispatchEvent( startEvent ); + }, + isIntersectionPlane: function ( plane ) { - } + console.warn( 'THREE.Ray: .isIntersectionPlane() has been renamed to .intersectsPlane().' ); + return this.intersectsPlane( plane ); - } + }, + isIntersectionSphere: function ( sphere ) { - function onMouseMove( event ) { + console.warn( 'THREE.Ray: .isIntersectionSphere() has been renamed to .intersectsSphere().' ); + return this.intersectsSphere( sphere ); - if ( scope.enabled === false ) return; + } - event.preventDefault(); +} ); - var element = scope.domElement === document ? scope.domElement.body : scope.domElement; +Object.assign( Triangle.prototype, { - if ( state === STATE.ROTATE ) { + area: function () { - if ( scope.enableRotate === false ) return; + console.warn( 'THREE.Triangle: .area() has been renamed to .getArea().' ); + return this.getArea(); - rotateEnd.set( event.clientX, event.clientY ); - rotateDelta.subVectors( rotateEnd, rotateStart ); + }, + barycoordFromPoint: function ( point, target ) { - // rotating across whole screen goes 360 degrees around - constraint.rotateLeft( 2 * Math.PI * rotateDelta.x / element.clientWidth * scope.rotateSpeed ); + console.warn( 'THREE.Triangle: .barycoordFromPoint() has been renamed to .getBarycoord().' ); + return this.getBarycoord( point, target ); - // rotating up and down along whole screen attempts to go 360, but limited to 180 - constraint.rotateUp( 2 * Math.PI * rotateDelta.y / element.clientHeight * scope.rotateSpeed ); + }, + midpoint: function ( target ) { - rotateStart.copy( rotateEnd ); + console.warn( 'THREE.Triangle: .midpoint() has been renamed to .getMidpoint().' ); + return this.getMidpoint( target ); - } else if ( state === STATE.DOLLY ) { + }, + normal: function ( target ) { - if ( scope.enableZoom === false ) return; + console.warn( 'THREE.Triangle: .normal() has been renamed to .getNormal().' ); + return this.getNormal( target ); - dollyEnd.set( event.clientX, event.clientY ); - dollyDelta.subVectors( dollyEnd, dollyStart ); + }, + plane: function ( target ) { - if ( dollyDelta.y > 0 ) { + console.warn( 'THREE.Triangle: .plane() has been renamed to .getPlane().' ); + return this.getPlane( target ); - constraint.dollyIn( getZoomScale() ); + } - } else if ( dollyDelta.y < 0 ) { +} ); - constraint.dollyOut( getZoomScale() ); +Object.assign( Triangle, { - } + barycoordFromPoint: function ( point, a, b, c, target ) { - dollyStart.copy( dollyEnd ); + console.warn( 'THREE.Triangle: .barycoordFromPoint() has been renamed to .getBarycoord().' ); + return Triangle.getBarycoord( point, a, b, c, target ); - } else if ( state === STATE.PAN ) { + }, + normal: function ( a, b, c, target ) { - if ( scope.enablePan === false ) return; + console.warn( 'THREE.Triangle: .normal() has been renamed to .getNormal().' ); + return Triangle.getNormal( a, b, c, target ); - panEnd.set( event.clientX, event.clientY ); - panDelta.subVectors( panEnd, panStart ); + } - pan( panDelta.x, panDelta.y ); +} ); - panStart.copy( panEnd ); +Object.assign( Shape.prototype, { - } + extractAllPoints: function ( divisions ) { - if ( state !== STATE.NONE ) scope.update(); + console.warn( 'THREE.Shape: .extractAllPoints() has been removed. Use .extractPoints() instead.' ); + return this.extractPoints( divisions ); - } + }, + extrude: function ( options ) { - function onMouseUp( /* event */ ) { + console.warn( 'THREE.Shape: .extrude() has been removed. Use ExtrudeGeometry() instead.' ); + return new ExtrudeGeometry( this, options ); - if ( scope.enabled === false ) return; + }, + makeGeometry: function ( options ) { - document.removeEventListener( 'mousemove', onMouseMove, false ); - document.removeEventListener( 'mouseup', onMouseUp, false ); - scope.dispatchEvent( endEvent ); - state = STATE.NONE; + console.warn( 'THREE.Shape: .makeGeometry() has been removed. Use ShapeGeometry() instead.' ); + return new ShapeGeometry( this, options ); - } + } - function onMouseWheel( event ) { +} ); - if ( scope.enabled === false || scope.enableZoom === false || state !== STATE.NONE ) return; +Object.assign( Vector2.prototype, { - event.preventDefault(); - event.stopPropagation(); + fromAttribute: function ( attribute, index, offset ) { - var delta = 0; + console.warn( 'THREE.Vector2: .fromAttribute() has been renamed to .fromBufferAttribute().' ); + return this.fromBufferAttribute( attribute, index, offset ); - if ( event.wheelDelta !== undefined ) { + }, + distanceToManhattan: function ( v ) { - // WebKit / Opera / Explorer 9 + console.warn( 'THREE.Vector2: .distanceToManhattan() has been renamed to .manhattanDistanceTo().' ); + return this.manhattanDistanceTo( v ); - delta = event.wheelDelta; + }, + lengthManhattan: function () { - } else if ( event.detail !== undefined ) { + console.warn( 'THREE.Vector2: .lengthManhattan() has been renamed to .manhattanLength().' ); + return this.manhattanLength(); - // Firefox + } - delta = - event.detail; +} ); - } +Object.assign( Vector3.prototype, { - if ( delta > 0 ) { + setEulerFromRotationMatrix: function () { - constraint.dollyOut( getZoomScale() ); + console.error( 'THREE.Vector3: .setEulerFromRotationMatrix() has been removed. Use Euler.setFromRotationMatrix() instead.' ); - } else if ( delta < 0 ) { + }, + setEulerFromQuaternion: function () { - constraint.dollyIn( getZoomScale() ); + console.error( 'THREE.Vector3: .setEulerFromQuaternion() has been removed. Use Euler.setFromQuaternion() instead.' ); - } + }, + getPositionFromMatrix: function ( m ) { - scope.update(); - scope.dispatchEvent( startEvent ); - scope.dispatchEvent( endEvent ); + console.warn( 'THREE.Vector3: .getPositionFromMatrix() has been renamed to .setFromMatrixPosition().' ); + return this.setFromMatrixPosition( m ); - } + }, + getScaleFromMatrix: function ( m ) { - function onKeyDown( event ) { + console.warn( 'THREE.Vector3: .getScaleFromMatrix() has been renamed to .setFromMatrixScale().' ); + return this.setFromMatrixScale( m ); - if ( scope.enabled === false || scope.enableKeys === false || scope.enablePan === false ) return; - - switch ( event.keyCode ) { - - case scope.keys.UP: - pan( 0, scope.keyPanSpeed ); - scope.update(); - break; + }, + getColumnFromMatrix: function ( index, matrix ) { - case scope.keys.BOTTOM: - pan( 0, - scope.keyPanSpeed ); - scope.update(); - break; + console.warn( 'THREE.Vector3: .getColumnFromMatrix() has been renamed to .setFromMatrixColumn().' ); + return this.setFromMatrixColumn( matrix, index ); - case scope.keys.LEFT: - pan( scope.keyPanSpeed, 0 ); - scope.update(); - break; + }, + applyProjection: function ( m ) { - case scope.keys.RIGHT: - pan( - scope.keyPanSpeed, 0 ); - scope.update(); - break; + 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 ); - function touchstart( event ) { + }, + distanceToManhattan: function ( v ) { - if ( scope.enabled === false ) return; + console.warn( 'THREE.Vector3: .distanceToManhattan() has been renamed to .manhattanDistanceTo().' ); + return this.manhattanDistanceTo( v ); - switch ( event.touches.length ) { + }, + lengthManhattan: function () { - case 1: // one-fingered touch: rotate + console.warn( 'THREE.Vector3: .lengthManhattan() has been renamed to .manhattanLength().' ); + return this.manhattanLength(); - if ( scope.enableRotate === false ) return; + } - state = STATE.TOUCH_ROTATE; +} ); - rotateStart.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ); - break; +Object.assign( Vector4.prototype, { - case 2: // two-fingered touch: dolly + fromAttribute: function ( attribute, index, offset ) { - if ( scope.enableZoom === false ) return; + console.warn( 'THREE.Vector4: .fromAttribute() has been renamed to .fromBufferAttribute().' ); + return this.fromBufferAttribute( attribute, index, offset ); - state = STATE.TOUCH_DOLLY; + }, + lengthManhattan: function () { - var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX; - var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY; - var distance = Math.sqrt( dx * dx + dy * dy ); - dollyStart.set( 0, distance ); - break; + console.warn( 'THREE.Vector4: .lengthManhattan() has been renamed to .manhattanLength().' ); + return this.manhattanLength(); - case 3: // three-fingered touch: pan + } - if ( scope.enablePan === false ) return; +} ); - state = STATE.TOUCH_PAN; +// - panStart.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ); - break; +Object.assign( Geometry.prototype, { - default: + computeTangents: function () { - state = STATE.NONE; + console.error( 'THREE.Geometry: .computeTangents() has been removed.' ); - } + }, + computeLineDistances: function () { - if ( state !== STATE.NONE ) scope.dispatchEvent( startEvent ); + console.error( 'THREE.Geometry: .computeLineDistances() has been removed. Use THREE.Line.computeLineDistances() instead.' ); - } + } - function touchmove( event ) { +} ); - if ( scope.enabled === false ) return; +Object.assign( Object3D.prototype, { - event.preventDefault(); - event.stopPropagation(); + getChildByName: function ( name ) { - var element = scope.domElement === document ? scope.domElement.body : scope.domElement; + console.warn( 'THREE.Object3D: .getChildByName() has been renamed to .getObjectByName().' ); + return this.getObjectByName( name ); - switch ( event.touches.length ) { + }, + renderDepth: function () { - case 1: // one-fingered touch: rotate + console.warn( 'THREE.Object3D: .renderDepth has been removed. Use .renderOrder, instead.' ); - if ( scope.enableRotate === false ) return; - if ( state !== STATE.TOUCH_ROTATE ) return; + }, + translate: function ( distance, axis ) { - rotateEnd.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ); - rotateDelta.subVectors( rotateEnd, rotateStart ); + console.warn( 'THREE.Object3D: .translate() has been removed. Use .translateOnAxis( axis, distance ) instead.' ); + return this.translateOnAxis( axis, distance ); - // rotating across whole screen goes 360 degrees around - constraint.rotateLeft( 2 * Math.PI * rotateDelta.x / element.clientWidth * scope.rotateSpeed ); - // rotating up and down along whole screen attempts to go 360, but limited to 180 - constraint.rotateUp( 2 * Math.PI * rotateDelta.y / element.clientHeight * scope.rotateSpeed ); + }, + getWorldRotation: function () { - rotateStart.copy( rotateEnd ); + console.error( 'THREE.Object3D: .getWorldRotation() has been removed. Use THREE.Object3D.getWorldQuaternion( target ) instead.' ); - scope.update(); - break; + } - case 2: // two-fingered touch: dolly +} ); - if ( scope.enableZoom === false ) return; - if ( state !== STATE.TOUCH_DOLLY ) return; +Object.defineProperties( Object3D.prototype, { - var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX; - var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY; - var distance = Math.sqrt( dx * dx + dy * dy ); + eulerOrder: { + get: function () { - dollyEnd.set( 0, distance ); - dollyDelta.subVectors( dollyEnd, dollyStart ); + console.warn( 'THREE.Object3D: .eulerOrder is now .rotation.order.' ); + return this.rotation.order; - if ( dollyDelta.y > 0 ) { + }, + set: function ( value ) { - constraint.dollyOut( getZoomScale() ); + console.warn( 'THREE.Object3D: .eulerOrder is now .rotation.order.' ); + this.rotation.order = value; - } else if ( dollyDelta.y < 0 ) { + } + }, + useQuaternion: { + get: function () { - constraint.dollyIn( getZoomScale() ); + console.warn( 'THREE.Object3D: .useQuaternion has been removed. The library now uses quaternions by default.' ); - } + }, + set: function () { - dollyStart.copy( dollyEnd ); + console.warn( 'THREE.Object3D: .useQuaternion has been removed. The library now uses quaternions by default.' ); - scope.update(); - break; + } + } - case 3: // three-fingered touch: pan +} ); - if ( scope.enablePan === false ) return; - if ( state !== STATE.TOUCH_PAN ) return; +Object.defineProperties( LOD.prototype, { - panEnd.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ); - panDelta.subVectors( panEnd, panStart ); + objects: { + get: function () { - pan( panDelta.x, panDelta.y ); + console.warn( 'THREE.LOD: .objects has been renamed to .levels.' ); + return this.levels; - panStart.copy( panEnd ); + } + } - scope.update(); - break; +} ); - default: +Object.defineProperty( Skeleton.prototype, 'useVertexTexture', { - state = STATE.NONE; + get: function () { - } + console.warn( 'THREE.Skeleton: useVertexTexture has been removed.' ); - } + }, + set: function () { - function touchend( /* event */ ) { + console.warn( 'THREE.Skeleton: useVertexTexture has been removed.' ); - if ( scope.enabled === false ) return; + } - scope.dispatchEvent( endEvent ); - state = STATE.NONE; +} ); - } +SkinnedMesh.prototype.initBones = function () { - function contextmenu( event ) { + console.error( 'THREE.SkinnedMesh: initBones() has been removed.' ); - event.preventDefault(); +}; - } +Object.defineProperty( Curve.prototype, '__arcLengthDivisions', { - this.dispose = function() { + get: function () { - this.domElement.removeEventListener( 'contextmenu', contextmenu, false ); - this.domElement.removeEventListener( 'mousedown', onMouseDown, false ); - this.domElement.removeEventListener( 'mousewheel', onMouseWheel, false ); - this.domElement.removeEventListener( 'MozMousePixelScroll', onMouseWheel, false ); // firefox + console.warn( 'THREE.Curve: .__arcLengthDivisions is now .arcLengthDivisions.' ); + return this.arcLengthDivisions; - this.domElement.removeEventListener( 'touchstart', touchstart, false ); - this.domElement.removeEventListener( 'touchend', touchend, false ); - this.domElement.removeEventListener( 'touchmove', touchmove, false ); + }, + set: function ( value ) { - document.removeEventListener( 'mousemove', onMouseMove, false ); - document.removeEventListener( 'mouseup', onMouseUp, false ); + console.warn( 'THREE.Curve: .__arcLengthDivisions is now .arcLengthDivisions.' ); + this.arcLengthDivisions = value; - window.removeEventListener( 'keydown', onKeyDown, false ); + } - } +} ); - this.domElement.addEventListener( 'contextmenu', contextmenu, false ); +// - this.domElement.addEventListener( 'mousedown', onMouseDown, false ); - this.domElement.addEventListener( 'mousewheel', onMouseWheel, false ); - this.domElement.addEventListener( 'MozMousePixelScroll', onMouseWheel, false ); // firefox +PerspectiveCamera.prototype.setLens = function ( focalLength, filmGauge ) { - this.domElement.addEventListener( 'touchstart', touchstart, false ); - this.domElement.addEventListener( 'touchend', touchend, false ); - this.domElement.addEventListener( 'touchmove', touchmove, false ); + console.warn( "THREE.PerspectiveCamera.setLens is deprecated. " + + "Use .setFocalLength and .filmGauge for a photographic setup." ); - window.addEventListener( 'keydown', onKeyDown, false ); + if ( filmGauge !== undefined ) this.filmGauge = filmGauge; + this.setFocalLength( focalLength ); - // force an update at start - this.update(); +}; - }; +// - OrbitControls.prototype = Object.create( THREE.EventDispatcher.prototype ); - OrbitControls.prototype.constructor = OrbitControls; +Object.defineProperties( Light.prototype, { + onlyShadow: { + set: function () { - Object.defineProperties( OrbitControls.prototype, { + console.warn( 'THREE.Light: .onlyShadow has been removed.' ); - object: { + } + }, + shadowCameraFov: { + set: function ( value ) { - get: function () { + console.warn( 'THREE.Light: .shadowCameraFov is now .shadow.camera.fov.' ); + this.shadow.camera.fov = value; - return this.constraint.object; + } + }, + shadowCameraLeft: { + set: function ( value ) { - } + console.warn( 'THREE.Light: .shadowCameraLeft is now .shadow.camera.left.' ); + this.shadow.camera.left = value; - }, + } + }, + shadowCameraRight: { + set: function ( value ) { - target: { + console.warn( 'THREE.Light: .shadowCameraRight is now .shadow.camera.right.' ); + this.shadow.camera.right = value; - get: function () { + } + }, + shadowCameraTop: { + set: function ( value ) { - return this.constraint.target; + console.warn( 'THREE.Light: .shadowCameraTop is now .shadow.camera.top.' ); + this.shadow.camera.top = value; - }, + } + }, + shadowCameraBottom: { + set: function ( value ) { - set: function ( value ) { + console.warn( 'THREE.Light: .shadowCameraBottom is now .shadow.camera.bottom.' ); + this.shadow.camera.bottom = value; - console.warn( 'THREE.OrbitControls: target is now immutable. Use target.set() instead.' ); - this.constraint.target.copy( value ); + } + }, + shadowCameraNear: { + set: function ( value ) { - } + console.warn( 'THREE.Light: .shadowCameraNear is now .shadow.camera.near.' ); + this.shadow.camera.near = value; - }, + } + }, + shadowCameraFar: { + set: function ( value ) { - minDistance : { + console.warn( 'THREE.Light: .shadowCameraFar is now .shadow.camera.far.' ); + this.shadow.camera.far = value; - get: function () { + } + }, + shadowCameraVisible: { + set: function () { - return this.constraint.minDistance; + console.warn( 'THREE.Light: .shadowCameraVisible has been removed. Use new THREE.CameraHelper( light.shadow.camera ) instead.' ); - }, + } + }, + shadowBias: { + set: function ( value ) { - set: function ( value ) { + console.warn( 'THREE.Light: .shadowBias is now .shadow.bias.' ); + this.shadow.bias = value; - this.constraint.minDistance = value; + } + }, + shadowDarkness: { + set: function () { - } + console.warn( 'THREE.Light: .shadowDarkness has been removed.' ); - }, + } + }, + shadowMapWidth: { + set: function ( value ) { - maxDistance : { + console.warn( 'THREE.Light: .shadowMapWidth is now .shadow.mapSize.width.' ); + this.shadow.mapSize.width = value; - get: function () { + } + }, + shadowMapHeight: { + set: function ( value ) { - return this.constraint.maxDistance; + console.warn( 'THREE.Light: .shadowMapHeight is now .shadow.mapSize.height.' ); + this.shadow.mapSize.height = value; - }, + } + } +} ); - set: function ( value ) { +// - this.constraint.maxDistance = value; +Object.defineProperties( BufferAttribute.prototype, { - } + length: { + get: function () { - }, + console.warn( 'THREE.BufferAttribute: .length has been deprecated. Use .count instead.' ); + return this.array.length; - minZoom : { + } + }, + copyIndicesArray: function ( /* indices */ ) { - get: function () { + console.error( 'THREE.BufferAttribute: .copyIndicesArray() has been removed.' ); - return this.constraint.minZoom; + } - }, +} ); - set: function ( value ) { +Object.assign( BufferGeometry.prototype, { - this.constraint.minZoom = value; + addIndex: function ( index ) { - } + console.warn( 'THREE.BufferGeometry: .addIndex() has been renamed to .setIndex().' ); + this.setIndex( index ); - }, + }, + addDrawCall: function ( start, count, indexOffset ) { - maxZoom : { + if ( indexOffset !== undefined ) { - get: function () { + console.warn( 'THREE.BufferGeometry: .addDrawCall() no longer supports indexOffset.' ); - return this.constraint.maxZoom; + } + console.warn( 'THREE.BufferGeometry: .addDrawCall() is now .addGroup().' ); + this.addGroup( start, count ); - }, + }, + clearDrawCalls: function () { - set: function ( value ) { + console.warn( 'THREE.BufferGeometry: .clearDrawCalls() is now .clearGroups().' ); + this.clearGroups(); - this.constraint.maxZoom = value; + }, + computeTangents: function () { - } + console.warn( 'THREE.BufferGeometry: .computeTangents() has been removed.' ); - }, + }, + computeOffsets: function () { - minPolarAngle : { + console.warn( 'THREE.BufferGeometry: .computeOffsets() has been removed.' ); - get: function () { + } - return this.constraint.minPolarAngle; +} ); - }, +Object.defineProperties( BufferGeometry.prototype, { - set: function ( value ) { + drawcalls: { + get: function () { - this.constraint.minPolarAngle = value; + 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; - maxPolarAngle : { + } + } - get: function () { +} ); - return this.constraint.maxPolarAngle; +// - }, +Object.assign( ExtrudeBufferGeometry.prototype, { - set: function ( value ) { + getArrays: function () { - this.constraint.maxPolarAngle = value; + console.error( 'THREE.ExtrudeBufferGeometry: .getArrays() has been removed.' ); - } + }, - }, + addShapeList: function () { - minAzimuthAngle : { + console.error( 'THREE.ExtrudeBufferGeometry: .addShapeList() has been removed.' ); - get: function () { + }, - return this.constraint.minAzimuthAngle; + addShape: function () { - }, + console.error( 'THREE.ExtrudeBufferGeometry: .addShape() has been removed.' ); - set: function ( value ) { + } - this.constraint.minAzimuthAngle = value; +} ); - } +// - }, +Object.defineProperties( Uniform.prototype, { - maxAzimuthAngle : { + dynamic: { + set: function () { - get: function () { + console.warn( 'THREE.Uniform: .dynamic has been removed. Use object.onBeforeRender() instead.' ); - return this.constraint.maxAzimuthAngle; + } + }, + onUpdate: { + value: function () { - }, + console.warn( 'THREE.Uniform: .onUpdate() has been removed. Use object.onBeforeRender() instead.' ); + return this; - set: function ( value ) { + } + } - this.constraint.maxAzimuthAngle = value; +} ); - } +// - }, +Object.defineProperties( Material.prototype, { - enableDamping : { + wrapAround: { + get: function () { - get: function () { + console.warn( 'THREE.Material: .wrapAround has been removed.' ); - return this.constraint.enableDamping; + }, + set: function () { - }, + console.warn( 'THREE.Material: .wrapAround has been removed.' ); - set: function ( value ) { + } + }, - this.constraint.enableDamping = value; + overdraw: { + get: function () { - } + console.warn( 'THREE.Material: .overdraw has been removed.' ); }, + set: function () { - dampingFactor : { + console.warn( 'THREE.Material: .overdraw has been removed.' ); - get: function () { + } + }, - return this.constraint.dampingFactor; + wrapRGB: { + get: function () { - }, + console.warn( 'THREE.Material: .wrapRGB has been removed.' ); + return new Color(); - set: function ( value ) { + } + }, - this.constraint.dampingFactor = value; + shading: { + get: function () { - } + console.error( 'THREE.' + this.type + ': .shading has been removed. Use the boolean .flatShading instead.' ); }, + set: function ( value ) { - // backward compatibility - - noZoom: { - - get: function () { + console.warn( 'THREE.' + this.type + ': .shading has been removed. Use the boolean .flatShading instead.' ); + this.flatShading = ( value === FlatShading ); - console.warn( 'THREE.OrbitControls: .noZoom has been deprecated. Use .enableZoom instead.' ); - return ! this.enableZoom; + } + } - }, +} ); - set: function ( value ) { +Object.defineProperties( MeshPhongMaterial.prototype, { - console.warn( 'THREE.OrbitControls: .noZoom has been deprecated. Use .enableZoom instead.' ); - this.enableZoom = ! value; + metal: { + get: function () { - } + console.warn( 'THREE.MeshPhongMaterial: .metal has been removed. Use THREE.MeshStandardMaterial instead.' ); + return false; }, + set: function () { - noRotate: { - - get: function () { + console.warn( 'THREE.MeshPhongMaterial: .metal has been removed. Use THREE.MeshStandardMaterial instead' ); - console.warn( 'THREE.OrbitControls: .noRotate has been deprecated. Use .enableRotate instead.' ); - return ! this.enableRotate; + } + } - }, +} ); - set: function ( value ) { +Object.defineProperties( ShaderMaterial.prototype, { - console.warn( 'THREE.OrbitControls: .noRotate has been deprecated. Use .enableRotate instead.' ); - this.enableRotate = ! value; + derivatives: { + get: function () { - } + console.warn( 'THREE.ShaderMaterial: .derivatives has been moved to .extensions.derivatives.' ); + return this.extensions.derivatives; }, + set: function ( value ) { - noPan: { + console.warn( 'THREE. ShaderMaterial: .derivatives has been moved to .extensions.derivatives.' ); + this.extensions.derivatives = value; - get: function () { + } + } - console.warn( 'THREE.OrbitControls: .noPan has been deprecated. Use .enablePan instead.' ); - return ! this.enablePan; +} ); - }, +// - set: function ( value ) { +Object.assign( WebGLRenderer.prototype, { - console.warn( 'THREE.OrbitControls: .noPan has been deprecated. Use .enablePan instead.' ); - this.enablePan = ! value; + 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 ); - }, + }, - noKeys: { + animate: function ( callback ) { - get: function () { + console.warn( 'THREE.WebGLRenderer: .animate() is now .setAnimationLoop().' ); + this.setAnimationLoop( callback ); - console.warn( 'THREE.OrbitControls: .noKeys has been deprecated. Use .enableKeys instead.' ); - return ! this.enableKeys; + }, - }, + getCurrentRenderTarget: function () { - set: function ( value ) { + console.warn( 'THREE.WebGLRenderer: .getCurrentRenderTarget() is now .getRenderTarget().' ); + return this.getRenderTarget(); - console.warn( 'THREE.OrbitControls: .noKeys has been deprecated. Use .enableKeys instead.' ); - this.enableKeys = ! value; + }, - } + getMaxAnisotropy: function () { - }, + console.warn( 'THREE.WebGLRenderer: .getMaxAnisotropy() is now .capabilities.getMaxAnisotropy().' ); + return this.capabilities.getMaxAnisotropy(); - staticMoving : { + }, - get: function () { + getPrecision: function () { - console.warn( 'THREE.OrbitControls: .staticMoving has been deprecated. Use .enableDamping instead.' ); - return ! this.constraint.enableDamping; + console.warn( 'THREE.WebGLRenderer: .getPrecision() is now .capabilities.precision.' ); + return this.capabilities.precision; - }, + }, - set: function ( value ) { + resetGLState: function () { - console.warn( 'THREE.OrbitControls: .staticMoving has been deprecated. Use .enableDamping instead.' ); - this.constraint.enableDamping = ! value; + console.warn( 'THREE.WebGLRenderer: .resetGLState() is now .state.reset().' ); + return this.state.reset(); - } + }, - }, + supportsFloatTextures: function () { - dynamicDampingFactor : { + console.warn( 'THREE.WebGLRenderer: .supportsFloatTextures() is now .extensions.get( \'OES_texture_float\' ).' ); + return this.extensions.get( 'OES_texture_float' ); - get: function () { + }, + supportsHalfFloatTextures: function () { - console.warn( 'THREE.OrbitControls: .dynamicDampingFactor has been renamed. Use .dampingFactor instead.' ); - return this.constraint.dampingFactor; + console.warn( 'THREE.WebGLRenderer: .supportsHalfFloatTextures() is now .extensions.get( \'OES_texture_half_float\' ).' ); + return this.extensions.get( 'OES_texture_half_float' ); - }, + }, + supportsStandardDerivatives: function () { - set: function ( value ) { + console.warn( 'THREE.WebGLRenderer: .supportsStandardDerivatives() is now .extensions.get( \'OES_standard_derivatives\' ).' ); + return this.extensions.get( 'OES_standard_derivatives' ); - console.warn( 'THREE.OrbitControls: .dynamicDampingFactor has been renamed. Use .dampingFactor instead.' ); - this.constraint.dampingFactor = value; + }, + 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' ); - return OrbitControls; -} + }, + supportsBlendMinMax: function () { + console.warn( 'THREE.WebGLRenderer: .supportsBlendMinMax() is now .extensions.get( \'EXT_blend_minmax\' ).' ); + return this.extensions.get( 'EXT_blend_minmax' ); -/***/ }), -/* 21 */ -/***/ (function(module, exports, __webpack_require__) { + }, + supportsVertexTextures: function () { -module.exports = __webpack_require__(36); + console.warn( 'THREE.WebGLRenderer: .supportsVertexTextures() is now .capabilities.vertexTextures.' ); + return this.capabilities.vertexTextures; -/***/ }), -/* 22 */ -/***/ (function(module, exports, __webpack_require__) { + }, + supportsInstancedArrays: function () { -var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;(function (global, factory) { - if (true) { - !(__WEBPACK_AMD_DEFINE_ARRAY__ = [exports], __WEBPACK_AMD_DEFINE_FACTORY__ = (factory), - __WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ? - (__WEBPACK_AMD_DEFINE_FACTORY__.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__)) : __WEBPACK_AMD_DEFINE_FACTORY__), - __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); - } else if (typeof exports !== "undefined") { - factory(exports); - } else { - var mod = { - exports: {} - }; - factory(mod.exports); - global.index = mod.exports; - } -})(this, function (exports) { - 'use strict'; + console.warn( 'THREE.WebGLRenderer: .supportsInstancedArrays() is now .extensions.get( \'ANGLE_instanced_arrays\' ).' ); + return this.extensions.get( 'ANGLE_instanced_arrays' ); - Object.defineProperty(exports, "__esModule", { - value: true - }); - var calculateRgba = exports.calculateRgba = function calculateRgba(color, opacity) { - if (color[0] === '#') { - color = color.slice(1); - } + }, + enableScissorTest: function ( boolean ) { - if (color.length === 3) { - var res = ''; - color.split('').forEach(function (c) { - res += c; - res += c; - }); - color = res; - } + console.warn( 'THREE.WebGLRenderer: .enableScissorTest() is now .setScissorTest().' ); + this.setScissorTest( boolean ); - var rgbValues = color.match(/.{2}/g).map(function (hex) { - return parseInt(hex, 16); - }).join(', '); - return 'rgba(' + rgbValues + ', ' + opacity + ')'; - }; -}); + }, + initMaterial: function () { -/***/ }), -/* 23 */ -/***/ (function(module, exports, __webpack_require__) { + console.warn( 'THREE.WebGLRenderer: .initMaterial() has been removed.' ); -"use strict"; + }, + addPrePlugin: function () { + console.warn( 'THREE.WebGLRenderer: .addPrePlugin() has been removed.' ); -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.STLViewer = exports.OBJViewer = undefined; + }, + addPostPlugin: function () { -var _OBJViewer = __webpack_require__(24); + console.warn( 'THREE.WebGLRenderer: .addPostPlugin() has been removed.' ); -var _OBJViewer2 = _interopRequireDefault(_OBJViewer); + }, + updateShadowMap: function () { -var _STLViewer = __webpack_require__(64); + console.warn( 'THREE.WebGLRenderer: .updateShadowMap() has been removed.' ); -var _STLViewer2 = _interopRequireDefault(_STLViewer); + }, + setFaceCulling: function () { -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + console.warn( 'THREE.WebGLRenderer: .setFaceCulling() has been removed.' ); -exports.OBJViewer = _OBJViewer2.default; -exports.STLViewer = _STLViewer2.default; + } -/***/ }), -/* 24 */ -/***/ (function(module, exports, __webpack_require__) { +} ); -"use strict"; +Object.defineProperties( WebGLRenderer.prototype, { + shadowMapEnabled: { + get: function () { -var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + return this.shadowMap.enabled; -var _react = __webpack_require__(0); + }, + set: function ( value ) { -var _react2 = _interopRequireDefault(_react); + console.warn( 'THREE.WebGLRenderer: .shadowMapEnabled is now .shadowMap.enabled.' ); + this.shadowMap.enabled = value; -var _propTypes = __webpack_require__(1); + } + }, + shadowMapType: { + get: function () { -var _propTypes2 = _interopRequireDefault(_propTypes); + return this.shadowMap.type; -var _reactDom = __webpack_require__(12); + }, + set: function ( value ) { -var _reactDom2 = _interopRequireDefault(_reactDom); + console.warn( 'THREE.WebGLRenderer: .shadowMapType is now .shadowMap.type.' ); + this.shadowMap.type = value; -var _three = __webpack_require__(19); + } + }, + shadowMapCullFace: { + get: function () { -var THREE = _interopRequireWildcard(_three); + console.warn( 'THREE.WebGLRenderer: .shadowMapCullFace has been removed. Set Material.shadowSide instead.' ); + return undefined; -var _threeOrbitControls = __webpack_require__(20); + }, + set: function ( /* value */ ) { -var _threeOrbitControls2 = _interopRequireDefault(_threeOrbitControls); + console.warn( 'THREE.WebGLRenderer: .shadowMapCullFace has been removed. Set Material.shadowSide instead.' ); -var _threeAddons = __webpack_require__(35); + } + } +} ); -var _reactSpinners = __webpack_require__(21); +Object.defineProperties( WebGLShadowMap.prototype, { -function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + cullFace: { + get: function () { -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + console.warn( 'THREE.WebGLRenderer: .shadowMap.cullFace has been removed. Set Material.shadowSide instead.' ); + return undefined; -function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + }, + set: function ( /* cullFace */ ) { -function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + console.warn( 'THREE.WebGLRenderer: .shadowMap.cullFace has been removed. Set Material.shadowSide instead.' ); -function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } + } + }, + renderReverseSided: { + get: function () { -var OrbitControls = (0, _threeOrbitControls2.default)(THREE); + console.warn( 'THREE.WebGLRenderer: .shadowMap.renderReverseSided has been removed. Set Material.shadowSide instead.' ); + return undefined; -var OBJViewer = function (_Component) { - _inherits(OBJViewer, _Component); + }, + set: function () { - function OBJViewer(props) { - _classCallCheck(this, OBJViewer); + console.warn( 'THREE.WebGLRenderer: .shadowMap.renderReverseSided has been removed. Set Material.shadowSide instead.' ); - return _possibleConstructorReturn(this, (OBJViewer.__proto__ || Object.getPrototypeOf(OBJViewer)).call(this, props)); - } + } + }, + renderSingleSided: { + get: function () { - _createClass(OBJViewer, [{ - key: 'componentDidMount', - value: function componentDidMount() { - this.renderModel(this.props); - } - }, { - key: 'componentWillUpdate', - value: function componentWillUpdate(nextProps) { - this.renderModel(nextProps); - } - }, { - key: 'renderModel', - value: function renderModel(props) { - var _this2 = this; + console.warn( 'THREE.WebGLRenderer: .shadowMap.renderSingleSided has been removed. Set Material.shadowSide instead.' ); + return undefined; - var camera = void 0, - scene = void 0, - renderer = void 0, - controls = void 0; - var url = props.url, - file = props.file, - width = props.width, - height = props.height, - modelColor = props.modelColor, - backgroundColor = props.backgroundColor, - orbitControls = props.orbitControls, - onSceneRendered = props.onSceneRendered, - sceneClassName = props.sceneClassName; + }, + set: function () { - var xDims = void 0, - yDims = void 0, - zDims = void 0; + console.warn( 'THREE.WebGLRenderer: .shadowMap.renderSingleSided has been removed. Set Material.shadowSide instead.' ); - camera = new THREE.PerspectiveCamera(30, width / height, 1, 10000); - scene = new THREE.Scene(); + } + } - var directionalLight = new THREE.DirectionalLight(0xffffff, 0.8); - directionalLight.position.x = 0; - directionalLight.position.y = 1; - directionalLight.position.z = 0; - directionalLight.position.normalize(); - scene.add(directionalLight); +} ); - var ambientLight = new THREE.AmbientLight(0x404040); // soft white light +// - scene.add(ambientLight); - scene.add(camera); +Object.defineProperties( WebGLRenderTarget.prototype, { - var loader = new _threeAddons.OBJLoader(); + wrapS: { + get: function () { - var onProgress = function onProgress(xhr) { - if (xhr.lengthComputable) { - // var percentComplete = xhr.loaded / xhr.total * 100; - } - }; + console.warn( 'THREE.WebGLRenderTarget: .wrapS is now .texture.wrapS.' ); + return this.texture.wrapS; - var onLoad = function onLoad(object) { - var bbox = new THREE.Box3().setFromObject(object); + }, + set: function ( value ) { - xDims = bbox.max.x - bbox.min.x; - yDims = bbox.max.y - bbox.min.y; - zDims = bbox.max.z - bbox.min.z; - camera.position.set(0, 0, Math.max(xDims * 3, yDims * 3, zDims * 3)); + console.warn( 'THREE.WebGLRenderTarget: .wrapS is now .texture.wrapS.' ); + this.texture.wrapS = value; - object.traverse(function (child) { - if (child.isMesh) { - child.material.color.setStyle(modelColor); - } - }); + } + }, + wrapT: { + get: function () { - object.position.y = -95; - scene.add(object); + console.warn( 'THREE.WebGLRenderTarget: .wrapT is now .texture.wrapT.' ); + return this.texture.wrapT; - renderer = new THREE.WebGLRenderer({ preserveDrawingBuffer: true, antialias: true }); - renderer.setPixelRatio(window.devicePixelRatio); - renderer.setClearColor(backgroundColor, 1); - renderer.setSize(width, height); - renderer.domElement.className = sceneClassName; + }, + set: function ( value ) { - if (orbitControls) { - controls = new OrbitControls(camera, _reactDom2.default.findDOMNode(_this2)); - controls.enableKeys = false; - controls.addEventListener('change', orbitRender); - } + console.warn( 'THREE.WebGLRenderTarget: .wrapT is now .texture.wrapT.' ); + this.texture.wrapT = value; - _reactDom2.default.findDOMNode(_this2).replaceChild(renderer.domElement, _reactDom2.default.findDOMNode(_this2).firstChild); + } + }, + magFilter: { + get: function () { - render(); + console.warn( 'THREE.WebGLRenderTarget: .magFilter is now .texture.magFilter.' ); + return this.texture.magFilter; - if (typeof onSceneRendered === "function") { - onSceneRendered(_reactDom2.default.findDOMNode(renderer.domElement)); - } - }; + }, + set: function ( value ) { - var onError = function onError(xhr) {}; + console.warn( 'THREE.WebGLRenderTarget: .magFilter is now .texture.magFilter.' ); + this.texture.magFilter = value; - if (file) { - var reader = new FileReader(); + } + }, + minFilter: { + get: function () { - reader.onload = function (evt) { - if (evt.target.readyState != 2) return; - if (evt.target.error) { - alert('Error while reading file'); - return; - } + console.warn( 'THREE.WebGLRenderTarget: .minFilter is now .texture.minFilter.' ); + return this.texture.minFilter; - onLoad(loader.parse(evt.target.result)); - }; + }, + set: function ( value ) { - reader.readAsText(file); - } else { - loader.load(url, onLoad, onProgress, onError); - } + console.warn( 'THREE.WebGLRenderTarget: .minFilter is now .texture.minFilter.' ); + this.texture.minFilter = value; - var render = function render() { - renderer.render(scene, camera); - }; + } + }, + anisotropy: { + get: function () { - var orbitRender = function orbitRender() { - render(); - }; - } - }, { - key: 'componentWillReceiveProps', - value: function componentWillReceiveProps() { - this.setState({ allowUpdate: true }); - } - }, { - key: 'shouldComponentUpdate', - value: function shouldComponentUpdate(nextProps, nextState) { - if (JSON.stringify(nextProps) === JSON.stringify(this.props)) { - return false; - } - return true; - } - }, { - key: 'componentDidCatch', - value: function componentDidCatch(error, info) { - console.log(error, info); - } - }, { - key: 'render', - value: function render() { - return _react2.default.createElement( - 'div', - { - className: this.props.className, - style: { - width: this.props.width, - height: this.props.height, - overflow: 'hidden' - } - }, - _react2.default.createElement( - 'div', - { style: { - height: '100%', - display: 'flex', - justifyContent: 'center', - alignItems: 'center' - } }, - _react2.default.createElement(_reactSpinners.ScaleLoader, { - color: '#123abc', - loading: true - }) - ) - ); - } - }]); + console.warn( 'THREE.WebGLRenderTarget: .anisotropy is now .texture.anisotropy.' ); + return this.texture.anisotropy; - return OBJViewer; -}(_react.Component); + }, + set: function ( value ) { -OBJViewer.propTypes = { - className: _propTypes2.default.string, - url: _propTypes2.default.string, - file: _propTypes2.default.object, - width: _propTypes2.default.number, - height: _propTypes2.default.number, - backgroundColor: _propTypes2.default.string, - modelColor: _propTypes2.default.string, - sceneClassName: _propTypes2.default.string, - onSceneRendered: _propTypes2.default.func -}; -OBJViewer.defaultProps = { - backgroundColor: '#EAEAEA', - modelColor: '#B92C2C', - height: 400, - width: 400, - orbitControls: true, - sceneClassName: '' -}; -; + console.warn( 'THREE.WebGLRenderTarget: .anisotropy is now .texture.anisotropy.' ); + this.texture.anisotropy = value; -module.exports = OBJViewer; + } + }, + offset: { + get: function () { -/***/ }), -/* 25 */ -/***/ (function(module, exports, __webpack_require__) { + console.warn( 'THREE.WebGLRenderTarget: .offset is now .texture.offset.' ); + return this.texture.offset; -"use strict"; -/* WEBPACK VAR INJECTION */(function(process) {/** - * Copyright (c) 2013-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ + }, + set: function ( value ) { + console.warn( 'THREE.WebGLRenderTarget: .offset is now .texture.offset.' ); + this.texture.offset = value; + } + }, + repeat: { + get: function () { -var emptyFunction = __webpack_require__(5); -var invariant = __webpack_require__(6); -var warning = __webpack_require__(7); -var assign = __webpack_require__(8); + console.warn( 'THREE.WebGLRenderTarget: .repeat is now .texture.repeat.' ); + return this.texture.repeat; -var ReactPropTypesSecret = __webpack_require__(9); -var checkPropTypes = __webpack_require__(11); + }, + set: function ( value ) { -module.exports = function(isValidElement, throwOnDirectAccess) { - /* global Symbol */ - var ITERATOR_SYMBOL = typeof Symbol === 'function' && Symbol.iterator; - var FAUX_ITERATOR_SYMBOL = '@@iterator'; // Before Symbol spec. + console.warn( 'THREE.WebGLRenderTarget: .repeat is now .texture.repeat.' ); + this.texture.repeat = value; - /** - * Returns the iterator method function contained on the iterable object. - * - * Be sure to invoke the function with the iterable as context: - * - * var iteratorFn = getIteratorFn(myIterable); - * if (iteratorFn) { - * var iterator = iteratorFn.call(myIterable); - * ... - * } - * - * @param {?object} maybeIterable - * @return {?function} - */ - function getIteratorFn(maybeIterable) { - var iteratorFn = maybeIterable && (ITERATOR_SYMBOL && maybeIterable[ITERATOR_SYMBOL] || maybeIterable[FAUX_ITERATOR_SYMBOL]); - if (typeof iteratorFn === 'function') { - return iteratorFn; - } - } + } + }, + format: { + get: function () { - /** - * Collection of methods that allow declaration and validation of props that are - * supplied to React components. Example usage: - * - * var Props = require('ReactPropTypes'); - * var MyArticle = React.createClass({ - * propTypes: { - * // An optional string prop named "description". - * description: Props.string, - * - * // A required enum prop named "category". - * category: Props.oneOf(['News','Photos']).isRequired, - * - * // A prop named "dialog" that requires an instance of Dialog. - * dialog: Props.instanceOf(Dialog).isRequired - * }, - * render: function() { ... } - * }); - * - * A more formal specification of how these methods are used: - * - * type := array|bool|func|object|number|string|oneOf([...])|instanceOf(...) - * decl := ReactPropTypes.{type}(.isRequired)? - * - * Each and every declaration produces a function with the same signature. This - * allows the creation of custom validation functions. For example: - * - * var MyLink = React.createClass({ - * propTypes: { - * // An optional string or URI prop named "href". - * href: function(props, propName, componentName) { - * var propValue = props[propName]; - * if (propValue != null && typeof propValue !== 'string' && - * !(propValue instanceof URI)) { - * return new Error( - * 'Expected a string or an URI for ' + propName + ' in ' + - * componentName - * ); - * } - * } - * }, - * render: function() {...} - * }); - * - * @internal - */ + console.warn( 'THREE.WebGLRenderTarget: .format is now .texture.format.' ); + return this.texture.format; - var ANONYMOUS = '<>'; + }, + set: function ( value ) { - // Important! - // Keep this list in sync with production version in `./factoryWithThrowingShims.js`. - var ReactPropTypes = { - array: createPrimitiveTypeChecker('array'), - bool: createPrimitiveTypeChecker('boolean'), - func: createPrimitiveTypeChecker('function'), - number: createPrimitiveTypeChecker('number'), - object: createPrimitiveTypeChecker('object'), - string: createPrimitiveTypeChecker('string'), - symbol: createPrimitiveTypeChecker('symbol'), + console.warn( 'THREE.WebGLRenderTarget: .format is now .texture.format.' ); + this.texture.format = value; - any: createAnyTypeChecker(), - arrayOf: createArrayOfTypeChecker, - element: createElementTypeChecker(), - instanceOf: createInstanceTypeChecker, - node: createNodeChecker(), - objectOf: createObjectOfTypeChecker, - oneOf: createEnumTypeChecker, - oneOfType: createUnionTypeChecker, - shape: createShapeTypeChecker, - exact: createStrictShapeTypeChecker, - }; + } + }, + type: { + get: function () { - /** - * inlined Object.is polyfill to avoid requiring consumers ship their own - * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is - */ - /*eslint-disable no-self-compare*/ - function is(x, y) { - // SameValue algorithm - if (x === y) { - // Steps 1-5, 7-10 - // Steps 6.b-6.e: +0 != -0 - return x !== 0 || 1 / x === 1 / y; - } else { - // Step 6.a: NaN == NaN - return x !== x && y !== y; - } - } - /*eslint-enable no-self-compare*/ + console.warn( 'THREE.WebGLRenderTarget: .type is now .texture.type.' ); + return this.texture.type; - /** - * We use an Error-like object for backward compatibility as people may call - * PropTypes directly and inspect their output. However, we don't use real - * Errors anymore. We don't inspect their stack anyway, and creating them - * is prohibitively expensive if they are created too often, such as what - * happens in oneOfType() for any type before the one that matched. - */ - function PropTypeError(message) { - this.message = message; - this.stack = ''; - } - // Make `instanceof Error` still work for returned errors. - PropTypeError.prototype = Error.prototype; + }, + set: function ( value ) { - function createChainableTypeChecker(validate) { - if (process.env.NODE_ENV !== 'production') { - var manualPropTypeCallCache = {}; - var manualPropTypeWarningCount = 0; - } - function checkType(isRequired, props, propName, componentName, location, propFullName, secret) { - componentName = componentName || ANONYMOUS; - propFullName = propFullName || propName; + console.warn( 'THREE.WebGLRenderTarget: .type is now .texture.type.' ); + this.texture.type = value; - if (secret !== ReactPropTypesSecret) { - if (throwOnDirectAccess) { - // New behavior only for users of `prop-types` package - invariant( - false, - 'Calling PropTypes validators directly is not supported by the `prop-types` package. ' + - 'Use `PropTypes.checkPropTypes()` to call them. ' + - 'Read more at http://fb.me/use-check-prop-types' - ); - } else if (process.env.NODE_ENV !== 'production' && typeof console !== 'undefined') { - // Old behavior for people using React.PropTypes - var cacheKey = componentName + ':' + propName; - if ( - !manualPropTypeCallCache[cacheKey] && - // Avoid spamming the console because they are often not actionable except for lib authors - manualPropTypeWarningCount < 3 - ) { - warning( - false, - 'You are manually calling a React.PropTypes validation ' + - 'function for the `%s` prop on `%s`. This is deprecated ' + - 'and will throw in the standalone `prop-types` package. ' + - 'You may be seeing this warning due to a third-party PropTypes ' + - 'library. See https://fb.me/react-warning-dont-call-proptypes ' + 'for details.', - propFullName, - componentName - ); - manualPropTypeCallCache[cacheKey] = true; - manualPropTypeWarningCount++; - } - } - } - if (props[propName] == null) { - if (isRequired) { - if (props[propName] === null) { - return new PropTypeError('The ' + location + ' `' + propFullName + '` is marked as required ' + ('in `' + componentName + '`, but its value is `null`.')); - } - return new PropTypeError('The ' + location + ' `' + propFullName + '` is marked as required in ' + ('`' + componentName + '`, but its value is `undefined`.')); - } - return null; - } else { - return validate(props, propName, componentName, location, propFullName); - } - } + } + }, + generateMipmaps: { + get: function () { - var chainedCheckType = checkType.bind(null, false); - chainedCheckType.isRequired = checkType.bind(null, true); + console.warn( 'THREE.WebGLRenderTarget: .generateMipmaps is now .texture.generateMipmaps.' ); + return this.texture.generateMipmaps; - return chainedCheckType; - } + }, + set: function ( value ) { - function createPrimitiveTypeChecker(expectedType) { - function validate(props, propName, componentName, location, propFullName, secret) { - var propValue = props[propName]; - var propType = getPropType(propValue); - if (propType !== expectedType) { - // `propValue` being instance of, say, date/regexp, pass the 'object' - // check, but we can offer a more precise error message here rather than - // 'of type `object`'. - var preciseType = getPreciseType(propValue); + console.warn( 'THREE.WebGLRenderTarget: .generateMipmaps is now .texture.generateMipmaps.' ); + this.texture.generateMipmaps = value; - return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of type ' + ('`' + preciseType + '` supplied to `' + componentName + '`, expected ') + ('`' + expectedType + '`.')); - } - return null; - } - return createChainableTypeChecker(validate); - } + } + } - function createAnyTypeChecker() { - return createChainableTypeChecker(emptyFunction.thatReturnsNull); - } +} ); - function createArrayOfTypeChecker(typeChecker) { - function validate(props, propName, componentName, location, propFullName) { - if (typeof typeChecker !== 'function') { - return new PropTypeError('Property `' + propFullName + '` of component `' + componentName + '` has invalid PropType notation inside arrayOf.'); - } - var propValue = props[propName]; - if (!Array.isArray(propValue)) { - var propType = getPropType(propValue); - return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of type ' + ('`' + propType + '` supplied to `' + componentName + '`, expected an array.')); - } - for (var i = 0; i < propValue.length; i++) { - var error = typeChecker(propValue, i, componentName, location, propFullName + '[' + i + ']', ReactPropTypesSecret); - if (error instanceof Error) { - return error; - } - } - return null; - } - return createChainableTypeChecker(validate); - } +// - function createElementTypeChecker() { - function validate(props, propName, componentName, location, propFullName) { - var propValue = props[propName]; - if (!isValidElement(propValue)) { - var propType = getPropType(propValue); - return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of type ' + ('`' + propType + '` supplied to `' + componentName + '`, expected a single ReactElement.')); - } - return null; - } - return createChainableTypeChecker(validate); - } +Object.defineProperties( WebVRManager.prototype, { - function createInstanceTypeChecker(expectedClass) { - function validate(props, propName, componentName, location, propFullName) { - if (!(props[propName] instanceof expectedClass)) { - var expectedClassName = expectedClass.name || ANONYMOUS; - var actualClassName = getClassName(props[propName]); - return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of type ' + ('`' + actualClassName + '` supplied to `' + componentName + '`, expected ') + ('instance of `' + expectedClassName + '`.')); - } - return null; - } - return createChainableTypeChecker(validate); - } + standing: { + set: function ( /* value */ ) { - function createEnumTypeChecker(expectedValues) { - if (!Array.isArray(expectedValues)) { - process.env.NODE_ENV !== 'production' ? warning(false, 'Invalid argument supplied to oneOf, expected an instance of array.') : void 0; - return emptyFunction.thatReturnsNull; - } + console.warn( 'THREE.WebVRManager: .standing has been removed.' ); - function validate(props, propName, componentName, location, propFullName) { - var propValue = props[propName]; - for (var i = 0; i < expectedValues.length; i++) { - if (is(propValue, expectedValues[i])) { - return null; - } - } + } + }, + userHeight: { + set: function ( /* value */ ) { - var valuesString = JSON.stringify(expectedValues); - return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of value `' + propValue + '` ' + ('supplied to `' + componentName + '`, expected one of ' + valuesString + '.')); - } - return createChainableTypeChecker(validate); - } + console.warn( 'THREE.WebVRManager: .userHeight has been removed.' ); - function createObjectOfTypeChecker(typeChecker) { - function validate(props, propName, componentName, location, propFullName) { - if (typeof typeChecker !== 'function') { - return new PropTypeError('Property `' + propFullName + '` of component `' + componentName + '` has invalid PropType notation inside objectOf.'); - } - var propValue = props[propName]; - var propType = getPropType(propValue); - if (propType !== 'object') { - return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of type ' + ('`' + propType + '` supplied to `' + componentName + '`, expected an object.')); - } - for (var key in propValue) { - if (propValue.hasOwnProperty(key)) { - var error = typeChecker(propValue, key, componentName, location, propFullName + '.' + key, ReactPropTypesSecret); - if (error instanceof Error) { - return error; - } - } - } - return null; - } - return createChainableTypeChecker(validate); - } + } + } - function createUnionTypeChecker(arrayOfTypeCheckers) { - if (!Array.isArray(arrayOfTypeCheckers)) { - process.env.NODE_ENV !== 'production' ? warning(false, 'Invalid argument supplied to oneOfType, expected an instance of array.') : void 0; - return emptyFunction.thatReturnsNull; - } +} ); - for (var i = 0; i < arrayOfTypeCheckers.length; i++) { - var checker = arrayOfTypeCheckers[i]; - if (typeof checker !== 'function') { - warning( - false, - 'Invalid argument supplied to oneOfType. Expected an array of check functions, but ' + - 'received %s at index %s.', - getPostfixForTypeWarning(checker), - i - ); - return emptyFunction.thatReturnsNull; - } - } +// - function validate(props, propName, componentName, location, propFullName) { - for (var i = 0; i < arrayOfTypeCheckers.length; i++) { - var checker = arrayOfTypeCheckers[i]; - if (checker(props, propName, componentName, location, propFullName, ReactPropTypesSecret) == null) { - return null; - } - } +Audio.prototype.load = function ( file ) { - return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` supplied to ' + ('`' + componentName + '`.')); - } - return createChainableTypeChecker(validate); - } + console.warn( 'THREE.Audio: .load has been deprecated. Use THREE.AudioLoader instead.' ); + var scope = this; + var audioLoader = new AudioLoader(); + audioLoader.load( file, function ( buffer ) { - function createNodeChecker() { - function validate(props, propName, componentName, location, propFullName) { - if (!isNode(props[propName])) { - return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` supplied to ' + ('`' + componentName + '`, expected a ReactNode.')); - } - return null; - } - return createChainableTypeChecker(validate); - } + scope.setBuffer( buffer ); - function createShapeTypeChecker(shapeTypes) { - function validate(props, propName, componentName, location, propFullName) { - var propValue = props[propName]; - var propType = getPropType(propValue); - if (propType !== 'object') { - return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of type `' + propType + '` ' + ('supplied to `' + componentName + '`, expected `object`.')); - } - for (var key in shapeTypes) { - var checker = shapeTypes[key]; - if (!checker) { - continue; - } - var error = checker(propValue, key, componentName, location, propFullName + '.' + key, ReactPropTypesSecret); - if (error) { - return error; - } - } - return null; - } - return createChainableTypeChecker(validate); - } + } ); + return this; - function createStrictShapeTypeChecker(shapeTypes) { - function validate(props, propName, componentName, location, propFullName) { - var propValue = props[propName]; - var propType = getPropType(propValue); - if (propType !== 'object') { - return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of type `' + propType + '` ' + ('supplied to `' + componentName + '`, expected `object`.')); - } - // We need to check all keys in case some are required but missing from - // props. - var allKeys = assign({}, props[propName], shapeTypes); - for (var key in allKeys) { - var checker = shapeTypes[key]; - if (!checker) { - return new PropTypeError( - 'Invalid ' + location + ' `' + propFullName + '` key `' + key + '` supplied to `' + componentName + '`.' + - '\nBad object: ' + JSON.stringify(props[propName], null, ' ') + - '\nValid keys: ' + JSON.stringify(Object.keys(shapeTypes), null, ' ') - ); - } - var error = checker(propValue, key, componentName, location, propFullName + '.' + key, ReactPropTypesSecret); - if (error) { - return error; - } - } - return null; - } +}; - return createChainableTypeChecker(validate); - } +AudioAnalyser.prototype.getData = function () { - function isNode(propValue) { - switch (typeof propValue) { - case 'number': - case 'string': - case 'undefined': - return true; - case 'boolean': - return !propValue; - case 'object': - if (Array.isArray(propValue)) { - return propValue.every(isNode); - } - if (propValue === null || isValidElement(propValue)) { - return true; - } + console.warn( 'THREE.AudioAnalyser: .getData() is now .getFrequencyData().' ); + return this.getFrequencyData(); - var iteratorFn = getIteratorFn(propValue); - if (iteratorFn) { - var iterator = iteratorFn.call(propValue); - var step; - if (iteratorFn !== propValue.entries) { - while (!(step = iterator.next()).done) { - if (!isNode(step.value)) { - return false; - } - } - } else { - // Iterator will provide entry [k,v] tuples rather than values. - while (!(step = iterator.next()).done) { - var entry = step.value; - if (entry) { - if (!isNode(entry[1])) { - return false; - } - } - } - } - } else { - return false; - } +}; - return true; - default: - return false; - } - } +// - function isSymbol(propType, propValue) { - // Native Symbol. - if (propType === 'symbol') { - return true; - } +CubeCamera.prototype.updateCubeMap = function ( renderer, scene ) { - // 19.4.3.5 Symbol.prototype[@@toStringTag] === 'Symbol' - if (propValue['@@toStringTag'] === 'Symbol') { - return true; - } + console.warn( 'THREE.CubeCamera: .updateCubeMap() is now .update().' ); + return this.update( renderer, scene ); - // Fallback for non-spec compliant Symbols which are polyfilled. - if (typeof Symbol === 'function' && propValue instanceof Symbol) { - return true; - } +}; - return false; - } +// - // Equivalent of `typeof` but with special handling for array and regexp. - function getPropType(propValue) { - var propType = typeof propValue; - if (Array.isArray(propValue)) { - return 'array'; - } - if (propValue instanceof RegExp) { - // Old webkits (at least until Android 4.0) return 'function' rather than - // 'object' for typeof a RegExp. We'll normalize this here so that /bla/ - // passes PropTypes.object. - return 'object'; - } - if (isSymbol(propType, propValue)) { - return 'symbol'; - } - return propType; - } +var GeometryUtils = { - // This handles more types than `getPropType`. Only used for error messages. - // See `createPrimitiveTypeChecker`. - function getPreciseType(propValue) { - if (typeof propValue === 'undefined' || propValue === null) { - return '' + propValue; - } - var propType = getPropType(propValue); - if (propType === 'object') { - if (propValue instanceof Date) { - return 'date'; - } else if (propValue instanceof RegExp) { - return 'regexp'; - } - } - return propType; - } + merge: function ( geometry1, geometry2, materialIndexOffset ) { - // Returns a string that is postfixed to a warning about an invalid type. - // For example, "undefined" or "of type array" - function getPostfixForTypeWarning(value) { - var type = getPreciseType(value); - switch (type) { - case 'array': - case 'object': - return 'an ' + type; - case 'boolean': - case 'date': - case 'regexp': - return 'a ' + type; - default: - return type; - } - } + console.warn( 'THREE.GeometryUtils: .merge() has been moved to Geometry. Use geometry.merge( geometry2, matrix, materialIndexOffset ) instead.' ); + var matrix; - // Returns class name of the object, if any. - function getClassName(propValue) { - if (!propValue.constructor || !propValue.constructor.name) { - return ANONYMOUS; - } - return propValue.constructor.name; - } + if ( geometry2.isMesh ) { - ReactPropTypes.checkPropTypes = checkPropTypes; - ReactPropTypes.PropTypes = ReactPropTypes; + geometry2.matrixAutoUpdate && geometry2.updateMatrix(); - return ReactPropTypes; -}; + matrix = geometry2.matrix; + geometry2 = geometry2.geometry; -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(4))) + } -/***/ }), -/* 26 */ -/***/ (function(module, exports, __webpack_require__) { + geometry1.merge( geometry2, matrix, materialIndexOffset ); -"use strict"; -/** - * Copyright (c) 2013-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ + }, + center: function ( geometry ) { + console.warn( 'THREE.GeometryUtils: .center() has been moved to Geometry. Use geometry.center() instead.' ); + return geometry.center(); -var emptyFunction = __webpack_require__(5); -var invariant = __webpack_require__(6); -var ReactPropTypesSecret = __webpack_require__(9); + } -module.exports = function() { - function shim(props, propName, componentName, location, propFullName, secret) { - if (secret === ReactPropTypesSecret) { - // It is still safe when called from React. - return; - } - invariant( - false, - 'Calling PropTypes validators directly is not supported by the `prop-types` package. ' + - 'Use PropTypes.checkPropTypes() to call them. ' + - 'Read more at http://fb.me/use-check-prop-types' - ); - }; - shim.isRequired = shim; - function getShim() { - return shim; - }; - // Important! - // Keep this list in sync with production version in `./factoryWithTypeCheckers.js`. - var ReactPropTypes = { - array: shim, - bool: shim, - func: shim, - number: shim, - object: shim, - string: shim, - symbol: shim, +}; - any: shim, - arrayOf: getShim, - element: shim, - instanceOf: getShim, - node: shim, - objectOf: getShim, - oneOf: getShim, - oneOfType: getShim, - shape: getShim, - exact: getShim - }; +ImageUtils.crossOrigin = undefined; - ReactPropTypes.checkPropTypes = emptyFunction; - ReactPropTypes.PropTypes = ReactPropTypes; +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; - return ReactPropTypes; }; +ImageUtils.loadTextureCube = function ( urls, mapping, onLoad, onError ) { -/***/ }), -/* 27 */ -/***/ (function(module, exports, __webpack_require__) { + console.warn( 'THREE.ImageUtils.loadTextureCube has been deprecated. Use THREE.CubeTextureLoader() instead.' ); -"use strict"; -/** @license React v16.2.0 - * react-dom.production.min.js - * - * Copyright (c) 2013-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ + var loader = new CubeTextureLoader(); + loader.setCrossOrigin( this.crossOrigin ); -/* - Modernizr 3.0.0pre (Custom Build) | MIT -*/ -var aa=__webpack_require__(0),l=__webpack_require__(13),B=__webpack_require__(8),C=__webpack_require__(5),ba=__webpack_require__(14),da=__webpack_require__(15),ea=__webpack_require__(10),fa=__webpack_require__(16),ia=__webpack_require__(17),D=__webpack_require__(18); -function E(a){for(var b=arguments.length-1,c="Minified React error #"+a+"; visit http://facebook.github.io/react/docs/error-decoder.html?invariant\x3d"+a,d=0;d=g.hasBooleanValue+g.hasNumericValue+g.hasOverloadedBooleanValue?void 0:E("50",f);e.hasOwnProperty(f)&&(g.attributeName=e[f]);d.hasOwnProperty(f)&&(g.attributeNamespace=d[f]);a.hasOwnProperty(f)&&(g.mutationMethod=a[f]);ua[f]=g}}},ua={}; -function va(a,b){if(oa.hasOwnProperty(a)||2this.eventPool.length&&this.eventPool.push(a)}function Jb(a){a.eventPool=[];a.getPooled=Kb;a.release=Lb}function Mb(a,b,c,d){return T.call(this,a,b,c,d)}T.augmentClass(Mb,{data:null});function Nb(a,b,c,d){return T.call(this,a,b,c,d)}T.augmentClass(Nb,{data:null});var Pb=[9,13,27,32],Vb=l.canUseDOM&&"CompositionEvent"in window,Wb=null;l.canUseDOM&&"documentMode"in document&&(Wb=document.documentMode);var Xb; -if(Xb=l.canUseDOM&&"TextEvent"in window&&!Wb){var Yb=window.opera;Xb=!("object"===typeof Yb&&"function"===typeof Yb.version&&12>=parseInt(Yb.version(),10))} -var Zb=Xb,$b=l.canUseDOM&&(!Vb||Wb&&8=Wb),ac=String.fromCharCode(32),bc={beforeInput:{phasedRegistrationNames:{bubbled:"onBeforeInput",captured:"onBeforeInputCapture"},dependencies:["topCompositionEnd","topKeyPress","topTextInput","topPaste"]},compositionEnd:{phasedRegistrationNames:{bubbled:"onCompositionEnd",captured:"onCompositionEndCapture"},dependencies:"topBlur topCompositionEnd topKeyDown topKeyPress topKeyUp topMouseDown".split(" ")},compositionStart:{phasedRegistrationNames:{bubbled:"onCompositionStart", -captured:"onCompositionStartCapture"},dependencies:"topBlur topCompositionStart topKeyDown topKeyPress topKeyUp topMouseDown".split(" ")},compositionUpdate:{phasedRegistrationNames:{bubbled:"onCompositionUpdate",captured:"onCompositionUpdateCapture"},dependencies:"topBlur topCompositionUpdate topKeyDown topKeyPress topKeyUp topMouseDown".split(" ")}},cc=!1; -function dc(a,b){switch(a){case "topKeyUp":return-1!==Pb.indexOf(b.keyCode);case "topKeyDown":return 229!==b.keyCode;case "topKeyPress":case "topMouseDown":case "topBlur":return!0;default:return!1}}function ec(a){a=a.detail;return"object"===typeof a&&"data"in a?a.data:null}var fc=!1;function gc(a,b){switch(a){case "topCompositionEnd":return ec(b);case "topKeyPress":if(32!==b.which)return null;cc=!0;return ac;case "topTextInput":return a=b.data,a===ac&&cc?null:a;default:return null}} -function hc(a,b){if(fc)return"topCompositionEnd"===a||!Vb&&dc(a,b)?(a=Fb(),S._root=null,S._startText=null,S._fallbackText=null,fc=!1,a):null;switch(a){case "topPaste":return null;case "topKeyPress":if(!(b.ctrlKey||b.altKey||b.metaKey)||b.ctrlKey&&b.altKey){if(b.char&&1qd.length&&qd.push(a)}}} -var xd=Object.freeze({get _enabled(){return td},get _handleTopLevel(){return sd},setHandleTopLevel:function(a){sd=a},setEnabled:ud,isEnabled:function(){return td},trapBubbledEvent:U,trapCapturedEvent:wd,dispatchEvent:vd});function yd(a,b){var c={};c[a.toLowerCase()]=b.toLowerCase();c["Webkit"+a]="webkit"+b;c["Moz"+a]="moz"+b;c["ms"+a]="MS"+b;c["O"+a]="o"+b.toLowerCase();return c} -var zd={animationend:yd("Animation","AnimationEnd"),animationiteration:yd("Animation","AnimationIteration"),animationstart:yd("Animation","AnimationStart"),transitionend:yd("Transition","TransitionEnd")},Ad={},Bd={};l.canUseDOM&&(Bd=document.createElement("div").style,"AnimationEvent"in window||(delete zd.animationend.animation,delete zd.animationiteration.animation,delete zd.animationstart.animation),"TransitionEvent"in window||delete zd.transitionend.transition); -function Cd(a){if(Ad[a])return Ad[a];if(!zd[a])return a;var b=zd[a],c;for(c in b)if(b.hasOwnProperty(c)&&c in Bd)return Ad[a]=b[c];return""} -var Dd={topAbort:"abort",topAnimationEnd:Cd("animationend")||"animationend",topAnimationIteration:Cd("animationiteration")||"animationiteration",topAnimationStart:Cd("animationstart")||"animationstart",topBlur:"blur",topCancel:"cancel",topCanPlay:"canplay",topCanPlayThrough:"canplaythrough",topChange:"change",topClick:"click",topClose:"close",topCompositionEnd:"compositionend",topCompositionStart:"compositionstart",topCompositionUpdate:"compositionupdate",topContextMenu:"contextmenu",topCopy:"copy", -topCut:"cut",topDoubleClick:"dblclick",topDrag:"drag",topDragEnd:"dragend",topDragEnter:"dragenter",topDragExit:"dragexit",topDragLeave:"dragleave",topDragOver:"dragover",topDragStart:"dragstart",topDrop:"drop",topDurationChange:"durationchange",topEmptied:"emptied",topEncrypted:"encrypted",topEnded:"ended",topError:"error",topFocus:"focus",topInput:"input",topKeyDown:"keydown",topKeyPress:"keypress",topKeyUp:"keyup",topLoadedData:"loadeddata",topLoad:"load",topLoadedMetadata:"loadedmetadata",topLoadStart:"loadstart", -topMouseDown:"mousedown",topMouseMove:"mousemove",topMouseOut:"mouseout",topMouseOver:"mouseover",topMouseUp:"mouseup",topPaste:"paste",topPause:"pause",topPlay:"play",topPlaying:"playing",topProgress:"progress",topRateChange:"ratechange",topScroll:"scroll",topSeeked:"seeked",topSeeking:"seeking",topSelectionChange:"selectionchange",topStalled:"stalled",topSuspend:"suspend",topTextInput:"textInput",topTimeUpdate:"timeupdate",topToggle:"toggle",topTouchCancel:"touchcancel",topTouchEnd:"touchend",topTouchMove:"touchmove", -topTouchStart:"touchstart",topTransitionEnd:Cd("transitionend")||"transitionend",topVolumeChange:"volumechange",topWaiting:"waiting",topWheel:"wheel"},Ed={},Fd=0,Gd="_reactListenersID"+(""+Math.random()).slice(2);function Hd(a){Object.prototype.hasOwnProperty.call(a,Gd)||(a[Gd]=Fd++,Ed[a[Gd]]={});return Ed[a[Gd]]}function Id(a){for(;a&&a.firstChild;)a=a.firstChild;return a} -function Jd(a,b){var c=Id(a);a=0;for(var d;c;){if(3===c.nodeType){d=a+c.textContent.length;if(a<=b&&d>=b)return{node:c,offset:b-a};a=d}a:{for(;c;){if(c.nextSibling){c=c.nextSibling;break a}c=c.parentNode}c=void 0}c=Id(c)}}function Kd(a){var b=a&&a.nodeName&&a.nodeName.toLowerCase();return b&&("input"===b&&"text"===a.type||"textarea"===b||"true"===a.contentEditable)} -var Ld=l.canUseDOM&&"documentMode"in document&&11>=document.documentMode,Md={select:{phasedRegistrationNames:{bubbled:"onSelect",captured:"onSelectCapture"},dependencies:"topBlur topContextMenu topFocus topKeyDown topKeyUp topMouseDown topMouseUp topSelectionChange".split(" ")}},Nd=null,Od=null,Pd=null,Qd=!1; -function Rd(a,b){if(Qd||null==Nd||Nd!==da())return null;var c=Nd;"selectionStart"in c&&Kd(c)?c={start:c.selectionStart,end:c.selectionEnd}:window.getSelection?(c=window.getSelection(),c={anchorNode:c.anchorNode,anchorOffset:c.anchorOffset,focusNode:c.focusNode,focusOffset:c.focusOffset}):c=void 0;return Pd&&ea(Pd,c)?null:(Pd=c,a=T.getPooled(Md.select,Od,a,b),a.type="select",a.target=Nd,Ab(a),a)} -var Sd={eventTypes:Md,extractEvents:function(a,b,c,d){var e=d.window===d?d.document:9===d.nodeType?d:d.ownerDocument,f;if(!(f=!e)){a:{e=Hd(e);f=Sa.onSelect;for(var g=0;ghe||(a.current=ge[he],ge[he]=null,he--)}function W(a,b){he++;ge[he]=a.current;a.current=b}new Set;var ie={current:D},X={current:!1},je=D;function ke(a){return le(a)?je:ie.current} -function me(a,b){var c=a.type.contextTypes;if(!c)return D;var d=a.stateNode;if(d&&d.__reactInternalMemoizedUnmaskedChildContext===b)return d.__reactInternalMemoizedMaskedChildContext;var e={},f;for(f in c)e[f]=b[f];d&&(a=a.stateNode,a.__reactInternalMemoizedUnmaskedChildContext=b,a.__reactInternalMemoizedMaskedChildContext=e);return e}function le(a){return 2===a.tag&&null!=a.type.childContextTypes}function ne(a){le(a)&&(V(X,a),V(ie,a))} -function oe(a,b,c){null!=ie.cursor?E("168"):void 0;W(ie,b,a);W(X,c,a)}function pe(a,b){var c=a.stateNode,d=a.type.childContextTypes;if("function"!==typeof c.getChildContext)return b;c=c.getChildContext();for(var e in c)e in d?void 0:E("108",jd(a)||"Unknown",e);return B({},b,c)}function qe(a){if(!le(a))return!1;var b=a.stateNode;b=b&&b.__reactInternalMemoizedMergedChildContext||D;je=ie.current;W(ie,b,a);W(X,X.current,a);return!0} -function re(a,b){var c=a.stateNode;c?void 0:E("169");if(b){var d=pe(a,je);c.__reactInternalMemoizedMergedChildContext=d;V(X,a);V(ie,a);W(ie,d,a)}else V(X,a);W(X,b,a)} -function Y(a,b,c){this.tag=a;this.key=b;this.stateNode=this.type=null;this.sibling=this.child=this["return"]=null;this.index=0;this.memoizedState=this.updateQueue=this.memoizedProps=this.pendingProps=this.ref=null;this.internalContextTag=c;this.effectTag=0;this.lastEffect=this.firstEffect=this.nextEffect=null;this.expirationTime=0;this.alternate=null} -function se(a,b,c){var d=a.alternate;null===d?(d=new Y(a.tag,a.key,a.internalContextTag),d.type=a.type,d.stateNode=a.stateNode,d.alternate=a,a.alternate=d):(d.effectTag=0,d.nextEffect=null,d.firstEffect=null,d.lastEffect=null);d.expirationTime=c;d.pendingProps=b;d.child=a.child;d.memoizedProps=a.memoizedProps;d.memoizedState=a.memoizedState;d.updateQueue=a.updateQueue;d.sibling=a.sibling;d.index=a.index;d.ref=a.ref;return d} -function te(a,b,c){var d=void 0,e=a.type,f=a.key;"function"===typeof e?(d=e.prototype&&e.prototype.isReactComponent?new Y(2,f,b):new Y(0,f,b),d.type=e,d.pendingProps=a.props):"string"===typeof e?(d=new Y(5,f,b),d.type=e,d.pendingProps=a.props):"object"===typeof e&&null!==e&&"number"===typeof e.tag?(d=e,d.pendingProps=a.props):E("130",null==e?e:typeof e,"");d.expirationTime=c;return d}function ue(a,b,c,d){b=new Y(10,d,b);b.pendingProps=a;b.expirationTime=c;return b} -function ve(a,b,c){b=new Y(6,null,b);b.pendingProps=a;b.expirationTime=c;return b}function we(a,b,c){b=new Y(7,a.key,b);b.type=a.handler;b.pendingProps=a;b.expirationTime=c;return b}function xe(a,b,c){a=new Y(9,null,b);a.expirationTime=c;return a}function ye(a,b,c){b=new Y(4,a.key,b);b.pendingProps=a.children||[];b.expirationTime=c;b.stateNode={containerInfo:a.containerInfo,pendingChildren:null,implementation:a.implementation};return b}var ze=null,Ae=null; -function Be(a){return function(b){try{return a(b)}catch(c){}}}function Ce(a){if("undefined"===typeof __REACT_DEVTOOLS_GLOBAL_HOOK__)return!1;var b=__REACT_DEVTOOLS_GLOBAL_HOOK__;if(b.isDisabled||!b.supportsFiber)return!0;try{var c=b.inject(a);ze=Be(function(a){return b.onCommitFiberRoot(c,a)});Ae=Be(function(a){return b.onCommitFiberUnmount(c,a)})}catch(d){}return!0}function De(a){"function"===typeof ze&&ze(a)}function Ee(a){"function"===typeof Ae&&Ae(a)} -function Fe(a){return{baseState:a,expirationTime:0,first:null,last:null,callbackList:null,hasForceUpdate:!1,isInitialized:!1}}function Ge(a,b){null===a.last?a.first=a.last=b:(a.last.next=b,a.last=b);if(0===a.expirationTime||a.expirationTime>b.expirationTime)a.expirationTime=b.expirationTime} -function He(a,b){var c=a.alternate,d=a.updateQueue;null===d&&(d=a.updateQueue=Fe(null));null!==c?(a=c.updateQueue,null===a&&(a=c.updateQueue=Fe(null))):a=null;a=a!==d?a:null;null===a?Ge(d,b):null===d.last||null===a.last?(Ge(d,b),Ge(a,b)):(Ge(d,b),a.last=b)}function Ie(a,b,c,d){a=a.partialState;return"function"===typeof a?a.call(b,c,d):a} -function Je(a,b,c,d,e,f){null!==a&&a.updateQueue===c&&(c=b.updateQueue={baseState:c.baseState,expirationTime:c.expirationTime,first:c.first,last:c.last,isInitialized:c.isInitialized,callbackList:null,hasForceUpdate:!1});c.expirationTime=0;c.isInitialized?a=c.baseState:(a=c.baseState=b.memoizedState,c.isInitialized=!0);for(var g=!0,h=c.first,k=!1;null!==h;){var q=h.expirationTime;if(q>f){var v=c.expirationTime;if(0===v||v>q)c.expirationTime=q;k||(k=!0,c.baseState=a)}else{k||(c.first=h.next,null=== -c.first&&(c.last=null));if(h.isReplace)a=Ie(h,d,a,e),g=!0;else if(q=Ie(h,d,a,e))a=g?B({},a,q):B(a,q),g=!1;h.isForced&&(c.hasForceUpdate=!0);null!==h.callback&&(q=c.callbackList,null===q&&(q=c.callbackList=[]),q.push(h))}h=h.next}null!==c.callbackList?b.effectTag|=32:null!==c.first||c.hasForceUpdate||(b.updateQueue=null);k||(c.baseState=a);return a} -function Ke(a,b){var c=a.callbackList;if(null!==c)for(a.callbackList=null,a=0;aw?(k=n,n=null):k=n.sibling;var x=G(e,n,m[w],A);if(null===x){null===n&&(n=k);break}a&&n&&null===x.alternate&&b(e,n);g=f(x,g,w);null===r?h=x:r.sibling=x;r=x;n=k}if(w===m.length)return c(e,n),h;if(null===n){for(;ww?(k=n,n=null):k=n.sibling;var J=G(e,n,x.value,A);if(null===J){n||(n=k);break}a&&n&&null===J.alternate&&b(e,n);g=f(J, -g,w);null===r?h=J:r.sibling=J;r=J;n=k}if(x.done)return c(e,n),h;if(null===n){for(;!x.done;w++,x=m.next())x=z(e,x.value,A),null!==x&&(g=f(x,g,w),null===r?h=x:r.sibling=x,r=x);return h}for(n=d(e,n);!x.done;w++,x=m.next())if(x=I(n,e,w,x.value,A),null!==x){if(a&&null!==x.alternate)n["delete"](null===x.key?w:x.key);g=f(x,g,w);null===r?h=x:r.sibling=x;r=x}a&&n.forEach(function(a){return b(e,a)});return h}return function(a,d,f,h){"object"===typeof f&&null!==f&&f.type===Ve&&null===f.key&&(f=f.props.children); -var m="object"===typeof f&&null!==f;if(m)switch(f.$$typeof){case Re:a:{var r=f.key;for(m=d;null!==m;){if(m.key===r)if(10===m.tag?f.type===Ve:m.type===f.type){c(a,m.sibling);d=e(m,f.type===Ve?f.props.children:f.props,h);d.ref=Ze(m,f);d["return"]=a;a=d;break a}else{c(a,m);break}else b(a,m);m=m.sibling}f.type===Ve?(d=ue(f.props.children,a.internalContextTag,h,f.key),d["return"]=a,a=d):(h=te(f,a.internalContextTag,h),h.ref=Ze(d,f),h["return"]=a,a=h)}return g(a);case Se:a:{for(m=f.key;null!==d;){if(d.key=== -m)if(7===d.tag){c(a,d.sibling);d=e(d,f,h);d["return"]=a;a=d;break a}else{c(a,d);break}else b(a,d);d=d.sibling}d=we(f,a.internalContextTag,h);d["return"]=a;a=d}return g(a);case Te:a:{if(null!==d)if(9===d.tag){c(a,d.sibling);d=e(d,null,h);d.type=f.value;d["return"]=a;a=d;break a}else c(a,d);d=xe(f,a.internalContextTag,h);d.type=f.value;d["return"]=a;a=d}return g(a);case Ue:a:{for(m=f.key;null!==d;){if(d.key===m)if(4===d.tag&&d.stateNode.containerInfo===f.containerInfo&&d.stateNode.implementation=== -f.implementation){c(a,d.sibling);d=e(d,f.children||[],h);d["return"]=a;a=d;break a}else{c(a,d);break}else b(a,d);d=d.sibling}d=ye(f,a.internalContextTag,h);d["return"]=a;a=d}return g(a)}if("string"===typeof f||"number"===typeof f)return f=""+f,null!==d&&6===d.tag?(c(a,d.sibling),d=e(d,f,h)):(c(a,d),d=ve(f,a.internalContextTag,h)),d["return"]=a,a=d,g(a);if(Ye(f))return L(a,d,f,h);if(Xe(f))return N(a,d,f,h);m&&$e(a,f);if("undefined"===typeof f)switch(a.tag){case 2:case 1:h=a.type,E("152",h.displayName|| -h.name||"Component")}return c(a,d)}}var bf=af(!0),cf=af(!1); -function df(a,b,c,d,e){function f(a,b,c){var d=b.expirationTime;b.child=null===a?cf(b,null,c,d):bf(b,a.child,c,d)}function g(a,b){var c=b.ref;null===c||a&&a.ref===c||(b.effectTag|=128)}function h(a,b,c,d){g(a,b);if(!c)return d&&re(b,!1),q(a,b);c=b.stateNode;id.current=b;var e=c.render();b.effectTag|=1;f(a,b,e);b.memoizedState=c.state;b.memoizedProps=c.props;d&&re(b,!0);return b.child}function k(a){var b=a.stateNode;b.pendingContext?oe(a,b.pendingContext,b.pendingContext!==b.context):b.context&&oe(a, -b.context,!1);I(a,b.containerInfo)}function q(a,b){null!==a&&b.child!==a.child?E("153"):void 0;if(null!==b.child){a=b.child;var c=se(a,a.pendingProps,a.expirationTime);b.child=c;for(c["return"]=b;null!==a.sibling;)a=a.sibling,c=c.sibling=se(a,a.pendingProps,a.expirationTime),c["return"]=b;c.sibling=null}return b.child}function v(a,b){switch(b.tag){case 3:k(b);break;case 2:qe(b);break;case 4:I(b,b.stateNode.containerInfo)}return null}var y=a.shouldSetTextContent,u=a.useSyncScheduling,z=a.shouldDeprioritizeSubtree, -G=b.pushHostContext,I=b.pushHostContainer,L=c.enterHydrationState,N=c.resetHydrationState,J=c.tryToClaimNextHydratableInstance;a=Le(d,e,function(a,b){a.memoizedProps=b},function(a,b){a.memoizedState=b});var w=a.adoptClassInstance,m=a.constructClassInstance,A=a.mountClassInstance,Ob=a.updateClassInstance;return{beginWork:function(a,b,c){if(0===b.expirationTime||b.expirationTime>c)return v(a,b);switch(b.tag){case 0:null!==a?E("155"):void 0;var d=b.type,e=b.pendingProps,r=ke(b);r=me(b,r);d=d(e,r);b.effectTag|= -1;"object"===typeof d&&null!==d&&"function"===typeof d.render?(b.tag=2,e=qe(b),w(b,d),A(b,c),b=h(a,b,!0,e)):(b.tag=1,f(a,b,d),b.memoizedProps=e,b=b.child);return b;case 1:a:{e=b.type;c=b.pendingProps;d=b.memoizedProps;if(X.current)null===c&&(c=d);else if(null===c||d===c){b=q(a,b);break a}d=ke(b);d=me(b,d);e=e(c,d);b.effectTag|=1;f(a,b,e);b.memoizedProps=c;b=b.child}return b;case 2:return e=qe(b),d=void 0,null===a?b.stateNode?E("153"):(m(b,b.pendingProps),A(b,c),d=!0):d=Ob(a,b,c),h(a,b,d,e);case 3:return k(b), -e=b.updateQueue,null!==e?(d=b.memoizedState,e=Je(a,b,e,null,null,c),d===e?(N(),b=q(a,b)):(d=e.element,r=b.stateNode,(null===a||null===a.child)&&r.hydrate&&L(b)?(b.effectTag|=2,b.child=cf(b,null,d,c)):(N(),f(a,b,d)),b.memoizedState=e,b=b.child)):(N(),b=q(a,b)),b;case 5:G(b);null===a&&J(b);e=b.type;var n=b.memoizedProps;d=b.pendingProps;null===d&&(d=n,null===d?E("154"):void 0);r=null!==a?a.memoizedProps:null;X.current||null!==d&&n!==d?(n=d.children,y(e,d)?n=null:r&&y(e,r)&&(b.effectTag|=16),g(a,b), -2147483647!==c&&!u&&z(e,d)?(b.expirationTime=2147483647,b=null):(f(a,b,n),b.memoizedProps=d,b=b.child)):b=q(a,b);return b;case 6:return null===a&&J(b),a=b.pendingProps,null===a&&(a=b.memoizedProps),b.memoizedProps=a,null;case 8:b.tag=7;case 7:e=b.pendingProps;if(X.current)null===e&&(e=a&&a.memoizedProps,null===e?E("154"):void 0);else if(null===e||b.memoizedProps===e)e=b.memoizedProps;d=e.children;b.stateNode=null===a?cf(b,b.stateNode,d,c):bf(b,b.stateNode,d,c);b.memoizedProps=e;return b.stateNode; -case 9:return null;case 4:a:{I(b,b.stateNode.containerInfo);e=b.pendingProps;if(X.current)null===e&&(e=a&&a.memoizedProps,null==e?E("154"):void 0);else if(null===e||b.memoizedProps===e){b=q(a,b);break a}null===a?b.child=bf(b,null,e,c):f(a,b,e);b.memoizedProps=e;b=b.child}return b;case 10:a:{c=b.pendingProps;if(X.current)null===c&&(c=b.memoizedProps);else if(null===c||b.memoizedProps===c){b=q(a,b);break a}f(a,b,c);b.memoizedProps=c;b=b.child}return b;default:E("156")}},beginFailedWork:function(a,b, -c){switch(b.tag){case 2:qe(b);break;case 3:k(b);break;default:E("157")}b.effectTag|=64;null===a?b.child=null:b.child!==a.child&&(b.child=a.child);if(0===b.expirationTime||b.expirationTime>c)return v(a,b);b.firstEffect=null;b.lastEffect=null;b.child=null===a?cf(b,null,null,c):bf(b,a.child,null,c);2===b.tag&&(a=b.stateNode,b.memoizedProps=a.props,b.memoizedState=a.state);return b.child}}} -function ef(a,b,c){function d(a){a.effectTag|=4}var e=a.createInstance,f=a.createTextInstance,g=a.appendInitialChild,h=a.finalizeInitialChildren,k=a.prepareUpdate,q=a.persistence,v=b.getRootHostContainer,y=b.popHostContext,u=b.getHostContext,z=b.popHostContainer,G=c.prepareToHydrateHostInstance,I=c.prepareToHydrateHostTextInstance,L=c.popHydrationState,N=void 0,J=void 0,w=void 0;a.mutation?(N=function(){},J=function(a,b,c){(b.updateQueue=c)&&d(b)},w=function(a,b,c,e){c!==e&&d(b)}):q?E("235"):E("236"); -return{completeWork:function(a,b,c){var m=b.pendingProps;if(null===m)m=b.memoizedProps;else if(2147483647!==b.expirationTime||2147483647===c)b.pendingProps=null;switch(b.tag){case 1:return null;case 2:return ne(b),null;case 3:z(b);V(X,b);V(ie,b);m=b.stateNode;m.pendingContext&&(m.context=m.pendingContext,m.pendingContext=null);if(null===a||null===a.child)L(b),b.effectTag&=-3;N(b);return null;case 5:y(b);c=v();var A=b.type;if(null!==a&&null!=b.stateNode){var p=a.memoizedProps,q=b.stateNode,x=u();q= -k(q,A,p,m,c,x);J(a,b,q,A,p,m,c);a.ref!==b.ref&&(b.effectTag|=128)}else{if(!m)return null===b.stateNode?E("166"):void 0,null;a=u();if(L(b))G(b,c,a)&&d(b);else{a=e(A,m,c,a,b);a:for(p=b.child;null!==p;){if(5===p.tag||6===p.tag)g(a,p.stateNode);else if(4!==p.tag&&null!==p.child){p.child["return"]=p;p=p.child;continue}if(p===b)break;for(;null===p.sibling;){if(null===p["return"]||p["return"]===b)break a;p=p["return"]}p.sibling["return"]=p["return"];p=p.sibling}h(a,A,m,c)&&d(b);b.stateNode=a}null!==b.ref&& -(b.effectTag|=128)}return null;case 6:if(a&&null!=b.stateNode)w(a,b,a.memoizedProps,m);else{if("string"!==typeof m)return null===b.stateNode?E("166"):void 0,null;a=v();c=u();L(b)?I(b)&&d(b):b.stateNode=f(m,a,c,b)}return null;case 7:(m=b.memoizedProps)?void 0:E("165");b.tag=8;A=[];a:for((p=b.stateNode)&&(p["return"]=b);null!==p;){if(5===p.tag||6===p.tag||4===p.tag)E("247");else if(9===p.tag)A.push(p.type);else if(null!==p.child){p.child["return"]=p;p=p.child;continue}for(;null===p.sibling;){if(null=== -p["return"]||p["return"]===b)break a;p=p["return"]}p.sibling["return"]=p["return"];p=p.sibling}p=m.handler;m=p(m.props,A);b.child=bf(b,null!==a?a.child:null,m,c);return b.child;case 8:return b.tag=7,null;case 9:return null;case 10:return null;case 4:return z(b),N(b),null;case 0:E("167");default:E("156")}}}} -function ff(a,b){function c(a){var c=a.ref;if(null!==c)try{c(null)}catch(A){b(a,A)}}function d(a){"function"===typeof Ee&&Ee(a);switch(a.tag){case 2:c(a);var d=a.stateNode;if("function"===typeof d.componentWillUnmount)try{d.props=a.memoizedProps,d.state=a.memoizedState,d.componentWillUnmount()}catch(A){b(a,A)}break;case 5:c(a);break;case 7:e(a.stateNode);break;case 4:k&&g(a)}}function e(a){for(var b=a;;)if(d(b),null===b.child||k&&4===b.tag){if(b===a)break;for(;null===b.sibling;){if(null===b["return"]|| -b["return"]===a)return;b=b["return"]}b.sibling["return"]=b["return"];b=b.sibling}else b.child["return"]=b,b=b.child}function f(a){return 5===a.tag||3===a.tag||4===a.tag}function g(a){for(var b=a,c=!1,f=void 0,g=void 0;;){if(!c){c=b["return"];a:for(;;){null===c?E("160"):void 0;switch(c.tag){case 5:f=c.stateNode;g=!1;break a;case 3:f=c.stateNode.containerInfo;g=!0;break a;case 4:f=c.stateNode.containerInfo;g=!0;break a}c=c["return"]}c=!0}if(5===b.tag||6===b.tag)e(b),g?J(f,b.stateNode):N(f,b.stateNode); -else if(4===b.tag?f=b.stateNode.containerInfo:d(b),null!==b.child){b.child["return"]=b;b=b.child;continue}if(b===a)break;for(;null===b.sibling;){if(null===b["return"]||b["return"]===a)return;b=b["return"];4===b.tag&&(c=!1)}b.sibling["return"]=b["return"];b=b.sibling}}var h=a.getPublicInstance,k=a.mutation;a=a.persistence;k||(a?E("235"):E("236"));var q=k.commitMount,v=k.commitUpdate,y=k.resetTextContent,u=k.commitTextUpdate,z=k.appendChild,G=k.appendChildToContainer,I=k.insertBefore,L=k.insertInContainerBefore, -N=k.removeChild,J=k.removeChildFromContainer;return{commitResetTextContent:function(a){y(a.stateNode)},commitPlacement:function(a){a:{for(var b=a["return"];null!==b;){if(f(b)){var c=b;break a}b=b["return"]}E("160");c=void 0}var d=b=void 0;switch(c.tag){case 5:b=c.stateNode;d=!1;break;case 3:b=c.stateNode.containerInfo;d=!0;break;case 4:b=c.stateNode.containerInfo;d=!0;break;default:E("161")}c.effectTag&16&&(y(b),c.effectTag&=-17);a:b:for(c=a;;){for(;null===c.sibling;){if(null===c["return"]||f(c["return"])){c= -null;break a}c=c["return"]}c.sibling["return"]=c["return"];for(c=c.sibling;5!==c.tag&&6!==c.tag;){if(c.effectTag&2)continue b;if(null===c.child||4===c.tag)continue b;else c.child["return"]=c,c=c.child}if(!(c.effectTag&2)){c=c.stateNode;break a}}for(var e=a;;){if(5===e.tag||6===e.tag)c?d?L(b,e.stateNode,c):I(b,e.stateNode,c):d?G(b,e.stateNode):z(b,e.stateNode);else if(4!==e.tag&&null!==e.child){e.child["return"]=e;e=e.child;continue}if(e===a)break;for(;null===e.sibling;){if(null===e["return"]||e["return"]=== -a)return;e=e["return"]}e.sibling["return"]=e["return"];e=e.sibling}},commitDeletion:function(a){g(a);a["return"]=null;a.child=null;a.alternate&&(a.alternate.child=null,a.alternate["return"]=null)},commitWork:function(a,b){switch(b.tag){case 2:break;case 5:var c=b.stateNode;if(null!=c){var d=b.memoizedProps;a=null!==a?a.memoizedProps:d;var e=b.type,f=b.updateQueue;b.updateQueue=null;null!==f&&v(c,f,e,a,d,b)}break;case 6:null===b.stateNode?E("162"):void 0;c=b.memoizedProps;u(b.stateNode,null!==a?a.memoizedProps: -c,c);break;case 3:break;default:E("163")}},commitLifeCycles:function(a,b){switch(b.tag){case 2:var c=b.stateNode;if(b.effectTag&4)if(null===a)c.props=b.memoizedProps,c.state=b.memoizedState,c.componentDidMount();else{var d=a.memoizedProps;a=a.memoizedState;c.props=b.memoizedProps;c.state=b.memoizedState;c.componentDidUpdate(d,a)}b=b.updateQueue;null!==b&&Ke(b,c);break;case 3:c=b.updateQueue;null!==c&&Ke(c,null!==b.child?b.child.stateNode:null);break;case 5:c=b.stateNode;null===a&&b.effectTag&4&&q(c, -b.type,b.memoizedProps,b);break;case 6:break;case 4:break;default:E("163")}},commitAttachRef:function(a){var b=a.ref;if(null!==b){var c=a.stateNode;switch(a.tag){case 5:b(h(c));break;default:b(c)}}},commitDetachRef:function(a){a=a.ref;null!==a&&a(null)}}}var gf={}; -function hf(a){function b(a){a===gf?E("174"):void 0;return a}var c=a.getChildHostContext,d=a.getRootHostContext,e={current:gf},f={current:gf},g={current:gf};return{getHostContext:function(){return b(e.current)},getRootHostContainer:function(){return b(g.current)},popHostContainer:function(a){V(e,a);V(f,a);V(g,a)},popHostContext:function(a){f.current===a&&(V(e,a),V(f,a))},pushHostContainer:function(a,b){W(g,b,a);b=d(b);W(f,a,a);W(e,b,a)},pushHostContext:function(a){var d=b(g.current),h=b(e.current); -d=c(h,a.type,d);h!==d&&(W(f,a,a),W(e,d,a))},resetHostContainer:function(){e.current=gf;g.current=gf}}} -function jf(a){function b(a,b){var c=new Y(5,null,0);c.type="DELETED";c.stateNode=b;c["return"]=a;c.effectTag=8;null!==a.lastEffect?(a.lastEffect.nextEffect=c,a.lastEffect=c):a.firstEffect=a.lastEffect=c}function c(a,b){switch(a.tag){case 5:return b=f(b,a.type,a.pendingProps),null!==b?(a.stateNode=b,!0):!1;case 6:return b=g(b,a.pendingProps),null!==b?(a.stateNode=b,!0):!1;default:return!1}}function d(a){for(a=a["return"];null!==a&&5!==a.tag&&3!==a.tag;)a=a["return"];y=a}var e=a.shouldSetTextContent; -a=a.hydration;if(!a)return{enterHydrationState:function(){return!1},resetHydrationState:function(){},tryToClaimNextHydratableInstance:function(){},prepareToHydrateHostInstance:function(){E("175")},prepareToHydrateHostTextInstance:function(){E("176")},popHydrationState:function(){return!1}};var f=a.canHydrateInstance,g=a.canHydrateTextInstance,h=a.getNextHydratableSibling,k=a.getFirstHydratableChild,q=a.hydrateInstance,v=a.hydrateTextInstance,y=null,u=null,z=!1;return{enterHydrationState:function(a){u= -k(a.stateNode.containerInfo);y=a;return z=!0},resetHydrationState:function(){u=y=null;z=!1},tryToClaimNextHydratableInstance:function(a){if(z){var d=u;if(d){if(!c(a,d)){d=h(d);if(!d||!c(a,d)){a.effectTag|=2;z=!1;y=a;return}b(y,u)}y=a;u=k(d)}else a.effectTag|=2,z=!1,y=a}},prepareToHydrateHostInstance:function(a,b,c){b=q(a.stateNode,a.type,a.memoizedProps,b,c,a);a.updateQueue=b;return null!==b?!0:!1},prepareToHydrateHostTextInstance:function(a){return v(a.stateNode,a.memoizedProps,a)},popHydrationState:function(a){if(a!== -y)return!1;if(!z)return d(a),z=!0,!1;var c=a.type;if(5!==a.tag||"head"!==c&&"body"!==c&&!e(c,a.memoizedProps))for(c=u;c;)b(a,c),c=h(c);d(a);u=y?h(a.stateNode):null;return!0}}} -function kf(a){function b(a){Qb=ja=!0;var b=a.stateNode;b.current===a?E("177"):void 0;b.isReadyForCommit=!1;id.current=null;if(1g.expirationTime)&&(f=g.expirationTime),g=g.sibling;e.expirationTime=f}if(null!==b)return b;null!==c&&(null===c.firstEffect&&(c.firstEffect=a.firstEffect),null!==a.lastEffect&&(null!==c.lastEffect&&(c.lastEffect.nextEffect=a.firstEffect),c.lastEffect=a.lastEffect),1a))if(H<=Uc)for(;null!==F;)F=k(F)?e(F):d(F);else for(;null!==F&&!A();)F=k(F)?e(F):d(F)}else if(!(0===H||H>a))if(H<=Uc)for(;null!==F;)F=d(F);else for(;null!==F&&!A();)F=d(F)}function g(a,b){ja?E("243"):void 0;ja=!0;a.isReadyForCommit= -!1;if(a!==ra||b!==H||null===F){for(;-1b)a.expirationTime=b;null!==a.alternate&&(0===a.alternate.expirationTime||a.alternate.expirationTime>b)&&(a.alternate.expirationTime=b);if(null===a["return"])if(3===a.tag){var c=a.stateNode;!ja&&c===ra&&bIg&&E("185");if(null===d.nextScheduledRoot)d.remainingExpirationTime=e,null===O?(sa=O=d,d.nextScheduledRoot=d):(O=O.nextScheduledRoot=d,O.nextScheduledRoot=sa);else{var f=d.remainingExpirationTime;if(0===f||eTb)return;Jg(Xc)}var b=Wc()-Pe;Tb=a;Xc=Kg(J,{timeout:10*(a-2)-b})}function N(){var a=0,b=null;if(null!==O)for(var c=O,d=sa;null!==d;){var e=d.remainingExpirationTime;if(0===e){null===c||null===O?E("244"):void 0;if(d===d.nextScheduledRoot){sa=O=d.nextScheduledRoot=null;break}else if(d===sa)sa=e=d.nextScheduledRoot, -O.nextScheduledRoot=e,d.nextScheduledRoot=null;else if(d===O){O=c;O.nextScheduledRoot=sa;d.nextScheduledRoot=null;break}else c.nextScheduledRoot=d.nextScheduledRoot,d.nextScheduledRoot=null;d=c.nextScheduledRoot}else{if(0===a||eLg?!1:Yc=!0}function Ob(a){null===ma?E("246"): -void 0;ma.remainingExpirationTime=0;Ub||(Ub=!0,Zc=a)}var r=hf(a),n=jf(a),p=r.popHostContainer,qg=r.popHostContext,x=r.resetHostContainer,Me=df(a,r,n,u,y),rg=Me.beginWork,Gg=Me.beginFailedWork,Fg=ef(a,r,n).completeWork;r=ff(a,h);var zg=r.commitResetTextContent,Ne=r.commitPlacement,Bg=r.commitDeletion,Oe=r.commitWork,Dg=r.commitLifeCycles,Eg=r.commitAttachRef,Ag=r.commitDetachRef,Wc=a.now,Kg=a.scheduleDeferredCallback,Jg=a.cancelDeferredCallback,Hg=a.useSyncScheduling,yg=a.prepareForCommit,Cg=a.resetAfterCommit, -Pe=Wc(),Uc=2,ka=0,ja=!1,F=null,ra=null,H=0,t=null,R=null,qa=null,ha=null,ca=null,eb=!1,Qb=!1,Sc=!1,sa=null,O=null,Tb=0,Xc=-1,Fa=!1,ma=null,na=0,Yc=!1,Ub=!1,Zc=null,fb=null,la=!1,Sb=!1,Ig=1E3,Rb=0,Lg=1;return{computeAsyncExpiration:v,computeExpirationForFiber:y,scheduleWork:u,batchedUpdates:function(a,b){var c=la;la=!0;try{return a(b)}finally{(la=c)||Fa||w(1,null)}},unbatchedUpdates:function(a){if(la&&!Sb){Sb=!0;try{return a()}finally{Sb=!1}}return a()},flushSync:function(a){var b=la;la=!0;try{a:{var c= -ka;ka=1;try{var d=a();break a}finally{ka=c}d=void 0}return d}finally{la=b,Fa?E("187"):void 0,w(1,null)}},deferredUpdates:function(a){var b=ka;ka=v();try{return a()}finally{ka=b}}}} -function lf(a){function b(a){a=od(a);return null===a?null:a.stateNode}var c=a.getPublicInstance;a=kf(a);var d=a.computeAsyncExpiration,e=a.computeExpirationForFiber,f=a.scheduleWork;return{createContainer:function(a,b){var c=new Y(3,null,0);a={current:c,containerInfo:a,pendingChildren:null,remainingExpirationTime:0,isReadyForCommit:!1,finishedWork:null,context:null,pendingContext:null,hydrate:b,nextScheduledRoot:null};return c.stateNode=a},updateContainer:function(a,b,c,q){var g=b.current;if(c){c= -c._reactInternalFiber;var h;b:{2===kd(c)&&2===c.tag?void 0:E("170");for(h=c;3!==h.tag;){if(le(h)){h=h.stateNode.__reactInternalMemoizedMergedChildContext;break b}(h=h["return"])?void 0:E("171")}h=h.stateNode.context}c=le(c)?pe(c,h):h}else c=D;null===b.context?b.context=c:b.pendingContext=c;b=q;b=void 0===b?null:b;q=null!=a&&null!=a.type&&null!=a.type.prototype&&!0===a.type.prototype.unstable_isAsyncReactComponent?d():e(g);He(g,{expirationTime:q,partialState:{element:a},callback:b,isReplace:!1,isForced:!1, -nextCallback:null,next:null});f(g,q)},batchedUpdates:a.batchedUpdates,unbatchedUpdates:a.unbatchedUpdates,deferredUpdates:a.deferredUpdates,flushSync:a.flushSync,getPublicRootInstance:function(a){a=a.current;if(!a.child)return null;switch(a.child.tag){case 5:return c(a.child.stateNode);default:return a.child.stateNode}},findHostInstance:b,findHostInstanceWithNoPortals:function(a){a=pd(a);return null===a?null:a.stateNode},injectIntoDevTools:function(a){var c=a.findFiberByHostInstance;return Ce(B({}, -a,{findHostInstanceByFiber:function(a){return b(a)},findFiberByHostInstance:function(a){return c?c(a):null}}))}}}var mf=Object.freeze({default:lf}),nf=mf&&lf||mf,of=nf["default"]?nf["default"]:nf;function pf(a,b,c){var d=3=yf-a)if(-1!==wf&&wf<= -a)Bf.didTimeout=!0;else{xf||(xf=!0,requestAnimationFrame(Df));return}else Bf.didTimeout=!1;wf=-1;a=uf;uf=null;null!==a&&a(Bf)}},!1);var Df=function(a){xf=!1;var b=a-yf+Af;bb&&(b=8),Af=bc||d.hasOverloadedBooleanValue&&!1===c?Jf(a,b):d.mustUseProperty?a[d.propertyName]=c:(b=d.attributeName,(e=d.attributeNamespace)?a.setAttributeNS(e,b,""+c):d.hasBooleanValue||d.hasOverloadedBooleanValue&&!0===c?a.setAttribute(b,""):a.setAttribute(b,""+c))}else Kf(a,b,va(b,c)?c:null)} -function Kf(a,b,c){Hf(b)&&(null==c?a.removeAttribute(b):a.setAttribute(b,""+c))}function Jf(a,b){var c=wa(b);c?(b=c.mutationMethod)?b(a,void 0):c.mustUseProperty?a[c.propertyName]=c.hasBooleanValue?!1:"":a.removeAttribute(c.attributeName):a.removeAttribute(b)} -function Lf(a,b){var c=b.value,d=b.checked;return B({type:void 0,step:void 0,min:void 0,max:void 0},b,{defaultChecked:void 0,defaultValue:void 0,value:null!=c?c:a._wrapperState.initialValue,checked:null!=d?d:a._wrapperState.initialChecked})}function Mf(a,b){var c=b.defaultValue;a._wrapperState={initialChecked:null!=b.checked?b.checked:b.defaultChecked,initialValue:null!=b.value?b.value:c,controlled:"checkbox"===b.type||"radio"===b.type?null!=b.checked:null!=b.value}} -function Nf(a,b){b=b.checked;null!=b&&If(a,"checked",b)}function Of(a,b){Nf(a,b);var c=b.value;if(null!=c)if(0===c&&""===a.value)a.value="0";else if("number"===b.type){if(b=parseFloat(a.value)||0,c!=b||c==b&&a.value!=c)a.value=""+c}else a.value!==""+c&&(a.value=""+c);else null==b.value&&null!=b.defaultValue&&a.defaultValue!==""+b.defaultValue&&(a.defaultValue=""+b.defaultValue),null==b.checked&&null!=b.defaultChecked&&(a.defaultChecked=!!b.defaultChecked)} -function Pf(a,b){switch(b.type){case "submit":case "reset":break;case "color":case "date":case "datetime":case "datetime-local":case "month":case "time":case "week":a.value="";a.value=a.defaultValue;break;default:a.value=a.value}b=a.name;""!==b&&(a.name="");a.defaultChecked=!a.defaultChecked;a.defaultChecked=!a.defaultChecked;""!==b&&(a.name=b)}function Qf(a){var b="";aa.Children.forEach(a,function(a){null==a||"string"!==typeof a&&"number"!==typeof a||(b+=a)});return b} -function Rf(a,b){a=B({children:void 0},b);if(b=Qf(b.children))a.children=b;return a}function Sf(a,b,c,d){a=a.options;if(b){b={};for(var e=0;e=b.length?void 0:E("93"),b=b[0]),c=""+b),null==c&&(c=""));a._wrapperState={initialValue:""+c}} -function Wf(a,b){var c=b.value;null!=c&&(c=""+c,c!==a.value&&(a.value=c),null==b.defaultValue&&(a.defaultValue=c));null!=b.defaultValue&&(a.defaultValue=b.defaultValue)}function Xf(a){var b=a.textContent;b===a._wrapperState.initialValue&&(a.value=b)}var Yf={html:"http://www.w3.org/1999/xhtml",mathml:"http://www.w3.org/1998/Math/MathML",svg:"http://www.w3.org/2000/svg"}; -function Zf(a){switch(a){case "svg":return"http://www.w3.org/2000/svg";case "math":return"http://www.w3.org/1998/Math/MathML";default:return"http://www.w3.org/1999/xhtml"}}function $f(a,b){return null==a||"http://www.w3.org/1999/xhtml"===a?Zf(b):"http://www.w3.org/2000/svg"===a&&"foreignObject"===b?"http://www.w3.org/1999/xhtml":a} -var ag=void 0,bg=function(a){return"undefined"!==typeof MSApp&&MSApp.execUnsafeLocalFunction?function(b,c,d,e){MSApp.execUnsafeLocalFunction(function(){return a(b,c,d,e)})}:a}(function(a,b){if(a.namespaceURI!==Yf.svg||"innerHTML"in a)a.innerHTML=b;else{ag=ag||document.createElement("div");ag.innerHTML="\x3csvg\x3e"+b+"\x3c/svg\x3e";for(b=ag.firstChild;a.firstChild;)a.removeChild(a.firstChild);for(;b.firstChild;)a.appendChild(b.firstChild)}}); -function cg(a,b){if(b){var c=a.firstChild;if(c&&c===a.lastChild&&3===c.nodeType){c.nodeValue=b;return}}a.textContent=b} -var dg={animationIterationCount:!0,borderImageOutset:!0,borderImageSlice:!0,borderImageWidth:!0,boxFlex:!0,boxFlexGroup:!0,boxOrdinalGroup:!0,columnCount:!0,columns:!0,flex:!0,flexGrow:!0,flexPositive:!0,flexShrink:!0,flexNegative:!0,flexOrder:!0,gridRow:!0,gridRowEnd:!0,gridRowSpan:!0,gridRowStart:!0,gridColumn:!0,gridColumnEnd:!0,gridColumnSpan:!0,gridColumnStart:!0,fontWeight:!0,lineClamp:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,tabSize:!0,widows:!0,zIndex:!0,zoom:!0,fillOpacity:!0,floodOpacity:!0, -stopOpacity:!0,strokeDasharray:!0,strokeDashoffset:!0,strokeMiterlimit:!0,strokeOpacity:!0,strokeWidth:!0},eg=["Webkit","ms","Moz","O"];Object.keys(dg).forEach(function(a){eg.forEach(function(b){b=b+a.charAt(0).toUpperCase()+a.substring(1);dg[b]=dg[a]})}); -function fg(a,b){a=a.style;for(var c in b)if(b.hasOwnProperty(c)){var d=0===c.indexOf("--");var e=c;var f=b[c];e=null==f||"boolean"===typeof f||""===f?"":d||"number"!==typeof f||0===f||dg.hasOwnProperty(e)&&dg[e]?(""+f).trim():f+"px";"float"===c&&(c="cssFloat");d?a.setProperty(c,e):a[c]=e}}var gg=B({menuitem:!0},{area:!0,base:!0,br:!0,col:!0,embed:!0,hr:!0,img:!0,input:!0,keygen:!0,link:!0,meta:!0,param:!0,source:!0,track:!0,wbr:!0}); -function hg(a,b,c){b&&(gg[a]&&(null!=b.children||null!=b.dangerouslySetInnerHTML?E("137",a,c()):void 0),null!=b.dangerouslySetInnerHTML&&(null!=b.children?E("60"):void 0,"object"===typeof b.dangerouslySetInnerHTML&&"__html"in b.dangerouslySetInnerHTML?void 0:E("61")),null!=b.style&&"object"!==typeof b.style?E("62",c()):void 0)} -function ig(a,b){if(-1===a.indexOf("-"))return"string"===typeof b.is;switch(a){case "annotation-xml":case "color-profile":case "font-face":case "font-face-src":case "font-face-uri":case "font-face-format":case "font-face-name":case "missing-glyph":return!1;default:return!0}}var jg=Yf.html,kg=C.thatReturns(""); -function lg(a,b){a=9===a.nodeType||11===a.nodeType?a:a.ownerDocument;var c=Hd(a);b=Sa[b];for(var d=0;d -d&&(e=d,d=a,a=e);e=Jd(c,a);var f=Jd(c,d);if(e&&f&&(1!==b.rangeCount||b.anchorNode!==e.node||b.anchorOffset!==e.offset||b.focusNode!==f.node||b.focusOffset!==f.offset)){var g=document.createRange();g.setStart(e.node,e.offset);b.removeAllRanges();a>d?(b.addRange(g),b.extend(f.node,f.offset)):(g.setEnd(f.node,f.offset),b.addRange(g))}}b=[];for(a=c;a=a.parentNode;)1===a.nodeType&&b.push({element:a,left:a.scrollLeft,top:a.scrollTop});ia(c);for(c=0;c 2 && (name[0] === 'o' || name[0] === 'O') && (name[1] === 'n' || name[1] === 'N')) { - return false; - } - if (value === null) { - return true; - } - switch (typeof value) { - case 'boolean': - return shouldAttributeAcceptBooleanValue(name); - case 'undefined': - case 'number': - case 'string': - case 'object': - return true; - default: - // function, symbol - return false; - } -} + }, -function getPropertyInfo(name) { - return properties.hasOwnProperty(name) ? properties[name] : null; -} + attach: function ( /* child, scene, parent */ ) { -function shouldAttributeAcceptBooleanValue(name) { - if (isReservedProp(name)) { - return true; - } - var propertyInfo = getPropertyInfo(name); - if (propertyInfo) { - return propertyInfo.hasBooleanValue || propertyInfo.hasStringBooleanValue || propertyInfo.hasOverloadedBooleanValue; - } - var prefix = name.toLowerCase().slice(0, 5); - return prefix === 'data-' || prefix === 'aria-'; -} + console.error( 'THREE.SceneUtils has been moved to /examples/js/utils/SceneUtils.js' ); + + } -/** - * Checks to see if a property name is within the list of properties - * reserved for internal React operations. These properties should - * not be set on an HTML element. - * - * @private - * @param {string} name - * @return {boolean} If the name is within reserved props - */ -function isReservedProp(name) { - return RESERVED_PROPS.hasOwnProperty(name); -} - -var injection = DOMPropertyInjection; - -var MUST_USE_PROPERTY = injection.MUST_USE_PROPERTY; -var HAS_BOOLEAN_VALUE = injection.HAS_BOOLEAN_VALUE; -var HAS_NUMERIC_VALUE = injection.HAS_NUMERIC_VALUE; -var HAS_POSITIVE_NUMERIC_VALUE = injection.HAS_POSITIVE_NUMERIC_VALUE; -var HAS_OVERLOADED_BOOLEAN_VALUE = injection.HAS_OVERLOADED_BOOLEAN_VALUE; -var HAS_STRING_BOOLEAN_VALUE = injection.HAS_STRING_BOOLEAN_VALUE; - -var HTMLDOMPropertyConfig = { - // When adding attributes to this list, be sure to also add them to - // the `possibleStandardNames` module to ensure casing and incorrect - // name warnings. - Properties: { - allowFullScreen: HAS_BOOLEAN_VALUE, - // specifies target context for links with `preload` type - async: HAS_BOOLEAN_VALUE, - // Note: there is a special case that prevents it from being written to the DOM - // on the client side because the browsers are inconsistent. Instead we call focus(). - autoFocus: HAS_BOOLEAN_VALUE, - autoPlay: HAS_BOOLEAN_VALUE, - capture: HAS_OVERLOADED_BOOLEAN_VALUE, - checked: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE, - cols: HAS_POSITIVE_NUMERIC_VALUE, - contentEditable: HAS_STRING_BOOLEAN_VALUE, - controls: HAS_BOOLEAN_VALUE, - 'default': HAS_BOOLEAN_VALUE, - defer: HAS_BOOLEAN_VALUE, - disabled: HAS_BOOLEAN_VALUE, - download: HAS_OVERLOADED_BOOLEAN_VALUE, - draggable: HAS_STRING_BOOLEAN_VALUE, - formNoValidate: HAS_BOOLEAN_VALUE, - hidden: HAS_BOOLEAN_VALUE, - loop: HAS_BOOLEAN_VALUE, - // Caution; `option.selected` is not updated if `select.multiple` is - // disabled with `removeAttribute`. - multiple: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE, - muted: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE, - noValidate: HAS_BOOLEAN_VALUE, - open: HAS_BOOLEAN_VALUE, - playsInline: HAS_BOOLEAN_VALUE, - readOnly: HAS_BOOLEAN_VALUE, - required: HAS_BOOLEAN_VALUE, - reversed: HAS_BOOLEAN_VALUE, - rows: HAS_POSITIVE_NUMERIC_VALUE, - rowSpan: HAS_NUMERIC_VALUE, - scoped: HAS_BOOLEAN_VALUE, - seamless: HAS_BOOLEAN_VALUE, - selected: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE, - size: HAS_POSITIVE_NUMERIC_VALUE, - start: HAS_NUMERIC_VALUE, - // support for projecting regular DOM Elements via V1 named slots ( shadow dom ) - span: HAS_POSITIVE_NUMERIC_VALUE, - spellCheck: HAS_STRING_BOOLEAN_VALUE, - // Style must be explicitly set in the attribute list. React components - // expect a style object - style: 0, - // Keep it in the whitelist because it is case-sensitive for SVG. - tabIndex: 0, - // itemScope is for for Microdata support. - // See http://schema.org/docs/gs.html - itemScope: HAS_BOOLEAN_VALUE, - // These attributes must stay in the white-list because they have - // different attribute names (see DOMAttributeNames below) - acceptCharset: 0, - className: 0, - htmlFor: 0, - httpEquiv: 0, - // Attributes with mutation methods must be specified in the whitelist - // Set the string boolean flag to allow the behavior - value: HAS_STRING_BOOLEAN_VALUE - }, - DOMAttributeNames: { - acceptCharset: 'accept-charset', - className: 'class', - htmlFor: 'for', - httpEquiv: 'http-equiv' - }, - DOMMutationMethods: { - value: function (node, value) { - if (value == null) { - return node.removeAttribute('value'); - } - - // Number inputs get special treatment due to some edge cases in - // Chrome. Let everything else assign the value attribute as normal. - // https://github.com/facebook/react/issues/7253#issuecomment-236074326 - if (node.type !== 'number' || node.hasAttribute('value') === false) { - node.setAttribute('value', '' + value); - } else if (node.validity && !node.validity.badInput && node.ownerDocument.activeElement !== node) { - // Don't assign an attribute if validation reports bad - // input. Chrome will clear the value. Additionally, don't - // operate on inputs that have focus, otherwise Chrome might - // strip off trailing decimal places and cause the user's - // cursor position to jump to the beginning of the input. - // - // In ReactDOMInput, we have an onBlur event that will trigger - // this function again when focus is lost. - node.setAttribute('value', '' + value); - } - } - } }; -var HAS_STRING_BOOLEAN_VALUE$1 = injection.HAS_STRING_BOOLEAN_VALUE; +// +function LensFlare() { -var NS = { - xlink: 'http://www.w3.org/1999/xlink', - xml: 'http://www.w3.org/XML/1998/namespace' -}; + console.error( 'THREE.LensFlare has been moved to /examples/js/objects/Lensflare.js' ); -/** - * This is a list of all SVG attributes that need special casing, - * namespacing, or boolean value assignment. - * - * When adding attributes to this list, be sure to also add them to - * the `possibleStandardNames` module to ensure casing and incorrect - * name warnings. - * - * SVG Attributes List: - * https://www.w3.org/TR/SVG/attindex.html - * SMIL Spec: - * https://www.w3.org/TR/smil - */ -var ATTRS = ['accent-height', 'alignment-baseline', 'arabic-form', 'baseline-shift', 'cap-height', 'clip-path', 'clip-rule', 'color-interpolation', 'color-interpolation-filters', 'color-profile', 'color-rendering', 'dominant-baseline', 'enable-background', 'fill-opacity', 'fill-rule', 'flood-color', 'flood-opacity', 'font-family', 'font-size', 'font-size-adjust', 'font-stretch', 'font-style', 'font-variant', 'font-weight', 'glyph-name', 'glyph-orientation-horizontal', 'glyph-orientation-vertical', 'horiz-adv-x', 'horiz-origin-x', 'image-rendering', 'letter-spacing', 'lighting-color', 'marker-end', 'marker-mid', 'marker-start', 'overline-position', 'overline-thickness', 'paint-order', 'panose-1', 'pointer-events', 'rendering-intent', 'shape-rendering', 'stop-color', 'stop-opacity', 'strikethrough-position', 'strikethrough-thickness', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'text-anchor', 'text-decoration', 'text-rendering', 'underline-position', 'underline-thickness', 'unicode-bidi', 'unicode-range', 'units-per-em', 'v-alphabetic', 'v-hanging', 'v-ideographic', 'v-mathematical', 'vector-effect', 'vert-adv-y', 'vert-origin-x', 'vert-origin-y', 'word-spacing', 'writing-mode', 'x-height', 'xlink:actuate', 'xlink:arcrole', 'xlink:href', 'xlink:role', 'xlink:show', 'xlink:title', 'xlink:type', 'xml:base', 'xmlns:xlink', 'xml:lang', 'xml:space']; +} -var SVGDOMPropertyConfig = { - Properties: { - autoReverse: HAS_STRING_BOOLEAN_VALUE$1, - externalResourcesRequired: HAS_STRING_BOOLEAN_VALUE$1, - preserveAlpha: HAS_STRING_BOOLEAN_VALUE$1 - }, - DOMAttributeNames: { - autoReverse: 'autoReverse', - externalResourcesRequired: 'externalResourcesRequired', - preserveAlpha: 'preserveAlpha' - }, - DOMAttributeNamespaces: { - xlinkActuate: NS.xlink, - xlinkArcrole: NS.xlink, - xlinkHref: NS.xlink, - xlinkRole: NS.xlink, - xlinkShow: NS.xlink, - xlinkTitle: NS.xlink, - xlinkType: NS.xlink, - xmlBase: NS.xml, - xmlLang: NS.xml, - xmlSpace: NS.xml - } -}; -var CAMELIZE = /[\-\:]([a-z])/g; -var capitalize = function (token) { - return token[1].toUpperCase(); -}; -ATTRS.forEach(function (original) { - var reactName = original.replace(CAMELIZE, capitalize); - SVGDOMPropertyConfig.Properties[reactName] = 0; - SVGDOMPropertyConfig.DOMAttributeNames[reactName] = original; -}); +/***/ }), +/* 13 */ +/***/ (function(module, exports) { -injection.injectDOMPropertyConfig(HTMLDOMPropertyConfig); -injection.injectDOMPropertyConfig(SVGDOMPropertyConfig); +module.exports = function( THREE ) { + /** + * @author qiao / https://github.com/qiao + * @author mrdoob / http://mrdoob.com + * @author alteredq / http://alteredqualia.com/ + * @author WestLangley / http://github.com/WestLangley + * @author erich666 / http://erichaines.com + */ -var ReactErrorUtils = { - // Used by Fiber to simulate a try-catch. - _caughtError: null, - _hasCaughtError: false, +// This set of controls performs orbiting, dollying (zooming), and panning. +// Unlike TrackballControls, it maintains the "up" direction object.up (+Y by default). +// +// Orbit - left mouse / touch: one finger move +// Zoom - middle mouse, or mousewheel / touch: two finger spread or squish +// Pan - right mouse, or arrow keys / touch: three finter swipe - // Used by event system to capture/rethrow the first error. - _rethrowError: null, - _hasRethrowError: false, + function OrbitControls( object, domElement ) { - injection: { - injectErrorUtils: function (injectedErrorUtils) { - !(typeof injectedErrorUtils.invokeGuardedCallback === 'function') ? invariant(false, 'Injected invokeGuardedCallback() must be a function.') : void 0; - invokeGuardedCallback = injectedErrorUtils.invokeGuardedCallback; - } - }, + this.object = object; - /** - * Call a function while guarding against errors that happens within it. - * Returns an error if it throws, otherwise null. - * - * In production, this is implemented using a try-catch. The reason we don't - * use a try-catch directly is so that we can swap out a different - * implementation in DEV mode. - * - * @param {String} name of the guard to use for logging or debugging - * @param {Function} func The function to invoke - * @param {*} context The context to use when calling the function - * @param {...*} args Arguments for function - */ - invokeGuardedCallback: function (name, func, context, a, b, c, d, e, f) { - invokeGuardedCallback.apply(ReactErrorUtils, arguments); - }, + this.domElement = ( domElement !== undefined ) ? domElement : document; - /** - * Same as invokeGuardedCallback, but instead of returning an error, it stores - * it in a global so it can be rethrown by `rethrowCaughtError` later. - * TODO: See if _caughtError and _rethrowError can be unified. - * - * @param {String} name of the guard to use for logging or debugging - * @param {Function} func The function to invoke - * @param {*} context The context to use when calling the function - * @param {...*} args Arguments for function - */ - invokeGuardedCallbackAndCatchFirstError: function (name, func, context, a, b, c, d, e, f) { - ReactErrorUtils.invokeGuardedCallback.apply(this, arguments); - if (ReactErrorUtils.hasCaughtError()) { - var error = ReactErrorUtils.clearCaughtError(); - if (!ReactErrorUtils._hasRethrowError) { - ReactErrorUtils._hasRethrowError = true; - ReactErrorUtils._rethrowError = error; - } - } - }, + // Set to false to disable this control + this.enabled = true; - /** - * During execution of guarded functions we will capture the first error which - * we will rethrow to be handled by the top level error handler. - */ - rethrowCaughtError: function () { - return rethrowCaughtError.apply(ReactErrorUtils, arguments); - }, + // "target" sets the location of focus, where the object orbits around + this.target = new THREE.Vector3(); - hasCaughtError: function () { - return ReactErrorUtils._hasCaughtError; - }, + // How far you can dolly in and out ( PerspectiveCamera only ) + this.minDistance = 0; + this.maxDistance = Infinity; - clearCaughtError: function () { - if (ReactErrorUtils._hasCaughtError) { - var error = ReactErrorUtils._caughtError; - ReactErrorUtils._caughtError = null; - ReactErrorUtils._hasCaughtError = false; - return error; - } else { - invariant(false, 'clearCaughtError was called but no error was captured. This error is likely caused by a bug in React. Please file an issue.'); - } - } -}; + // How far you can zoom in and out ( OrthographicCamera only ) + this.minZoom = 0; + this.maxZoom = Infinity; -var invokeGuardedCallback = function (name, func, context, a, b, c, d, e, f) { - ReactErrorUtils._hasCaughtError = false; - ReactErrorUtils._caughtError = null; - var funcArgs = Array.prototype.slice.call(arguments, 3); - try { - func.apply(context, funcArgs); - } catch (error) { - ReactErrorUtils._caughtError = error; - ReactErrorUtils._hasCaughtError = true; - } -}; + // How far you can orbit vertically, upper and lower limits. + // Range is 0 to Math.PI radians. + this.minPolarAngle = 0; // radians + this.maxPolarAngle = Math.PI; // radians -{ - // In DEV mode, we swap out invokeGuardedCallback for a special version - // that plays more nicely with the browser's DevTools. The idea is to preserve - // "Pause on exceptions" behavior. Because React wraps all user-provided - // functions in invokeGuardedCallback, and the production version of - // invokeGuardedCallback uses a try-catch, all user exceptions are treated - // like caught exceptions, and the DevTools won't pause unless the developer - // takes the extra step of enabling pause on caught exceptions. This is - // untintuitive, though, because even though React has caught the error, from - // the developer's perspective, the error is uncaught. - // - // To preserve the expected "Pause on exceptions" behavior, we don't use a - // try-catch in DEV. Instead, we synchronously dispatch a fake event to a fake - // DOM node, and call the user-provided callback from inside an event handler - // for that fake event. If the callback throws, the error is "captured" using - // a global event handler. But because the error happens in a different - // event loop context, it does not interrupt the normal program flow. - // Effectively, this gives us try-catch behavior without actually using - // try-catch. Neat! + // How far you can orbit horizontally, upper and lower limits. + // If set, must be a sub-interval of the interval [ - Math.PI, Math.PI ]. + this.minAzimuthAngle = - Infinity; // radians + this.maxAzimuthAngle = Infinity; // radians - // Check that the browser supports the APIs we need to implement our special - // DEV version of invokeGuardedCallback - if (typeof window !== 'undefined' && typeof window.dispatchEvent === 'function' && typeof document !== 'undefined' && typeof document.createEvent === 'function') { - var fakeNode = document.createElement('react'); + // Set to true to enable damping (inertia) + // If damping is enabled, you must call controls.update() in your animation loop + this.enableDamping = false; + this.dampingFactor = 0.25; - var invokeGuardedCallbackDev = function (name, func, context, a, b, c, d, e, f) { - // Keeps track of whether the user-provided callback threw an error. We - // set this to true at the beginning, then set it to false right after - // calling the function. If the function errors, `didError` will never be - // set to false. This strategy works even if the browser is flaky and - // fails to call our global error handler, because it doesn't rely on - // the error event at all. - var didError = true; + // This option actually enables dollying in and out; left as "zoom" for backwards compatibility. + // Set to false to disable zooming + this.enableZoom = true; + this.zoomSpeed = 1.0; - // Create an event handler for our fake event. We will synchronously - // dispatch our fake event using `dispatchEvent`. Inside the handler, we - // call the user-provided callback. - var funcArgs = Array.prototype.slice.call(arguments, 3); - function callCallback() { - // We immediately remove the callback from event listeners so that - // nested `invokeGuardedCallback` calls do not clash. Otherwise, a - // nested call would trigger the fake event handlers of any call higher - // in the stack. - fakeNode.removeEventListener(evtType, callCallback, false); - func.apply(context, funcArgs); - didError = false; - } + // Set to false to disable rotating + this.enableRotate = true; + this.rotateSpeed = 1.0; - // Create a global error event handler. We use this to capture the value - // that was thrown. It's possible that this error handler will fire more - // than once; for example, if non-React code also calls `dispatchEvent` - // and a handler for that event throws. We should be resilient to most of - // those cases. Even if our error event handler fires more than once, the - // last error event is always used. If the callback actually does error, - // we know that the last error event is the correct one, because it's not - // possible for anything else to have happened in between our callback - // erroring and the code that follows the `dispatchEvent` call below. If - // the callback doesn't error, but the error event was fired, we know to - // ignore it because `didError` will be false, as described above. - var error = void 0; - // Use this to track whether the error event is ever called. - var didSetError = false; - var isCrossOriginError = false; + // Set to false to disable panning + this.enablePan = true; + this.keyPanSpeed = 7.0; // pixels moved per arrow key push - function onError(event) { - error = event.error; - didSetError = true; - if (error === null && event.colno === 0 && event.lineno === 0) { - isCrossOriginError = true; - } - } + // Set to true to automatically rotate around the target + // If auto-rotate is enabled, you must call controls.update() in your animation loop + this.autoRotate = false; + this.autoRotateSpeed = 2.0; // 30 seconds per round when fps is 60 - // Create a fake event type. - var evtType = 'react-' + (name ? name : 'invokeguardedcallback'); + // Set to false to disable use of the keys + this.enableKeys = true; - // Attach our event handlers - window.addEventListener('error', onError); - fakeNode.addEventListener(evtType, callCallback, false); + // The four arrow keys + this.keys = { LEFT: 37, UP: 38, RIGHT: 39, BOTTOM: 40 }; - // Synchronously dispatch our fake event. If the user-provided function - // errors, it will trigger our global error handler. - var evt = document.createEvent('Event'); - evt.initEvent(evtType, false, false); - fakeNode.dispatchEvent(evt); + // Mouse buttons + this.mouseButtons = { ORBIT: THREE.MOUSE.LEFT, ZOOM: THREE.MOUSE.MIDDLE, PAN: THREE.MOUSE.RIGHT }; - if (didError) { - if (!didSetError) { - // The callback errored, but the error event never fired. - error = new Error('An error was thrown inside one of your components, but React ' + "doesn't know what it was. This is likely due to browser " + 'flakiness. React does its best to preserve the "Pause on ' + 'exceptions" behavior of the DevTools, which requires some ' + "DEV-mode only tricks. It's possible that these don't work in " + 'your browser. Try triggering the error in production mode, ' + 'or switching to a modern browser. If you suspect that this is ' + 'actually an issue with React, please file an issue.'); - } else if (isCrossOriginError) { - error = new Error("A cross-origin error was thrown. React doesn't have access to " + 'the actual error object in development. ' + 'See https://fb.me/react-crossorigin-error for more information.'); - } - ReactErrorUtils._hasCaughtError = true; - ReactErrorUtils._caughtError = error; - } else { - ReactErrorUtils._hasCaughtError = false; - ReactErrorUtils._caughtError = null; - } + // for reset + this.target0 = this.target.clone(); + this.position0 = this.object.position.clone(); + this.zoom0 = this.object.zoom; - // Remove our event listeners - window.removeEventListener('error', onError); - }; + // + // public methods + // - invokeGuardedCallback = invokeGuardedCallbackDev; - } -} + this.getPolarAngle = function () { -var rethrowCaughtError = function () { - if (ReactErrorUtils._hasRethrowError) { - var error = ReactErrorUtils._rethrowError; - ReactErrorUtils._rethrowError = null; - ReactErrorUtils._hasRethrowError = false; - throw error; - } -}; + return spherical.phi; -/** - * Injectable ordering of event plugins. - */ -var eventPluginOrder = null; + }; -/** - * Injectable mapping from names to event plugin modules. - */ -var namesToPlugins = {}; + this.getAzimuthalAngle = function () { -/** - * Recomputes the plugin list using the injected plugins and plugin ordering. - * - * @private - */ -function recomputePluginOrdering() { - if (!eventPluginOrder) { - // Wait until an `eventPluginOrder` is injected. - return; - } - for (var pluginName in namesToPlugins) { - var pluginModule = namesToPlugins[pluginName]; - var pluginIndex = eventPluginOrder.indexOf(pluginName); - !(pluginIndex > -1) ? invariant(false, 'EventPluginRegistry: Cannot inject event plugins that do not exist in the plugin ordering, `%s`.', pluginName) : void 0; - if (plugins[pluginIndex]) { - continue; - } - !pluginModule.extractEvents ? invariant(false, 'EventPluginRegistry: Event plugins must implement an `extractEvents` method, but `%s` does not.', pluginName) : void 0; - plugins[pluginIndex] = pluginModule; - var publishedEvents = pluginModule.eventTypes; - for (var eventName in publishedEvents) { - !publishEventForPlugin(publishedEvents[eventName], pluginModule, eventName) ? invariant(false, 'EventPluginRegistry: Failed to publish event `%s` for plugin `%s`.', eventName, pluginName) : void 0; - } - } -} + return spherical.theta; -/** - * Publishes an event so that it can be dispatched by the supplied plugin. - * - * @param {object} dispatchConfig Dispatch configuration for the event. - * @param {object} PluginModule Plugin publishing the event. - * @return {boolean} True if the event was successfully published. - * @private - */ -function publishEventForPlugin(dispatchConfig, pluginModule, eventName) { - !!eventNameDispatchConfigs.hasOwnProperty(eventName) ? invariant(false, 'EventPluginHub: More than one plugin attempted to publish the same event name, `%s`.', eventName) : void 0; - eventNameDispatchConfigs[eventName] = dispatchConfig; + }; - var phasedRegistrationNames = dispatchConfig.phasedRegistrationNames; - if (phasedRegistrationNames) { - for (var phaseName in phasedRegistrationNames) { - if (phasedRegistrationNames.hasOwnProperty(phaseName)) { - var phasedRegistrationName = phasedRegistrationNames[phaseName]; - publishRegistrationName(phasedRegistrationName, pluginModule, eventName); - } - } - return true; - } else if (dispatchConfig.registrationName) { - publishRegistrationName(dispatchConfig.registrationName, pluginModule, eventName); - return true; - } - return false; -} + this.reset = function () { -/** - * Publishes a registration name that is used to identify dispatched events. - * - * @param {string} registrationName Registration name to add. - * @param {object} PluginModule Plugin publishing the event. - * @private - */ -function publishRegistrationName(registrationName, pluginModule, eventName) { - !!registrationNameModules[registrationName] ? invariant(false, 'EventPluginHub: More than one plugin attempted to publish the same registration name, `%s`.', registrationName) : void 0; - registrationNameModules[registrationName] = pluginModule; - registrationNameDependencies[registrationName] = pluginModule.eventTypes[eventName].dependencies; + scope.target.copy( scope.target0 ); + scope.object.position.copy( scope.position0 ); + scope.object.zoom = scope.zoom0; - { - var lowerCasedName = registrationName.toLowerCase(); - possibleRegistrationNames[lowerCasedName] = registrationName; + scope.object.updateProjectionMatrix(); + scope.dispatchEvent( changeEvent ); - if (registrationName === 'onDoubleClick') { - possibleRegistrationNames.ondblclick = registrationName; - } - } -} + scope.update(); -/** - * Registers plugins so that they can extract and dispatch events. - * - * @see {EventPluginHub} - */ + state = STATE.NONE; -/** - * Ordered list of injected plugins. - */ -var plugins = []; + }; -/** - * Mapping from event name to dispatch config - */ -var eventNameDispatchConfigs = {}; + // this method is exposed, but perhaps it would be better if we can make it private... + this.update = function() { -/** - * Mapping from registration name to plugin module - */ -var registrationNameModules = {}; + var offset = new THREE.Vector3(); -/** - * Mapping from registration name to event name - */ -var registrationNameDependencies = {}; + // so camera.up is the orbit axis + var quat = new THREE.Quaternion().setFromUnitVectors( object.up, new THREE.Vector3( 0, 1, 0 ) ); + var quatInverse = quat.clone().inverse(); -/** - * Mapping from lowercase registration names to the properly cased version, - * used to warn in the case of missing event handlers. Available - * only in true. - * @type {Object} - */ -var possibleRegistrationNames = {}; -// Trust the developer to only use possibleRegistrationNames in true + var lastPosition = new THREE.Vector3(); + var lastQuaternion = new THREE.Quaternion(); -/** - * Injects an ordering of plugins (by plugin name). This allows the ordering - * to be decoupled from injection of the actual plugins so that ordering is - * always deterministic regardless of packaging, on-the-fly injection, etc. - * - * @param {array} InjectedEventPluginOrder - * @internal - * @see {EventPluginHub.injection.injectEventPluginOrder} - */ -function injectEventPluginOrder(injectedEventPluginOrder) { - !!eventPluginOrder ? invariant(false, 'EventPluginRegistry: Cannot inject event plugin ordering more than once. You are likely trying to load more than one copy of React.') : void 0; - // Clone the ordering so it cannot be dynamically mutated. - eventPluginOrder = Array.prototype.slice.call(injectedEventPluginOrder); - recomputePluginOrdering(); -} + return function update () { -/** - * Injects plugins to be used by `EventPluginHub`. The plugin names must be - * in the ordering injected by `injectEventPluginOrder`. - * - * Plugins can be injected as part of page initialization or on-the-fly. - * - * @param {object} injectedNamesToPlugins Map from names to plugin modules. - * @internal - * @see {EventPluginHub.injection.injectEventPluginsByName} - */ -function injectEventPluginsByName(injectedNamesToPlugins) { - var isOrderingDirty = false; - for (var pluginName in injectedNamesToPlugins) { - if (!injectedNamesToPlugins.hasOwnProperty(pluginName)) { - continue; - } - var pluginModule = injectedNamesToPlugins[pluginName]; - if (!namesToPlugins.hasOwnProperty(pluginName) || namesToPlugins[pluginName] !== pluginModule) { - !!namesToPlugins[pluginName] ? invariant(false, 'EventPluginRegistry: Cannot inject two different event plugins using the same name, `%s`.', pluginName) : void 0; - namesToPlugins[pluginName] = pluginModule; - isOrderingDirty = true; - } - } - if (isOrderingDirty) { - recomputePluginOrdering(); - } -} + var position = scope.object.position; -var EventPluginRegistry = Object.freeze({ - plugins: plugins, - eventNameDispatchConfigs: eventNameDispatchConfigs, - registrationNameModules: registrationNameModules, - registrationNameDependencies: registrationNameDependencies, - possibleRegistrationNames: possibleRegistrationNames, - injectEventPluginOrder: injectEventPluginOrder, - injectEventPluginsByName: injectEventPluginsByName -}); + offset.copy( position ).sub( scope.target ); -var getFiberCurrentPropsFromNode = null; -var getInstanceFromNode = null; -var getNodeFromInstance = null; + // rotate offset to "y-axis-is-up" space + offset.applyQuaternion( quat ); -var injection$2 = { - injectComponentTree: function (Injected) { - getFiberCurrentPropsFromNode = Injected.getFiberCurrentPropsFromNode; - getInstanceFromNode = Injected.getInstanceFromNode; - getNodeFromInstance = Injected.getNodeFromInstance; + // angle from z-axis around y-axis + spherical.setFromVector3( offset ); - { - warning(getNodeFromInstance && getInstanceFromNode, 'EventPluginUtils.injection.injectComponentTree(...): Injected ' + 'module is missing getNodeFromInstance or getInstanceFromNode.'); - } - } -}; + if ( scope.autoRotate && state === STATE.NONE ) { + rotateLeft( getAutoRotationAngle() ); + } + spherical.theta += sphericalDelta.theta; + spherical.phi += sphericalDelta.phi; + // restrict theta to be between desired limits + spherical.theta = Math.max( scope.minAzimuthAngle, Math.min( scope.maxAzimuthAngle, spherical.theta ) ); + // restrict phi to be between desired limits + spherical.phi = Math.max( scope.minPolarAngle, Math.min( scope.maxPolarAngle, spherical.phi ) ); -var validateEventDispatches; -{ - validateEventDispatches = function (event) { - var dispatchListeners = event._dispatchListeners; - var dispatchInstances = event._dispatchInstances; + spherical.makeSafe(); - var listenersIsArr = Array.isArray(dispatchListeners); - var listenersLen = listenersIsArr ? dispatchListeners.length : dispatchListeners ? 1 : 0; - var instancesIsArr = Array.isArray(dispatchInstances); - var instancesLen = instancesIsArr ? dispatchInstances.length : dispatchInstances ? 1 : 0; + spherical.radius *= scale; - warning(instancesIsArr === listenersIsArr && instancesLen === listenersLen, 'EventPluginUtils: Invalid `event`.'); - }; -} + // restrict radius to be between desired limits + spherical.radius = Math.max( scope.minDistance, Math.min( scope.maxDistance, spherical.radius ) ); -/** - * Dispatch the event to the listener. - * @param {SyntheticEvent} event SyntheticEvent to handle - * @param {boolean} simulated If the event is simulated (changes exn behavior) - * @param {function} listener Application-level callback - * @param {*} inst Internal component instance - */ -function executeDispatch(event, simulated, listener, inst) { - var type = event.type || 'unknown-event'; - event.currentTarget = getNodeFromInstance(inst); - ReactErrorUtils.invokeGuardedCallbackAndCatchFirstError(type, listener, undefined, event); - event.currentTarget = null; -} + // move target to panned location + scope.target.add( panOffset ); -/** - * Standard/simple iteration through an event's collected dispatches. - */ -function executeDispatchesInOrder(event, simulated) { - var dispatchListeners = event._dispatchListeners; - var dispatchInstances = event._dispatchInstances; - { - validateEventDispatches(event); - } - if (Array.isArray(dispatchListeners)) { - for (var i = 0; i < dispatchListeners.length; i++) { - if (event.isPropagationStopped()) { - break; - } - // Listeners and Instances are two parallel arrays that are always in sync. - executeDispatch(event, simulated, dispatchListeners[i], dispatchInstances[i]); - } - } else if (dispatchListeners) { - executeDispatch(event, simulated, dispatchListeners, dispatchInstances); - } - event._dispatchListeners = null; - event._dispatchInstances = null; -} + offset.setFromSpherical( spherical ); -/** - * @see executeDispatchesInOrderStopAtTrueImpl - */ + // rotate offset back to "camera-up-vector-is-up" space + offset.applyQuaternion( quatInverse ); + position.copy( scope.target ).add( offset ); -/** - * Execution of a "direct" dispatch - there must be at most one dispatch - * accumulated on the event or it is considered an error. It doesn't really make - * sense for an event with multiple dispatches (bubbled) to keep track of the - * return values at each dispatch execution, but it does tend to make sense when - * dealing with "direct" dispatches. - * - * @return {*} The return value of executing the single dispatch. - */ + scope.object.lookAt( scope.target ); + if ( scope.enableDamping === true ) { -/** - * @param {SyntheticEvent} event - * @return {boolean} True iff number of dispatches accumulated is greater than 0. - */ + sphericalDelta.theta *= ( 1 - scope.dampingFactor ); + sphericalDelta.phi *= ( 1 - scope.dampingFactor ); -/** - * Accumulates items that must not be null or undefined into the first one. This - * is used to conserve memory by avoiding array allocations, and thus sacrifices - * API cleanness. Since `current` can be null before being passed in and not - * null after this function, make sure to assign it back to `current`: - * - * `a = accumulateInto(a, b);` - * - * This API should be sparingly used. Try `accumulate` for something cleaner. - * - * @return {*|array<*>} An accumulation of items. - */ + } else { -function accumulateInto(current, next) { - !(next != null) ? invariant(false, 'accumulateInto(...): Accumulated items must not be null or undefined.') : void 0; + sphericalDelta.set( 0, 0, 0 ); - if (current == null) { - return next; - } + } - // Both are not empty. Warning: Never call x.concat(y) when you are not - // certain that x is an Array (x could be a string with concat method). - if (Array.isArray(current)) { - if (Array.isArray(next)) { - current.push.apply(current, next); - return current; - } - current.push(next); - return current; - } + scale = 1; + panOffset.set( 0, 0, 0 ); - if (Array.isArray(next)) { - // A bit too dangerous to mutate `next`. - return [current].concat(next); - } + // update condition is: + // min(camera displacement, camera rotation in radians)^2 > EPS + // using small-angle approximation cos(x/2) = 1 - x^2 / 8 - return [current, next]; -} + if ( zoomChanged || + lastPosition.distanceToSquared( scope.object.position ) > EPS || + 8 * ( 1 - lastQuaternion.dot( scope.object.quaternion ) ) > EPS ) { -/** - * @param {array} arr an "accumulation" of items which is either an Array or - * a single item. Useful when paired with the `accumulate` module. This is a - * simple utility that allows us to reason about a collection of items, but - * handling the case when there is exactly one item (and we do not need to - * allocate an array). - * @param {function} cb Callback invoked with each element or a collection. - * @param {?} [scope] Scope used as `this` in a callback. - */ -function forEachAccumulated(arr, cb, scope) { - if (Array.isArray(arr)) { - arr.forEach(cb, scope); - } else if (arr) { - cb.call(scope, arr); - } -} + scope.dispatchEvent( changeEvent ); -/** - * Internal queue of events that have accumulated their dispatches and are - * waiting to have their dispatches executed. - */ -var eventQueue = null; + lastPosition.copy( scope.object.position ); + lastQuaternion.copy( scope.object.quaternion ); + zoomChanged = false; -/** - * Dispatches an event and releases it back into the pool, unless persistent. - * - * @param {?object} event Synthetic event to be dispatched. - * @param {boolean} simulated If the event is simulated (changes exn behavior) - * @private - */ -var executeDispatchesAndRelease = function (event, simulated) { - if (event) { - executeDispatchesInOrder(event, simulated); + return true; - if (!event.isPersistent()) { - event.constructor.release(event); - } - } -}; -var executeDispatchesAndReleaseSimulated = function (e) { - return executeDispatchesAndRelease(e, true); -}; -var executeDispatchesAndReleaseTopLevel = function (e) { - return executeDispatchesAndRelease(e, false); -}; + } -function isInteractive(tag) { - return tag === 'button' || tag === 'input' || tag === 'select' || tag === 'textarea'; -} + return false; -function shouldPreventMouseEvent(name, type, props) { - switch (name) { - case 'onClick': - case 'onClickCapture': - case 'onDoubleClick': - case 'onDoubleClickCapture': - case 'onMouseDown': - case 'onMouseDownCapture': - case 'onMouseMove': - case 'onMouseMoveCapture': - case 'onMouseUp': - case 'onMouseUpCapture': - return !!(props.disabled && isInteractive(type)); - default: - return false; - } -} + }; -/** - * This is a unified interface for event plugins to be installed and configured. - * - * Event plugins can implement the following properties: - * - * `extractEvents` {function(string, DOMEventTarget, string, object): *} - * Required. When a top-level event is fired, this method is expected to - * extract synthetic events that will in turn be queued and dispatched. - * - * `eventTypes` {object} - * Optional, plugins that fire events must publish a mapping of registration - * names that are used to register listeners. Values of this mapping must - * be objects that contain `registrationName` or `phasedRegistrationNames`. - * - * `executeDispatch` {function(object, function, string)} - * Optional, allows plugins to override how an event gets dispatched. By - * default, the listener is simply invoked. - * - * Each plugin that is injected into `EventsPluginHub` is immediately operable. - * - * @public - */ + }(); -/** - * Methods for injecting dependencies. - */ -var injection$1 = { - /** - * @param {array} InjectedEventPluginOrder - * @public - */ - injectEventPluginOrder: injectEventPluginOrder, + this.dispose = function() { - /** - * @param {object} injectedNamesToPlugins Map from names to plugin modules. - */ - injectEventPluginsByName: injectEventPluginsByName -}; + scope.domElement.removeEventListener( 'contextmenu', onContextMenu, false ); + scope.domElement.removeEventListener( 'mousedown', onMouseDown, false ); + scope.domElement.removeEventListener( 'wheel', onMouseWheel, false ); -/** - * @param {object} inst The instance, which is the source of events. - * @param {string} registrationName Name of listener (e.g. `onClick`). - * @return {?function} The stored callback. - */ -function getListener(inst, registrationName) { - var listener; + scope.domElement.removeEventListener( 'touchstart', onTouchStart, false ); + scope.domElement.removeEventListener( 'touchend', onTouchEnd, false ); + scope.domElement.removeEventListener( 'touchmove', onTouchMove, false ); - // TODO: shouldPreventMouseEvent is DOM-specific and definitely should not - // live here; needs to be moved to a better place soon - var stateNode = inst.stateNode; - if (!stateNode) { - // Work in progress (ex: onload events in incremental mode). - return null; - } - var props = getFiberCurrentPropsFromNode(stateNode); - if (!props) { - // Work in progress. - return null; - } - listener = props[registrationName]; - if (shouldPreventMouseEvent(registrationName, inst.type, props)) { - return null; - } - !(!listener || typeof listener === 'function') ? invariant(false, 'Expected `%s` listener to be a function, instead got a value of `%s` type.', registrationName, typeof listener) : void 0; - return listener; -} + document.removeEventListener( 'mousemove', onMouseMove, false ); + document.removeEventListener( 'mouseup', onMouseUp, false ); -/** - * Allows registered plugins an opportunity to extract events from top-level - * native browser events. - * - * @return {*} An accumulation of synthetic events. - * @internal - */ -function extractEvents(topLevelType, targetInst, nativeEvent, nativeEventTarget) { - var events; - for (var i = 0; i < plugins.length; i++) { - // Not every plugin in the ordering may be loaded at runtime. - var possiblePlugin = plugins[i]; - if (possiblePlugin) { - var extractedEvents = possiblePlugin.extractEvents(topLevelType, targetInst, nativeEvent, nativeEventTarget); - if (extractedEvents) { - events = accumulateInto(events, extractedEvents); - } - } - } - return events; -} + window.removeEventListener( 'keydown', onKeyDown, false ); -/** - * Enqueues a synthetic event that should be dispatched when - * `processEventQueue` is invoked. - * - * @param {*} events An accumulation of synthetic events. - * @internal - */ -function enqueueEvents(events) { - if (events) { - eventQueue = accumulateInto(eventQueue, events); - } -} + //scope.dispatchEvent( { type: 'dispose' } ); // should this be added here? -/** - * Dispatches all synthetic events on the event queue. - * - * @internal - */ -function processEventQueue(simulated) { - // Set `eventQueue` to null before processing it so that we can tell if more - // events get enqueued while processing. - var processingEventQueue = eventQueue; - eventQueue = null; + }; - if (!processingEventQueue) { - return; - } + // + // internals + // - if (simulated) { - forEachAccumulated(processingEventQueue, executeDispatchesAndReleaseSimulated); - } else { - forEachAccumulated(processingEventQueue, executeDispatchesAndReleaseTopLevel); - } - !!eventQueue ? invariant(false, 'processEventQueue(): Additional events were enqueued while processing an event queue. Support for this has not yet been implemented.') : void 0; - // This would be a good time to rethrow if any of the event handlers threw. - ReactErrorUtils.rethrowCaughtError(); -} + var scope = this; -var EventPluginHub = Object.freeze({ - injection: injection$1, - getListener: getListener, - extractEvents: extractEvents, - enqueueEvents: enqueueEvents, - processEventQueue: processEventQueue -}); + var changeEvent = { type: 'change' }; + var startEvent = { type: 'start' }; + var endEvent = { type: 'end' }; -var IndeterminateComponent = 0; // Before we know whether it is functional or class -var FunctionalComponent = 1; -var ClassComponent = 2; -var HostRoot = 3; // Root of a host tree. Could be nested inside another node. -var HostPortal = 4; // A subtree. Could be an entry point to a different renderer. -var HostComponent = 5; -var HostText = 6; -var CallComponent = 7; -var CallHandlerPhase = 8; -var ReturnComponent = 9; -var Fragment = 10; + var STATE = { NONE : - 1, ROTATE : 0, DOLLY : 1, PAN : 2, TOUCH_ROTATE : 3, TOUCH_DOLLY : 4, TOUCH_PAN : 5 }; -var randomKey = Math.random().toString(36).slice(2); -var internalInstanceKey = '__reactInternalInstance$' + randomKey; -var internalEventHandlersKey = '__reactEventHandlers$' + randomKey; + var state = STATE.NONE; -function precacheFiberNode$1(hostInst, node) { - node[internalInstanceKey] = hostInst; -} + var EPS = 0.000001; -/** - * Given a DOM node, return the closest ReactDOMComponent or - * ReactDOMTextComponent instance ancestor. - */ -function getClosestInstanceFromNode(node) { - if (node[internalInstanceKey]) { - return node[internalInstanceKey]; - } + // current position in spherical coordinates + var spherical = new THREE.Spherical(); + var sphericalDelta = new THREE.Spherical(); - // Walk up the tree until we find an ancestor whose instance we have cached. - var parents = []; - while (!node[internalInstanceKey]) { - parents.push(node); - if (node.parentNode) { - node = node.parentNode; - } else { - // Top of the tree. This node must not be part of a React tree (or is - // unmounted, potentially). - return null; - } - } + var scale = 1; + var panOffset = new THREE.Vector3(); + var zoomChanged = false; - var closest = void 0; - var inst = node[internalInstanceKey]; - if (inst.tag === HostComponent || inst.tag === HostText) { - // In Fiber, this will always be the deepest root. - return inst; - } - for (; node && (inst = node[internalInstanceKey]); node = parents.pop()) { - closest = inst; - } + var rotateStart = new THREE.Vector2(); + var rotateEnd = new THREE.Vector2(); + var rotateDelta = new THREE.Vector2(); - return closest; -} + var panStart = new THREE.Vector2(); + var panEnd = new THREE.Vector2(); + var panDelta = new THREE.Vector2(); -/** - * Given a DOM node, return the ReactDOMComponent or ReactDOMTextComponent - * instance, or null if the node was not rendered by this React. - */ -function getInstanceFromNode$1(node) { - var inst = node[internalInstanceKey]; - if (inst) { - if (inst.tag === HostComponent || inst.tag === HostText) { - return inst; - } else { - return null; - } - } - return null; -} + var dollyStart = new THREE.Vector2(); + var dollyEnd = new THREE.Vector2(); + var dollyDelta = new THREE.Vector2(); -/** - * Given a ReactDOMComponent or ReactDOMTextComponent, return the corresponding - * DOM node. - */ -function getNodeFromInstance$1(inst) { - if (inst.tag === HostComponent || inst.tag === HostText) { - // In Fiber this, is just the state node right now. We assume it will be - // a host component or host text. - return inst.stateNode; - } + function getAutoRotationAngle() { - // Without this first invariant, passing a non-DOM-component triggers the next - // invariant for a missing parent, which is super confusing. - invariant(false, 'getNodeFromInstance: Invalid argument.'); -} + return 2 * Math.PI / 60 / 60 * scope.autoRotateSpeed; -function getFiberCurrentPropsFromNode$1(node) { - return node[internalEventHandlersKey] || null; -} + } -function updateFiberProps$1(node, props) { - node[internalEventHandlersKey] = props; -} + function getZoomScale() { -var ReactDOMComponentTree = Object.freeze({ - precacheFiberNode: precacheFiberNode$1, - getClosestInstanceFromNode: getClosestInstanceFromNode, - getInstanceFromNode: getInstanceFromNode$1, - getNodeFromInstance: getNodeFromInstance$1, - getFiberCurrentPropsFromNode: getFiberCurrentPropsFromNode$1, - updateFiberProps: updateFiberProps$1 -}); + return Math.pow( 0.95, scope.zoomSpeed ); -function getParent(inst) { - do { - inst = inst['return']; - // TODO: If this is a HostRoot we might want to bail out. - // That is depending on if we want nested subtrees (layers) to bubble - // events to their parent. We could also go through parentNode on the - // host node but that wouldn't work for React Native and doesn't let us - // do the portal feature. - } while (inst && inst.tag !== HostComponent); - if (inst) { - return inst; - } - return null; -} + } -/** - * Return the lowest common ancestor of A and B, or null if they are in - * different trees. - */ -function getLowestCommonAncestor(instA, instB) { - var depthA = 0; - for (var tempA = instA; tempA; tempA = getParent(tempA)) { - depthA++; - } - var depthB = 0; - for (var tempB = instB; tempB; tempB = getParent(tempB)) { - depthB++; - } + function rotateLeft( angle ) { - // If A is deeper, crawl up. - while (depthA - depthB > 0) { - instA = getParent(instA); - depthA--; - } + sphericalDelta.theta -= angle; - // If B is deeper, crawl up. - while (depthB - depthA > 0) { - instB = getParent(instB); - depthB--; - } + } - // Walk in lockstep until we find a match. - var depth = depthA; - while (depth--) { - if (instA === instB || instA === instB.alternate) { - return instA; - } - instA = getParent(instA); - instB = getParent(instB); - } - return null; -} + function rotateUp( angle ) { -/** - * Return if A is an ancestor of B. - */ + sphericalDelta.phi -= angle; + } -/** - * Return the parent instance of the passed-in instance. - */ -function getParentInstance(inst) { - return getParent(inst); -} + var panLeft = function() { -/** - * Simulates the traversal of a two-phase, capture/bubble event dispatch. - */ -function traverseTwoPhase(inst, fn, arg) { - var path = []; - while (inst) { - path.push(inst); - inst = getParent(inst); - } - var i; - for (i = path.length; i-- > 0;) { - fn(path[i], 'captured', arg); - } - for (i = 0; i < path.length; i++) { - fn(path[i], 'bubbled', arg); - } -} + var v = new THREE.Vector3(); -/** - * Traverses the ID hierarchy and invokes the supplied `cb` on any IDs that - * should would receive a `mouseEnter` or `mouseLeave` event. - * - * Does not invoke the callback on the nearest common ancestor because nothing - * "entered" or "left" that element. - */ -function traverseEnterLeave(from, to, fn, argFrom, argTo) { - var common = from && to ? getLowestCommonAncestor(from, to) : null; - var pathFrom = []; - while (true) { - if (!from) { - break; - } - if (from === common) { - break; - } - var alternate = from.alternate; - if (alternate !== null && alternate === common) { - break; - } - pathFrom.push(from); - from = getParent(from); - } - var pathTo = []; - while (true) { - if (!to) { - break; - } - if (to === common) { - break; - } - var _alternate = to.alternate; - if (_alternate !== null && _alternate === common) { - break; - } - pathTo.push(to); - to = getParent(to); - } - for (var i = 0; i < pathFrom.length; i++) { - fn(pathFrom[i], 'bubbled', argFrom); - } - for (var _i = pathTo.length; _i-- > 0;) { - fn(pathTo[_i], 'captured', argTo); - } -} + return function panLeft( distance, objectMatrix ) { -/** - * Some event types have a notion of different registration names for different - * "phases" of propagation. This finds listeners by a given phase. - */ -function listenerAtPhase(inst, event, propagationPhase) { - var registrationName = event.dispatchConfig.phasedRegistrationNames[propagationPhase]; - return getListener(inst, registrationName); -} + v.setFromMatrixColumn( objectMatrix, 0 ); // get X column of objectMatrix + v.multiplyScalar( - distance ); -/** - * A small set of propagation patterns, each of which will accept a small amount - * of information, and generate a set of "dispatch ready event objects" - which - * are sets of events that have already been annotated with a set of dispatched - * listener functions/ids. The API is designed this way to discourage these - * propagation strategies from actually executing the dispatches, since we - * always want to collect the entire set of dispatches before executing even a - * single one. - */ + panOffset.add( v ); -/** - * Tags a `SyntheticEvent` with dispatched listeners. Creating this function - * here, allows us to not have to bind or create functions for each event. - * Mutating the event's members allows us to not have to create a wrapping - * "dispatch" object that pairs the event with the listener. - */ -function accumulateDirectionalDispatches(inst, phase, event) { - { - warning(inst, 'Dispatching inst must not be null'); - } - var listener = listenerAtPhase(inst, event, phase); - if (listener) { - event._dispatchListeners = accumulateInto(event._dispatchListeners, listener); - event._dispatchInstances = accumulateInto(event._dispatchInstances, inst); - } -} + }; -/** - * Collect dispatches (must be entirely collected before dispatching - see unit - * tests). Lazily allocate the array to conserve memory. We must loop through - * each event and perform the traversal for each one. We cannot perform a - * single traversal for the entire collection of events because each event may - * have a different target. - */ -function accumulateTwoPhaseDispatchesSingle(event) { - if (event && event.dispatchConfig.phasedRegistrationNames) { - traverseTwoPhase(event._targetInst, accumulateDirectionalDispatches, event); - } -} + }(); -/** - * Same as `accumulateTwoPhaseDispatchesSingle`, but skips over the targetID. - */ -function accumulateTwoPhaseDispatchesSingleSkipTarget(event) { - if (event && event.dispatchConfig.phasedRegistrationNames) { - var targetInst = event._targetInst; - var parentInst = targetInst ? getParentInstance(targetInst) : null; - traverseTwoPhase(parentInst, accumulateDirectionalDispatches, event); - } -} + var panUp = function() { -/** - * Accumulates without regard to direction, does not look for phased - * registration names. Same as `accumulateDirectDispatchesSingle` but without - * requiring that the `dispatchMarker` be the same as the dispatched ID. - */ -function accumulateDispatches(inst, ignoredDirection, event) { - if (inst && event && event.dispatchConfig.registrationName) { - var registrationName = event.dispatchConfig.registrationName; - var listener = getListener(inst, registrationName); - if (listener) { - event._dispatchListeners = accumulateInto(event._dispatchListeners, listener); - event._dispatchInstances = accumulateInto(event._dispatchInstances, inst); - } - } -} + var v = new THREE.Vector3(); -/** - * Accumulates dispatches on an `SyntheticEvent`, but only for the - * `dispatchMarker`. - * @param {SyntheticEvent} event - */ -function accumulateDirectDispatchesSingle(event) { - if (event && event.dispatchConfig.registrationName) { - accumulateDispatches(event._targetInst, null, event); - } -} + return function panUp( distance, objectMatrix ) { -function accumulateTwoPhaseDispatches(events) { - forEachAccumulated(events, accumulateTwoPhaseDispatchesSingle); -} + v.setFromMatrixColumn( objectMatrix, 1 ); // get Y column of objectMatrix + v.multiplyScalar( distance ); -function accumulateTwoPhaseDispatchesSkipTarget(events) { - forEachAccumulated(events, accumulateTwoPhaseDispatchesSingleSkipTarget); -} + panOffset.add( v ); -function accumulateEnterLeaveDispatches(leave, enter, from, to) { - traverseEnterLeave(from, to, accumulateDispatches, leave, enter); -} + }; -function accumulateDirectDispatches(events) { - forEachAccumulated(events, accumulateDirectDispatchesSingle); -} + }(); -var EventPropagators = Object.freeze({ - accumulateTwoPhaseDispatches: accumulateTwoPhaseDispatches, - accumulateTwoPhaseDispatchesSkipTarget: accumulateTwoPhaseDispatchesSkipTarget, - accumulateEnterLeaveDispatches: accumulateEnterLeaveDispatches, - accumulateDirectDispatches: accumulateDirectDispatches -}); + // deltaX and deltaY are in pixels; right and down are positive + var pan = function() { -var contentKey = null; + var offset = new THREE.Vector3(); -/** - * Gets the key used to access text content on a DOM node. - * - * @return {?string} Key used to access text content. - * @internal - */ -function getTextContentAccessor() { - if (!contentKey && ExecutionEnvironment.canUseDOM) { - // Prefer textContent to innerText because many browsers support both but - // SVG elements don't support innerText even when
does. - contentKey = 'textContent' in document.documentElement ? 'textContent' : 'innerText'; - } - return contentKey; -} + return function pan ( deltaX, deltaY ) { -/** - * This helper object stores information about text content of a target node, - * allowing comparison of content before and after a given event. - * - * Identify the node where selection currently begins, then observe - * both its text content and its current position in the DOM. Since the - * browser may natively replace the target node during composition, we can - * use its position to find its replacement. - * - * - */ -var compositionState = { - _root: null, - _startText: null, - _fallbackText: null -}; + var element = scope.domElement === document ? scope.domElement.body : scope.domElement; -function initialize(nativeEventTarget) { - compositionState._root = nativeEventTarget; - compositionState._startText = getText(); - return true; -} + if ( scope.object instanceof THREE.PerspectiveCamera ) { -function reset() { - compositionState._root = null; - compositionState._startText = null; - compositionState._fallbackText = null; -} + // perspective + var position = scope.object.position; + offset.copy( position ).sub( scope.target ); + var targetDistance = offset.length(); -function getData() { - if (compositionState._fallbackText) { - return compositionState._fallbackText; - } + // half of the fov is center to top of screen + targetDistance *= Math.tan( ( scope.object.fov / 2 ) * Math.PI / 180.0 ); - var start; - var startValue = compositionState._startText; - var startLength = startValue.length; - var end; - var endValue = getText(); - var endLength = endValue.length; + // we actually don't use screenWidth, since perspective camera is fixed to screen height + panLeft( 2 * deltaX * targetDistance / element.clientHeight, scope.object.matrix ); + panUp( 2 * deltaY * targetDistance / element.clientHeight, scope.object.matrix ); - for (start = 0; start < startLength; start++) { - if (startValue[start] !== endValue[start]) { - break; - } - } + } else if ( scope.object instanceof THREE.OrthographicCamera ) { - var minEnd = startLength - start; - for (end = 1; end <= minEnd; end++) { - if (startValue[startLength - end] !== endValue[endLength - end]) { - break; - } - } + // orthographic + panLeft( deltaX * ( scope.object.right - scope.object.left ) / scope.object.zoom / element.clientWidth, scope.object.matrix ); + panUp( deltaY * ( scope.object.top - scope.object.bottom ) / scope.object.zoom / element.clientHeight, scope.object.matrix ); - var sliceTail = end > 1 ? 1 - end : undefined; - compositionState._fallbackText = endValue.slice(start, sliceTail); - return compositionState._fallbackText; -} + } else { -function getText() { - if ('value' in compositionState._root) { - return compositionState._root.value; - } - return compositionState._root[getTextContentAccessor()]; -} + // camera neither orthographic nor perspective + console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - pan disabled.' ); + scope.enablePan = false; -/* eslint valid-typeof: 0 */ + } -var didWarnForAddedNewProperty = false; -var isProxySupported = typeof Proxy === 'function'; -var EVENT_POOL_SIZE = 10; + }; -var shouldBeReleasedProperties = ['dispatchConfig', '_targetInst', 'nativeEvent', 'isDefaultPrevented', 'isPropagationStopped', '_dispatchListeners', '_dispatchInstances']; + }(); -/** - * @interface Event - * @see http://www.w3.org/TR/DOM-Level-3-Events/ - */ -var EventInterface = { - type: null, - target: null, - // currentTarget is set when dispatching; no use in copying it here - currentTarget: emptyFunction.thatReturnsNull, - eventPhase: null, - bubbles: null, - cancelable: null, - timeStamp: function (event) { - return event.timeStamp || Date.now(); - }, - defaultPrevented: null, - isTrusted: null -}; + function dollyIn( dollyScale ) { -/** - * Synthetic events are dispatched by event plugins, typically in response to a - * top-level event delegation handler. - * - * These systems should generally use pooling to reduce the frequency of garbage - * collection. The system should check `isPersistent` to determine whether the - * event should be released into the pool after being dispatched. Users that - * need a persisted event should invoke `persist`. - * - * Synthetic events (and subclasses) implement the DOM Level 3 Events API by - * normalizing browser quirks. Subclasses do not necessarily have to implement a - * DOM interface; custom application-specific events can also subclass this. - * - * @param {object} dispatchConfig Configuration used to dispatch this event. - * @param {*} targetInst Marker identifying the event target. - * @param {object} nativeEvent Native browser event. - * @param {DOMEventTarget} nativeEventTarget Target node. - */ -function SyntheticEvent(dispatchConfig, targetInst, nativeEvent, nativeEventTarget) { - { - // these have a getter/setter for warnings - delete this.nativeEvent; - delete this.preventDefault; - delete this.stopPropagation; - } + if ( scope.object instanceof THREE.PerspectiveCamera ) { - this.dispatchConfig = dispatchConfig; - this._targetInst = targetInst; - this.nativeEvent = nativeEvent; + scale /= dollyScale; - var Interface = this.constructor.Interface; - for (var propName in Interface) { - if (!Interface.hasOwnProperty(propName)) { - continue; - } - { - delete this[propName]; // this has a getter/setter for warnings - } - var normalize = Interface[propName]; - if (normalize) { - this[propName] = normalize(nativeEvent); - } else { - if (propName === 'target') { - this.target = nativeEventTarget; - } else { - this[propName] = nativeEvent[propName]; - } - } - } + } else if ( scope.object instanceof THREE.OrthographicCamera ) { - var defaultPrevented = nativeEvent.defaultPrevented != null ? nativeEvent.defaultPrevented : nativeEvent.returnValue === false; - if (defaultPrevented) { - this.isDefaultPrevented = emptyFunction.thatReturnsTrue; - } else { - this.isDefaultPrevented = emptyFunction.thatReturnsFalse; - } - this.isPropagationStopped = emptyFunction.thatReturnsFalse; - return this; -} + scope.object.zoom = Math.max( scope.minZoom, Math.min( scope.maxZoom, scope.object.zoom * dollyScale ) ); + scope.object.updateProjectionMatrix(); + zoomChanged = true; -_assign(SyntheticEvent.prototype, { - preventDefault: function () { - this.defaultPrevented = true; - var event = this.nativeEvent; - if (!event) { - return; - } + } else { - if (event.preventDefault) { - event.preventDefault(); - } else if (typeof event.returnValue !== 'unknown') { - event.returnValue = false; - } - this.isDefaultPrevented = emptyFunction.thatReturnsTrue; - }, + console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.' ); + scope.enableZoom = false; - stopPropagation: function () { - var event = this.nativeEvent; - if (!event) { - return; - } + } - if (event.stopPropagation) { - event.stopPropagation(); - } else if (typeof event.cancelBubble !== 'unknown') { - // The ChangeEventPlugin registers a "propertychange" event for - // IE. This event does not support bubbling or cancelling, and - // any references to cancelBubble throw "Member not found". A - // typeof check of "unknown" circumvents this issue (and is also - // IE specific). - event.cancelBubble = true; - } + } - this.isPropagationStopped = emptyFunction.thatReturnsTrue; - }, + function dollyOut( dollyScale ) { - /** - * We release all dispatched `SyntheticEvent`s after each event loop, adding - * them back into the pool. This allows a way to hold onto a reference that - * won't be added back into the pool. - */ - persist: function () { - this.isPersistent = emptyFunction.thatReturnsTrue; - }, + if ( scope.object instanceof THREE.PerspectiveCamera ) { - /** - * Checks if this event should be released back into the pool. - * - * @return {boolean} True if this should not be released, false otherwise. - */ - isPersistent: emptyFunction.thatReturnsFalse, + scale *= dollyScale; - /** - * `PooledClass` looks for `destructor` on each instance it releases. - */ - destructor: function () { - var Interface = this.constructor.Interface; - for (var propName in Interface) { - { - Object.defineProperty(this, propName, getPooledWarningPropertyDefinition(propName, Interface[propName])); - } - } - for (var i = 0; i < shouldBeReleasedProperties.length; i++) { - this[shouldBeReleasedProperties[i]] = null; - } - { - Object.defineProperty(this, 'nativeEvent', getPooledWarningPropertyDefinition('nativeEvent', null)); - Object.defineProperty(this, 'preventDefault', getPooledWarningPropertyDefinition('preventDefault', emptyFunction)); - Object.defineProperty(this, 'stopPropagation', getPooledWarningPropertyDefinition('stopPropagation', emptyFunction)); - } - } -}); + } else if ( scope.object instanceof THREE.OrthographicCamera ) { -SyntheticEvent.Interface = EventInterface; + scope.object.zoom = Math.max( scope.minZoom, Math.min( scope.maxZoom, scope.object.zoom / dollyScale ) ); + scope.object.updateProjectionMatrix(); + zoomChanged = true; -/** - * Helper to reduce boilerplate when creating subclasses. - * - * @param {function} Class - * @param {?object} Interface - */ -SyntheticEvent.augmentClass = function (Class, Interface) { - var Super = this; + } else { - var E = function () {}; - E.prototype = Super.prototype; - var prototype = new E(); + console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.' ); + scope.enableZoom = false; - _assign(prototype, Class.prototype); - Class.prototype = prototype; - Class.prototype.constructor = Class; + } - Class.Interface = _assign({}, Super.Interface, Interface); - Class.augmentClass = Super.augmentClass; - addEventPoolingTo(Class); -}; + } -/** Proxying after everything set on SyntheticEvent - * to resolve Proxy issue on some WebKit browsers - * in which some Event properties are set to undefined (GH#10010) - */ -{ - if (isProxySupported) { - /*eslint-disable no-func-assign */ - SyntheticEvent = new Proxy(SyntheticEvent, { - construct: function (target, args) { - return this.apply(target, Object.create(target.prototype), args); - }, - apply: function (constructor, that, args) { - return new Proxy(constructor.apply(that, args), { - set: function (target, prop, value) { - if (prop !== 'isPersistent' && !target.constructor.Interface.hasOwnProperty(prop) && shouldBeReleasedProperties.indexOf(prop) === -1) { - warning(didWarnForAddedNewProperty || target.isPersistent(), "This synthetic event is reused for performance reasons. If you're " + "seeing this, you're adding a new property in the synthetic event object. " + 'The property is never released. See ' + 'https://fb.me/react-event-pooling for more information.'); - didWarnForAddedNewProperty = true; - } - target[prop] = value; - return true; - } - }); - } - }); - /*eslint-enable no-func-assign */ - } -} + // + // event callbacks - update the object state + // -addEventPoolingTo(SyntheticEvent); + function handleMouseDownRotate( event ) { -/** - * Helper to nullify syntheticEvent instance properties when destructing - * - * @param {String} propName - * @param {?object} getVal - * @return {object} defineProperty object - */ -function getPooledWarningPropertyDefinition(propName, getVal) { - var isFunction = typeof getVal === 'function'; - return { - configurable: true, - set: set, - get: get - }; + //console.log( 'handleMouseDownRotate' ); - function set(val) { - var action = isFunction ? 'setting the method' : 'setting the property'; - warn(action, 'This is effectively a no-op'); - return val; - } + rotateStart.set( event.clientX, event.clientY ); - function get() { - var action = isFunction ? 'accessing the method' : 'accessing the property'; - var result = isFunction ? 'This is a no-op function' : 'This is set to null'; - warn(action, result); - return getVal; - } + } - function warn(action, result) { - var warningCondition = false; - warning(warningCondition, "This synthetic event is reused for performance reasons. If you're seeing this, " + "you're %s `%s` on a released/nullified synthetic event. %s. " + 'If you must keep the original synthetic event around, use event.persist(). ' + 'See https://fb.me/react-event-pooling for more information.', action, propName, result); - } -} + function handleMouseDownDolly( event ) { -function getPooledEvent(dispatchConfig, targetInst, nativeEvent, nativeInst) { - var EventConstructor = this; - if (EventConstructor.eventPool.length) { - var instance = EventConstructor.eventPool.pop(); - EventConstructor.call(instance, dispatchConfig, targetInst, nativeEvent, nativeInst); - return instance; - } - return new EventConstructor(dispatchConfig, targetInst, nativeEvent, nativeInst); -} + //console.log( 'handleMouseDownDolly' ); -function releasePooledEvent(event) { - var EventConstructor = this; - !(event instanceof EventConstructor) ? invariant(false, 'Trying to release an event instance into a pool of a different type.') : void 0; - event.destructor(); - if (EventConstructor.eventPool.length < EVENT_POOL_SIZE) { - EventConstructor.eventPool.push(event); - } -} + dollyStart.set( event.clientX, event.clientY ); -function addEventPoolingTo(EventConstructor) { - EventConstructor.eventPool = []; - EventConstructor.getPooled = getPooledEvent; - EventConstructor.release = releasePooledEvent; -} + } -var SyntheticEvent$1 = SyntheticEvent; + function handleMouseDownPan( event ) { -/** - * @interface Event - * @see http://www.w3.org/TR/DOM-Level-3-Events/#events-compositionevents - */ -var CompositionEventInterface = { - data: null -}; + //console.log( 'handleMouseDownPan' ); -/** - * @param {object} dispatchConfig Configuration used to dispatch this event. - * @param {string} dispatchMarker Marker identifying the event target. - * @param {object} nativeEvent Native browser event. - * @extends {SyntheticEvent} - */ -function SyntheticCompositionEvent(dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget) { - return SyntheticEvent$1.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget); -} + panStart.set( event.clientX, event.clientY ); -SyntheticEvent$1.augmentClass(SyntheticCompositionEvent, CompositionEventInterface); + } -/** - * @interface Event - * @see http://www.w3.org/TR/2013/WD-DOM-Level-3-Events-20131105 - * /#events-inputevents - */ -var InputEventInterface = { - data: null -}; + function handleMouseMoveRotate( event ) { -/** - * @param {object} dispatchConfig Configuration used to dispatch this event. - * @param {string} dispatchMarker Marker identifying the event target. - * @param {object} nativeEvent Native browser event. - * @extends {SyntheticEvent} - */ -function SyntheticInputEvent(dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget) { - return SyntheticEvent$1.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget); -} + //console.log( 'handleMouseMoveRotate' ); -SyntheticEvent$1.augmentClass(SyntheticInputEvent, InputEventInterface); + rotateEnd.set( event.clientX, event.clientY ); + rotateDelta.subVectors( rotateEnd, rotateStart ); -var END_KEYCODES = [9, 13, 27, 32]; // Tab, Return, Esc, Space -var START_KEYCODE = 229; + var element = scope.domElement === document ? scope.domElement.body : scope.domElement; -var canUseCompositionEvent = ExecutionEnvironment.canUseDOM && 'CompositionEvent' in window; + // rotating across whole screen goes 360 degrees around + rotateLeft( 2 * Math.PI * rotateDelta.x / element.clientWidth * scope.rotateSpeed ); -var documentMode = null; -if (ExecutionEnvironment.canUseDOM && 'documentMode' in document) { - documentMode = document.documentMode; -} + // rotating up and down along whole screen attempts to go 360, but limited to 180 + rotateUp( 2 * Math.PI * rotateDelta.y / element.clientHeight * scope.rotateSpeed ); -// Webkit offers a very useful `textInput` event that can be used to -// directly represent `beforeInput`. The IE `textinput` event is not as -// useful, so we don't use it. -var canUseTextInputEvent = ExecutionEnvironment.canUseDOM && 'TextEvent' in window && !documentMode && !isPresto(); + rotateStart.copy( rotateEnd ); -// In IE9+, we have access to composition events, but the data supplied -// by the native compositionend event may be incorrect. Japanese ideographic -// spaces, for instance (\u3000) are not recorded correctly. -var useFallbackCompositionData = ExecutionEnvironment.canUseDOM && (!canUseCompositionEvent || documentMode && documentMode > 8 && documentMode <= 11); + scope.update(); -/** - * Opera <= 12 includes TextEvent in window, but does not fire - * text input events. Rely on keypress instead. - */ -function isPresto() { - var opera = window.opera; - return typeof opera === 'object' && typeof opera.version === 'function' && parseInt(opera.version(), 10) <= 12; -} + } -var SPACEBAR_CODE = 32; -var SPACEBAR_CHAR = String.fromCharCode(SPACEBAR_CODE); + function handleMouseMoveDolly( event ) { -// Events and their corresponding property names. -var eventTypes = { - beforeInput: { - phasedRegistrationNames: { - bubbled: 'onBeforeInput', - captured: 'onBeforeInputCapture' - }, - dependencies: ['topCompositionEnd', 'topKeyPress', 'topTextInput', 'topPaste'] - }, - compositionEnd: { - phasedRegistrationNames: { - bubbled: 'onCompositionEnd', - captured: 'onCompositionEndCapture' - }, - dependencies: ['topBlur', 'topCompositionEnd', 'topKeyDown', 'topKeyPress', 'topKeyUp', 'topMouseDown'] - }, - compositionStart: { - phasedRegistrationNames: { - bubbled: 'onCompositionStart', - captured: 'onCompositionStartCapture' - }, - dependencies: ['topBlur', 'topCompositionStart', 'topKeyDown', 'topKeyPress', 'topKeyUp', 'topMouseDown'] - }, - compositionUpdate: { - phasedRegistrationNames: { - bubbled: 'onCompositionUpdate', - captured: 'onCompositionUpdateCapture' - }, - dependencies: ['topBlur', 'topCompositionUpdate', 'topKeyDown', 'topKeyPress', 'topKeyUp', 'topMouseDown'] - } -}; + //console.log( 'handleMouseMoveDolly' ); -// Track whether we've ever handled a keypress on the space key. -var hasSpaceKeypress = false; + dollyEnd.set( event.clientX, event.clientY ); -/** - * Return whether a native keypress event is assumed to be a command. - * This is required because Firefox fires `keypress` events for key commands - * (cut, copy, select-all, etc.) even though no character is inserted. - */ -function isKeypressCommand(nativeEvent) { - return (nativeEvent.ctrlKey || nativeEvent.altKey || nativeEvent.metaKey) && - // ctrlKey && altKey is equivalent to AltGr, and is not a command. - !(nativeEvent.ctrlKey && nativeEvent.altKey); -} + dollyDelta.subVectors( dollyEnd, dollyStart ); -/** - * Translate native top level events into event types. - * - * @param {string} topLevelType - * @return {object} - */ -function getCompositionEventType(topLevelType) { - switch (topLevelType) { - case 'topCompositionStart': - return eventTypes.compositionStart; - case 'topCompositionEnd': - return eventTypes.compositionEnd; - case 'topCompositionUpdate': - return eventTypes.compositionUpdate; - } -} + if ( dollyDelta.y > 0 ) { -/** - * Does our fallback best-guess model think this event signifies that - * composition has begun? - * - * @param {string} topLevelType - * @param {object} nativeEvent - * @return {boolean} - */ -function isFallbackCompositionStart(topLevelType, nativeEvent) { - return topLevelType === 'topKeyDown' && nativeEvent.keyCode === START_KEYCODE; -} + dollyIn( getZoomScale() ); -/** - * Does our fallback mode think that this event is the end of composition? - * - * @param {string} topLevelType - * @param {object} nativeEvent - * @return {boolean} - */ -function isFallbackCompositionEnd(topLevelType, nativeEvent) { - switch (topLevelType) { - case 'topKeyUp': - // Command keys insert or clear IME input. - return END_KEYCODES.indexOf(nativeEvent.keyCode) !== -1; - case 'topKeyDown': - // Expect IME keyCode on each keydown. If we get any other - // code we must have exited earlier. - return nativeEvent.keyCode !== START_KEYCODE; - case 'topKeyPress': - case 'topMouseDown': - case 'topBlur': - // Events are not possible without cancelling IME. - return true; - default: - return false; - } -} + } else if ( dollyDelta.y < 0 ) { -/** - * Google Input Tools provides composition data via a CustomEvent, - * with the `data` property populated in the `detail` object. If this - * is available on the event object, use it. If not, this is a plain - * composition event and we have nothing special to extract. - * - * @param {object} nativeEvent - * @return {?string} - */ -function getDataFromCustomEvent(nativeEvent) { - var detail = nativeEvent.detail; - if (typeof detail === 'object' && 'data' in detail) { - return detail.data; - } - return null; -} + dollyOut( getZoomScale() ); -// Track the current IME composition status, if any. -var isComposing = false; + } -/** - * @return {?object} A SyntheticCompositionEvent. - */ -function extractCompositionEvent(topLevelType, targetInst, nativeEvent, nativeEventTarget) { - var eventType; - var fallbackData; + dollyStart.copy( dollyEnd ); - if (canUseCompositionEvent) { - eventType = getCompositionEventType(topLevelType); - } else if (!isComposing) { - if (isFallbackCompositionStart(topLevelType, nativeEvent)) { - eventType = eventTypes.compositionStart; - } - } else if (isFallbackCompositionEnd(topLevelType, nativeEvent)) { - eventType = eventTypes.compositionEnd; - } + scope.update(); - if (!eventType) { - return null; - } + } - if (useFallbackCompositionData) { - // The current composition is stored statically and must not be - // overwritten while composition continues. - if (!isComposing && eventType === eventTypes.compositionStart) { - isComposing = initialize(nativeEventTarget); - } else if (eventType === eventTypes.compositionEnd) { - if (isComposing) { - fallbackData = getData(); - } - } - } + function handleMouseMovePan( event ) { - var event = SyntheticCompositionEvent.getPooled(eventType, targetInst, nativeEvent, nativeEventTarget); + //console.log( 'handleMouseMovePan' ); - if (fallbackData) { - // Inject data generated from fallback path into the synthetic event. - // This matches the property of native CompositionEventInterface. - event.data = fallbackData; - } else { - var customData = getDataFromCustomEvent(nativeEvent); - if (customData !== null) { - event.data = customData; - } - } + panEnd.set( event.clientX, event.clientY ); - accumulateTwoPhaseDispatches(event); - return event; -} + panDelta.subVectors( panEnd, panStart ); -/** - * @param {TopLevelTypes} topLevelType Record from `BrowserEventConstants`. - * @param {object} nativeEvent Native browser event. - * @return {?string} The string corresponding to this `beforeInput` event. - */ -function getNativeBeforeInputChars(topLevelType, nativeEvent) { - switch (topLevelType) { - case 'topCompositionEnd': - return getDataFromCustomEvent(nativeEvent); - case 'topKeyPress': - /** - * If native `textInput` events are available, our goal is to make - * use of them. However, there is a special case: the spacebar key. - * In Webkit, preventing default on a spacebar `textInput` event - * cancels character insertion, but it *also* causes the browser - * to fall back to its default spacebar behavior of scrolling the - * page. - * - * Tracking at: - * https://code.google.com/p/chromium/issues/detail?id=355103 - * - * To avoid this issue, use the keypress event as if no `textInput` - * event is available. - */ - var which = nativeEvent.which; - if (which !== SPACEBAR_CODE) { - return null; - } + pan( panDelta.x, panDelta.y ); - hasSpaceKeypress = true; - return SPACEBAR_CHAR; + panStart.copy( panEnd ); - case 'topTextInput': - // Record the characters to be added to the DOM. - var chars = nativeEvent.data; + scope.update(); - // If it's a spacebar character, assume that we have already handled - // it at the keypress level and bail immediately. Android Chrome - // doesn't give us keycodes, so we need to blacklist it. - if (chars === SPACEBAR_CHAR && hasSpaceKeypress) { - return null; - } + } - return chars; + function handleMouseUp( event ) { - default: - // For other native event types, do nothing. - return null; - } -} + //console.log( 'handleMouseUp' ); -/** - * For browsers that do not provide the `textInput` event, extract the - * appropriate string to use for SyntheticInputEvent. - * - * @param {string} topLevelType Record from `BrowserEventConstants`. - * @param {object} nativeEvent Native browser event. - * @return {?string} The fallback string for this `beforeInput` event. - */ -function getFallbackBeforeInputChars(topLevelType, nativeEvent) { - // If we are currently composing (IME) and using a fallback to do so, - // try to extract the composed characters from the fallback object. - // If composition event is available, we extract a string only at - // compositionevent, otherwise extract it at fallback events. - if (isComposing) { - if (topLevelType === 'topCompositionEnd' || !canUseCompositionEvent && isFallbackCompositionEnd(topLevelType, nativeEvent)) { - var chars = getData(); - reset(); - isComposing = false; - return chars; - } - return null; - } + } - switch (topLevelType) { - case 'topPaste': - // If a paste event occurs after a keypress, throw out the input - // chars. Paste events should not lead to BeforeInput events. - return null; - case 'topKeyPress': - /** - * As of v27, Firefox may fire keypress events even when no character - * will be inserted. A few possibilities: - * - * - `which` is `0`. Arrow keys, Esc key, etc. - * - * - `which` is the pressed key code, but no char is available. - * Ex: 'AltGr + d` in Polish. There is no modified character for - * this key combination and no character is inserted into the - * document, but FF fires the keypress for char code `100` anyway. - * No `input` event will occur. - * - * - `which` is the pressed key code, but a command combination is - * being used. Ex: `Cmd+C`. No character is inserted, and no - * `input` event will occur. - */ - if (!isKeypressCommand(nativeEvent)) { - // IE fires the `keypress` event when a user types an emoji via - // Touch keyboard of Windows. In such a case, the `char` property - // holds an emoji character like `\uD83D\uDE0A`. Because its length - // is 2, the property `which` does not represent an emoji correctly. - // In such a case, we directly return the `char` property instead of - // using `which`. - if (nativeEvent.char && nativeEvent.char.length > 1) { - return nativeEvent.char; - } else if (nativeEvent.which) { - return String.fromCharCode(nativeEvent.which); - } - } - return null; - case 'topCompositionEnd': - return useFallbackCompositionData ? null : nativeEvent.data; - default: - return null; - } -} + function handleMouseWheel( event ) { -/** - * Extract a SyntheticInputEvent for `beforeInput`, based on either native - * `textInput` or fallback behavior. - * - * @return {?object} A SyntheticInputEvent. - */ -function extractBeforeInputEvent(topLevelType, targetInst, nativeEvent, nativeEventTarget) { - var chars; + //console.log( 'handleMouseWheel' ); - if (canUseTextInputEvent) { - chars = getNativeBeforeInputChars(topLevelType, nativeEvent); - } else { - chars = getFallbackBeforeInputChars(topLevelType, nativeEvent); - } + if ( event.deltaY < 0 ) { - // If no characters are being inserted, no BeforeInput event should - // be fired. - if (!chars) { - return null; - } + dollyOut( getZoomScale() ); - var event = SyntheticInputEvent.getPooled(eventTypes.beforeInput, targetInst, nativeEvent, nativeEventTarget); + } else if ( event.deltaY > 0 ) { - event.data = chars; - accumulateTwoPhaseDispatches(event); - return event; -} + dollyIn( getZoomScale() ); -/** - * Create an `onBeforeInput` event to match - * http://www.w3.org/TR/2013/WD-DOM-Level-3-Events-20131105/#events-inputevents. - * - * This event plugin is based on the native `textInput` event - * available in Chrome, Safari, Opera, and IE. This event fires after - * `onKeyPress` and `onCompositionEnd`, but before `onInput`. - * - * `beforeInput` is spec'd but not implemented in any browsers, and - * the `input` event does not provide any useful information about what has - * actually been added, contrary to the spec. Thus, `textInput` is the best - * available event to identify the characters that have actually been inserted - * into the target node. - * - * This plugin is also responsible for emitting `composition` events, thus - * allowing us to share composition fallback code for both `beforeInput` and - * `composition` event types. - */ -var BeforeInputEventPlugin = { - eventTypes: eventTypes, + } - extractEvents: function (topLevelType, targetInst, nativeEvent, nativeEventTarget) { - return [extractCompositionEvent(topLevelType, targetInst, nativeEvent, nativeEventTarget), extractBeforeInputEvent(topLevelType, targetInst, nativeEvent, nativeEventTarget)]; - } -}; + scope.update(); -// Use to restore controlled state after a change event has fired. + } -var fiberHostComponent = null; + function handleKeyDown( event ) { -var ReactControlledComponentInjection = { - injectFiberControlledHostComponent: function (hostComponentImpl) { - // The fiber implementation doesn't use dynamic dispatch so we need to - // inject the implementation. - fiberHostComponent = hostComponentImpl; - } -}; + //console.log( 'handleKeyDown' ); -var restoreTarget = null; -var restoreQueue = null; + switch ( event.keyCode ) { -function restoreStateOfTarget(target) { - // We perform this translation at the end of the event loop so that we - // always receive the correct fiber here - var internalInstance = getInstanceFromNode(target); - if (!internalInstance) { - // Unmounted - return; - } - !(fiberHostComponent && typeof fiberHostComponent.restoreControlledState === 'function') ? invariant(false, 'Fiber needs to be injected to handle a fiber target for controlled events. This error is likely caused by a bug in React. Please file an issue.') : void 0; - var props = getFiberCurrentPropsFromNode(internalInstance.stateNode); - fiberHostComponent.restoreControlledState(internalInstance.stateNode, internalInstance.type, props); -} + case scope.keys.UP: + pan( 0, scope.keyPanSpeed ); + scope.update(); + break; -var injection$3 = ReactControlledComponentInjection; + case scope.keys.BOTTOM: + pan( 0, - scope.keyPanSpeed ); + scope.update(); + break; -function enqueueStateRestore(target) { - if (restoreTarget) { - if (restoreQueue) { - restoreQueue.push(target); - } else { - restoreQueue = [target]; - } - } else { - restoreTarget = target; - } -} + case scope.keys.LEFT: + pan( scope.keyPanSpeed, 0 ); + scope.update(); + break; -function restoreStateIfNeeded() { - if (!restoreTarget) { - return; - } - var target = restoreTarget; - var queuedTargets = restoreQueue; - restoreTarget = null; - restoreQueue = null; + case scope.keys.RIGHT: + pan( - scope.keyPanSpeed, 0 ); + scope.update(); + break; - restoreStateOfTarget(target); - if (queuedTargets) { - for (var i = 0; i < queuedTargets.length; i++) { - restoreStateOfTarget(queuedTargets[i]); - } - } -} + } -var ReactControlledComponent = Object.freeze({ - injection: injection$3, - enqueueStateRestore: enqueueStateRestore, - restoreStateIfNeeded: restoreStateIfNeeded -}); + } -// Used as a way to call batchedUpdates when we don't have a reference to -// the renderer. Such as when we're dispatching events or if third party -// libraries need to call batchedUpdates. Eventually, this API will go away when -// everything is batched by default. We'll then have a similar API to opt-out of -// scheduled work and instead do synchronous work. + function handleTouchStartRotate( event ) { -// Defaults -var fiberBatchedUpdates = function (fn, bookkeeping) { - return fn(bookkeeping); -}; + //console.log( 'handleTouchStartRotate' ); -var isNestingBatched = false; -function batchedUpdates(fn, bookkeeping) { - if (isNestingBatched) { - // If we are currently inside another batch, we need to wait until it - // fully completes before restoring state. Therefore, we add the target to - // a queue of work. - return fiberBatchedUpdates(fn, bookkeeping); - } - isNestingBatched = true; - try { - return fiberBatchedUpdates(fn, bookkeeping); - } finally { - // Here we wait until all updates have propagated, which is important - // when using controlled components within layers: - // https://github.com/facebook/react/issues/1698 - // Then we restore state of any controlled component. - isNestingBatched = false; - restoreStateIfNeeded(); - } -} + rotateStart.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ); -var ReactGenericBatchingInjection = { - injectFiberBatchedUpdates: function (_batchedUpdates) { - fiberBatchedUpdates = _batchedUpdates; - } -}; + } -var injection$4 = ReactGenericBatchingInjection; + function handleTouchStartDolly( event ) { -/** - * @see http://www.whatwg.org/specs/web-apps/current-work/multipage/the-input-element.html#input-type-attr-summary - */ -var supportedInputTypes = { - color: true, - date: true, - datetime: true, - 'datetime-local': true, - email: true, - month: true, - number: true, - password: true, - range: true, - search: true, - tel: true, - text: true, - time: true, - url: true, - week: true -}; + //console.log( 'handleTouchStartDolly' ); -function isTextInputElement(elem) { - var nodeName = elem && elem.nodeName && elem.nodeName.toLowerCase(); + var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX; + var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY; - if (nodeName === 'input') { - return !!supportedInputTypes[elem.type]; - } + var distance = Math.sqrt( dx * dx + dy * dy ); - if (nodeName === 'textarea') { - return true; - } + dollyStart.set( 0, distance ); - return false; -} + } -/** - * HTML nodeType values that represent the type of the node - */ + function handleTouchStartPan( event ) { -var ELEMENT_NODE = 1; -var TEXT_NODE = 3; -var COMMENT_NODE = 8; -var DOCUMENT_NODE = 9; -var DOCUMENT_FRAGMENT_NODE = 11; + //console.log( 'handleTouchStartPan' ); -/** - * Gets the target node from a native browser event by accounting for - * inconsistencies in browser DOM APIs. - * - * @param {object} nativeEvent Native browser event. - * @return {DOMEventTarget} Target node. - */ -function getEventTarget(nativeEvent) { - var target = nativeEvent.target || nativeEvent.srcElement || window; + panStart.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ); - // Normalize SVG element events #4963 - if (target.correspondingUseElement) { - target = target.correspondingUseElement; - } + } - // Safari may fire events on text nodes (Node.TEXT_NODE is 3). - // @see http://www.quirksmode.org/js/events_properties.html - return target.nodeType === TEXT_NODE ? target.parentNode : target; -} + function handleTouchMoveRotate( event ) { -var useHasFeature; -if (ExecutionEnvironment.canUseDOM) { - useHasFeature = document.implementation && document.implementation.hasFeature && - // always returns true in newer browsers as per the standard. - // @see http://dom.spec.whatwg.org/#dom-domimplementation-hasfeature - document.implementation.hasFeature('', '') !== true; -} + //console.log( 'handleTouchMoveRotate' ); -/** - * Checks if an event is supported in the current execution environment. - * - * NOTE: This will not work correctly for non-generic events such as `change`, - * `reset`, `load`, `error`, and `select`. - * - * Borrows from Modernizr. - * - * @param {string} eventNameSuffix Event name, e.g. "click". - * @param {?boolean} capture Check if the capture phase is supported. - * @return {boolean} True if the event is supported. - * @internal - * @license Modernizr 3.0.0pre (Custom Build) | MIT - */ -function isEventSupported(eventNameSuffix, capture) { - if (!ExecutionEnvironment.canUseDOM || capture && !('addEventListener' in document)) { - return false; - } + rotateEnd.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ); + rotateDelta.subVectors( rotateEnd, rotateStart ); - var eventName = 'on' + eventNameSuffix; - var isSupported = eventName in document; + var element = scope.domElement === document ? scope.domElement.body : scope.domElement; - if (!isSupported) { - var element = document.createElement('div'); - element.setAttribute(eventName, 'return;'); - isSupported = typeof element[eventName] === 'function'; - } + // rotating across whole screen goes 360 degrees around + rotateLeft( 2 * Math.PI * rotateDelta.x / element.clientWidth * scope.rotateSpeed ); - if (!isSupported && useHasFeature && eventNameSuffix === 'wheel') { - // This is the only way to test support for the `wheel` event in IE9+. - isSupported = document.implementation.hasFeature('Events.wheel', '3.0'); - } + // rotating up and down along whole screen attempts to go 360, but limited to 180 + rotateUp( 2 * Math.PI * rotateDelta.y / element.clientHeight * scope.rotateSpeed ); - return isSupported; -} + rotateStart.copy( rotateEnd ); -function isCheckable(elem) { - var type = elem.type; - var nodeName = elem.nodeName; - return nodeName && nodeName.toLowerCase() === 'input' && (type === 'checkbox' || type === 'radio'); -} + scope.update(); -function getTracker(node) { - return node._valueTracker; -} + } -function detachTracker(node) { - node._valueTracker = null; -} + function handleTouchMoveDolly( event ) { -function getValueFromNode(node) { - var value = ''; - if (!node) { - return value; - } + //console.log( 'handleTouchMoveDolly' ); - if (isCheckable(node)) { - value = node.checked ? 'true' : 'false'; - } else { - value = node.value; - } + var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX; + var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY; - return value; -} + var distance = Math.sqrt( dx * dx + dy * dy ); -function trackValueOnNode(node) { - var valueField = isCheckable(node) ? 'checked' : 'value'; - var descriptor = Object.getOwnPropertyDescriptor(node.constructor.prototype, valueField); + dollyEnd.set( 0, distance ); - var currentValue = '' + node[valueField]; + dollyDelta.subVectors( dollyEnd, dollyStart ); - // if someone has already defined a value or Safari, then bail - // and don't track value will cause over reporting of changes, - // but it's better then a hard failure - // (needed for certain tests that spyOn input values and Safari) - if (node.hasOwnProperty(valueField) || typeof descriptor.get !== 'function' || typeof descriptor.set !== 'function') { - return; - } + if ( dollyDelta.y > 0 ) { - Object.defineProperty(node, valueField, { - enumerable: descriptor.enumerable, - configurable: true, - get: function () { - return descriptor.get.call(this); - }, - set: function (value) { - currentValue = '' + value; - descriptor.set.call(this, value); - } - }); + dollyOut( getZoomScale() ); - var tracker = { - getValue: function () { - return currentValue; - }, - setValue: function (value) { - currentValue = '' + value; - }, - stopTracking: function () { - detachTracker(node); - delete node[valueField]; - } - }; - return tracker; -} + } else if ( dollyDelta.y < 0 ) { -function track(node) { - if (getTracker(node)) { - return; - } + dollyIn( getZoomScale() ); - // TODO: Once it's just Fiber we can move this to node._wrapperState - node._valueTracker = trackValueOnNode(node); -} + } -function updateValueIfChanged(node) { - if (!node) { - return false; - } + dollyStart.copy( dollyEnd ); - var tracker = getTracker(node); - // if there is no tracker at this point it's unlikely - // that trying again will succeed - if (!tracker) { - return true; - } + scope.update(); - var lastValue = tracker.getValue(); - var nextValue = getValueFromNode(node); - if (nextValue !== lastValue) { - tracker.setValue(nextValue); - return true; - } - return false; -} + } -var eventTypes$1 = { - change: { - phasedRegistrationNames: { - bubbled: 'onChange', - captured: 'onChangeCapture' - }, - dependencies: ['topBlur', 'topChange', 'topClick', 'topFocus', 'topInput', 'topKeyDown', 'topKeyUp', 'topSelectionChange'] - } -}; + function handleTouchMovePan( event ) { -function createAndAccumulateChangeEvent(inst, nativeEvent, target) { - var event = SyntheticEvent$1.getPooled(eventTypes$1.change, inst, nativeEvent, target); - event.type = 'change'; - // Flag this event loop as needing state restore. - enqueueStateRestore(target); - accumulateTwoPhaseDispatches(event); - return event; -} -/** - * For IE shims - */ -var activeElement = null; -var activeElementInst = null; + //console.log( 'handleTouchMovePan' ); -/** - * SECTION: handle `change` event - */ -function shouldUseChangeEvent(elem) { - var nodeName = elem.nodeName && elem.nodeName.toLowerCase(); - return nodeName === 'select' || nodeName === 'input' && elem.type === 'file'; -} + panEnd.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ); -function manualDispatchChangeEvent(nativeEvent) { - var event = createAndAccumulateChangeEvent(activeElementInst, nativeEvent, getEventTarget(nativeEvent)); + panDelta.subVectors( panEnd, panStart ); - // If change and propertychange bubbled, we'd just bind to it like all the - // other events and have it go through ReactBrowserEventEmitter. Since it - // doesn't, we manually listen for the events and so we have to enqueue and - // process the abstract event manually. - // - // Batching is necessary here in order to ensure that all event handlers run - // before the next rerender (including event handlers attached to ancestor - // elements instead of directly on the input). Without this, controlled - // components don't work properly in conjunction with event bubbling because - // the component is rerendered and the value reverted before all the event - // handlers can run. See https://github.com/facebook/react/issues/708. - batchedUpdates(runEventInBatch, event); -} + pan( panDelta.x, panDelta.y ); -function runEventInBatch(event) { - enqueueEvents(event); - processEventQueue(false); -} + panStart.copy( panEnd ); -function getInstIfValueChanged(targetInst) { - var targetNode = getNodeFromInstance$1(targetInst); - if (updateValueIfChanged(targetNode)) { - return targetInst; - } -} + scope.update(); -function getTargetInstForChangeEvent(topLevelType, targetInst) { - if (topLevelType === 'topChange') { - return targetInst; - } -} + } -/** - * SECTION: handle `input` event - */ -var isInputEventSupported = false; -if (ExecutionEnvironment.canUseDOM) { - // IE9 claims to support the input event but fails to trigger it when - // deleting text, so we ignore its input events. - isInputEventSupported = isEventSupported('input') && (!document.documentMode || document.documentMode > 9); -} + function handleTouchEnd( event ) { -/** - * (For IE <=9) Starts tracking propertychange events on the passed-in element - * and override the value property so that we can distinguish user events from - * value changes in JS. - */ -function startWatchingForValueChange(target, targetInst) { - activeElement = target; - activeElementInst = targetInst; - activeElement.attachEvent('onpropertychange', handlePropertyChange); -} + //console.log( 'handleTouchEnd' ); -/** - * (For IE <=9) Removes the event listeners from the currently-tracked element, - * if any exists. - */ -function stopWatchingForValueChange() { - if (!activeElement) { - return; - } - activeElement.detachEvent('onpropertychange', handlePropertyChange); - activeElement = null; - activeElementInst = null; -} + } -/** - * (For IE <=9) Handles a propertychange event, sending a `change` event if - * the value of the active element has changed. - */ -function handlePropertyChange(nativeEvent) { - if (nativeEvent.propertyName !== 'value') { - return; - } - if (getInstIfValueChanged(activeElementInst)) { - manualDispatchChangeEvent(nativeEvent); - } -} + // + // event handlers - FSM: listen for events and reset state + // -function handleEventsForInputEventPolyfill(topLevelType, target, targetInst) { - if (topLevelType === 'topFocus') { - // In IE9, propertychange fires for most input events but is buggy and - // doesn't fire when text is deleted, but conveniently, selectionchange - // appears to fire in all of the remaining cases so we catch those and - // forward the event if the value has changed - // In either case, we don't want to call the event handler if the value - // is changed from JS so we redefine a setter for `.value` that updates - // our activeElementValue variable, allowing us to ignore those changes - // - // stopWatching() should be a noop here but we call it just in case we - // missed a blur event somehow. - stopWatchingForValueChange(); - startWatchingForValueChange(target, targetInst); - } else if (topLevelType === 'topBlur') { - stopWatchingForValueChange(); - } -} + function onMouseDown( event ) { -// For IE8 and IE9. -function getTargetInstForInputEventPolyfill(topLevelType, targetInst) { - if (topLevelType === 'topSelectionChange' || topLevelType === 'topKeyUp' || topLevelType === 'topKeyDown') { - // On the selectionchange event, the target is just document which isn't - // helpful for us so just check activeElement instead. - // - // 99% of the time, keydown and keyup aren't necessary. IE8 fails to fire - // propertychange on the first input event after setting `value` from a - // script and fires only keydown, keypress, keyup. Catching keyup usually - // gets it and catching keydown lets us fire an event for the first - // keystroke if user does a key repeat (it'll be a little delayed: right - // before the second keystroke). Other input methods (e.g., paste) seem to - // fire selectionchange normally. - return getInstIfValueChanged(activeElementInst); - } -} + if ( scope.enabled === false ) return; -/** - * SECTION: handle `click` event - */ -function shouldUseClickEvent(elem) { - // Use the `click` event to detect changes to checkbox and radio inputs. - // This approach works across all browsers, whereas `change` does not fire - // until `blur` in IE8. - var nodeName = elem.nodeName; - return nodeName && nodeName.toLowerCase() === 'input' && (elem.type === 'checkbox' || elem.type === 'radio'); -} + event.preventDefault(); -function getTargetInstForClickEvent(topLevelType, targetInst) { - if (topLevelType === 'topClick') { - return getInstIfValueChanged(targetInst); - } -} + if ( event.button === scope.mouseButtons.ORBIT ) { -function getTargetInstForInputOrChangeEvent(topLevelType, targetInst) { - if (topLevelType === 'topInput' || topLevelType === 'topChange') { - return getInstIfValueChanged(targetInst); - } -} + if ( scope.enableRotate === false ) return; -function handleControlledInputBlur(inst, node) { - // TODO: In IE, inst is occasionally null. Why? - if (inst == null) { - return; - } + handleMouseDownRotate( event ); - // Fiber and ReactDOM keep wrapper state in separate places - var state = inst._wrapperState || node._wrapperState; + state = STATE.ROTATE; - if (!state || !state.controlled || node.type !== 'number') { - return; - } + } else if ( event.button === scope.mouseButtons.ZOOM ) { - // If controlled, assign the value attribute to the current value on blur - var value = '' + node.value; - if (node.getAttribute('value') !== value) { - node.setAttribute('value', value); - } -} + if ( scope.enableZoom === false ) return; -/** - * This plugin creates an `onChange` event that normalizes change events - * across form elements. This event fires at a time when it's possible to - * change the element's value without seeing a flicker. - * - * Supported elements are: - * - input (see `isTextInputElement`) - * - textarea - * - select - */ -var ChangeEventPlugin = { - eventTypes: eventTypes$1, + handleMouseDownDolly( event ); - _isInputEventSupported: isInputEventSupported, + state = STATE.DOLLY; - extractEvents: function (topLevelType, targetInst, nativeEvent, nativeEventTarget) { - var targetNode = targetInst ? getNodeFromInstance$1(targetInst) : window; + } else if ( event.button === scope.mouseButtons.PAN ) { - var getTargetInstFunc, handleEventFunc; - if (shouldUseChangeEvent(targetNode)) { - getTargetInstFunc = getTargetInstForChangeEvent; - } else if (isTextInputElement(targetNode)) { - if (isInputEventSupported) { - getTargetInstFunc = getTargetInstForInputOrChangeEvent; - } else { - getTargetInstFunc = getTargetInstForInputEventPolyfill; - handleEventFunc = handleEventsForInputEventPolyfill; - } - } else if (shouldUseClickEvent(targetNode)) { - getTargetInstFunc = getTargetInstForClickEvent; - } + if ( scope.enablePan === false ) return; - if (getTargetInstFunc) { - var inst = getTargetInstFunc(topLevelType, targetInst); - if (inst) { - var event = createAndAccumulateChangeEvent(inst, nativeEvent, nativeEventTarget); - return event; - } - } + handleMouseDownPan( event ); - if (handleEventFunc) { - handleEventFunc(topLevelType, targetNode, targetInst); - } + state = STATE.PAN; - // When blurring, set the value attribute for number inputs - if (topLevelType === 'topBlur') { - handleControlledInputBlur(targetInst, targetNode); - } - } -}; + } -/** - * Module that is injectable into `EventPluginHub`, that specifies a - * deterministic ordering of `EventPlugin`s. A convenient way to reason about - * plugins, without having to package every one of them. This is better than - * having plugins be ordered in the same order that they are injected because - * that ordering would be influenced by the packaging order. - * `ResponderEventPlugin` must occur before `SimpleEventPlugin` so that - * preventing default on events is convenient in `SimpleEventPlugin` handlers. - */ -var DOMEventPluginOrder = ['ResponderEventPlugin', 'SimpleEventPlugin', 'TapEventPlugin', 'EnterLeaveEventPlugin', 'ChangeEventPlugin', 'SelectEventPlugin', 'BeforeInputEventPlugin']; + if ( state !== STATE.NONE ) { -/** - * @interface UIEvent - * @see http://www.w3.org/TR/DOM-Level-3-Events/ - */ -var UIEventInterface = { - view: null, - detail: null -}; + document.addEventListener( 'mousemove', onMouseMove, false ); + document.addEventListener( 'mouseup', onMouseUp, false ); -/** - * @param {object} dispatchConfig Configuration used to dispatch this event. - * @param {string} dispatchMarker Marker identifying the event target. - * @param {object} nativeEvent Native browser event. - * @extends {SyntheticEvent} - */ -function SyntheticUIEvent(dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget) { - return SyntheticEvent$1.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget); -} + scope.dispatchEvent( startEvent ); -SyntheticEvent$1.augmentClass(SyntheticUIEvent, UIEventInterface); + } -/** - * Translation from modifier key to the associated property in the event. - * @see http://www.w3.org/TR/DOM-Level-3-Events/#keys-Modifiers - */ + } -var modifierKeyToProp = { - Alt: 'altKey', - Control: 'ctrlKey', - Meta: 'metaKey', - Shift: 'shiftKey' -}; + function onMouseMove( event ) { -// IE8 does not implement getModifierState so we simply map it to the only -// modifier keys exposed by the event itself, does not support Lock-keys. -// Currently, all major browsers except Chrome seems to support Lock-keys. -function modifierStateGetter(keyArg) { - var syntheticEvent = this; - var nativeEvent = syntheticEvent.nativeEvent; - if (nativeEvent.getModifierState) { - return nativeEvent.getModifierState(keyArg); - } - var keyProp = modifierKeyToProp[keyArg]; - return keyProp ? !!nativeEvent[keyProp] : false; -} + if ( scope.enabled === false ) return; -function getEventModifierState(nativeEvent) { - return modifierStateGetter; -} + event.preventDefault(); -/** - * @interface MouseEvent - * @see http://www.w3.org/TR/DOM-Level-3-Events/ - */ -var MouseEventInterface = { - screenX: null, - screenY: null, - clientX: null, - clientY: null, - pageX: null, - pageY: null, - ctrlKey: null, - shiftKey: null, - altKey: null, - metaKey: null, - getModifierState: getEventModifierState, - button: null, - buttons: null, - relatedTarget: function (event) { - return event.relatedTarget || (event.fromElement === event.srcElement ? event.toElement : event.fromElement); - } -}; + if ( state === STATE.ROTATE ) { -/** - * @param {object} dispatchConfig Configuration used to dispatch this event. - * @param {string} dispatchMarker Marker identifying the event target. - * @param {object} nativeEvent Native browser event. - * @extends {SyntheticUIEvent} - */ -function SyntheticMouseEvent(dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget) { - return SyntheticUIEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget); -} + if ( scope.enableRotate === false ) return; -SyntheticUIEvent.augmentClass(SyntheticMouseEvent, MouseEventInterface); + handleMouseMoveRotate( event ); -var eventTypes$2 = { - mouseEnter: { - registrationName: 'onMouseEnter', - dependencies: ['topMouseOut', 'topMouseOver'] - }, - mouseLeave: { - registrationName: 'onMouseLeave', - dependencies: ['topMouseOut', 'topMouseOver'] - } -}; + } else if ( state === STATE.DOLLY ) { -var EnterLeaveEventPlugin = { - eventTypes: eventTypes$2, + if ( scope.enableZoom === false ) return; - /** - * For almost every interaction we care about, there will be both a top-level - * `mouseover` and `mouseout` event that occurs. Only use `mouseout` so that - * we do not extract duplicate events. However, moving the mouse into the - * browser from outside will not fire a `mouseout` event. In this case, we use - * the `mouseover` top-level event. - */ - extractEvents: function (topLevelType, targetInst, nativeEvent, nativeEventTarget) { - if (topLevelType === 'topMouseOver' && (nativeEvent.relatedTarget || nativeEvent.fromElement)) { - return null; - } - if (topLevelType !== 'topMouseOut' && topLevelType !== 'topMouseOver') { - // Must not be a mouse in or mouse out - ignoring. - return null; - } + handleMouseMoveDolly( event ); - var win; - if (nativeEventTarget.window === nativeEventTarget) { - // `nativeEventTarget` is probably a window object. - win = nativeEventTarget; - } else { - // TODO: Figure out why `ownerDocument` is sometimes undefined in IE8. - var doc = nativeEventTarget.ownerDocument; - if (doc) { - win = doc.defaultView || doc.parentWindow; - } else { - win = window; - } - } + } else if ( state === STATE.PAN ) { - var from; - var to; - if (topLevelType === 'topMouseOut') { - from = targetInst; - var related = nativeEvent.relatedTarget || nativeEvent.toElement; - to = related ? getClosestInstanceFromNode(related) : null; - } else { - // Moving to a node from outside the window. - from = null; - to = targetInst; - } + if ( scope.enablePan === false ) return; - if (from === to) { - // Nothing pertains to our managed components. - return null; - } + handleMouseMovePan( event ); - var fromNode = from == null ? win : getNodeFromInstance$1(from); - var toNode = to == null ? win : getNodeFromInstance$1(to); + } - var leave = SyntheticMouseEvent.getPooled(eventTypes$2.mouseLeave, from, nativeEvent, nativeEventTarget); - leave.type = 'mouseleave'; - leave.target = fromNode; - leave.relatedTarget = toNode; + } - var enter = SyntheticMouseEvent.getPooled(eventTypes$2.mouseEnter, to, nativeEvent, nativeEventTarget); - enter.type = 'mouseenter'; - enter.target = toNode; - enter.relatedTarget = fromNode; + function onMouseUp( event ) { - accumulateEnterLeaveDispatches(leave, enter, from, to); + if ( scope.enabled === false ) return; - return [leave, enter]; - } -}; + handleMouseUp( event ); -/** - * `ReactInstanceMap` maintains a mapping from a public facing stateful - * instance (key) and the internal representation (value). This allows public - * methods to accept the user facing instance as an argument and map them back - * to internal methods. - * - * Note that this module is currently shared and assumed to be stateless. - * If this becomes an actual Map, that will break. - */ + document.removeEventListener( 'mousemove', onMouseMove, false ); + document.removeEventListener( 'mouseup', onMouseUp, false ); -/** - * This API should be called `delete` but we'd have to make sure to always - * transform these to strings for IE support. When this transform is fully - * supported we can rename it. - */ + scope.dispatchEvent( endEvent ); + state = STATE.NONE; -function get(key) { - return key._reactInternalFiber; -} + } -function has(key) { - return key._reactInternalFiber !== undefined; -} + function onMouseWheel( event ) { -function set(key, value) { - key._reactInternalFiber = value; -} + if ( scope.enabled === false || scope.enableZoom === false || ( state !== STATE.NONE && state !== STATE.ROTATE ) ) return; -var ReactInternals = React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED; + event.preventDefault(); + event.stopPropagation(); -var ReactCurrentOwner = ReactInternals.ReactCurrentOwner; -var ReactDebugCurrentFrame = ReactInternals.ReactDebugCurrentFrame; + handleMouseWheel( event ); -function getComponentName(fiber) { - var type = fiber.type; + scope.dispatchEvent( startEvent ); // not sure why these are here... + scope.dispatchEvent( endEvent ); - if (typeof type === 'string') { - return type; - } - if (typeof type === 'function') { - return type.displayName || type.name; - } - return null; -} + } -// Don't change these two values: -var NoEffect = 0; // 0b00000000 -var PerformedWork = 1; // 0b00000001 + function onKeyDown( event ) { -// You can change the rest (and add more). -var Placement = 2; // 0b00000010 -var Update = 4; // 0b00000100 -var PlacementAndUpdate = 6; // 0b00000110 -var Deletion = 8; // 0b00001000 -var ContentReset = 16; // 0b00010000 -var Callback = 32; // 0b00100000 -var Err = 64; // 0b01000000 -var Ref = 128; // 0b10000000 + if ( scope.enabled === false || scope.enableKeys === false || scope.enablePan === false ) return; -var MOUNTING = 1; -var MOUNTED = 2; -var UNMOUNTED = 3; + handleKeyDown( event ); -function isFiberMountedImpl(fiber) { - var node = fiber; - if (!fiber.alternate) { - // If there is no alternate, this might be a new tree that isn't inserted - // yet. If it is, then it will have a pending insertion effect on it. - if ((node.effectTag & Placement) !== NoEffect) { - return MOUNTING; - } - while (node['return']) { - node = node['return']; - if ((node.effectTag & Placement) !== NoEffect) { - return MOUNTING; - } - } - } else { - while (node['return']) { - node = node['return']; - } - } - if (node.tag === HostRoot) { - // TODO: Check if this was a nested HostRoot when used with - // renderContainerIntoSubtree. - return MOUNTED; - } - // If we didn't hit the root, that means that we're in an disconnected tree - // that has been unmounted. - return UNMOUNTED; -} + } -function isFiberMounted(fiber) { - return isFiberMountedImpl(fiber) === MOUNTED; -} + function onTouchStart( event ) { -function isMounted(component) { - { - var owner = ReactCurrentOwner.current; - if (owner !== null && owner.tag === ClassComponent) { - var ownerFiber = owner; - var instance = ownerFiber.stateNode; - warning(instance._warnedAboutRefsInRender, '%s is accessing isMounted inside its render() function. ' + 'render() should be a pure function of props and state. It should ' + 'never access something that requires stale data from the previous ' + 'render, such as refs. Move this logic to componentDidMount and ' + 'componentDidUpdate instead.', getComponentName(ownerFiber) || 'A component'); - instance._warnedAboutRefsInRender = true; - } - } + if ( scope.enabled === false ) return; - var fiber = get(component); - if (!fiber) { - return false; - } - return isFiberMountedImpl(fiber) === MOUNTED; -} + switch ( event.touches.length ) { -function assertIsMounted(fiber) { - !(isFiberMountedImpl(fiber) === MOUNTED) ? invariant(false, 'Unable to find node on an unmounted component.') : void 0; -} + case 1: // one-fingered touch: rotate -function findCurrentFiberUsingSlowPath(fiber) { - var alternate = fiber.alternate; - if (!alternate) { - // If there is no alternate, then we only need to check if it is mounted. - var state = isFiberMountedImpl(fiber); - !(state !== UNMOUNTED) ? invariant(false, 'Unable to find node on an unmounted component.') : void 0; - if (state === MOUNTING) { - return null; - } - return fiber; - } - // If we have two possible branches, we'll walk backwards up to the root - // to see what path the root points to. On the way we may hit one of the - // special cases and we'll deal with them. - var a = fiber; - var b = alternate; - while (true) { - var parentA = a['return']; - var parentB = parentA ? parentA.alternate : null; - if (!parentA || !parentB) { - // We're at the root. - break; - } + if ( scope.enableRotate === false ) return; - // If both copies of the parent fiber point to the same child, we can - // assume that the child is current. This happens when we bailout on low - // priority: the bailed out fiber's child reuses the current child. - if (parentA.child === parentB.child) { - var child = parentA.child; - while (child) { - if (child === a) { - // We've determined that A is the current branch. - assertIsMounted(parentA); - return fiber; - } - if (child === b) { - // We've determined that B is the current branch. - assertIsMounted(parentA); - return alternate; - } - child = child.sibling; - } - // We should never have an alternate for any mounting node. So the only - // way this could possibly happen is if this was unmounted, if at all. - invariant(false, 'Unable to find node on an unmounted component.'); - } + handleTouchStartRotate( event ); - if (a['return'] !== b['return']) { - // The return pointer of A and the return pointer of B point to different - // fibers. We assume that return pointers never criss-cross, so A must - // belong to the child set of A.return, and B must belong to the child - // set of B.return. - a = parentA; - b = parentB; - } else { - // The return pointers point to the same fiber. We'll have to use the - // default, slow path: scan the child sets of each parent alternate to see - // which child belongs to which set. - // - // Search parent A's child set - var didFindChild = false; - var _child = parentA.child; - while (_child) { - if (_child === a) { - didFindChild = true; - a = parentA; - b = parentB; - break; - } - if (_child === b) { - didFindChild = true; - b = parentA; - a = parentB; - break; - } - _child = _child.sibling; - } - if (!didFindChild) { - // Search parent B's child set - _child = parentB.child; - while (_child) { - if (_child === a) { - didFindChild = true; - a = parentB; - b = parentA; - break; - } - if (_child === b) { - didFindChild = true; - b = parentB; - a = parentA; - break; - } - _child = _child.sibling; - } - !didFindChild ? invariant(false, 'Child was not found in either parent set. This indicates a bug in React related to the return pointer. Please file an issue.') : void 0; - } - } + state = STATE.TOUCH_ROTATE; - !(a.alternate === b) ? invariant(false, 'Return fibers should always be each others\' alternates. This error is likely caused by a bug in React. Please file an issue.') : void 0; - } - // If the root is not a host container, we're in a disconnected tree. I.e. - // unmounted. - !(a.tag === HostRoot) ? invariant(false, 'Unable to find node on an unmounted component.') : void 0; - if (a.stateNode.current === a) { - // We've determined that A is the current branch. - return fiber; - } - // Otherwise B has to be current branch. - return alternate; -} + break; -function findCurrentHostFiber(parent) { - var currentParent = findCurrentFiberUsingSlowPath(parent); - if (!currentParent) { - return null; - } + case 2: // two-fingered touch: dolly - // Next we'll drill down this component to find the first HostComponent/Text. - var node = currentParent; - while (true) { - if (node.tag === HostComponent || node.tag === HostText) { - return node; - } else if (node.child) { - node.child['return'] = node; - node = node.child; - continue; - } - if (node === currentParent) { - return null; - } - while (!node.sibling) { - if (!node['return'] || node['return'] === currentParent) { - return null; - } - node = node['return']; - } - node.sibling['return'] = node['return']; - node = node.sibling; - } - // Flow needs the return null here, but ESLint complains about it. - // eslint-disable-next-line no-unreachable - return null; -} + if ( scope.enableZoom === false ) return; -function findCurrentHostFiberWithNoPortals(parent) { - var currentParent = findCurrentFiberUsingSlowPath(parent); - if (!currentParent) { - return null; - } + handleTouchStartDolly( event ); - // Next we'll drill down this component to find the first HostComponent/Text. - var node = currentParent; - while (true) { - if (node.tag === HostComponent || node.tag === HostText) { - return node; - } else if (node.child && node.tag !== HostPortal) { - node.child['return'] = node; - node = node.child; - continue; - } - if (node === currentParent) { - return null; - } - while (!node.sibling) { - if (!node['return'] || node['return'] === currentParent) { - return null; - } - node = node['return']; - } - node.sibling['return'] = node['return']; - node = node.sibling; - } - // Flow needs the return null here, but ESLint complains about it. - // eslint-disable-next-line no-unreachable - return null; -} + state = STATE.TOUCH_DOLLY; -var CALLBACK_BOOKKEEPING_POOL_SIZE = 10; -var callbackBookkeepingPool = []; + break; -/** - * Find the deepest React component completely containing the root of the - * passed-in instance (for use when entire React trees are nested within each - * other). If React trees are not nested, returns null. - */ -function findRootContainerNode(inst) { - // TODO: It may be a good idea to cache this to prevent unnecessary DOM - // traversal, but caching is difficult to do correctly without using a - // mutation observer to listen for all DOM changes. - while (inst['return']) { - inst = inst['return']; - } - if (inst.tag !== HostRoot) { - // This can happen if we're in a detached tree. - return null; - } - return inst.stateNode.containerInfo; -} + case 3: // three-fingered touch: pan -// Used to store ancestor hierarchy in top level callback -function getTopLevelCallbackBookKeeping(topLevelType, nativeEvent, targetInst) { - if (callbackBookkeepingPool.length) { - var instance = callbackBookkeepingPool.pop(); - instance.topLevelType = topLevelType; - instance.nativeEvent = nativeEvent; - instance.targetInst = targetInst; - return instance; - } - return { - topLevelType: topLevelType, - nativeEvent: nativeEvent, - targetInst: targetInst, - ancestors: [] - }; -} + if ( scope.enablePan === false ) return; -function releaseTopLevelCallbackBookKeeping(instance) { - instance.topLevelType = null; - instance.nativeEvent = null; - instance.targetInst = null; - instance.ancestors.length = 0; - if (callbackBookkeepingPool.length < CALLBACK_BOOKKEEPING_POOL_SIZE) { - callbackBookkeepingPool.push(instance); - } -} + handleTouchStartPan( event ); -function handleTopLevelImpl(bookKeeping) { - var targetInst = bookKeeping.targetInst; + state = STATE.TOUCH_PAN; - // Loop through the hierarchy, in case there's any nested components. - // It's important that we build the array of ancestors before calling any - // event handlers, because event handlers can modify the DOM, leading to - // inconsistencies with ReactMount's node cache. See #1105. - var ancestor = targetInst; - do { - if (!ancestor) { - bookKeeping.ancestors.push(ancestor); - break; - } - var root = findRootContainerNode(ancestor); - if (!root) { - break; - } - bookKeeping.ancestors.push(ancestor); - ancestor = getClosestInstanceFromNode(root); - } while (ancestor); + break; - for (var i = 0; i < bookKeeping.ancestors.length; i++) { - targetInst = bookKeeping.ancestors[i]; - _handleTopLevel(bookKeeping.topLevelType, targetInst, bookKeeping.nativeEvent, getEventTarget(bookKeeping.nativeEvent)); - } -} + default: -// TODO: can we stop exporting these? -var _enabled = true; -var _handleTopLevel = void 0; + state = STATE.NONE; -function setHandleTopLevel(handleTopLevel) { - _handleTopLevel = handleTopLevel; -} + } -function setEnabled(enabled) { - _enabled = !!enabled; -} + if ( state !== STATE.NONE ) { -function isEnabled() { - return _enabled; -} + scope.dispatchEvent( startEvent ); -/** - * Traps top-level events by using event bubbling. - * - * @param {string} topLevelType Record from `BrowserEventConstants`. - * @param {string} handlerBaseName Event name (e.g. "click"). - * @param {object} element Element on which to attach listener. - * @return {?object} An object with a remove function which will forcefully - * remove the listener. - * @internal - */ -function trapBubbledEvent(topLevelType, handlerBaseName, element) { - if (!element) { - return null; - } - return EventListener.listen(element, handlerBaseName, dispatchEvent.bind(null, topLevelType)); -} + } -/** - * Traps a top-level event by using event capturing. - * - * @param {string} topLevelType Record from `BrowserEventConstants`. - * @param {string} handlerBaseName Event name (e.g. "click"). - * @param {object} element Element on which to attach listener. - * @return {?object} An object with a remove function which will forcefully - * remove the listener. - * @internal - */ -function trapCapturedEvent(topLevelType, handlerBaseName, element) { - if (!element) { - return null; - } - return EventListener.capture(element, handlerBaseName, dispatchEvent.bind(null, topLevelType)); -} + } -function dispatchEvent(topLevelType, nativeEvent) { - if (!_enabled) { - return; - } + function onTouchMove( event ) { - var nativeEventTarget = getEventTarget(nativeEvent); - var targetInst = getClosestInstanceFromNode(nativeEventTarget); - if (targetInst !== null && typeof targetInst.tag === 'number' && !isFiberMounted(targetInst)) { - // If we get an event (ex: img onload) before committing that - // component's mount, ignore it for now (that is, treat it as if it was an - // event on a non-React tree). We might also consider queueing events and - // dispatching them after the mount. - targetInst = null; - } + if ( scope.enabled === false ) return; - var bookKeeping = getTopLevelCallbackBookKeeping(topLevelType, nativeEvent, targetInst); + event.preventDefault(); + event.stopPropagation(); - try { - // Event queue being processed in the same cycle allows - // `preventDefault`. - batchedUpdates(handleTopLevelImpl, bookKeeping); - } finally { - releaseTopLevelCallbackBookKeeping(bookKeeping); - } -} + switch ( event.touches.length ) { -var ReactDOMEventListener = Object.freeze({ - get _enabled () { return _enabled; }, - get _handleTopLevel () { return _handleTopLevel; }, - setHandleTopLevel: setHandleTopLevel, - setEnabled: setEnabled, - isEnabled: isEnabled, - trapBubbledEvent: trapBubbledEvent, - trapCapturedEvent: trapCapturedEvent, - dispatchEvent: dispatchEvent -}); + case 1: // one-fingered touch: rotate -/** - * Generate a mapping of standard vendor prefixes using the defined style property and event name. - * - * @param {string} styleProp - * @param {string} eventName - * @returns {object} - */ -function makePrefixMap(styleProp, eventName) { - var prefixes = {}; + if ( scope.enableRotate === false ) return; + if ( state !== STATE.TOUCH_ROTATE ) return; // is this needed?... - prefixes[styleProp.toLowerCase()] = eventName.toLowerCase(); - prefixes['Webkit' + styleProp] = 'webkit' + eventName; - prefixes['Moz' + styleProp] = 'moz' + eventName; - prefixes['ms' + styleProp] = 'MS' + eventName; - prefixes['O' + styleProp] = 'o' + eventName.toLowerCase(); + handleTouchMoveRotate( event ); - return prefixes; -} + break; -/** - * A list of event names to a configurable list of vendor prefixes. - */ -var vendorPrefixes = { - animationend: makePrefixMap('Animation', 'AnimationEnd'), - animationiteration: makePrefixMap('Animation', 'AnimationIteration'), - animationstart: makePrefixMap('Animation', 'AnimationStart'), - transitionend: makePrefixMap('Transition', 'TransitionEnd') -}; + case 2: // two-fingered touch: dolly -/** - * Event names that have already been detected and prefixed (if applicable). - */ -var prefixedEventNames = {}; + if ( scope.enableZoom === false ) return; + if ( state !== STATE.TOUCH_DOLLY ) return; // is this needed?... -/** - * Element to check for prefixes on. - */ -var style = {}; + handleTouchMoveDolly( event ); -/** - * Bootstrap if a DOM exists. - */ -if (ExecutionEnvironment.canUseDOM) { - style = document.createElement('div').style; + break; - // On some platforms, in particular some releases of Android 4.x, - // the un-prefixed "animation" and "transition" properties are defined on the - // style object but the events that fire will still be prefixed, so we need - // to check if the un-prefixed events are usable, and if not remove them from the map. - if (!('AnimationEvent' in window)) { - delete vendorPrefixes.animationend.animation; - delete vendorPrefixes.animationiteration.animation; - delete vendorPrefixes.animationstart.animation; - } + case 3: // three-fingered touch: pan - // Same as above - if (!('TransitionEvent' in window)) { - delete vendorPrefixes.transitionend.transition; - } -} + if ( scope.enablePan === false ) return; + if ( state !== STATE.TOUCH_PAN ) return; // is this needed?... -/** - * Attempts to determine the correct vendor prefixed event name. - * - * @param {string} eventName - * @returns {string} - */ -function getVendorPrefixedEventName(eventName) { - if (prefixedEventNames[eventName]) { - return prefixedEventNames[eventName]; - } else if (!vendorPrefixes[eventName]) { - return eventName; - } + handleTouchMovePan( event ); - var prefixMap = vendorPrefixes[eventName]; + break; - for (var styleProp in prefixMap) { - if (prefixMap.hasOwnProperty(styleProp) && styleProp in style) { - return prefixedEventNames[eventName] = prefixMap[styleProp]; - } - } + default: - return ''; -} + state = STATE.NONE; -/** - * Types of raw signals from the browser caught at the top level. - * - * For events like 'submit' which don't consistently bubble (which we - * trap at a lower node than `document`), binding at `document` would - * cause duplicate events so we don't include them here. - */ -var topLevelTypes$1 = { - topAbort: 'abort', - topAnimationEnd: getVendorPrefixedEventName('animationend') || 'animationend', - topAnimationIteration: getVendorPrefixedEventName('animationiteration') || 'animationiteration', - topAnimationStart: getVendorPrefixedEventName('animationstart') || 'animationstart', - topBlur: 'blur', - topCancel: 'cancel', - topCanPlay: 'canplay', - topCanPlayThrough: 'canplaythrough', - topChange: 'change', - topClick: 'click', - topClose: 'close', - topCompositionEnd: 'compositionend', - topCompositionStart: 'compositionstart', - topCompositionUpdate: 'compositionupdate', - topContextMenu: 'contextmenu', - topCopy: 'copy', - topCut: 'cut', - topDoubleClick: 'dblclick', - topDrag: 'drag', - topDragEnd: 'dragend', - topDragEnter: 'dragenter', - topDragExit: 'dragexit', - topDragLeave: 'dragleave', - topDragOver: 'dragover', - topDragStart: 'dragstart', - topDrop: 'drop', - topDurationChange: 'durationchange', - topEmptied: 'emptied', - topEncrypted: 'encrypted', - topEnded: 'ended', - topError: 'error', - topFocus: 'focus', - topInput: 'input', - topKeyDown: 'keydown', - topKeyPress: 'keypress', - topKeyUp: 'keyup', - topLoadedData: 'loadeddata', - topLoad: 'load', - topLoadedMetadata: 'loadedmetadata', - topLoadStart: 'loadstart', - topMouseDown: 'mousedown', - topMouseMove: 'mousemove', - topMouseOut: 'mouseout', - topMouseOver: 'mouseover', - topMouseUp: 'mouseup', - topPaste: 'paste', - topPause: 'pause', - topPlay: 'play', - topPlaying: 'playing', - topProgress: 'progress', - topRateChange: 'ratechange', - topScroll: 'scroll', - topSeeked: 'seeked', - topSeeking: 'seeking', - topSelectionChange: 'selectionchange', - topStalled: 'stalled', - topSuspend: 'suspend', - topTextInput: 'textInput', - topTimeUpdate: 'timeupdate', - topToggle: 'toggle', - topTouchCancel: 'touchcancel', - topTouchEnd: 'touchend', - topTouchMove: 'touchmove', - topTouchStart: 'touchstart', - topTransitionEnd: getVendorPrefixedEventName('transitionend') || 'transitionend', - topVolumeChange: 'volumechange', - topWaiting: 'waiting', - topWheel: 'wheel' -}; + } -var BrowserEventConstants = { - topLevelTypes: topLevelTypes$1 -}; + } -function runEventQueueInBatch(events) { - enqueueEvents(events); - processEventQueue(false); -} + function onTouchEnd( event ) { -/** - * Streams a fired top-level event to `EventPluginHub` where plugins have the - * opportunity to create `ReactEvent`s to be dispatched. - */ -function handleTopLevel(topLevelType, targetInst, nativeEvent, nativeEventTarget) { - var events = extractEvents(topLevelType, targetInst, nativeEvent, nativeEventTarget); - runEventQueueInBatch(events); -} + if ( scope.enabled === false ) return; -var topLevelTypes = BrowserEventConstants.topLevelTypes; + handleTouchEnd( event ); -/** - * Summary of `ReactBrowserEventEmitter` event handling: - * - * - Top-level delegation is used to trap most native browser events. This - * may only occur in the main thread and is the responsibility of - * ReactDOMEventListener, which is injected and can therefore support - * pluggable event sources. This is the only work that occurs in the main - * thread. - * - * - We normalize and de-duplicate events to account for browser quirks. This - * may be done in the worker thread. - * - * - Forward these native events (with the associated top-level type used to - * trap it) to `EventPluginHub`, which in turn will ask plugins if they want - * to extract any synthetic events. - * - * - The `EventPluginHub` will then process each event by annotating them with - * "dispatches", a sequence of listeners and IDs that care about that event. - * - * - The `EventPluginHub` then dispatches the events. - * - * Overview of React and the event system: - * - * +------------+ . - * | DOM | . - * +------------+ . - * | . - * v . - * +------------+ . - * | ReactEvent | . - * | Listener | . - * +------------+ . +-----------+ - * | . +--------+|SimpleEvent| - * | . | |Plugin | - * +-----|------+ . v +-----------+ - * | | | . +--------------+ +------------+ - * | +-----------.--->|EventPluginHub| | Event | - * | | . | | +-----------+ | Propagators| - * | ReactEvent | . | | |TapEvent | |------------| - * | Emitter | . | |<---+|Plugin | |other plugin| - * | | . | | +-----------+ | utilities | - * | +-----------.--->| | +------------+ - * | | | . +--------------+ - * +-----|------+ . ^ +-----------+ - * | . | |Enter/Leave| - * + . +-------+|Plugin | - * +-------------+ . +-----------+ - * | application | . - * |-------------| . - * | | . - * | | . - * +-------------+ . - * . - * React Core . General Purpose Event Plugin System - */ + scope.dispatchEvent( endEvent ); -var alreadyListeningTo = {}; -var reactTopListenersCounter = 0; + state = STATE.NONE; -/** - * To ensure no conflicts with other potential React instances on the page - */ -var topListenersIDKey = '_reactListenersID' + ('' + Math.random()).slice(2); + } -function getListeningForDocument(mountAt) { - // In IE8, `mountAt` is a host object and doesn't have `hasOwnProperty` - // directly. - if (!Object.prototype.hasOwnProperty.call(mountAt, topListenersIDKey)) { - mountAt[topListenersIDKey] = reactTopListenersCounter++; - alreadyListeningTo[mountAt[topListenersIDKey]] = {}; - } - return alreadyListeningTo[mountAt[topListenersIDKey]]; -} + function onContextMenu( event ) { -/** - * We listen for bubbled touch events on the document object. - * - * Firefox v8.01 (and possibly others) exhibited strange behavior when - * mounting `onmousemove` events at some node that was not the document - * element. The symptoms were that if your mouse is not moving over something - * contained within that mount point (for example on the background) the - * top-level listeners for `onmousemove` won't be called. However, if you - * register the `mousemove` on the document object, then it will of course - * catch all `mousemove`s. This along with iOS quirks, justifies restricting - * top-level listeners to the document object only, at least for these - * movement types of events and possibly all events. - * - * @see http://www.quirksmode.org/blog/archives/2010/09/click_event_del.html - * - * Also, `keyup`/`keypress`/`keydown` do not bubble to the window on IE, but - * they bubble to document. - * - * @param {string} registrationName Name of listener (e.g. `onClick`). - * @param {object} contentDocumentHandle Document which owns the container - */ -function listenTo(registrationName, contentDocumentHandle) { - var mountAt = contentDocumentHandle; - var isListening = getListeningForDocument(mountAt); - var dependencies = registrationNameDependencies[registrationName]; + event.preventDefault(); - for (var i = 0; i < dependencies.length; i++) { - var dependency = dependencies[i]; - if (!(isListening.hasOwnProperty(dependency) && isListening[dependency])) { - if (dependency === 'topScroll') { - trapCapturedEvent('topScroll', 'scroll', mountAt); - } else if (dependency === 'topFocus' || dependency === 'topBlur') { - trapCapturedEvent('topFocus', 'focus', mountAt); - trapCapturedEvent('topBlur', 'blur', mountAt); - - // to make sure blur and focus event listeners are only attached once - isListening.topBlur = true; - isListening.topFocus = true; - } else if (dependency === 'topCancel') { - if (isEventSupported('cancel', true)) { - trapCapturedEvent('topCancel', 'cancel', mountAt); - } - isListening.topCancel = true; - } else if (dependency === 'topClose') { - if (isEventSupported('close', true)) { - trapCapturedEvent('topClose', 'close', mountAt); - } - isListening.topClose = true; - } else if (topLevelTypes.hasOwnProperty(dependency)) { - trapBubbledEvent(dependency, topLevelTypes[dependency], mountAt); - } + } - isListening[dependency] = true; - } - } -} + // -function isListeningToAllDependencies(registrationName, mountAt) { - var isListening = getListeningForDocument(mountAt); - var dependencies = registrationNameDependencies[registrationName]; - for (var i = 0; i < dependencies.length; i++) { - var dependency = dependencies[i]; - if (!(isListening.hasOwnProperty(dependency) && isListening[dependency])) { - return false; - } - } - return true; -} + scope.domElement.addEventListener( 'contextmenu', onContextMenu, false ); -/** - * Given any node return the first leaf node without children. - * - * @param {DOMElement|DOMTextNode} node - * @return {DOMElement|DOMTextNode} - */ -function getLeafNode(node) { - while (node && node.firstChild) { - node = node.firstChild; - } - return node; -} + scope.domElement.addEventListener( 'mousedown', onMouseDown, false ); + scope.domElement.addEventListener( 'wheel', onMouseWheel, false ); -/** - * Get the next sibling within a container. This will walk up the - * DOM if a node's siblings have been exhausted. - * - * @param {DOMElement|DOMTextNode} node - * @return {?DOMElement|DOMTextNode} - */ -function getSiblingNode(node) { - while (node) { - if (node.nextSibling) { - return node.nextSibling; - } - node = node.parentNode; - } -} + scope.domElement.addEventListener( 'touchstart', onTouchStart, false ); + scope.domElement.addEventListener( 'touchend', onTouchEnd, false ); + scope.domElement.addEventListener( 'touchmove', onTouchMove, false ); -/** - * Get object describing the nodes which contain characters at offset. - * - * @param {DOMElement|DOMTextNode} root - * @param {number} offset - * @return {?object} - */ -function getNodeForCharacterOffset(root, offset) { - var node = getLeafNode(root); - var nodeStart = 0; - var nodeEnd = 0; + window.addEventListener( 'keydown', onKeyDown, false ); - while (node) { - if (node.nodeType === TEXT_NODE) { - nodeEnd = nodeStart + node.textContent.length; + // force an update at start - if (nodeStart <= offset && nodeEnd >= offset) { - return { - node: node, - offset: offset - nodeStart - }; - } + this.update(); - nodeStart = nodeEnd; - } + }; - node = getLeafNode(getSiblingNode(node)); - } -} + OrbitControls.prototype = Object.create( THREE.EventDispatcher.prototype ); + OrbitControls.prototype.constructor = OrbitControls; -/** - * @param {DOMElement} outerNode - * @return {?object} - */ -function getOffsets(outerNode) { - var selection = window.getSelection && window.getSelection(); + Object.defineProperties( OrbitControls.prototype, { - if (!selection || selection.rangeCount === 0) { - return null; - } + center: { - var anchorNode = selection.anchorNode, - anchorOffset = selection.anchorOffset, - focusNode$$1 = selection.focusNode, - focusOffset = selection.focusOffset; + get: function () { - // In Firefox, anchorNode and focusNode can be "anonymous divs", e.g. the - // up/down buttons on an . Anonymous divs do not seem to - // expose properties, triggering a "Permission denied error" if any of its - // properties are accessed. The only seemingly possible way to avoid erroring - // is to access a property that typically works for non-anonymous divs and - // catch any error that may otherwise arise. See - // https://bugzilla.mozilla.org/show_bug.cgi?id=208427 + console.warn( 'THREE.OrbitControls: .center has been renamed to .target' ); + return this.target; - try { - /* eslint-disable no-unused-expressions */ - anchorNode.nodeType; - focusNode$$1.nodeType; - /* eslint-enable no-unused-expressions */ - } catch (e) { - return null; - } + } - return getModernOffsetsFromPoints(outerNode, anchorNode, anchorOffset, focusNode$$1, focusOffset); -} + }, -/** - * Returns {start, end} where `start` is the character/codepoint index of - * (anchorNode, anchorOffset) within the textContent of `outerNode`, and - * `end` is the index of (focusNode, focusOffset). - * - * Returns null if you pass in garbage input but we should probably just crash. - * - * Exported only for testing. - */ -function getModernOffsetsFromPoints(outerNode, anchorNode, anchorOffset, focusNode$$1, focusOffset) { - var length = 0; - var start = -1; - var end = -1; - var indexWithinAnchor = 0; - var indexWithinFocus = 0; - var node = outerNode; - var parentNode = null; + // backward compatibility - outer: while (true) { - var next = null; + noZoom: { - while (true) { - if (node === anchorNode && (anchorOffset === 0 || node.nodeType === TEXT_NODE)) { - start = length + anchorOffset; - } - if (node === focusNode$$1 && (focusOffset === 0 || node.nodeType === TEXT_NODE)) { - end = length + focusOffset; - } + get: function () { - if (node.nodeType === TEXT_NODE) { - length += node.nodeValue.length; - } - - if ((next = node.firstChild) === null) { - break; - } - // Moving from `node` to its first child `next`. - parentNode = node; - node = next; - } + console.warn( 'THREE.OrbitControls: .noZoom has been deprecated. Use .enableZoom instead.' ); + return ! this.enableZoom; - while (true) { - if (node === outerNode) { - // If `outerNode` has children, this is always the second time visiting - // it. If it has no children, this is still the first loop, and the only - // valid selection is anchorNode and focusNode both equal to this node - // and both offsets 0, in which case we will have handled above. - break outer; - } - if (parentNode === anchorNode && ++indexWithinAnchor === anchorOffset) { - start = length; - } - if (parentNode === focusNode$$1 && ++indexWithinFocus === focusOffset) { - end = length; - } - if ((next = node.nextSibling) !== null) { - break; - } - node = parentNode; - parentNode = node.parentNode; - } + }, - // Moving from `node` to its next sibling `next`. - node = next; - } + set: function ( value ) { - if (start === -1 || end === -1) { - // This should never happen. (Would happen if the anchor/focus nodes aren't - // actually inside the passed-in node.) - return null; - } + console.warn( 'THREE.OrbitControls: .noZoom has been deprecated. Use .enableZoom instead.' ); + this.enableZoom = ! value; - return { - start: start, - end: end - }; -} + } -/** - * In modern non-IE browsers, we can support both forward and backward - * selections. - * - * Note: IE10+ supports the Selection object, but it does not support - * the `extend` method, which means that even in modern IE, it's not possible - * to programmatically create a backward selection. Thus, for all IE - * versions, we use the old IE API to create our selections. - * - * @param {DOMElement|DOMTextNode} node - * @param {object} offsets - */ -function setOffsets(node, offsets) { - if (!window.getSelection) { - return; - } + }, - var selection = window.getSelection(); - var length = node[getTextContentAccessor()].length; - var start = Math.min(offsets.start, length); - var end = offsets.end === undefined ? start : Math.min(offsets.end, length); + noRotate: { - // IE 11 uses modern selection, but doesn't support the extend method. - // Flip backward selections, so we can set with a single range. - if (!selection.extend && start > end) { - var temp = end; - end = start; - start = temp; - } + get: function () { - var startMarker = getNodeForCharacterOffset(node, start); - var endMarker = getNodeForCharacterOffset(node, end); + console.warn( 'THREE.OrbitControls: .noRotate has been deprecated. Use .enableRotate instead.' ); + return ! this.enableRotate; - if (startMarker && endMarker) { - if (selection.rangeCount === 1 && selection.anchorNode === startMarker.node && selection.anchorOffset === startMarker.offset && selection.focusNode === endMarker.node && selection.focusOffset === endMarker.offset) { - return; - } - var range = document.createRange(); - range.setStart(startMarker.node, startMarker.offset); - selection.removeAllRanges(); + }, - if (start > end) { - selection.addRange(range); - selection.extend(endMarker.node, endMarker.offset); - } else { - range.setEnd(endMarker.node, endMarker.offset); - selection.addRange(range); - } - } -} + set: function ( value ) { -function isInDocument(node) { - return containsNode(document.documentElement, node); -} + console.warn( 'THREE.OrbitControls: .noRotate has been deprecated. Use .enableRotate instead.' ); + this.enableRotate = ! value; -/** - * @ReactInputSelection: React input selection module. Based on Selection.js, - * but modified to be suitable for react and has a couple of bug fixes (doesn't - * assume buttons have range selections allowed). - * Input selection module for React. - */ + } -function hasSelectionCapabilities(elem) { - var nodeName = elem && elem.nodeName && elem.nodeName.toLowerCase(); - return nodeName && (nodeName === 'input' && elem.type === 'text' || nodeName === 'textarea' || elem.contentEditable === 'true'); -} + }, -function getSelectionInformation() { - var focusedElem = getActiveElement(); - return { - focusedElem: focusedElem, - selectionRange: hasSelectionCapabilities(focusedElem) ? getSelection$1(focusedElem) : null - }; -} + noPan: { -/** - * @restoreSelection: If any selection information was potentially lost, - * restore it. This is useful when performing operations that could remove dom - * nodes and place them back in, resulting in focus being lost. - */ -function restoreSelection(priorSelectionInformation) { - var curFocusedElem = getActiveElement(); - var priorFocusedElem = priorSelectionInformation.focusedElem; - var priorSelectionRange = priorSelectionInformation.selectionRange; - if (curFocusedElem !== priorFocusedElem && isInDocument(priorFocusedElem)) { - if (hasSelectionCapabilities(priorFocusedElem)) { - setSelection(priorFocusedElem, priorSelectionRange); - } + get: function () { - // Focusing a node can change the scroll position, which is undesirable - var ancestors = []; - var ancestor = priorFocusedElem; - while (ancestor = ancestor.parentNode) { - if (ancestor.nodeType === ELEMENT_NODE) { - ancestors.push({ - element: ancestor, - left: ancestor.scrollLeft, - top: ancestor.scrollTop - }); - } - } + console.warn( 'THREE.OrbitControls: .noPan has been deprecated. Use .enablePan instead.' ); + return ! this.enablePan; - focusNode(priorFocusedElem); + }, - for (var i = 0; i < ancestors.length; i++) { - var info = ancestors[i]; - info.element.scrollLeft = info.left; - info.element.scrollTop = info.top; - } - } -} + set: function ( value ) { -/** - * @getSelection: Gets the selection bounds of a focused textarea, input or - * contentEditable node. - * -@input: Look up selection bounds of this input - * -@return {start: selectionStart, end: selectionEnd} - */ -function getSelection$1(input) { - var selection = void 0; + console.warn( 'THREE.OrbitControls: .noPan has been deprecated. Use .enablePan instead.' ); + this.enablePan = ! value; - if ('selectionStart' in input) { - // Modern browser with input or textarea. - selection = { - start: input.selectionStart, - end: input.selectionEnd - }; - } else { - // Content editable or old IE textarea. - selection = getOffsets(input); - } + } - return selection || { start: 0, end: 0 }; -} + }, -/** - * @setSelection: Sets the selection bounds of a textarea or input and focuses - * the input. - * -@input Set selection bounds of this input or textarea - * -@offsets Object of same form that is returned from get* - */ -function setSelection(input, offsets) { - var start = offsets.start, - end = offsets.end; + noKeys: { - if (end === undefined) { - end = start; - } + get: function () { - if ('selectionStart' in input) { - input.selectionStart = start; - input.selectionEnd = Math.min(end, input.value.length); - } else { - setOffsets(input, offsets); - } -} + console.warn( 'THREE.OrbitControls: .noKeys has been deprecated. Use .enableKeys instead.' ); + return ! this.enableKeys; -var skipSelectionChangeEvent = ExecutionEnvironment.canUseDOM && 'documentMode' in document && document.documentMode <= 11; + }, -var eventTypes$3 = { - select: { - phasedRegistrationNames: { - bubbled: 'onSelect', - captured: 'onSelectCapture' - }, - dependencies: ['topBlur', 'topContextMenu', 'topFocus', 'topKeyDown', 'topKeyUp', 'topMouseDown', 'topMouseUp', 'topSelectionChange'] - } -}; + set: function ( value ) { -var activeElement$1 = null; -var activeElementInst$1 = null; -var lastSelection = null; -var mouseDown = false; + console.warn( 'THREE.OrbitControls: .noKeys has been deprecated. Use .enableKeys instead.' ); + this.enableKeys = ! value; -/** - * Get an object which is a unique representation of the current selection. - * - * The return value will not be consistent across nodes or browsers, but - * two identical selections on the same node will return identical objects. - * - * @param {DOMElement} node - * @return {object} - */ -function getSelection(node) { - if ('selectionStart' in node && hasSelectionCapabilities(node)) { - return { - start: node.selectionStart, - end: node.selectionEnd - }; - } else if (window.getSelection) { - var selection = window.getSelection(); - return { - anchorNode: selection.anchorNode, - anchorOffset: selection.anchorOffset, - focusNode: selection.focusNode, - focusOffset: selection.focusOffset - }; - } -} + } -/** - * Poll selection to see whether it's changed. - * - * @param {object} nativeEvent - * @return {?SyntheticEvent} - */ -function constructSelectEvent(nativeEvent, nativeEventTarget) { - // Ensure we have the right element, and that the user is not dragging a - // selection (this matches native `select` event behavior). In HTML5, select - // fires only on input and textarea thus if there's no focused element we - // won't dispatch. - if (mouseDown || activeElement$1 == null || activeElement$1 !== getActiveElement()) { - return null; - } + }, - // Only fire when selection has actually changed. - var currentSelection = getSelection(activeElement$1); - if (!lastSelection || !shallowEqual(lastSelection, currentSelection)) { - lastSelection = currentSelection; + staticMoving : { - var syntheticEvent = SyntheticEvent$1.getPooled(eventTypes$3.select, activeElementInst$1, nativeEvent, nativeEventTarget); + get: function () { - syntheticEvent.type = 'select'; - syntheticEvent.target = activeElement$1; + console.warn( 'THREE.OrbitControls: .staticMoving has been deprecated. Use .enableDamping instead.' ); + return ! this.enableDamping; - accumulateTwoPhaseDispatches(syntheticEvent); + }, - return syntheticEvent; - } + set: function ( value ) { - return null; -} + console.warn( 'THREE.OrbitControls: .staticMoving has been deprecated. Use .enableDamping instead.' ); + this.enableDamping = ! value; -/** - * This plugin creates an `onSelect` event that normalizes select events - * across form elements. - * - * Supported elements are: - * - input (see `isTextInputElement`) - * - textarea - * - contentEditable - * - * This differs from native browser implementations in the following ways: - * - Fires on contentEditable fields as well as inputs. - * - Fires for collapsed selection. - * - Fires after user input. - */ -var SelectEventPlugin = { - eventTypes: eventTypes$3, + } - extractEvents: function (topLevelType, targetInst, nativeEvent, nativeEventTarget) { - var doc = nativeEventTarget.window === nativeEventTarget ? nativeEventTarget.document : nativeEventTarget.nodeType === DOCUMENT_NODE ? nativeEventTarget : nativeEventTarget.ownerDocument; - // Track whether all listeners exists for this plugin. If none exist, we do - // not extract events. See #3639. - if (!doc || !isListeningToAllDependencies('onSelect', doc)) { - return null; - } + }, - var targetNode = targetInst ? getNodeFromInstance$1(targetInst) : window; + dynamicDampingFactor : { - switch (topLevelType) { - // Track the input node that has focus. - case 'topFocus': - if (isTextInputElement(targetNode) || targetNode.contentEditable === 'true') { - activeElement$1 = targetNode; - activeElementInst$1 = targetInst; - lastSelection = null; - } - break; - case 'topBlur': - activeElement$1 = null; - activeElementInst$1 = null; - lastSelection = null; - break; - // Don't fire the event while the user is dragging. This matches the - // semantics of the native select event. - case 'topMouseDown': - mouseDown = true; - break; - case 'topContextMenu': - case 'topMouseUp': - mouseDown = false; - return constructSelectEvent(nativeEvent, nativeEventTarget); - // Chrome and IE fire non-standard event when selection is changed (and - // sometimes when it hasn't). IE's event fires out of order with respect - // to key and input events on deletion, so we discard it. - // - // Firefox doesn't support selectionchange, so check selection status - // after each key entry. The selection changes after keydown and before - // keyup, but we check on keydown as well in the case of holding down a - // key, when multiple keydown events are fired but only one keyup is. - // This is also our approach for IE handling, for the reason above. - case 'topSelectionChange': - if (skipSelectionChangeEvent) { - break; - } - // falls through - case 'topKeyDown': - case 'topKeyUp': - return constructSelectEvent(nativeEvent, nativeEventTarget); - } + get: function () { - return null; - } -}; + console.warn( 'THREE.OrbitControls: .dynamicDampingFactor has been renamed. Use .dampingFactor instead.' ); + return this.dampingFactor; -/** - * @interface Event - * @see http://www.w3.org/TR/css3-animations/#AnimationEvent-interface - * @see https://developer.mozilla.org/en-US/docs/Web/API/AnimationEvent - */ -var AnimationEventInterface = { - animationName: null, - elapsedTime: null, - pseudoElement: null -}; + }, -/** - * @param {object} dispatchConfig Configuration used to dispatch this event. - * @param {string} dispatchMarker Marker identifying the event target. - * @param {object} nativeEvent Native browser event. - * @extends {SyntheticEvent} - */ -function SyntheticAnimationEvent(dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget) { - return SyntheticEvent$1.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget); -} + set: function ( value ) { -SyntheticEvent$1.augmentClass(SyntheticAnimationEvent, AnimationEventInterface); + console.warn( 'THREE.OrbitControls: .dynamicDampingFactor has been renamed. Use .dampingFactor instead.' ); + this.dampingFactor = value; -/** - * @interface Event - * @see http://www.w3.org/TR/clipboard-apis/ - */ -var ClipboardEventInterface = { - clipboardData: function (event) { - return 'clipboardData' in event ? event.clipboardData : window.clipboardData; - } -}; + } -/** - * @param {object} dispatchConfig Configuration used to dispatch this event. - * @param {string} dispatchMarker Marker identifying the event target. - * @param {object} nativeEvent Native browser event. - * @extends {SyntheticEvent} - */ -function SyntheticClipboardEvent(dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget) { - return SyntheticEvent$1.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget); -} + } -SyntheticEvent$1.augmentClass(SyntheticClipboardEvent, ClipboardEventInterface); + } ); -/** - * @interface FocusEvent - * @see http://www.w3.org/TR/DOM-Level-3-Events/ - */ -var FocusEventInterface = { - relatedTarget: null + return OrbitControls; }; -/** - * @param {object} dispatchConfig Configuration used to dispatch this event. - * @param {string} dispatchMarker Marker identifying the event target. - * @param {object} nativeEvent Native browser event. - * @extends {SyntheticUIEvent} - */ -function SyntheticFocusEvent(dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget) { - return SyntheticUIEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget); -} - -SyntheticUIEvent.augmentClass(SyntheticFocusEvent, FocusEventInterface); - -/** - * `charCode` represents the actual "character code" and is safe to use with - * `String.fromCharCode`. As such, only keys that correspond to printable - * characters produce a valid `charCode`, the only exception to this is Enter. - * The Tab-key is considered non-printable and does not have a `charCode`, - * presumably because it does not produce a tab-character in browsers. - * - * @param {object} nativeEvent Native browser event. - * @return {number} Normalized `charCode` property. - */ -function getEventCharCode(nativeEvent) { - var charCode; - var keyCode = nativeEvent.keyCode; - if ('charCode' in nativeEvent) { - charCode = nativeEvent.charCode; +/***/ }), +/* 14 */ +/***/ (function(module, exports, __webpack_require__) { - // FF does not set `charCode` for the Enter-key, check against `keyCode`. - if (charCode === 0 && keyCode === 13) { - charCode = 13; - } +var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;(function (global, factory) { + if (true) { + !(__WEBPACK_AMD_DEFINE_ARRAY__ = [module, __webpack_require__(33), __webpack_require__(48), __webpack_require__(49), __webpack_require__(50), __webpack_require__(51), __webpack_require__(52), __webpack_require__(53), __webpack_require__(54), __webpack_require__(55), __webpack_require__(65), __webpack_require__(56), __webpack_require__(57), __webpack_require__(58), __webpack_require__(59), __webpack_require__(60), __webpack_require__(61), __webpack_require__(62), __webpack_require__(63), __webpack_require__(64)], __WEBPACK_AMD_DEFINE_FACTORY__ = (factory), + __WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ? + (__WEBPACK_AMD_DEFINE_FACTORY__.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__)) : __WEBPACK_AMD_DEFINE_FACTORY__), + __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); + } else if (typeof exports !== "undefined") { + factory(module, require('./BarLoader'), require('./BeatLoader'), require('./BounceLoader'), require('./CircleLoader'), require('./ClipLoader'), require('./ClimbingBoxLoader'), require('./DotLoader'), require('./FadeLoader'), require('./GridLoader'), require('./HashLoader'), require('./MoonLoader'), require('./PacmanLoader'), require('./PropagateLoader'), require('./PulseLoader'), require('./RingLoader'), require('./RiseLoader'), require('./RotateLoader'), require('./ScaleLoader'), require('./SyncLoader')); } else { - // IE8 does not implement `charCode`, but `keyCode` has the correct value. - charCode = keyCode; + var mod = { + exports: {} + }; + factory(mod, global.BarLoader, global.BeatLoader, global.BounceLoader, global.CircleLoader, global.ClipLoader, global.ClimbingBoxLoader, global.DotLoader, global.FadeLoader, global.GridLoader, global.HashLoader, global.MoonLoader, global.PacmanLoader, global.PropagateLoader, global.PulseLoader, global.RingLoader, global.RiseLoader, global.RotateLoader, global.ScaleLoader, global.SyncLoader); + global.index = mod.exports; } +})(this, function (module, _BarLoader, _BeatLoader, _BounceLoader, _CircleLoader, _ClipLoader, _ClimbingBoxLoader, _DotLoader, _FadeLoader, _GridLoader, _HashLoader, _MoonLoader, _PacmanLoader, _PropagateLoader, _PulseLoader, _RingLoader, _RiseLoader, _RotateLoader, _ScaleLoader, _SyncLoader) { + 'use strict'; - // Some non-printable keys are reported in `charCode`/`keyCode`, discard them. - // Must not discard the (non-)printable Enter-key. - if (charCode >= 32 || charCode === 13) { - return charCode; - } + var _BarLoader2 = _interopRequireDefault(_BarLoader); - return 0; -} + var _BeatLoader2 = _interopRequireDefault(_BeatLoader); -/** - * Normalization of deprecated HTML5 `key` values - * @see https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent#Key_names - */ -var normalizeKey = { - Esc: 'Escape', - Spacebar: ' ', - Left: 'ArrowLeft', - Up: 'ArrowUp', - Right: 'ArrowRight', - Down: 'ArrowDown', - Del: 'Delete', - Win: 'OS', - Menu: 'ContextMenu', - Apps: 'ContextMenu', - Scroll: 'ScrollLock', - MozPrintableKey: 'Unidentified' -}; + var _BounceLoader2 = _interopRequireDefault(_BounceLoader); -/** - * Translation from legacy `keyCode` to HTML5 `key` - * Only special keys supported, all others depend on keyboard layout or browser - * @see https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent#Key_names - */ -var translateToKey = { - '8': 'Backspace', - '9': 'Tab', - '12': 'Clear', - '13': 'Enter', - '16': 'Shift', - '17': 'Control', - '18': 'Alt', - '19': 'Pause', - '20': 'CapsLock', - '27': 'Escape', - '32': ' ', - '33': 'PageUp', - '34': 'PageDown', - '35': 'End', - '36': 'Home', - '37': 'ArrowLeft', - '38': 'ArrowUp', - '39': 'ArrowRight', - '40': 'ArrowDown', - '45': 'Insert', - '46': 'Delete', - '112': 'F1', - '113': 'F2', - '114': 'F3', - '115': 'F4', - '116': 'F5', - '117': 'F6', - '118': 'F7', - '119': 'F8', - '120': 'F9', - '121': 'F10', - '122': 'F11', - '123': 'F12', - '144': 'NumLock', - '145': 'ScrollLock', - '224': 'Meta' -}; + var _CircleLoader2 = _interopRequireDefault(_CircleLoader); -/** - * @param {object} nativeEvent Native browser event. - * @return {string} Normalized `key` property. - */ -function getEventKey(nativeEvent) { - if (nativeEvent.key) { - // Normalize inconsistent values reported by browsers due to - // implementations of a working draft specification. + var _ClipLoader2 = _interopRequireDefault(_ClipLoader); - // FireFox implements `key` but returns `MozPrintableKey` for all - // printable characters (normalized to `Unidentified`), ignore it. - var key = normalizeKey[nativeEvent.key] || nativeEvent.key; - if (key !== 'Unidentified') { - return key; - } - } + var _ClimbingBoxLoader2 = _interopRequireDefault(_ClimbingBoxLoader); - // Browser does not implement `key`, polyfill as much of it as we can. - if (nativeEvent.type === 'keypress') { - var charCode = getEventCharCode(nativeEvent); + var _DotLoader2 = _interopRequireDefault(_DotLoader); - // The enter-key is technically both printable and non-printable and can - // thus be captured by `keypress`, no other non-printable key should. - return charCode === 13 ? 'Enter' : String.fromCharCode(charCode); - } - if (nativeEvent.type === 'keydown' || nativeEvent.type === 'keyup') { - // While user keyboard layout determines the actual meaning of each - // `keyCode` value, almost all function keys have a universal value. - return translateToKey[nativeEvent.keyCode] || 'Unidentified'; - } - return ''; -} + var _FadeLoader2 = _interopRequireDefault(_FadeLoader); -/** - * @interface KeyboardEvent - * @see http://www.w3.org/TR/DOM-Level-3-Events/ - */ -var KeyboardEventInterface = { - key: getEventKey, - location: null, - ctrlKey: null, - shiftKey: null, - altKey: null, - metaKey: null, - repeat: null, - locale: null, - getModifierState: getEventModifierState, - // Legacy Interface - charCode: function (event) { - // `charCode` is the result of a KeyPress event and represents the value of - // the actual printable character. + var _GridLoader2 = _interopRequireDefault(_GridLoader); - // KeyPress is deprecated, but its replacement is not yet final and not - // implemented in any major browser. Only KeyPress has charCode. - if (event.type === 'keypress') { - return getEventCharCode(event); - } - return 0; - }, - keyCode: function (event) { - // `keyCode` is the result of a KeyDown/Up event and represents the value of - // physical keyboard key. + var _HashLoader2 = _interopRequireDefault(_HashLoader); - // The actual meaning of the value depends on the users' keyboard layout - // which cannot be detected. Assuming that it is a US keyboard layout - // provides a surprisingly accurate mapping for US and European users. - // Due to this, it is left to the user to implement at this time. - if (event.type === 'keydown' || event.type === 'keyup') { - return event.keyCode; - } - return 0; - }, - which: function (event) { - // `which` is an alias for either `keyCode` or `charCode` depending on the - // type of the event. - if (event.type === 'keypress') { - return getEventCharCode(event); - } - if (event.type === 'keydown' || event.type === 'keyup') { - return event.keyCode; - } - return 0; + var _MoonLoader2 = _interopRequireDefault(_MoonLoader); + + var _PacmanLoader2 = _interopRequireDefault(_PacmanLoader); + + var _PropagateLoader2 = _interopRequireDefault(_PropagateLoader); + + var _PulseLoader2 = _interopRequireDefault(_PulseLoader); + + var _RingLoader2 = _interopRequireDefault(_RingLoader); + + var _RiseLoader2 = _interopRequireDefault(_RiseLoader); + + var _RotateLoader2 = _interopRequireDefault(_RotateLoader); + + var _ScaleLoader2 = _interopRequireDefault(_ScaleLoader); + + var _SyncLoader2 = _interopRequireDefault(_SyncLoader); + + function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { + default: obj + }; } -}; -/** - * @param {object} dispatchConfig Configuration used to dispatch this event. - * @param {string} dispatchMarker Marker identifying the event target. - * @param {object} nativeEvent Native browser event. - * @extends {SyntheticUIEvent} - */ -function SyntheticKeyboardEvent(dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget) { - return SyntheticUIEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget); -} + module.exports = { + BarLoader: _BarLoader2.default, + BeatLoader: _BeatLoader2.default, + BounceLoader: _BounceLoader2.default, + CircleLoader: _CircleLoader2.default, + ClipLoader: _ClipLoader2.default, + ClimbingBoxLoader: _ClimbingBoxLoader2.default, + DotLoader: _DotLoader2.default, + FadeLoader: _FadeLoader2.default, + GridLoader: _GridLoader2.default, + HashLoader: _HashLoader2.default, + MoonLoader: _MoonLoader2.default, + PacmanLoader: _PacmanLoader2.default, + PropagateLoader: _PropagateLoader2.default, + PulseLoader: _PulseLoader2.default, + RingLoader: _RingLoader2.default, + RiseLoader: _RiseLoader2.default, + RotateLoader: _RotateLoader2.default, + ScaleLoader: _ScaleLoader2.default, + SyncLoader: _SyncLoader2.default + }; +}); -SyntheticUIEvent.augmentClass(SyntheticKeyboardEvent, KeyboardEventInterface); +/***/ }), +/* 15 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { -/** - * @interface DragEvent - * @see http://www.w3.org/TR/DOM-Level-3-Events/ - */ -var DragEventInterface = { - dataTransfer: null -}; +"use strict"; +/* WEBPACK VAR INJECTION */(function(process) {/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return StyleSheet; }); +/* -/** - * @param {object} dispatchConfig Configuration used to dispatch this event. - * @param {string} dispatchMarker Marker identifying the event target. - * @param {object} nativeEvent Native browser event. - * @extends {SyntheticMouseEvent} - */ -function SyntheticDragEvent(dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget) { - return SyntheticMouseEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget); -} +Based off glamor's StyleSheet, thanks Sunil ❤️ -SyntheticMouseEvent.augmentClass(SyntheticDragEvent, DragEventInterface); +high performance StyleSheet for css-in-js systems -/** - * @interface TouchEvent - * @see http://www.w3.org/TR/touch-events/ - */ -var TouchEventInterface = { - touches: null, - targetTouches: null, - changedTouches: null, - altKey: null, - metaKey: null, - ctrlKey: null, - shiftKey: null, - getModifierState: getEventModifierState -}; +- uses multiple style tags behind the scenes for millions of rules +- uses `insertRule` for appending in production for *much* faster performance -/** - * @param {object} dispatchConfig Configuration used to dispatch this event. - * @param {string} dispatchMarker Marker identifying the event target. - * @param {object} nativeEvent Native browser event. - * @extends {SyntheticUIEvent} - */ -function SyntheticTouchEvent(dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget) { - return SyntheticUIEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget); -} +// usage -SyntheticUIEvent.augmentClass(SyntheticTouchEvent, TouchEventInterface); +import { StyleSheet } from '@emotion/sheet' -/** - * @interface Event - * @see http://www.w3.org/TR/2009/WD-css3-transitions-20090320/#transition-events- - * @see https://developer.mozilla.org/en-US/docs/Web/API/TransitionEvent - */ -var TransitionEventInterface = { - propertyName: null, - elapsedTime: null, - pseudoElement: null -}; +let styleSheet = new StyleSheet({ key: '', container: document.head }) -/** - * @param {object} dispatchConfig Configuration used to dispatch this event. - * @param {string} dispatchMarker Marker identifying the event target. - * @param {object} nativeEvent Native browser event. - * @extends {SyntheticEvent} - */ -function SyntheticTransitionEvent(dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget) { - return SyntheticEvent$1.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget); -} +styleSheet.insert('#box { border: 1px solid red; }') +- appends a css rule into the stylesheet -SyntheticEvent$1.augmentClass(SyntheticTransitionEvent, TransitionEventInterface); +styleSheet.flush() +- empties the stylesheet of all its contents -/** - * @interface WheelEvent - * @see http://www.w3.org/TR/DOM-Level-3-Events/ - */ -var WheelEventInterface = { - deltaX: function (event) { - return 'deltaX' in event ? event.deltaX : // Fallback to `wheelDeltaX` for Webkit and normalize (right is positive). - 'wheelDeltaX' in event ? -event.wheelDeltaX : 0; - }, - deltaY: function (event) { - return 'deltaY' in event ? event.deltaY : // Fallback to `wheelDeltaY` for Webkit and normalize (down is positive). - 'wheelDeltaY' in event ? -event.wheelDeltaY : // Fallback to `wheelDelta` for IE<9 and normalize (down is positive). - 'wheelDelta' in event ? -event.wheelDelta : 0; - }, - deltaZ: null, +*/ +// $FlowFixMe +function sheetForTag(tag) { + if (tag.sheet) { + // $FlowFixMe + return tag.sheet; + } // this weirdness brought to you by firefox - // Browsers without "deltaMode" is reporting in raw wheel delta where one - // notch on the scroll is always +/- 120, roughly equivalent to pixels. - // A good approximation of DOM_DELTA_LINE (1) is 5% of viewport size or - // ~40 pixels, for DOM_DELTA_SCREEN (2) it is 87.5% of viewport size. - deltaMode: null -}; + /* istanbul ignore next */ -/** - * @param {object} dispatchConfig Configuration used to dispatch this event. - * @param {string} dispatchMarker Marker identifying the event target. - * @param {object} nativeEvent Native browser event. - * @extends {SyntheticMouseEvent} - */ -function SyntheticWheelEvent(dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget) { - return SyntheticMouseEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget); + + for (var i = 0; i < document.styleSheets.length; i++) { + if (document.styleSheets[i].ownerNode === tag) { + // $FlowFixMe + return document.styleSheets[i]; + } + } } -SyntheticMouseEvent.augmentClass(SyntheticWheelEvent, WheelEventInterface); +function createStyleElement(options) { + var tag = document.createElement('style'); + tag.setAttribute('data-emotion', options.key); -/** - * Turns - * ['abort', ...] - * into - * eventTypes = { - * 'abort': { - * phasedRegistrationNames: { - * bubbled: 'onAbort', - * captured: 'onAbortCapture', - * }, - * dependencies: ['topAbort'], - * }, - * ... - * }; - * topLevelEventsToDispatchConfig = { - * 'topAbort': { sameConfig } - * }; - */ -var eventTypes$4 = {}; -var topLevelEventsToDispatchConfig = {}; -['abort', 'animationEnd', 'animationIteration', 'animationStart', 'blur', 'cancel', 'canPlay', 'canPlayThrough', 'click', 'close', 'contextMenu', 'copy', 'cut', 'doubleClick', 'drag', 'dragEnd', 'dragEnter', 'dragExit', 'dragLeave', 'dragOver', 'dragStart', 'drop', 'durationChange', 'emptied', 'encrypted', 'ended', 'error', 'focus', 'input', 'invalid', 'keyDown', 'keyPress', 'keyUp', 'load', 'loadedData', 'loadedMetadata', 'loadStart', 'mouseDown', 'mouseMove', 'mouseOut', 'mouseOver', 'mouseUp', 'paste', 'pause', 'play', 'playing', 'progress', 'rateChange', 'reset', 'scroll', 'seeked', 'seeking', 'stalled', 'submit', 'suspend', 'timeUpdate', 'toggle', 'touchCancel', 'touchEnd', 'touchMove', 'touchStart', 'transitionEnd', 'volumeChange', 'waiting', 'wheel'].forEach(function (event) { - var capitalizedEvent = event[0].toUpperCase() + event.slice(1); - var onEvent = 'on' + capitalizedEvent; - var topEvent = 'top' + capitalizedEvent; + if (options.nonce !== undefined) { + tag.setAttribute('nonce', options.nonce); + } - var type = { - phasedRegistrationNames: { - bubbled: onEvent, - captured: onEvent + 'Capture' - }, - dependencies: [topEvent] - }; - eventTypes$4[event] = type; - topLevelEventsToDispatchConfig[topEvent] = type; -}); + tag.appendChild(document.createTextNode('')); + return tag; +} -// Only used in DEV for exhaustiveness validation. -var knownHTMLTopLevelTypes = ['topAbort', 'topCancel', 'topCanPlay', 'topCanPlayThrough', 'topClose', 'topDurationChange', 'topEmptied', 'topEncrypted', 'topEnded', 'topError', 'topInput', 'topInvalid', 'topLoad', 'topLoadedData', 'topLoadedMetadata', 'topLoadStart', 'topPause', 'topPlay', 'topPlaying', 'topProgress', 'topRateChange', 'topReset', 'topSeeked', 'topSeeking', 'topStalled', 'topSubmit', 'topSuspend', 'topTimeUpdate', 'topToggle', 'topVolumeChange', 'topWaiting']; +var StyleSheet = +/*#__PURE__*/ +function () { + function StyleSheet(options) { + this.isSpeedy = options.speedy === undefined ? process.env.NODE_ENV === 'production' : options.speedy; + this.tags = []; + this.ctr = 0; + this.nonce = options.nonce; // key is the value of the data-emotion attribute, it's used to identify different sheets -var SimpleEventPlugin = { - eventTypes: eventTypes$4, + this.key = options.key; + this.container = options.container; + this.before = null; + } - extractEvents: function (topLevelType, targetInst, nativeEvent, nativeEventTarget) { - var dispatchConfig = topLevelEventsToDispatchConfig[topLevelType]; - if (!dispatchConfig) { - return null; + var _proto = StyleSheet.prototype; + + _proto.insert = function insert(rule) { + // the max length is how many rules we have per style tag, it's 65000 in speedy mode + // it's 1 in dev because we insert source maps that map a single rule to a location + // and you can only have one source map per style tag + if (this.ctr % (this.isSpeedy ? 65000 : 1) === 0) { + var _tag = createStyleElement(this); + + var before; + + if (this.tags.length === 0) { + before = this.before; + } else { + before = this.tags[this.tags.length - 1].nextSibling; + } + + this.container.insertBefore(_tag, before); + this.tags.push(_tag); } - var EventConstructor; - switch (topLevelType) { - case 'topKeyPress': - // Firefox creates a keypress event for function keys too. This removes - // the unwanted keypress events. Enter is however both printable and - // non-printable. One would expect Tab to be as well (but it isn't). - if (getEventCharCode(nativeEvent) === 0) { - return null; - } - /* falls through */ - case 'topKeyDown': - case 'topKeyUp': - EventConstructor = SyntheticKeyboardEvent; - break; - case 'topBlur': - case 'topFocus': - EventConstructor = SyntheticFocusEvent; - break; - case 'topClick': - // Firefox creates a click event on right mouse clicks. This removes the - // unwanted click events. - if (nativeEvent.button === 2) { - return null; - } - /* falls through */ - case 'topDoubleClick': - case 'topMouseDown': - case 'topMouseMove': - case 'topMouseUp': - // TODO: Disabled elements should not respond to mouse events - /* falls through */ - case 'topMouseOut': - case 'topMouseOver': - case 'topContextMenu': - EventConstructor = SyntheticMouseEvent; - break; - case 'topDrag': - case 'topDragEnd': - case 'topDragEnter': - case 'topDragExit': - case 'topDragLeave': - case 'topDragOver': - case 'topDragStart': - case 'topDrop': - EventConstructor = SyntheticDragEvent; - break; - case 'topTouchCancel': - case 'topTouchEnd': - case 'topTouchMove': - case 'topTouchStart': - EventConstructor = SyntheticTouchEvent; - break; - case 'topAnimationEnd': - case 'topAnimationIteration': - case 'topAnimationStart': - EventConstructor = SyntheticAnimationEvent; - break; - case 'topTransitionEnd': - EventConstructor = SyntheticTransitionEvent; - break; - case 'topScroll': - EventConstructor = SyntheticUIEvent; - break; - case 'topWheel': - EventConstructor = SyntheticWheelEvent; - break; - case 'topCopy': - case 'topCut': - case 'topPaste': - EventConstructor = SyntheticClipboardEvent; - break; - default: - { - if (knownHTMLTopLevelTypes.indexOf(topLevelType) === -1) { - warning(false, 'SimpleEventPlugin: Unhandled event type, `%s`. This warning ' + 'is likely caused by a bug in React. Please file an issue.', topLevelType); - } + + var tag = this.tags[this.tags.length - 1]; + + if (this.isSpeedy) { + var sheet = sheetForTag(tag); + + try { + // this is a really hot path + // we check the second character first because having "i" + // as the second character will happen less often than + // having "@" as the first character + var isImportRule = rule.charCodeAt(1) === 105 && rule.charCodeAt(0) === 64; // this is the ultrafast version, works across browsers + // the big drawback is that the css won't be editable in devtools + + sheet.insertRule(rule, // we need to insert @import rules before anything else + // otherwise there will be an error + // technically this means that the @import rules will + // _usually_(not always since there could be multiple style tags) + // be the first ones in prod and generally later in dev + // this shouldn't really matter in the real world though + // @import is generally only used for font faces from google fonts and etc. + // so while this could be technically correct then it would be slower and larger + // for a tiny bit of correctness that won't matter in the real world + isImportRule ? 0 : sheet.cssRules.length); + } catch (e) { + if (process.env.NODE_ENV !== 'production') { + console.warn("There was a problem inserting the following rule: \"" + rule + "\"", e); } - // HTML Events - // @see http://www.w3.org/TR/html5/index.html#events-0 - EventConstructor = SyntheticEvent$1; - break; + } + } else { + tag.appendChild(document.createTextNode(rule)); } - var event = EventConstructor.getPooled(dispatchConfig, targetInst, nativeEvent, nativeEventTarget); - accumulateTwoPhaseDispatches(event); - return event; - } -}; -setHandleTopLevel(handleTopLevel); + this.ctr++; + }; -/** - * Inject modules for resolving DOM hierarchy and plugin ordering. - */ -injection$1.injectEventPluginOrder(DOMEventPluginOrder); -injection$2.injectComponentTree(ReactDOMComponentTree); + _proto.flush = function flush() { + // $FlowFixMe + this.tags.forEach(function (tag) { + return tag.parentNode.removeChild(tag); + }); + this.tags = []; + this.ctr = 0; + }; -/** - * Some important event plugins included by default (without having to require - * them). - */ -injection$1.injectEventPluginsByName({ - SimpleEventPlugin: SimpleEventPlugin, - EnterLeaveEventPlugin: EnterLeaveEventPlugin, - ChangeEventPlugin: ChangeEventPlugin, - SelectEventPlugin: SelectEventPlugin, - BeforeInputEventPlugin: BeforeInputEventPlugin -}); + return StyleSheet; +}(); -var enableAsyncSubtreeAPI = true; -var enableAsyncSchedulingByDefaultInReactDOM = false; -// Exports ReactDOM.createRoot -var enableCreateRoot = false; -var enableUserTimingAPI = true; -// Mutating mode (React DOM, React ART, React Native): -var enableMutatingReconciler = true; -// Experimental noop mode (currently unused): -var enableNoopReconciler = false; -// Experimental persistent mode (CS): -var enablePersistentReconciler = false; -// Helps identify side effects in begin-phase lifecycle hooks and setState reducers: -var debugRenderPhaseSideEffects = false; +/* WEBPACK VAR INJECTION */}.call(__webpack_exports__, __webpack_require__(0))) -// Only used in www builds. +/***/ }), +/* 16 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { -var valueStack = []; +"use strict"; +/* WEBPACK VAR INJECTION */(function(process) {/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return serializeStyles; }); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__emotion_hash__ = __webpack_require__(38); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__emotion_unitless__ = __webpack_require__(39); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__emotion_memoize__ = __webpack_require__(40); -{ - var fiberStack = []; -} -var index = -1; -function createCursor(defaultValue) { - return { - current: defaultValue - }; -} +var hyphenateRegex = /[A-Z]|^ms/g; +var animationRegex = /_EMO_([^_]+?)_([^]*?)_EMO_/g; +var processStyleName = Object(__WEBPACK_IMPORTED_MODULE_2__emotion_memoize__["a" /* default */])(function (styleName) { + return styleName.replace(hyphenateRegex, '-$&').toLowerCase(); +}); +var processStyleValue = function processStyleValue(key, value) { + if (value == null || typeof value === 'boolean') { + return ''; + } -function pop(cursor, fiber) { - if (index < 0) { - { - warning(false, 'Unexpected pop.'); - } - return; + switch (key) { + case 'animation': + case 'animationName': + { + if (typeof value === 'string') { + value = value.replace(animationRegex, function (match, p1, p2) { + cursor = { + name: p1, + styles: p2, + next: cursor + }; + return p1; + }); + } + } } - { - if (fiber !== fiberStack[index]) { - warning(false, 'Unexpected Fiber popped.'); - } + if (__WEBPACK_IMPORTED_MODULE_1__emotion_unitless__["a" /* default */][key] !== 1 && key.charCodeAt(1) !== 45 && // custom properties + typeof value === 'number' && value !== 0) { + return value + 'px'; } - cursor.current = valueStack[index]; + return value; +}; - valueStack[index] = null; +if (process.env.NODE_ENV !== 'production') { + var contentValuePattern = /(attr|calc|counters?|url)\(/; + var contentValues = ['normal', 'none', 'counter', 'open-quote', 'close-quote', 'no-open-quote', 'no-close-quote', 'initial', 'inherit', 'unset']; + var oldProcessStyleValue = processStyleValue; + var msPattern = /^-ms-/; + var hyphenPattern = /-(.)/g; + var hyphenatedCache = {}; + + processStyleValue = function processStyleValue(key, value) { + if (key === 'content') { + if (typeof value !== 'string' || contentValues.indexOf(value) === -1 && !contentValuePattern.test(value) && (value.charAt(0) !== value.charAt(value.length - 1) || value.charAt(0) !== '"' && value.charAt(0) !== "'")) { + console.error("You seem to be using a value for 'content' without quotes, try replacing it with `content: '\"" + value + "\"'`"); + } + } - { - fiberStack[index] = null; - } + if (key.charCodeAt(1) !== 45 && key.indexOf('-') !== -1 && hyphenatedCache[key] === undefined) { + hyphenatedCache[key] = true; + console.error("Using kebab-case for css properties in objects is not supported. Did you mean " + key.replace(msPattern, 'ms-').replace(hyphenPattern, function (str, char) { + return char.toUpperCase(); + }) + "?"); + } - index--; + return oldProcessStyleValue(key, value); + }; } -function push(cursor, value, fiber) { - index++; +var shouldWarnAboutInterpolatingClassNameFromCss = true; - valueStack[index] = cursor.current; +function handleInterpolation(mergedProps, registered, interpolation, couldBeSelectorInterpolation) { + if (interpolation == null) { + return ''; + } - { - fiberStack[index] = fiber; + if (interpolation.__emotion_styles !== undefined) { + if (process.env.NODE_ENV !== 'production' && interpolation.toString() === 'NO_COMPONENT_SELECTOR') { + throw new Error('Component selectors can only be used in conjunction with babel-plugin-emotion.'); + } + + return interpolation; } - cursor.current = value; -} + switch (typeof interpolation) { + case 'boolean': + { + return ''; + } -function reset$1() { - while (index > -1) { - valueStack[index] = null; + case 'object': + { + if (interpolation.anim === 1) { + cursor = { + name: interpolation.name, + styles: interpolation.styles, + next: cursor + }; + return interpolation.name; + } - { - fiberStack[index] = null; - } + if (interpolation.styles !== undefined) { + var next = interpolation.next; + + if (next !== undefined) { + // not the most efficient thing ever but this is a pretty rare case + // and there will be very few iterations of this generally + while (next !== undefined) { + cursor = { + name: next.name, + styles: next.styles, + next: cursor + }; + next = next.next; + } + } - index--; - } -} + var styles = interpolation.styles; -var describeComponentFrame = function (name, source, ownerName) { - return '\n in ' + (name || 'Unknown') + (source ? ' (at ' + source.fileName.replace(/^.*[\\\/]/, '') + ':' + source.lineNumber + ')' : ownerName ? ' (created by ' + ownerName + ')' : ''); -}; + if (process.env.NODE_ENV !== 'production' && interpolation.map !== undefined) { + styles += interpolation.map; + } -function describeFiber(fiber) { - switch (fiber.tag) { - case IndeterminateComponent: - case FunctionalComponent: - case ClassComponent: - case HostComponent: - var owner = fiber._debugOwner; - var source = fiber._debugSource; - var name = getComponentName(fiber); - var ownerName = null; - if (owner) { - ownerName = getComponentName(owner); + return styles; + } + + return createStringFromObject(mergedProps, registered, interpolation); } - return describeComponentFrame(name, source, ownerName); + + case 'function': + { + if (mergedProps !== undefined) { + var previousCursor = cursor; + var result = interpolation(mergedProps); + cursor = previousCursor; + return handleInterpolation(mergedProps, registered, result, couldBeSelectorInterpolation); + } else if (process.env.NODE_ENV !== 'production') { + console.error('Functions that are interpolated in css calls will be stringified.\n' + 'If you want to have a css call based on props, create a function that returns a css call like this\n' + 'let dynamicStyle = (props) => css`color: ${props.color}`\n' + 'It can be called directly with props or interpolated in a styled call like this\n' + "let SomeComponent = styled('div')`${dynamicStyle}`"); + } + } + // eslint-disable-next-line no-fallthrough + default: - return ''; + { + if (registered == null) { + return interpolation; + } + + var cached = registered[interpolation]; + + if (process.env.NODE_ENV !== 'production' && couldBeSelectorInterpolation && shouldWarnAboutInterpolatingClassNameFromCss && cached !== undefined) { + console.error('Interpolating a className from css`` is not recommended and will cause problems with composition.\n' + 'Interpolating a className from css`` will be completely unsupported in a future major version of Emotion'); + shouldWarnAboutInterpolatingClassNameFromCss = false; + } + + return cached !== undefined && !couldBeSelectorInterpolation ? cached : interpolation; + } } } -// This function can only be called with a work-in-progress fiber and -// only during begin or complete phase. Do not call it under any other -// circumstances. -function getStackAddendumByWorkInProgressFiber(workInProgress) { - var info = ''; - var node = workInProgress; - do { - info += describeFiber(node); - // Otherwise this return pointer might point to the wrong tree: - node = node['return']; - } while (node); - return info; -} +function createStringFromObject(mergedProps, registered, obj) { + var string = ''; -function getCurrentFiberOwnerName() { - { - var fiber = ReactDebugCurrentFiber.current; - if (fiber === null) { - return null; - } - var owner = fiber._debugOwner; - if (owner !== null && typeof owner !== 'undefined') { - return getComponentName(owner); + if (Array.isArray(obj)) { + for (var i = 0; i < obj.length; i++) { + string += handleInterpolation(mergedProps, registered, obj[i], false); } - } - return null; -} + } else { + for (var _key in obj) { + var value = obj[_key]; -function getCurrentFiberStackAddendum() { - { - var fiber = ReactDebugCurrentFiber.current; - if (fiber === null) { - return null; + if (typeof value !== 'object') { + if (registered != null && registered[value] !== undefined) { + string += _key + "{" + registered[value] + "}"; + } else { + string += processStyleName(_key) + ":" + processStyleValue(_key, value) + ";"; + } + } else { + if (_key === 'NO_COMPONENT_SELECTOR' && process.env.NODE_ENV !== 'production') { + throw new Error('Component selectors can only be used in conjunction with babel-plugin-emotion.'); + } + + if (Array.isArray(value) && typeof value[0] === 'string' && (registered == null || registered[value[0]] === undefined)) { + for (var _i = 0; _i < value.length; _i++) { + string += processStyleName(_key) + ":" + processStyleValue(_key, value[_i]) + ";"; + } + } else { + string += _key + "{" + handleInterpolation(mergedProps, registered, value, false) + "}"; + } + } } - // Safe because if current fiber exists, we are reconciling, - // and it is guaranteed to be the work-in-progress version. - return getStackAddendumByWorkInProgressFiber(fiber); } - return null; -} -function resetCurrentFiber() { - ReactDebugCurrentFrame.getCurrentStack = null; - ReactDebugCurrentFiber.current = null; - ReactDebugCurrentFiber.phase = null; + return string; } -function setCurrentFiber(fiber) { - ReactDebugCurrentFrame.getCurrentStack = getCurrentFiberStackAddendum; - ReactDebugCurrentFiber.current = fiber; - ReactDebugCurrentFiber.phase = null; -} +var labelPattern = /label:\s*([^\s;\n{]+)\s*;/g; +var sourceMapPattern; -function setCurrentPhase(phase) { - ReactDebugCurrentFiber.phase = phase; -} +if (process.env.NODE_ENV !== 'production') { + sourceMapPattern = /\/\*#\ssourceMappingURL=data:application\/json;\S+\s+\*\//; +} // this is the cursor for keyframes +// keyframes are stored on the SerializedStyles object as a linked list -var ReactDebugCurrentFiber = { - current: null, - phase: null, - resetCurrentFiber: resetCurrentFiber, - setCurrentFiber: setCurrentFiber, - setCurrentPhase: setCurrentPhase, - getCurrentFiberOwnerName: getCurrentFiberOwnerName, - getCurrentFiberStackAddendum: getCurrentFiberStackAddendum -}; -// Prefix measurements so that it's possible to filter them. -// Longer prefixes are hard to read in DevTools. -var reactEmoji = '\u269B'; -var warningEmoji = '\u26D4'; -var supportsUserTiming = typeof performance !== 'undefined' && typeof performance.mark === 'function' && typeof performance.clearMarks === 'function' && typeof performance.measure === 'function' && typeof performance.clearMeasures === 'function'; +var cursor; +var serializeStyles = function serializeStyles(args, registered, mergedProps) { + if (args.length === 1 && typeof args[0] === 'object' && args[0] !== null && args[0].styles !== undefined) { + return args[0]; + } -// Keep track of current fiber so that we know the path to unwind on pause. -// TODO: this looks the same as nextUnitOfWork in scheduler. Can we unify them? -var currentFiber = null; -// If we're in the middle of user code, which fiber and method is it? -// Reusing `currentFiber` would be confusing for this because user code fiber -// can change during commit phase too, but we don't need to unwind it (since -// lifecycles in the commit phase don't resemble a tree). -var currentPhase = null; -var currentPhaseFiber = null; -// Did lifecycle hook schedule an update? This is often a performance problem, -// so we will keep track of it, and include it in the report. -// Track commits caused by cascading updates. -var isCommitting = false; -var hasScheduledUpdateInCurrentCommit = false; -var hasScheduledUpdateInCurrentPhase = false; -var commitCountInCurrentWorkLoop = 0; -var effectCountInCurrentCommit = 0; -var isWaitingForCallback = false; -// During commits, we only show a measurement once per method name -// to avoid stretch the commit phase with measurement overhead. -var labelsInCurrentCommit = new Set(); + var stringMode = true; + var styles = ''; + cursor = undefined; + var strings = args[0]; -var formatMarkName = function (markName) { - return reactEmoji + ' ' + markName; -}; + if (strings == null || strings.raw === undefined) { + stringMode = false; + styles += handleInterpolation(mergedProps, registered, strings, false); + } else { + styles += strings[0]; + } // we start at 1 since we've already handled the first arg -var formatLabel = function (label, warning$$1) { - var prefix = warning$$1 ? warningEmoji + ' ' : reactEmoji + ' '; - var suffix = warning$$1 ? ' Warning: ' + warning$$1 : ''; - return '' + prefix + label + suffix; -}; -var beginMark = function (markName) { - performance.mark(formatMarkName(markName)); -}; + for (var i = 1; i < args.length; i++) { + styles += handleInterpolation(mergedProps, registered, args[i], styles.charCodeAt(styles.length - 1) === 46); -var clearMark = function (markName) { - performance.clearMarks(formatMarkName(markName)); -}; + if (stringMode) { + styles += strings[i]; + } + } -var endMark = function (label, markName, warning$$1) { - var formattedMarkName = formatMarkName(markName); - var formattedLabel = formatLabel(label, warning$$1); - try { - performance.measure(formattedLabel, formattedMarkName); - } catch (err) {} - // If previous mark was missing for some reason, this will throw. - // This could only happen if React crashed in an unexpected place earlier. - // Don't pile on with more errors. + var sourceMap; - // Clear marks immediately to avoid growing buffer. - performance.clearMarks(formattedMarkName); - performance.clearMeasures(formattedLabel); -}; + if (process.env.NODE_ENV !== 'production') { + styles = styles.replace(sourceMapPattern, function (match) { + sourceMap = match; + return ''; + }); + } // using a global regex with .exec is stateful so lastIndex has to be reset each time -var getFiberMarkName = function (label, debugID) { - return label + ' (#' + debugID + ')'; -}; -var getFiberLabel = function (componentName, isMounted, phase) { - if (phase === null) { - // These are composite component total time measurements. - return componentName + ' [' + (isMounted ? 'update' : 'mount') + ']'; - } else { - // Composite component methods. - return componentName + '.' + phase; + labelPattern.lastIndex = 0; + var identifierName = ''; + var match; // https://esbench.com/bench/5b809c2cf2949800a0f61fb5 + + while ((match = labelPattern.exec(styles)) !== null) { + identifierName += '-' + // $FlowFixMe we know it's not null + match[1]; } -}; -var beginFiberMark = function (fiber, phase) { - var componentName = getComponentName(fiber) || 'Unknown'; - var debugID = fiber._debugID; - var isMounted = fiber.alternate !== null; - var label = getFiberLabel(componentName, isMounted, phase); + var name = Object(__WEBPACK_IMPORTED_MODULE_0__emotion_hash__["a" /* default */])(styles) + identifierName; - if (isCommitting && labelsInCurrentCommit.has(label)) { - // During the commit phase, we don't show duplicate labels because - // there is a fixed overhead for every measurement, and we don't - // want to stretch the commit phase beyond necessary. - return false; + if (process.env.NODE_ENV !== 'production') { + return { + name: name, + styles: styles, + map: sourceMap, + next: cursor + }; } - labelsInCurrentCommit.add(label); - var markName = getFiberMarkName(label, debugID); - beginMark(markName); - return true; + return { + name: name, + styles: styles, + next: cursor + }; }; -var clearFiberMark = function (fiber, phase) { - var componentName = getComponentName(fiber) || 'Unknown'; - var debugID = fiber._debugID; - var isMounted = fiber.alternate !== null; - var label = getFiberLabel(componentName, isMounted, phase); - var markName = getFiberMarkName(label, debugID); - clearMark(markName); -}; -var endFiberMark = function (fiber, phase, warning$$1) { - var componentName = getComponentName(fiber) || 'Unknown'; - var debugID = fiber._debugID; - var isMounted = fiber.alternate !== null; - var label = getFiberLabel(componentName, isMounted, phase); - var markName = getFiberMarkName(label, debugID); - endMark(label, markName, warning$$1); -}; -var shouldIgnoreFiber = function (fiber) { - // Host components should be skipped in the timeline. - // We could check typeof fiber.type, but does this work with RN? - switch (fiber.tag) { - case HostRoot: - case HostComponent: - case HostText: - case HostPortal: - case ReturnComponent: - case Fragment: - return true; - default: - return false; - } -}; +/* WEBPACK VAR INJECTION */}.call(__webpack_exports__, __webpack_require__(0))) -var clearPendingPhaseMeasurement = function () { - if (currentPhase !== null && currentPhaseFiber !== null) { - clearFiberMark(currentPhaseFiber, currentPhase); - } - currentPhaseFiber = null; - currentPhase = null; - hasScheduledUpdateInCurrentPhase = false; -}; +/***/ }), +/* 17 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { -var pauseTimers = function () { - // Stops all currently active measurements so that they can be resumed - // if we continue in a later deferred loop from the same unit of work. - var fiber = currentFiber; - while (fiber) { - if (fiber._debugIsCurrentlyTiming) { - endFiberMark(fiber, null, null); - } - fiber = fiber['return']; - } -}; +"use strict"; +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__emotion_serialize__ = __webpack_require__(16); -var resumeTimersRecursively = function (fiber) { - if (fiber['return'] !== null) { - resumeTimersRecursively(fiber['return']); - } - if (fiber._debugIsCurrentlyTiming) { - beginFiberMark(fiber, null); - } -}; -var resumeTimers = function () { - // Resumes all measurements that were active during the last deferred loop. - if (currentFiber !== null) { - resumeTimersRecursively(currentFiber); +function css() { + for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { + args[_key] = arguments[_key]; } -}; -function recordEffect() { - if (enableUserTimingAPI) { - effectCountInCurrentCommit++; - } + return Object(__WEBPACK_IMPORTED_MODULE_0__emotion_serialize__["a" /* serializeStyles */])(args); } -function recordScheduleUpdate() { - if (enableUserTimingAPI) { - if (isCommitting) { - hasScheduledUpdateInCurrentCommit = true; - } - if (currentPhase !== null && currentPhase !== 'componentWillMount' && currentPhase !== 'componentWillReceiveProps') { - hasScheduledUpdateInCurrentPhase = true; - } - } -} +/* harmony default export */ __webpack_exports__["a"] = (css); -function startRequestCallbackTimer() { - if (enableUserTimingAPI) { - if (supportsUserTiming && !isWaitingForCallback) { - isWaitingForCallback = true; - beginMark('(Waiting for async callback...)'); - } - } -} -function stopRequestCallbackTimer(didExpire) { - if (enableUserTimingAPI) { - if (supportsUserTiming) { - isWaitingForCallback = false; - var warning$$1 = didExpire ? 'React was blocked by main thread' : null; - endMark('(Waiting for async callback...)', '(Waiting for async callback...)', warning$$1); - } - } -} +/***/ }), +/* 18 */ +/***/ (function(module, exports, __webpack_require__) { -function startWorkTimer(fiber) { - if (enableUserTimingAPI) { - if (!supportsUserTiming || shouldIgnoreFiber(fiber)) { - return; - } - // If we pause, this is the fiber to unwind from. - currentFiber = fiber; - if (!beginFiberMark(fiber, null)) { - return; - } - fiber._debugIsCurrentlyTiming = true; - } -} +"use strict"; -function cancelWorkTimer(fiber) { - if (enableUserTimingAPI) { - if (!supportsUserTiming || shouldIgnoreFiber(fiber)) { - return; - } - // Remember we shouldn't complete measurement for this fiber. - // Otherwise flamechart will be deep even for small updates. - fiber._debugIsCurrentlyTiming = false; - clearFiberMark(fiber, null); - } -} -function stopWorkTimer(fiber) { - if (enableUserTimingAPI) { - if (!supportsUserTiming || shouldIgnoreFiber(fiber)) { - return; - } - // If we pause, its parent is the fiber to unwind from. - currentFiber = fiber['return']; - if (!fiber._debugIsCurrentlyTiming) { - return; - } - fiber._debugIsCurrentlyTiming = false; - endFiberMark(fiber, null, null); - } -} +var _interopRequireDefault = __webpack_require__(5); -function stopFailedWorkTimer(fiber) { - if (enableUserTimingAPI) { - if (!supportsUserTiming || shouldIgnoreFiber(fiber)) { - return; - } - // If we pause, its parent is the fiber to unwind from. - currentFiber = fiber['return']; - if (!fiber._debugIsCurrentlyTiming) { - return; - } - fiber._debugIsCurrentlyTiming = false; - var warning$$1 = 'An error was thrown inside this error boundary'; - endFiberMark(fiber, null, warning$$1); - } -} +exports.__esModule = true; +exports.default = void 0; -function startPhaseTimer(fiber, phase) { - if (enableUserTimingAPI) { - if (!supportsUserTiming) { - return; - } - clearPendingPhaseMeasurement(); - if (!beginFiberMark(fiber, phase)) { - return; - } - currentPhaseFiber = fiber; - currentPhase = phase; - } -} +var _setStatic = _interopRequireDefault(__webpack_require__(43)); -function stopPhaseTimer() { - if (enableUserTimingAPI) { - if (!supportsUserTiming) { - return; - } - if (currentPhase !== null && currentPhaseFiber !== null) { - var warning$$1 = hasScheduledUpdateInCurrentPhase ? 'Scheduled a cascading update' : null; - endFiberMark(currentPhaseFiber, currentPhase, warning$$1); - } - currentPhase = null; - currentPhaseFiber = null; - } -} +var setDisplayName = function setDisplayName(displayName) { + return (0, _setStatic.default)('displayName', displayName); +}; -function startWorkLoopTimer(nextUnitOfWork) { - if (enableUserTimingAPI) { - currentFiber = nextUnitOfWork; - if (!supportsUserTiming) { - return; - } - commitCountInCurrentWorkLoop = 0; - // This is top level call. - // Any other measurements are performed within. - beginMark('(React Tree Reconciliation)'); - // Resume any measurements that were in progress during the last loop. - resumeTimers(); - } -} +var _default = setDisplayName; +exports.default = _default; -function stopWorkLoopTimer(interruptedBy) { - if (enableUserTimingAPI) { - if (!supportsUserTiming) { - return; - } - var warning$$1 = null; - if (interruptedBy !== null) { - if (interruptedBy.tag === HostRoot) { - warning$$1 = 'A top-level update interrupted the previous render'; - } else { - var componentName = getComponentName(interruptedBy) || 'Unknown'; - warning$$1 = 'An update to ' + componentName + ' interrupted the previous render'; - } - } else if (commitCountInCurrentWorkLoop > 1) { - warning$$1 = 'There were cascading updates'; - } - commitCountInCurrentWorkLoop = 0; - // Pause any measurements until the next loop. - pauseTimers(); - endMark('(React Tree Reconciliation)', '(React Tree Reconciliation)', warning$$1); - } -} +/***/ }), +/* 19 */ +/***/ (function(module, exports, __webpack_require__) { -function startCommitTimer() { - if (enableUserTimingAPI) { - if (!supportsUserTiming) { - return; - } - isCommitting = true; - hasScheduledUpdateInCurrentCommit = false; - labelsInCurrentCommit.clear(); - beginMark('(Committing Changes)'); - } -} +"use strict"; -function stopCommitTimer() { - if (enableUserTimingAPI) { - if (!supportsUserTiming) { - return; - } - var warning$$1 = null; - if (hasScheduledUpdateInCurrentCommit) { - warning$$1 = 'Lifecycle hook scheduled a cascading update'; - } else if (commitCountInCurrentWorkLoop > 0) { - warning$$1 = 'Caused by a cascading update in earlier commit'; - } - hasScheduledUpdateInCurrentCommit = false; - commitCountInCurrentWorkLoop++; - isCommitting = false; - labelsInCurrentCommit.clear(); +var _interopRequireDefault = __webpack_require__(5); - endMark('(Committing Changes)', '(Committing Changes)', warning$$1); - } -} +exports.__esModule = true; +exports.default = void 0; -function startCommitHostEffectsTimer() { - if (enableUserTimingAPI) { - if (!supportsUserTiming) { - return; - } - effectCountInCurrentCommit = 0; - beginMark('(Committing Host Effects)'); - } -} +var _getDisplayName = _interopRequireDefault(__webpack_require__(44)); -function stopCommitHostEffectsTimer() { - if (enableUserTimingAPI) { - if (!supportsUserTiming) { - return; - } - var count = effectCountInCurrentCommit; - effectCountInCurrentCommit = 0; - endMark('(Committing Host Effects: ' + count + ' Total)', '(Committing Host Effects)', null); +var wrapDisplayName = function wrapDisplayName(BaseComponent, hocName) { + return hocName + "(" + (0, _getDisplayName.default)(BaseComponent) + ")"; +}; + +var _default = wrapDisplayName; +exports.default = _default; + +/***/ }), +/* 20 */ +/***/ (function(module, exports, __webpack_require__) { + +var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;(function (global, factory) { + if (true) { + !(__WEBPACK_AMD_DEFINE_ARRAY__ = [exports], __WEBPACK_AMD_DEFINE_FACTORY__ = (factory), + __WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ? + (__WEBPACK_AMD_DEFINE_FACTORY__.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__)) : __WEBPACK_AMD_DEFINE_FACTORY__), + __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); + } else if (typeof exports !== "undefined") { + factory(exports); + } else { + var mod = { + exports: {} + }; + factory(mod.exports); + global.index = mod.exports; } -} +})(this, function (exports) { + 'use strict'; -function startCommitLifeCyclesTimer() { - if (enableUserTimingAPI) { - if (!supportsUserTiming) { - return; + Object.defineProperty(exports, "__esModule", { + value: true + }); + var calculateRgba = exports.calculateRgba = function calculateRgba(color, opacity) { + if (color[0] === '#') { + color = color.slice(1); } - effectCountInCurrentCommit = 0; - beginMark('(Calling Lifecycle Methods)'); - } -} -function stopCommitLifeCyclesTimer() { - if (enableUserTimingAPI) { - if (!supportsUserTiming) { - return; + if (color.length === 3) { + var res = ''; + color.split('').forEach(function (c) { + res += c; + res += c; + }); + color = res; } - var count = effectCountInCurrentCommit; - effectCountInCurrentCommit = 0; - endMark('(Calling Lifecycle Methods: ' + count + ' Total)', '(Calling Lifecycle Methods)', null); - } -} -{ - var warnedAboutMissingGetChildContext = {}; -} + var rgbValues = color.match(/.{2}/g).map(function (hex) { + return parseInt(hex, 16); + }).join(', '); + return 'rgba(' + rgbValues + ', ' + opacity + ')'; + }; +}); -// A cursor to the current merged context object on the stack. -var contextStackCursor = createCursor(emptyObject); -// A cursor to a boolean indicating whether the context has changed. -var didPerformWorkStackCursor = createCursor(false); -// Keep track of the previous context object that was on the stack. -// We use this to get access to the parent context after we have already -// pushed the next context provider, and now need to merge their contexts. -var previousContext = emptyObject; +/***/ }), +/* 21 */ +/***/ (function(module, exports, __webpack_require__) { -function getUnmaskedContext(workInProgress) { - var hasOwnContext = isContextProvider(workInProgress); - if (hasOwnContext) { - // If the fiber is a context provider itself, when we read its context - // we have already pushed its own child context on the stack. A context - // provider should not "see" its own child context. Therefore we read the - // previous (parent) context instead for a context provider. - return previousContext; - } - return contextStackCursor.current; -} +"use strict"; -function cacheContext(workInProgress, unmaskedContext, maskedContext) { - var instance = workInProgress.stateNode; - instance.__reactInternalMemoizedUnmaskedChildContext = unmaskedContext; - instance.__reactInternalMemoizedMaskedChildContext = maskedContext; -} -function getMaskedContext(workInProgress, unmaskedContext) { - var type = workInProgress.type; - var contextTypes = type.contextTypes; - if (!contextTypes) { - return emptyObject; - } +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.STLViewer = exports.OBJViewer = undefined; - // Avoid recreating masked context unless unmasked context has changed. - // Failing to do this will result in unnecessary calls to componentWillReceiveProps. - // This may trigger infinite loops if componentWillReceiveProps calls setState. - var instance = workInProgress.stateNode; - if (instance && instance.__reactInternalMemoizedUnmaskedChildContext === unmaskedContext) { - return instance.__reactInternalMemoizedMaskedChildContext; - } +var _OBJViewer = __webpack_require__(22); - var context = {}; - for (var key in contextTypes) { - context[key] = unmaskedContext[key]; - } +var _OBJViewer2 = _interopRequireDefault(_OBJViewer); - { - var name = getComponentName(workInProgress) || 'Unknown'; - checkPropTypes(contextTypes, context, 'context', name, ReactDebugCurrentFiber.getCurrentFiberStackAddendum); - } +var _STLViewer = __webpack_require__(66); - // Cache unmasked context so we can avoid recreating masked context unless necessary. - // Context is created before the class component is instantiated so check for instance. - if (instance) { - cacheContext(workInProgress, unmaskedContext, context); - } +var _STLViewer2 = _interopRequireDefault(_STLViewer); - return context; -} +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } -function hasContextChanged() { - return didPerformWorkStackCursor.current; -} +exports.OBJViewer = _OBJViewer2.default; +exports.STLViewer = _STLViewer2.default; -function isContextConsumer(fiber) { - return fiber.tag === ClassComponent && fiber.type.contextTypes != null; -} +/***/ }), +/* 22 */ +/***/ (function(module, exports, __webpack_require__) { -function isContextProvider(fiber) { - return fiber.tag === ClassComponent && fiber.type.childContextTypes != null; -} +"use strict"; -function popContextProvider(fiber) { - if (!isContextProvider(fiber)) { - return; - } - pop(didPerformWorkStackCursor, fiber); - pop(contextStackCursor, fiber); -} +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); -function popTopLevelContextObject(fiber) { - pop(didPerformWorkStackCursor, fiber); - pop(contextStackCursor, fiber); -} +var _react = __webpack_require__(1); -function pushTopLevelContextObject(fiber, context, didChange) { - !(contextStackCursor.cursor == null) ? invariant(false, 'Unexpected context found on stack. This error is likely caused by a bug in React. Please file an issue.') : void 0; +var _react2 = _interopRequireDefault(_react); - push(contextStackCursor, context, fiber); - push(didPerformWorkStackCursor, didChange, fiber); -} +var _propTypes = __webpack_require__(2); -function processChildContext(fiber, parentContext) { - var instance = fiber.stateNode; - var childContextTypes = fiber.type.childContextTypes; +var _propTypes2 = _interopRequireDefault(_propTypes); - // TODO (bvaughn) Replace this behavior with an invariant() in the future. - // It has only been added in Fiber to match the (unintentional) behavior in Stack. - if (typeof instance.getChildContext !== 'function') { - { - var componentName = getComponentName(fiber) || 'Unknown'; +var _reactDom = __webpack_require__(9); - if (!warnedAboutMissingGetChildContext[componentName]) { - warnedAboutMissingGetChildContext[componentName] = true; - warning(false, '%s.childContextTypes is specified but there is no getChildContext() method ' + 'on the instance. You can either define getChildContext() on %s or remove ' + 'childContextTypes from it.', componentName, componentName); - } - } - return parentContext; - } +var _reactDom2 = _interopRequireDefault(_reactDom); - var childContext = void 0; - { - ReactDebugCurrentFiber.setCurrentPhase('getChildContext'); - } - startPhaseTimer(fiber, 'getChildContext'); - childContext = instance.getChildContext(); - stopPhaseTimer(); - { - ReactDebugCurrentFiber.setCurrentPhase(null); - } - for (var contextKey in childContext) { - !(contextKey in childContextTypes) ? invariant(false, '%s.getChildContext(): key "%s" is not defined in childContextTypes.', getComponentName(fiber) || 'Unknown', contextKey) : void 0; - } - { - var name = getComponentName(fiber) || 'Unknown'; - checkPropTypes(childContextTypes, childContext, 'child context', name, - // In practice, there is one case in which we won't get a stack. It's when - // somebody calls unstable_renderSubtreeIntoContainer() and we process - // context from the parent component instance. The stack will be missing - // because it's outside of the reconciliation, and so the pointer has not - // been set. This is rare and doesn't matter. We'll also remove that API. - ReactDebugCurrentFiber.getCurrentFiberStackAddendum); - } +var _three = __webpack_require__(12); - return _assign({}, parentContext, childContext); -} +var THREE = _interopRequireWildcard(_three); -function pushContextProvider(workInProgress) { - if (!isContextProvider(workInProgress)) { - return false; - } +var _threeOrbitControls = __webpack_require__(13); - var instance = workInProgress.stateNode; - // We push the context as early as possible to ensure stack integrity. - // If the instance does not exist yet, we will push null at first, - // and replace it on the stack later when invalidating the context. - var memoizedMergedChildContext = instance && instance.__reactInternalMemoizedMergedChildContext || emptyObject; +var _threeOrbitControls2 = _interopRequireDefault(_threeOrbitControls); - // Remember the parent context so we can merge with it later. - // Inherit the parent's did-perform-work value to avoid inadvertently blocking updates. - previousContext = contextStackCursor.current; - push(contextStackCursor, memoizedMergedChildContext, workInProgress); - push(didPerformWorkStackCursor, didPerformWorkStackCursor.current, workInProgress); +var _threeAddons = __webpack_require__(32); - return true; -} +var _reactSpinners = __webpack_require__(14); -function invalidateContextProvider(workInProgress, didChange) { - var instance = workInProgress.stateNode; - !instance ? invariant(false, 'Expected to have an instance by this point. This error is likely caused by a bug in React. Please file an issue.') : void 0; +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } - if (didChange) { - // Merge parent and own context. - // Skip this if we're not updating due to sCU. - // This avoids unnecessarily recomputing memoized values. - var mergedContext = processChildContext(workInProgress, previousContext); - instance.__reactInternalMemoizedMergedChildContext = mergedContext; +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - // Replace the old (or empty) context with the new one. - // It is important to unwind the context in the reverse order. - pop(didPerformWorkStackCursor, workInProgress); - pop(contextStackCursor, workInProgress); - // Now push the new context and mark that it has changed. - push(contextStackCursor, mergedContext, workInProgress); - push(didPerformWorkStackCursor, didChange, workInProgress); - } else { - pop(didPerformWorkStackCursor, workInProgress); - push(didPerformWorkStackCursor, didChange, workInProgress); - } -} +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } -function resetContext() { - previousContext = emptyObject; - contextStackCursor.current = emptyObject; - didPerformWorkStackCursor.current = false; -} +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } -function findCurrentUnmaskedContext(fiber) { - // Currently this is only used with renderSubtreeIntoContainer; not sure if it - // makes sense elsewhere - !(isFiberMounted(fiber) && fiber.tag === ClassComponent) ? invariant(false, 'Expected subtree parent to be a mounted class component. This error is likely caused by a bug in React. Please file an issue.') : void 0; +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } - var node = fiber; - while (node.tag !== HostRoot) { - if (isContextProvider(node)) { - return node.stateNode.__reactInternalMemoizedMergedChildContext; - } - var parent = node['return']; - !parent ? invariant(false, 'Found unexpected detached subtree parent. This error is likely caused by a bug in React. Please file an issue.') : void 0; - node = parent; - } - return node.stateNode.context; -} +var OrbitControls = (0, _threeOrbitControls2.default)(THREE); -var NoWork = 0; // TODO: Use an opaque type once ESLint et al support the syntax +var OBJViewer = function (_Component) { + _inherits(OBJViewer, _Component); -var Sync = 1; -var Never = 2147483647; // Max int32: Math.pow(2, 31) - 1 + function OBJViewer(props) { + _classCallCheck(this, OBJViewer); -var UNIT_SIZE = 10; -var MAGIC_NUMBER_OFFSET = 2; + return _possibleConstructorReturn(this, (OBJViewer.__proto__ || Object.getPrototypeOf(OBJViewer)).call(this, props)); + } -// 1 unit of expiration time represents 10ms. -function msToExpirationTime(ms) { - // Always add an offset so that we don't clash with the magic number for NoWork. - return (ms / UNIT_SIZE | 0) + MAGIC_NUMBER_OFFSET; -} + _createClass(OBJViewer, [{ + key: 'componentDidMount', + value: function componentDidMount() { + this.renderModel(this.props); + } + }, { + key: 'componentDidUpdate', + value: function componentDidUpdate(nextProps) { + this.renderModel(nextProps); + } + }, { + key: 'renderModel', + value: function renderModel(props) { + var _this2 = this; -function expirationTimeToMs(expirationTime) { - return (expirationTime - MAGIC_NUMBER_OFFSET) * UNIT_SIZE; -} + var camera = void 0, + scene = void 0, + renderer = void 0, + controls = void 0; + var url = props.url, + file = props.file, + width = props.width, + height = props.height, + modelColor = props.modelColor, + backgroundColor = props.backgroundColor, + orbitControls = props.orbitControls, + onSceneRendered = props.onSceneRendered, + sceneClassName = props.sceneClassName; -function ceiling(num, precision) { - return ((num / precision | 0) + 1) * precision; -} + var xDims = void 0, + yDims = void 0, + zDims = void 0; -function computeExpirationBucket(currentTime, expirationInMs, bucketSizeMs) { - return ceiling(currentTime + expirationInMs / UNIT_SIZE, bucketSizeMs / UNIT_SIZE); -} + camera = new THREE.PerspectiveCamera(30, width / height, 1, 10000); + scene = new THREE.Scene(); -var NoContext = 0; -var AsyncUpdates = 1; + var directionalLight = new THREE.DirectionalLight(0xffffff, 0.8); + directionalLight.position.x = 0; + directionalLight.position.y = 1; + directionalLight.position.z = 0; + directionalLight.position.normalize(); + scene.add(directionalLight); -{ - var hasBadMapPolyfill = false; - try { - var nonExtensibleObject = Object.preventExtensions({}); - /* eslint-disable no-new */ - - /* eslint-enable no-new */ - } catch (e) { - // TODO: Consider warning about bad polyfills - hasBadMapPolyfill = true; - } -} + var ambientLight = new THREE.AmbientLight(0x404040); // soft white light -// A Fiber is work on a Component that needs to be done or was done. There can -// be more than one per component. + scene.add(ambientLight); + scene.add(camera); + var loader = new _threeAddons.OBJLoader(); -{ - var debugCounter = 1; -} + var onProgress = function onProgress(xhr) { + if (xhr.lengthComputable) { + // var percentComplete = xhr.loaded / xhr.total * 100; + } + }; -function FiberNode(tag, key, internalContextTag) { - // Instance - this.tag = tag; - this.key = key; - this.type = null; - this.stateNode = null; + var onLoad = function onLoad(object) { + var bbox = new THREE.Box3().setFromObject(object); - // Fiber - this['return'] = null; - this.child = null; - this.sibling = null; - this.index = 0; + xDims = bbox.max.x - bbox.min.x; + yDims = bbox.max.y - bbox.min.y; + zDims = bbox.max.z - bbox.min.z; + camera.position.set(0, 0, Math.max(xDims * 3, yDims * 3, zDims * 3)); - this.ref = null; + object.traverse(function (child) { + if (child.isMesh) { + child.material.color.setStyle(modelColor); + } + }); - this.pendingProps = null; - this.memoizedProps = null; - this.updateQueue = null; - this.memoizedState = null; + object.position.y = -95; + scene.add(object); - this.internalContextTag = internalContextTag; + renderer = new THREE.WebGLRenderer({ preserveDrawingBuffer: true, antialias: true }); + renderer.setPixelRatio(window.devicePixelRatio); + renderer.setClearColor(backgroundColor, 1); + renderer.setSize(width, height); + renderer.domElement.className = sceneClassName; - // Effects - this.effectTag = NoEffect; - this.nextEffect = null; + if (orbitControls) { + controls = new OrbitControls(camera, _reactDom2.default.findDOMNode(_this2)); + controls.enableKeys = false; + controls.addEventListener('change', orbitRender); + } - this.firstEffect = null; - this.lastEffect = null; + _reactDom2.default.findDOMNode(_this2).replaceChild(renderer.domElement, _reactDom2.default.findDOMNode(_this2).firstChild); - this.expirationTime = NoWork; + render(); - this.alternate = null; + if (typeof onSceneRendered === "function") { + onSceneRendered(_reactDom2.default.findDOMNode(renderer.domElement)); + } + }; - { - this._debugID = debugCounter++; - this._debugSource = null; - this._debugOwner = null; - this._debugIsCurrentlyTiming = false; - if (!hasBadMapPolyfill && typeof Object.preventExtensions === 'function') { - Object.preventExtensions(this); - } - } -} + var onError = function onError(xhr) {}; -// This is a constructor function, rather than a POJO constructor, still -// please ensure we do the following: -// 1) Nobody should add any instance methods on this. Instance methods can be -// more difficult to predict when they get optimized and they are almost -// never inlined properly in static compilers. -// 2) Nobody should rely on `instanceof Fiber` for type testing. We should -// always know when it is a fiber. -// 3) We might want to experiment with using numeric keys since they are easier -// to optimize in a non-JIT environment. -// 4) We can easily go from a constructor to a createFiber object literal if that -// is faster. -// 5) It should be easy to port this to a C struct and keep a C implementation -// compatible. -var createFiber = function (tag, key, internalContextTag) { - // $FlowFixMe: the shapes are exact here but Flow doesn't like constructors - return new FiberNode(tag, key, internalContextTag); -}; + if (file) { + var reader = new FileReader(); -function shouldConstruct(Component) { - return !!(Component.prototype && Component.prototype.isReactComponent); -} + reader.onload = function (evt) { + if (evt.target.readyState != 2) return; + if (evt.target.error) { + alert('Error while reading file'); + return; + } -// This is used to create an alternate fiber to do work on. -function createWorkInProgress(current, pendingProps, expirationTime) { - var workInProgress = current.alternate; - if (workInProgress === null) { - // We use a double buffering pooling technique because we know that we'll - // only ever need at most two versions of a tree. We pool the "other" unused - // node that we're free to reuse. This is lazily created to avoid allocating - // extra objects for things that are never updated. It also allow us to - // reclaim the extra memory if needed. - workInProgress = createFiber(current.tag, current.key, current.internalContextTag); - workInProgress.type = current.type; - workInProgress.stateNode = current.stateNode; + onLoad(loader.parse(evt.target.result)); + }; - { - // DEV-only fields - workInProgress._debugID = current._debugID; - workInProgress._debugSource = current._debugSource; - workInProgress._debugOwner = current._debugOwner; - } + reader.readAsText(file); + } else { + loader.load(url, onLoad, onProgress, onError); + } - workInProgress.alternate = current; - current.alternate = workInProgress; - } else { - // We already have an alternate. - // Reset the effect tag. - workInProgress.effectTag = NoEffect; + var render = function render() { + renderer.render(scene, camera); + }; - // The effect list is no longer valid. - workInProgress.nextEffect = null; - workInProgress.firstEffect = null; - workInProgress.lastEffect = null; - } + var orbitRender = function orbitRender() { + render(); + }; + } + }, { + key: 'componentDidUpdate', + value: function componentDidUpdate() { + this.setState({ allowUpdate: true }); + } + }, { + key: 'shouldComponentUpdate', + value: function shouldComponentUpdate(nextProps, nextState) { + if (JSON.stringify(nextProps) === JSON.stringify(this.props)) { + return false; + } + return true; + } + }, { + key: 'componentDidCatch', + value: function componentDidCatch(error, info) { + console.log(error, info); + } + }, { + key: 'render', + value: function render() { + return _react2.default.createElement( + 'div', + { + className: this.props.className, + style: { + width: this.props.width, + height: this.props.height, + overflow: 'hidden' + } + }, + _react2.default.createElement( + 'div', + { style: { + height: '100%', + display: 'flex', + justifyContent: 'center', + alignItems: 'center' + } }, + _react2.default.createElement(_reactSpinners.ScaleLoader, { + color: '#123abc', + loading: true + }) + ) + ); + } + }]); - workInProgress.expirationTime = expirationTime; - workInProgress.pendingProps = pendingProps; + return OBJViewer; +}(_react.Component); - workInProgress.child = current.child; - workInProgress.memoizedProps = current.memoizedProps; - workInProgress.memoizedState = current.memoizedState; - workInProgress.updateQueue = current.updateQueue; +OBJViewer.propTypes = { + className: _propTypes2.default.string, + url: _propTypes2.default.string, + file: _propTypes2.default.object, + width: _propTypes2.default.number, + height: _propTypes2.default.number, + backgroundColor: _propTypes2.default.string, + modelColor: _propTypes2.default.string, + sceneClassName: _propTypes2.default.string, + onSceneRendered: _propTypes2.default.func +}; +OBJViewer.defaultProps = { + backgroundColor: '#EAEAEA', + modelColor: '#B92C2C', + height: 400, + width: 400, + orbitControls: true, + sceneClassName: '' +}; +; - // These will be overridden during the parent's reconciliation - workInProgress.sibling = current.sibling; - workInProgress.index = current.index; - workInProgress.ref = current.ref; +module.exports = OBJViewer; - return workInProgress; -} +/***/ }), +/* 23 */ +/***/ (function(module, exports, __webpack_require__) { -function createHostRootFiber() { - var fiber = createFiber(HostRoot, null, NoContext); - return fiber; -} +"use strict"; +/* WEBPACK VAR INJECTION */(function(process) {/** + * Copyright (c) 2013-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ -function createFiberFromElement(element, internalContextTag, expirationTime) { - var owner = null; - { - owner = element._owner; - } - var fiber = void 0; - var type = element.type, - key = element.key; - if (typeof type === 'function') { - fiber = shouldConstruct(type) ? createFiber(ClassComponent, key, internalContextTag) : createFiber(IndeterminateComponent, key, internalContextTag); - fiber.type = type; - fiber.pendingProps = element.props; - } else if (typeof type === 'string') { - fiber = createFiber(HostComponent, key, internalContextTag); - fiber.type = type; - fiber.pendingProps = element.props; - } else if (typeof type === 'object' && type !== null && typeof type.tag === 'number') { - // Currently assumed to be a continuation and therefore is a fiber already. - // TODO: The yield system is currently broken for updates in some cases. - // The reified yield stores a fiber, but we don't know which fiber that is; - // the current or a workInProgress? When the continuation gets rendered here - // we don't know if we can reuse that fiber or if we need to clone it. - // There is probably a clever way to restructure this. - fiber = type; - fiber.pendingProps = element.props; - } else { - var info = ''; - { - if (type === undefined || typeof type === 'object' && type !== null && Object.keys(type).length === 0) { - info += ' You likely forgot to export your component from the file ' + "it's defined in, or you might have mixed up default and named imports."; - } - var ownerName = owner ? getComponentName(owner) : null; - if (ownerName) { - info += '\n\nCheck the render method of `' + ownerName + '`.'; - } - } - invariant(false, 'Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: %s.%s', type == null ? type : typeof type, info); - } +var assign = __webpack_require__(6); - { - fiber._debugSource = element._source; - fiber._debugOwner = element._owner; - } +var ReactPropTypesSecret = __webpack_require__(7); +var checkPropTypes = __webpack_require__(8); - fiber.expirationTime = expirationTime; +var printWarning = function() {}; - return fiber; +if (process.env.NODE_ENV !== 'production') { + printWarning = function(text) { + var message = 'Warning: ' + text; + if (typeof console !== 'undefined') { + console.error(message); + } + try { + // --- Welcome to debugging React --- + // This error was thrown as a convenience so that you can use this stack + // to find the callsite that caused this warning to fire. + throw new Error(message); + } catch (x) {} + }; } -function createFiberFromFragment(elements, internalContextTag, expirationTime, key) { - var fiber = createFiber(Fragment, key, internalContextTag); - fiber.pendingProps = elements; - fiber.expirationTime = expirationTime; - return fiber; +function emptyFunctionThatReturnsNull() { + return null; } -function createFiberFromText(content, internalContextTag, expirationTime) { - var fiber = createFiber(HostText, null, internalContextTag); - fiber.pendingProps = content; - fiber.expirationTime = expirationTime; - return fiber; -} +module.exports = function(isValidElement, throwOnDirectAccess) { + /* global Symbol */ + var ITERATOR_SYMBOL = typeof Symbol === 'function' && Symbol.iterator; + var FAUX_ITERATOR_SYMBOL = '@@iterator'; // Before Symbol spec. -function createFiberFromHostInstanceForDeletion() { - var fiber = createFiber(HostComponent, null, NoContext); - fiber.type = 'DELETED'; - return fiber; -} + /** + * Returns the iterator method function contained on the iterable object. + * + * Be sure to invoke the function with the iterable as context: + * + * var iteratorFn = getIteratorFn(myIterable); + * if (iteratorFn) { + * var iterator = iteratorFn.call(myIterable); + * ... + * } + * + * @param {?object} maybeIterable + * @return {?function} + */ + function getIteratorFn(maybeIterable) { + var iteratorFn = maybeIterable && (ITERATOR_SYMBOL && maybeIterable[ITERATOR_SYMBOL] || maybeIterable[FAUX_ITERATOR_SYMBOL]); + if (typeof iteratorFn === 'function') { + return iteratorFn; + } + } -function createFiberFromCall(call, internalContextTag, expirationTime) { - var fiber = createFiber(CallComponent, call.key, internalContextTag); - fiber.type = call.handler; - fiber.pendingProps = call; - fiber.expirationTime = expirationTime; - return fiber; -} + /** + * Collection of methods that allow declaration and validation of props that are + * supplied to React components. Example usage: + * + * var Props = require('ReactPropTypes'); + * var MyArticle = React.createClass({ + * propTypes: { + * // An optional string prop named "description". + * description: Props.string, + * + * // A required enum prop named "category". + * category: Props.oneOf(['News','Photos']).isRequired, + * + * // A prop named "dialog" that requires an instance of Dialog. + * dialog: Props.instanceOf(Dialog).isRequired + * }, + * render: function() { ... } + * }); + * + * A more formal specification of how these methods are used: + * + * type := array|bool|func|object|number|string|oneOf([...])|instanceOf(...) + * decl := ReactPropTypes.{type}(.isRequired)? + * + * Each and every declaration produces a function with the same signature. This + * allows the creation of custom validation functions. For example: + * + * var MyLink = React.createClass({ + * propTypes: { + * // An optional string or URI prop named "href". + * href: function(props, propName, componentName) { + * var propValue = props[propName]; + * if (propValue != null && typeof propValue !== 'string' && + * !(propValue instanceof URI)) { + * return new Error( + * 'Expected a string or an URI for ' + propName + ' in ' + + * componentName + * ); + * } + * } + * }, + * render: function() {...} + * }); + * + * @internal + */ -function createFiberFromReturn(returnNode, internalContextTag, expirationTime) { - var fiber = createFiber(ReturnComponent, null, internalContextTag); - fiber.expirationTime = expirationTime; - return fiber; -} + var ANONYMOUS = '<>'; -function createFiberFromPortal(portal, internalContextTag, expirationTime) { - var fiber = createFiber(HostPortal, portal.key, internalContextTag); - fiber.pendingProps = portal.children || []; - fiber.expirationTime = expirationTime; - fiber.stateNode = { - containerInfo: portal.containerInfo, - pendingChildren: null, // Used by persistent updates - implementation: portal.implementation - }; - return fiber; -} + // Important! + // Keep this list in sync with production version in `./factoryWithThrowingShims.js`. + var ReactPropTypes = { + array: createPrimitiveTypeChecker('array'), + bool: createPrimitiveTypeChecker('boolean'), + func: createPrimitiveTypeChecker('function'), + number: createPrimitiveTypeChecker('number'), + object: createPrimitiveTypeChecker('object'), + string: createPrimitiveTypeChecker('string'), + symbol: createPrimitiveTypeChecker('symbol'), -function createFiberRoot(containerInfo, hydrate) { - // Cyclic construction. This cheats the type system right now because - // stateNode is any. - var uninitializedFiber = createHostRootFiber(); - var root = { - current: uninitializedFiber, - containerInfo: containerInfo, - pendingChildren: null, - remainingExpirationTime: NoWork, - isReadyForCommit: false, - finishedWork: null, - context: null, - pendingContext: null, - hydrate: hydrate, - nextScheduledRoot: null + any: createAnyTypeChecker(), + arrayOf: createArrayOfTypeChecker, + element: createElementTypeChecker(), + instanceOf: createInstanceTypeChecker, + node: createNodeChecker(), + objectOf: createObjectOfTypeChecker, + oneOf: createEnumTypeChecker, + oneOfType: createUnionTypeChecker, + shape: createShapeTypeChecker, + exact: createStrictShapeTypeChecker, }; - uninitializedFiber.stateNode = root; - return root; -} - -var onCommitFiberRoot = null; -var onCommitFiberUnmount = null; -var hasLoggedError = false; -function catchErrors(fn) { - return function (arg) { - try { - return fn(arg); - } catch (err) { - if (true && !hasLoggedError) { - hasLoggedError = true; - warning(false, 'React DevTools encountered an error: %s', err); - } + /** + * inlined Object.is polyfill to avoid requiring consumers ship their own + * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is + */ + /*eslint-disable no-self-compare*/ + function is(x, y) { + // SameValue algorithm + if (x === y) { + // Steps 1-5, 7-10 + // Steps 6.b-6.e: +0 != -0 + return x !== 0 || 1 / x === 1 / y; + } else { + // Step 6.a: NaN == NaN + return x !== x && y !== y; } - }; -} - -function injectInternals(internals) { - if (typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ === 'undefined') { - // No DevTools - return false; } - var hook = __REACT_DEVTOOLS_GLOBAL_HOOK__; - if (hook.isDisabled) { - // This isn't a real property on the hook, but it can be set to opt out - // of DevTools integration and associated warnings and logs. - // https://github.com/facebook/react/issues/3877 - return true; + /*eslint-enable no-self-compare*/ + + /** + * We use an Error-like object for backward compatibility as people may call + * PropTypes directly and inspect their output. However, we don't use real + * Errors anymore. We don't inspect their stack anyway, and creating them + * is prohibitively expensive if they are created too often, such as what + * happens in oneOfType() for any type before the one that matched. + */ + function PropTypeError(message) { + this.message = message; + this.stack = ''; } - if (!hook.supportsFiber) { - { - warning(false, 'The installed version of React DevTools is too old and will not work ' + 'with the current version of React. Please update React DevTools. ' + 'https://fb.me/react-devtools'); + // Make `instanceof Error` still work for returned errors. + PropTypeError.prototype = Error.prototype; + + function createChainableTypeChecker(validate) { + if (process.env.NODE_ENV !== 'production') { + var manualPropTypeCallCache = {}; + var manualPropTypeWarningCount = 0; } - // DevTools exists, even though it doesn't support Fiber. - return true; - } - try { - var rendererID = hook.inject(internals); - // We have successfully injected, so now it is safe to set up hooks. - onCommitFiberRoot = catchErrors(function (root) { - return hook.onCommitFiberRoot(rendererID, root); - }); - onCommitFiberUnmount = catchErrors(function (fiber) { - return hook.onCommitFiberUnmount(rendererID, fiber); - }); - } catch (err) { - // Catch all errors because it is unsafe to throw during initialization. - { - warning(false, 'React DevTools encountered an error: %s.', err); + function checkType(isRequired, props, propName, componentName, location, propFullName, secret) { + componentName = componentName || ANONYMOUS; + propFullName = propFullName || propName; + + if (secret !== ReactPropTypesSecret) { + if (throwOnDirectAccess) { + // New behavior only for users of `prop-types` package + var err = new Error( + 'Calling PropTypes validators directly is not supported by the `prop-types` package. ' + + 'Use `PropTypes.checkPropTypes()` to call them. ' + + 'Read more at http://fb.me/use-check-prop-types' + ); + err.name = 'Invariant Violation'; + throw err; + } else if (process.env.NODE_ENV !== 'production' && typeof console !== 'undefined') { + // Old behavior for people using React.PropTypes + var cacheKey = componentName + ':' + propName; + if ( + !manualPropTypeCallCache[cacheKey] && + // Avoid spamming the console because they are often not actionable except for lib authors + manualPropTypeWarningCount < 3 + ) { + printWarning( + 'You are manually calling a React.PropTypes validation ' + + 'function for the `' + propFullName + '` prop on `' + componentName + '`. This is deprecated ' + + 'and will throw in the standalone `prop-types` package. ' + + 'You may be seeing this warning due to a third-party PropTypes ' + + 'library. See https://fb.me/react-warning-dont-call-proptypes ' + 'for details.' + ); + manualPropTypeCallCache[cacheKey] = true; + manualPropTypeWarningCount++; + } + } + } + if (props[propName] == null) { + if (isRequired) { + if (props[propName] === null) { + return new PropTypeError('The ' + location + ' `' + propFullName + '` is marked as required ' + ('in `' + componentName + '`, but its value is `null`.')); + } + return new PropTypeError('The ' + location + ' `' + propFullName + '` is marked as required in ' + ('`' + componentName + '`, but its value is `undefined`.')); + } + return null; + } else { + return validate(props, propName, componentName, location, propFullName); + } } - } - // DevTools exists - return true; -} -function onCommitRoot(root) { - if (typeof onCommitFiberRoot === 'function') { - onCommitFiberRoot(root); - } -} + var chainedCheckType = checkType.bind(null, false); + chainedCheckType.isRequired = checkType.bind(null, true); -function onCommitUnmount(fiber) { - if (typeof onCommitFiberUnmount === 'function') { - onCommitFiberUnmount(fiber); + return chainedCheckType; } -} - -{ - var didWarnUpdateInsideUpdate = false; -} - -// Callbacks are not validated until invocation + function createPrimitiveTypeChecker(expectedType) { + function validate(props, propName, componentName, location, propFullName, secret) { + var propValue = props[propName]; + var propType = getPropType(propValue); + if (propType !== expectedType) { + // `propValue` being instance of, say, date/regexp, pass the 'object' + // check, but we can offer a more precise error message here rather than + // 'of type `object`'. + var preciseType = getPreciseType(propValue); -// Singly linked-list of updates. When an update is scheduled, it is added to -// the queue of the current fiber and the work-in-progress fiber. The two queues -// are separate but they share a persistent structure. -// -// During reconciliation, updates are removed from the work-in-progress fiber, -// but they remain on the current fiber. That ensures that if a work-in-progress -// is aborted, the aborted updates are recovered by cloning from current. -// -// The work-in-progress queue is always a subset of the current queue. -// -// When the tree is committed, the work-in-progress becomes the current. - - -function createUpdateQueue(baseState) { - var queue = { - baseState: baseState, - expirationTime: NoWork, - first: null, - last: null, - callbackList: null, - hasForceUpdate: false, - isInitialized: false - }; - { - queue.isProcessing = false; - } - return queue; -} - -function insertUpdateIntoQueue(queue, update) { - // Append the update to the end of the list. - if (queue.last === null) { - // Queue is empty - queue.first = queue.last = update; - } else { - queue.last.next = update; - queue.last = update; - } - if (queue.expirationTime === NoWork || queue.expirationTime > update.expirationTime) { - queue.expirationTime = update.expirationTime; + return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of type ' + ('`' + preciseType + '` supplied to `' + componentName + '`, expected ') + ('`' + expectedType + '`.')); + } + return null; + } + return createChainableTypeChecker(validate); } -} -function insertUpdateIntoFiber(fiber, update) { - // We'll have at least one and at most two distinct update queues. - var alternateFiber = fiber.alternate; - var queue1 = fiber.updateQueue; - if (queue1 === null) { - // TODO: We don't know what the base state will be until we begin work. - // It depends on which fiber is the next current. Initialize with an empty - // base state, then set to the memoizedState when rendering. Not super - // happy with this approach. - queue1 = fiber.updateQueue = createUpdateQueue(null); + function createAnyTypeChecker() { + return createChainableTypeChecker(emptyFunctionThatReturnsNull); } - var queue2 = void 0; - if (alternateFiber !== null) { - queue2 = alternateFiber.updateQueue; - if (queue2 === null) { - queue2 = alternateFiber.updateQueue = createUpdateQueue(null); + function createArrayOfTypeChecker(typeChecker) { + function validate(props, propName, componentName, location, propFullName) { + if (typeof typeChecker !== 'function') { + return new PropTypeError('Property `' + propFullName + '` of component `' + componentName + '` has invalid PropType notation inside arrayOf.'); + } + var propValue = props[propName]; + if (!Array.isArray(propValue)) { + var propType = getPropType(propValue); + return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of type ' + ('`' + propType + '` supplied to `' + componentName + '`, expected an array.')); + } + for (var i = 0; i < propValue.length; i++) { + var error = typeChecker(propValue, i, componentName, location, propFullName + '[' + i + ']', ReactPropTypesSecret); + if (error instanceof Error) { + return error; + } + } + return null; } - } else { - queue2 = null; + return createChainableTypeChecker(validate); } - queue2 = queue2 !== queue1 ? queue2 : null; - // Warn if an update is scheduled from inside an updater function. - { - if ((queue1.isProcessing || queue2 !== null && queue2.isProcessing) && !didWarnUpdateInsideUpdate) { - warning(false, 'An update (setState, replaceState, or forceUpdate) was scheduled ' + 'from inside an update function. Update functions should be pure, ' + 'with zero side-effects. Consider using componentDidUpdate or a ' + 'callback.'); - didWarnUpdateInsideUpdate = true; + function createElementTypeChecker() { + function validate(props, propName, componentName, location, propFullName) { + var propValue = props[propName]; + if (!isValidElement(propValue)) { + var propType = getPropType(propValue); + return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of type ' + ('`' + propType + '` supplied to `' + componentName + '`, expected a single ReactElement.')); + } + return null; } + return createChainableTypeChecker(validate); } - // If there's only one queue, add the update to that queue and exit. - if (queue2 === null) { - insertUpdateIntoQueue(queue1, update); - return; - } - - // If either queue is empty, we need to add to both queues. - if (queue1.last === null || queue2.last === null) { - insertUpdateIntoQueue(queue1, update); - insertUpdateIntoQueue(queue2, update); - return; + function createInstanceTypeChecker(expectedClass) { + function validate(props, propName, componentName, location, propFullName) { + if (!(props[propName] instanceof expectedClass)) { + var expectedClassName = expectedClass.name || ANONYMOUS; + var actualClassName = getClassName(props[propName]); + return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of type ' + ('`' + actualClassName + '` supplied to `' + componentName + '`, expected ') + ('instance of `' + expectedClassName + '`.')); + } + return null; + } + return createChainableTypeChecker(validate); } - // If both lists are not empty, the last update is the same for both lists - // because of structural sharing. So, we should only append to one of - // the lists. - insertUpdateIntoQueue(queue1, update); - // But we still need to update the `last` pointer of queue2. - queue2.last = update; -} - -function getUpdateExpirationTime(fiber) { - if (fiber.tag !== ClassComponent && fiber.tag !== HostRoot) { - return NoWork; - } - var updateQueue = fiber.updateQueue; - if (updateQueue === null) { - return NoWork; - } - return updateQueue.expirationTime; -} + function createEnumTypeChecker(expectedValues) { + if (!Array.isArray(expectedValues)) { + process.env.NODE_ENV !== 'production' ? printWarning('Invalid argument supplied to oneOf, expected an instance of array.') : void 0; + return emptyFunctionThatReturnsNull; + } -function getStateFromUpdate(update, instance, prevState, props) { - var partialState = update.partialState; - if (typeof partialState === 'function') { - var updateFn = partialState; + function validate(props, propName, componentName, location, propFullName) { + var propValue = props[propName]; + for (var i = 0; i < expectedValues.length; i++) { + if (is(propValue, expectedValues[i])) { + return null; + } + } - // Invoke setState callback an extra time to help detect side-effects. - if (debugRenderPhaseSideEffects) { - updateFn.call(instance, prevState, props); + var valuesString = JSON.stringify(expectedValues); + return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of value `' + propValue + '` ' + ('supplied to `' + componentName + '`, expected one of ' + valuesString + '.')); } - - return updateFn.call(instance, prevState, props); - } else { - return partialState; - } -} - -function processUpdateQueue(current, workInProgress, queue, instance, props, renderExpirationTime) { - if (current !== null && current.updateQueue === queue) { - // We need to create a work-in-progress queue, by cloning the current queue. - var currentQueue = queue; - queue = workInProgress.updateQueue = { - baseState: currentQueue.baseState, - expirationTime: currentQueue.expirationTime, - first: currentQueue.first, - last: currentQueue.last, - isInitialized: currentQueue.isInitialized, - // These fields are no longer valid because they were already committed. - // Reset them. - callbackList: null, - hasForceUpdate: false - }; + return createChainableTypeChecker(validate); } - { - // Set this flag so we can warn if setState is called inside the update - // function of another setState. - queue.isProcessing = true; - } - - // Reset the remaining expiration time. If we skip over any updates, we'll - // increase this accordingly. - queue.expirationTime = NoWork; - - // TODO: We don't know what the base state will be until we begin work. - // It depends on which fiber is the next current. Initialize with an empty - // base state, then set to the memoizedState when rendering. Not super - // happy with this approach. - var state = void 0; - if (queue.isInitialized) { - state = queue.baseState; - } else { - state = queue.baseState = workInProgress.memoizedState; - queue.isInitialized = true; - } - var dontMutatePrevState = true; - var update = queue.first; - var didSkip = false; - while (update !== null) { - var updateExpirationTime = update.expirationTime; - if (updateExpirationTime > renderExpirationTime) { - // This update does not have sufficient priority. Skip it. - var remainingExpirationTime = queue.expirationTime; - if (remainingExpirationTime === NoWork || remainingExpirationTime > updateExpirationTime) { - // Update the remaining expiration time. - queue.expirationTime = updateExpirationTime; + function createObjectOfTypeChecker(typeChecker) { + function validate(props, propName, componentName, location, propFullName) { + if (typeof typeChecker !== 'function') { + return new PropTypeError('Property `' + propFullName + '` of component `' + componentName + '` has invalid PropType notation inside objectOf.'); } - if (!didSkip) { - didSkip = true; - queue.baseState = state; + var propValue = props[propName]; + var propType = getPropType(propValue); + if (propType !== 'object') { + return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of type ' + ('`' + propType + '` supplied to `' + componentName + '`, expected an object.')); } - // Continue to the next update. - update = update.next; - continue; + for (var key in propValue) { + if (propValue.hasOwnProperty(key)) { + var error = typeChecker(propValue, key, componentName, location, propFullName + '.' + key, ReactPropTypesSecret); + if (error instanceof Error) { + return error; + } + } + } + return null; } + return createChainableTypeChecker(validate); + } - // This update does have sufficient priority. + function createUnionTypeChecker(arrayOfTypeCheckers) { + if (!Array.isArray(arrayOfTypeCheckers)) { + process.env.NODE_ENV !== 'production' ? printWarning('Invalid argument supplied to oneOfType, expected an instance of array.') : void 0; + return emptyFunctionThatReturnsNull; + } - // If no previous updates were skipped, drop this update from the queue by - // advancing the head of the list. - if (!didSkip) { - queue.first = update.next; - if (queue.first === null) { - queue.last = null; + for (var i = 0; i < arrayOfTypeCheckers.length; i++) { + var checker = arrayOfTypeCheckers[i]; + if (typeof checker !== 'function') { + printWarning( + 'Invalid argument supplied to oneOfType. Expected an array of check functions, but ' + + 'received ' + getPostfixForTypeWarning(checker) + ' at index ' + i + '.' + ); + return emptyFunctionThatReturnsNull; } } - // Process the update - var _partialState = void 0; - if (update.isReplace) { - state = getStateFromUpdate(update, instance, state, props); - dontMutatePrevState = true; - } else { - _partialState = getStateFromUpdate(update, instance, state, props); - if (_partialState) { - if (dontMutatePrevState) { - // $FlowFixMe: Idk how to type this properly. - state = _assign({}, state, _partialState); - } else { - state = _assign(state, _partialState); + function validate(props, propName, componentName, location, propFullName) { + for (var i = 0; i < arrayOfTypeCheckers.length; i++) { + var checker = arrayOfTypeCheckers[i]; + if (checker(props, propName, componentName, location, propFullName, ReactPropTypesSecret) == null) { + return null; } - dontMutatePrevState = false; } - } - if (update.isForced) { - queue.hasForceUpdate = true; - } - if (update.callback !== null) { - // Append to list of callbacks. - var _callbackList = queue.callbackList; - if (_callbackList === null) { - _callbackList = queue.callbackList = []; - } - _callbackList.push(update); - } - update = update.next; - } - - if (queue.callbackList !== null) { - workInProgress.effectTag |= Callback; - } else if (queue.first === null && !queue.hasForceUpdate) { - // The queue is empty. We can reset it. - workInProgress.updateQueue = null; - } - - if (!didSkip) { - didSkip = true; - queue.baseState = state; - } - - { - // No longer processing. - queue.isProcessing = false; - } - - return state; -} - -function commitCallbacks(queue, context) { - var callbackList = queue.callbackList; - if (callbackList === null) { - return; - } - // Set the list to null to make sure they don't get called more than once. - queue.callbackList = null; - for (var i = 0; i < callbackList.length; i++) { - var update = callbackList[i]; - var _callback = update.callback; - // This update might be processed again. Clear the callback so it's only - // called once. - update.callback = null; - !(typeof _callback === 'function') ? invariant(false, 'Invalid argument passed as callback. Expected a function. Instead received: %s', _callback) : void 0; - _callback.call(context); - } -} - -var fakeInternalInstance = {}; -var isArray = Array.isArray; - -{ - var didWarnAboutStateAssignmentForComponent = {}; - - var warnOnInvalidCallback = function (callback, callerName) { - warning(callback === null || typeof callback === 'function', '%s(...): Expected the last optional `callback` argument to be a ' + 'function. Instead received: %s.', callerName, callback); - }; - - // This is so gross but it's at least non-critical and can be removed if - // it causes problems. This is meant to give a nicer error message for - // ReactDOM15.unstable_renderSubtreeIntoContainer(reactDOM16Component, - // ...)) which otherwise throws a "_processChildContext is not a function" - // exception. - Object.defineProperty(fakeInternalInstance, '_processChildContext', { - enumerable: false, - value: function () { - invariant(false, '_processChildContext is not available in React 16+. This likely means you have multiple copies of React and are attempting to nest a React 15 tree inside a React 16 tree using unstable_renderSubtreeIntoContainer, which isn\'t supported. Try to make sure you have only one copy of React (and ideally, switch to ReactDOM.createPortal).'); - } - }); - Object.freeze(fakeInternalInstance); -} -var ReactFiberClassComponent = function (scheduleWork, computeExpirationForFiber, memoizeProps, memoizeState) { - // Class component state updater - var updater = { - isMounted: isMounted, - enqueueSetState: function (instance, partialState, callback) { - var fiber = get(instance); - callback = callback === undefined ? null : callback; - { - warnOnInvalidCallback(callback, 'setState'); - } - var expirationTime = computeExpirationForFiber(fiber); - var update = { - expirationTime: expirationTime, - partialState: partialState, - callback: callback, - isReplace: false, - isForced: false, - nextCallback: null, - next: null - }; - insertUpdateIntoFiber(fiber, update); - scheduleWork(fiber, expirationTime); - }, - enqueueReplaceState: function (instance, state, callback) { - var fiber = get(instance); - callback = callback === undefined ? null : callback; - { - warnOnInvalidCallback(callback, 'replaceState'); - } - var expirationTime = computeExpirationForFiber(fiber); - var update = { - expirationTime: expirationTime, - partialState: state, - callback: callback, - isReplace: true, - isForced: false, - nextCallback: null, - next: null - }; - insertUpdateIntoFiber(fiber, update); - scheduleWork(fiber, expirationTime); - }, - enqueueForceUpdate: function (instance, callback) { - var fiber = get(instance); - callback = callback === undefined ? null : callback; - { - warnOnInvalidCallback(callback, 'forceUpdate'); - } - var expirationTime = computeExpirationForFiber(fiber); - var update = { - expirationTime: expirationTime, - partialState: null, - callback: callback, - isReplace: false, - isForced: true, - nextCallback: null, - next: null - }; - insertUpdateIntoFiber(fiber, update); - scheduleWork(fiber, expirationTime); + return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` supplied to ' + ('`' + componentName + '`.')); } - }; + return createChainableTypeChecker(validate); + } - function checkShouldComponentUpdate(workInProgress, oldProps, newProps, oldState, newState, newContext) { - if (oldProps === null || workInProgress.updateQueue !== null && workInProgress.updateQueue.hasForceUpdate) { - // If the workInProgress already has an Update effect, return true - return true; + function createNodeChecker() { + function validate(props, propName, componentName, location, propFullName) { + if (!isNode(props[propName])) { + return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` supplied to ' + ('`' + componentName + '`, expected a ReactNode.')); + } + return null; } + return createChainableTypeChecker(validate); + } - var instance = workInProgress.stateNode; - var type = workInProgress.type; - if (typeof instance.shouldComponentUpdate === 'function') { - startPhaseTimer(workInProgress, 'shouldComponentUpdate'); - var shouldUpdate = instance.shouldComponentUpdate(newProps, newState, newContext); - stopPhaseTimer(); - - // Simulate an async bailout/interruption by invoking lifecycle twice. - if (debugRenderPhaseSideEffects) { - instance.shouldComponentUpdate(newProps, newState, newContext); + function createShapeTypeChecker(shapeTypes) { + function validate(props, propName, componentName, location, propFullName) { + var propValue = props[propName]; + var propType = getPropType(propValue); + if (propType !== 'object') { + return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of type `' + propType + '` ' + ('supplied to `' + componentName + '`, expected `object`.')); } - - { - warning(shouldUpdate !== undefined, '%s.shouldComponentUpdate(): Returned undefined instead of a ' + 'boolean value. Make sure to return true or false.', getComponentName(workInProgress) || 'Unknown'); + for (var key in shapeTypes) { + var checker = shapeTypes[key]; + if (!checker) { + continue; + } + var error = checker(propValue, key, componentName, location, propFullName + '.' + key, ReactPropTypesSecret); + if (error) { + return error; + } } - - return shouldUpdate; + return null; } + return createChainableTypeChecker(validate); + } - if (type.prototype && type.prototype.isPureReactComponent) { - return !shallowEqual(oldProps, newProps) || !shallowEqual(oldState, newState); + function createStrictShapeTypeChecker(shapeTypes) { + function validate(props, propName, componentName, location, propFullName) { + var propValue = props[propName]; + var propType = getPropType(propValue); + if (propType !== 'object') { + return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of type `' + propType + '` ' + ('supplied to `' + componentName + '`, expected `object`.')); + } + // We need to check all keys in case some are required but missing from + // props. + var allKeys = assign({}, props[propName], shapeTypes); + for (var key in allKeys) { + var checker = shapeTypes[key]; + if (!checker) { + return new PropTypeError( + 'Invalid ' + location + ' `' + propFullName + '` key `' + key + '` supplied to `' + componentName + '`.' + + '\nBad object: ' + JSON.stringify(props[propName], null, ' ') + + '\nValid keys: ' + JSON.stringify(Object.keys(shapeTypes), null, ' ') + ); + } + var error = checker(propValue, key, componentName, location, propFullName + '.' + key, ReactPropTypesSecret); + if (error) { + return error; + } + } + return null; } - return true; + return createChainableTypeChecker(validate); } - function checkClassInstance(workInProgress) { - var instance = workInProgress.stateNode; - var type = workInProgress.type; - { - var name = getComponentName(workInProgress); - var renderPresent = instance.render; + function isNode(propValue) { + switch (typeof propValue) { + case 'number': + case 'string': + case 'undefined': + return true; + case 'boolean': + return !propValue; + case 'object': + if (Array.isArray(propValue)) { + return propValue.every(isNode); + } + if (propValue === null || isValidElement(propValue)) { + return true; + } - if (!renderPresent) { - if (type.prototype && typeof type.prototype.render === 'function') { - warning(false, '%s(...): No `render` method found on the returned component ' + 'instance: did you accidentally return an object from the constructor?', name); + var iteratorFn = getIteratorFn(propValue); + if (iteratorFn) { + var iterator = iteratorFn.call(propValue); + var step; + if (iteratorFn !== propValue.entries) { + while (!(step = iterator.next()).done) { + if (!isNode(step.value)) { + return false; + } + } + } else { + // Iterator will provide entry [k,v] tuples rather than values. + while (!(step = iterator.next()).done) { + var entry = step.value; + if (entry) { + if (!isNode(entry[1])) { + return false; + } + } + } + } } else { - warning(false, '%s(...): No `render` method found on the returned component ' + 'instance: you may have forgotten to define `render`.', name); + return false; } - } - var noGetInitialStateOnES6 = !instance.getInitialState || instance.getInitialState.isReactClassApproved || instance.state; - warning(noGetInitialStateOnES6, 'getInitialState was defined on %s, a plain JavaScript class. ' + 'This is only supported for classes created using React.createClass. ' + 'Did you mean to define a state property instead?', name); - var noGetDefaultPropsOnES6 = !instance.getDefaultProps || instance.getDefaultProps.isReactClassApproved; - warning(noGetDefaultPropsOnES6, 'getDefaultProps was defined on %s, a plain JavaScript class. ' + 'This is only supported for classes created using React.createClass. ' + 'Use a static property to define defaultProps instead.', name); - var noInstancePropTypes = !instance.propTypes; - warning(noInstancePropTypes, 'propTypes was defined as an instance property on %s. Use a static ' + 'property to define propTypes instead.', name); - var noInstanceContextTypes = !instance.contextTypes; - warning(noInstanceContextTypes, 'contextTypes was defined as an instance property on %s. Use a static ' + 'property to define contextTypes instead.', name); - var noComponentShouldUpdate = typeof instance.componentShouldUpdate !== 'function'; - warning(noComponentShouldUpdate, '%s has a method called ' + 'componentShouldUpdate(). Did you mean shouldComponentUpdate()? ' + 'The name is phrased as a question because the function is ' + 'expected to return a value.', name); - if (type.prototype && type.prototype.isPureReactComponent && typeof instance.shouldComponentUpdate !== 'undefined') { - warning(false, '%s has a method called shouldComponentUpdate(). ' + 'shouldComponentUpdate should not be used when extending React.PureComponent. ' + 'Please extend React.Component if shouldComponentUpdate is used.', getComponentName(workInProgress) || 'A pure component'); - } - var noComponentDidUnmount = typeof instance.componentDidUnmount !== 'function'; - warning(noComponentDidUnmount, '%s has a method called ' + 'componentDidUnmount(). But there is no such lifecycle method. ' + 'Did you mean componentWillUnmount()?', name); - var noComponentDidReceiveProps = typeof instance.componentDidReceiveProps !== 'function'; - warning(noComponentDidReceiveProps, '%s has a method called ' + 'componentDidReceiveProps(). But there is no such lifecycle method. ' + 'If you meant to update the state in response to changing props, ' + 'use componentWillReceiveProps(). If you meant to fetch data or ' + 'run side-effects or mutations after React has updated the UI, use componentDidUpdate().', name); - var noComponentWillRecieveProps = typeof instance.componentWillRecieveProps !== 'function'; - warning(noComponentWillRecieveProps, '%s has a method called ' + 'componentWillRecieveProps(). Did you mean componentWillReceiveProps()?', name); - var hasMutatedProps = instance.props !== workInProgress.pendingProps; - warning(instance.props === undefined || !hasMutatedProps, '%s(...): When calling super() in `%s`, make sure to pass ' + "up the same props that your component's constructor was passed.", name, name); - var noInstanceDefaultProps = !instance.defaultProps; - warning(noInstanceDefaultProps, 'Setting defaultProps as an instance property on %s is not supported and will be ignored.' + ' Instead, define defaultProps as a static property on %s.', name, name); - } - - var state = instance.state; - if (state && (typeof state !== 'object' || isArray(state))) { - warning(false, '%s.state: must be set to an object or null', getComponentName(workInProgress)); - } - if (typeof instance.getChildContext === 'function') { - warning(typeof workInProgress.type.childContextTypes === 'object', '%s.getChildContext(): childContextTypes must be defined in order to ' + 'use getChildContext().', getComponentName(workInProgress)); + return true; + default: + return false; } } - function resetInputPointers(workInProgress, instance) { - instance.props = workInProgress.memoizedProps; - instance.state = workInProgress.memoizedState; - } - - function adoptClassInstance(workInProgress, instance) { - instance.updater = updater; - workInProgress.stateNode = instance; - // The instance needs access to the fiber so that it can schedule updates - set(instance, workInProgress); - { - instance._reactInternalInstance = fakeInternalInstance; + function isSymbol(propType, propValue) { + // Native Symbol. + if (propType === 'symbol') { + return true; } - } - function constructClassInstance(workInProgress, props) { - var ctor = workInProgress.type; - var unmaskedContext = getUnmaskedContext(workInProgress); - var needsContext = isContextConsumer(workInProgress); - var context = needsContext ? getMaskedContext(workInProgress, unmaskedContext) : emptyObject; - var instance = new ctor(props, context); - adoptClassInstance(workInProgress, instance); + // 19.4.3.5 Symbol.prototype[@@toStringTag] === 'Symbol' + if (propValue['@@toStringTag'] === 'Symbol') { + return true; + } - // Cache unmasked context so we can avoid recreating masked context unless necessary. - // ReactFiberContext usually updates this cache but can't for newly-created instances. - if (needsContext) { - cacheContext(workInProgress, unmaskedContext, context); + // Fallback for non-spec compliant Symbols which are polyfilled. + if (typeof Symbol === 'function' && propValue instanceof Symbol) { + return true; } - return instance; + return false; } - function callComponentWillMount(workInProgress, instance) { - startPhaseTimer(workInProgress, 'componentWillMount'); - var oldState = instance.state; - instance.componentWillMount(); - stopPhaseTimer(); - - // Simulate an async bailout/interruption by invoking lifecycle twice. - if (debugRenderPhaseSideEffects) { - instance.componentWillMount(); + // Equivalent of `typeof` but with special handling for array and regexp. + function getPropType(propValue) { + var propType = typeof propValue; + if (Array.isArray(propValue)) { + return 'array'; } - - if (oldState !== instance.state) { - { - warning(false, '%s.componentWillMount(): Assigning directly to this.state is ' + "deprecated (except inside a component's " + 'constructor). Use setState instead.', getComponentName(workInProgress)); - } - updater.enqueueReplaceState(instance, instance.state, null); + if (propValue instanceof RegExp) { + // Old webkits (at least until Android 4.0) return 'function' rather than + // 'object' for typeof a RegExp. We'll normalize this here so that /bla/ + // passes PropTypes.object. + return 'object'; + } + if (isSymbol(propType, propValue)) { + return 'symbol'; } + return propType; } - function callComponentWillReceiveProps(workInProgress, instance, newProps, newContext) { - startPhaseTimer(workInProgress, 'componentWillReceiveProps'); - var oldState = instance.state; - instance.componentWillReceiveProps(newProps, newContext); - stopPhaseTimer(); - - // Simulate an async bailout/interruption by invoking lifecycle twice. - if (debugRenderPhaseSideEffects) { - instance.componentWillReceiveProps(newProps, newContext); + // This handles more types than `getPropType`. Only used for error messages. + // See `createPrimitiveTypeChecker`. + function getPreciseType(propValue) { + if (typeof propValue === 'undefined' || propValue === null) { + return '' + propValue; } - - if (instance.state !== oldState) { - { - var componentName = getComponentName(workInProgress) || 'Component'; - if (!didWarnAboutStateAssignmentForComponent[componentName]) { - warning(false, '%s.componentWillReceiveProps(): Assigning directly to ' + "this.state is deprecated (except inside a component's " + 'constructor). Use setState instead.', componentName); - didWarnAboutStateAssignmentForComponent[componentName] = true; - } + var propType = getPropType(propValue); + if (propType === 'object') { + if (propValue instanceof Date) { + return 'date'; + } else if (propValue instanceof RegExp) { + return 'regexp'; } - updater.enqueueReplaceState(instance, instance.state, null); } + return propType; } - // Invokes the mount life-cycles on a previously never rendered instance. - function mountClassInstance(workInProgress, renderExpirationTime) { - var current = workInProgress.alternate; - - { - checkClassInstance(workInProgress); - } - - var instance = workInProgress.stateNode; - var state = instance.state || null; - - var props = workInProgress.pendingProps; - !props ? invariant(false, 'There must be pending props for an initial mount. This error is likely caused by a bug in React. Please file an issue.') : void 0; - - var unmaskedContext = getUnmaskedContext(workInProgress); - - instance.props = props; - instance.state = workInProgress.memoizedState = state; - instance.refs = emptyObject; - instance.context = getMaskedContext(workInProgress, unmaskedContext); - - if (enableAsyncSubtreeAPI && workInProgress.type != null && workInProgress.type.prototype != null && workInProgress.type.prototype.unstable_isAsyncReactComponent === true) { - workInProgress.internalContextTag |= AsyncUpdates; + // Returns a string that is postfixed to a warning about an invalid type. + // For example, "undefined" or "of type array" + function getPostfixForTypeWarning(value) { + var type = getPreciseType(value); + switch (type) { + case 'array': + case 'object': + return 'an ' + type; + case 'boolean': + case 'date': + case 'regexp': + return 'a ' + type; + default: + return type; } + } - if (typeof instance.componentWillMount === 'function') { - callComponentWillMount(workInProgress, instance); - // If we had additional state updates during this life-cycle, let's - // process them now. - var updateQueue = workInProgress.updateQueue; - if (updateQueue !== null) { - instance.state = processUpdateQueue(current, workInProgress, updateQueue, instance, props, renderExpirationTime); - } - } - if (typeof instance.componentDidMount === 'function') { - workInProgress.effectTag |= Update; + // Returns class name of the object, if any. + function getClassName(propValue) { + if (!propValue.constructor || !propValue.constructor.name) { + return ANONYMOUS; } + return propValue.constructor.name; } - // Called on a preexisting class instance. Returns false if a resumed render - // could be reused. - // function resumeMountClassInstance( - // workInProgress: Fiber, - // priorityLevel: PriorityLevel, - // ): boolean { - // const instance = workInProgress.stateNode; - // resetInputPointers(workInProgress, instance); - - // let newState = workInProgress.memoizedState; - // let newProps = workInProgress.pendingProps; - // if (!newProps) { - // // If there isn't any new props, then we'll reuse the memoized props. - // // This could be from already completed work. - // newProps = workInProgress.memoizedProps; - // invariant( - // newProps != null, - // 'There should always be pending or memoized props. This error is ' + - // 'likely caused by a bug in React. Please file an issue.', - // ); - // } - // const newUnmaskedContext = getUnmaskedContext(workInProgress); - // const newContext = getMaskedContext(workInProgress, newUnmaskedContext); - - // const oldContext = instance.context; - // const oldProps = workInProgress.memoizedProps; - - // if ( - // typeof instance.componentWillReceiveProps === 'function' && - // (oldProps !== newProps || oldContext !== newContext) - // ) { - // callComponentWillReceiveProps( - // workInProgress, - // instance, - // newProps, - // newContext, - // ); - // } - - // // Process the update queue before calling shouldComponentUpdate - // const updateQueue = workInProgress.updateQueue; - // if (updateQueue !== null) { - // newState = processUpdateQueue( - // workInProgress, - // updateQueue, - // instance, - // newState, - // newProps, - // priorityLevel, - // ); - // } - - // // TODO: Should we deal with a setState that happened after the last - // // componentWillMount and before this componentWillMount? Probably - // // unsupported anyway. - - // if ( - // !checkShouldComponentUpdate( - // workInProgress, - // workInProgress.memoizedProps, - // newProps, - // workInProgress.memoizedState, - // newState, - // newContext, - // ) - // ) { - // // Update the existing instance's state, props, and context pointers even - // // though we're bailing out. - // instance.props = newProps; - // instance.state = newState; - // instance.context = newContext; - // return false; - // } - - // // Update the input pointers now so that they are correct when we call - // // componentWillMount - // instance.props = newProps; - // instance.state = newState; - // instance.context = newContext; - - // if (typeof instance.componentWillMount === 'function') { - // callComponentWillMount(workInProgress, instance); - // // componentWillMount may have called setState. Process the update queue. - // const newUpdateQueue = workInProgress.updateQueue; - // if (newUpdateQueue !== null) { - // newState = processUpdateQueue( - // workInProgress, - // newUpdateQueue, - // instance, - // newState, - // newProps, - // priorityLevel, - // ); - // } - // } - - // if (typeof instance.componentDidMount === 'function') { - // workInProgress.effectTag |= Update; - // } - - // instance.state = newState; - - // return true; - // } - - // Invokes the update life-cycles and returns false if it shouldn't rerender. - function updateClassInstance(current, workInProgress, renderExpirationTime) { - var instance = workInProgress.stateNode; - resetInputPointers(workInProgress, instance); + ReactPropTypes.checkPropTypes = checkPropTypes; + ReactPropTypes.PropTypes = ReactPropTypes; - var oldProps = workInProgress.memoizedProps; - var newProps = workInProgress.pendingProps; - if (!newProps) { - // If there aren't any new props, then we'll reuse the memoized props. - // This could be from already completed work. - newProps = oldProps; - !(newProps != null) ? invariant(false, 'There should always be pending or memoized props. This error is likely caused by a bug in React. Please file an issue.') : void 0; - } - var oldContext = instance.context; - var newUnmaskedContext = getUnmaskedContext(workInProgress); - var newContext = getMaskedContext(workInProgress, newUnmaskedContext); - - // Note: During these life-cycles, instance.props/instance.state are what - // ever the previously attempted to render - not the "current". However, - // during componentDidUpdate we pass the "current" props. - - if (typeof instance.componentWillReceiveProps === 'function' && (oldProps !== newProps || oldContext !== newContext)) { - callComponentWillReceiveProps(workInProgress, instance, newProps, newContext); - } - - // Compute the next state using the memoized state and the update queue. - var oldState = workInProgress.memoizedState; - // TODO: Previous state can be null. - var newState = void 0; - if (workInProgress.updateQueue !== null) { - newState = processUpdateQueue(current, workInProgress, workInProgress.updateQueue, instance, newProps, renderExpirationTime); - } else { - newState = oldState; - } + return ReactPropTypes; +}; - if (oldProps === newProps && oldState === newState && !hasContextChanged() && !(workInProgress.updateQueue !== null && workInProgress.updateQueue.hasForceUpdate)) { - // If an update was already in progress, we should schedule an Update - // effect even though we're bailing out, so that cWU/cDU are called. - if (typeof instance.componentDidUpdate === 'function') { - if (oldProps !== current.memoizedProps || oldState !== current.memoizedState) { - workInProgress.effectTag |= Update; - } - } - return false; - } +/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0))) - var shouldUpdate = checkShouldComponentUpdate(workInProgress, oldProps, newProps, oldState, newState, newContext); +/***/ }), +/* 24 */ +/***/ (function(module, exports, __webpack_require__) { - if (shouldUpdate) { - if (typeof instance.componentWillUpdate === 'function') { - startPhaseTimer(workInProgress, 'componentWillUpdate'); - instance.componentWillUpdate(newProps, newState, newContext); - stopPhaseTimer(); +"use strict"; +/** + * Copyright (c) 2013-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ - // Simulate an async bailout/interruption by invoking lifecycle twice. - if (debugRenderPhaseSideEffects) { - instance.componentWillUpdate(newProps, newState, newContext); - } - } - if (typeof instance.componentDidUpdate === 'function') { - workInProgress.effectTag |= Update; - } - } else { - // If an update was already in progress, we should schedule an Update - // effect even though we're bailing out, so that cWU/cDU are called. - if (typeof instance.componentDidUpdate === 'function') { - if (oldProps !== current.memoizedProps || oldState !== current.memoizedState) { - workInProgress.effectTag |= Update; - } - } - // If shouldComponentUpdate returned false, we should still update the - // memoized props/state to indicate that this work can be reused. - memoizeProps(workInProgress, newProps); - memoizeState(workInProgress, newState); - } - // Update the existing instance's state, props, and context pointers even - // if shouldComponentUpdate returns false. - instance.props = newProps; - instance.state = newState; - instance.context = newContext; +var ReactPropTypesSecret = __webpack_require__(7); - return shouldUpdate; - } +function emptyFunction() {} - return { - adoptClassInstance: adoptClassInstance, - constructClassInstance: constructClassInstance, - mountClassInstance: mountClassInstance, - // resumeMountClassInstance, - updateClassInstance: updateClassInstance +module.exports = function() { + function shim(props, propName, componentName, location, propFullName, secret) { + if (secret === ReactPropTypesSecret) { + // It is still safe when called from React. + return; + } + var err = new Error( + 'Calling PropTypes validators directly is not supported by the `prop-types` package. ' + + 'Use PropTypes.checkPropTypes() to call them. ' + + 'Read more at http://fb.me/use-check-prop-types' + ); + err.name = 'Invariant Violation'; + throw err; }; -}; + shim.isRequired = shim; + function getShim() { + return shim; + }; + // Important! + // Keep this list in sync with production version in `./factoryWithTypeCheckers.js`. + var ReactPropTypes = { + array: shim, + bool: shim, + func: shim, + number: shim, + object: shim, + string: shim, + symbol: shim, -// The Symbol used to tag the ReactElement-like types. If there is no native Symbol -// nor polyfill, then a plain number is used for performance. -var hasSymbol = typeof Symbol === 'function' && Symbol['for']; + any: shim, + arrayOf: getShim, + element: shim, + instanceOf: getShim, + node: shim, + objectOf: getShim, + oneOf: getShim, + oneOfType: getShim, + shape: getShim, + exact: getShim + }; -var REACT_ELEMENT_TYPE = hasSymbol ? Symbol['for']('react.element') : 0xeac7; -var REACT_CALL_TYPE = hasSymbol ? Symbol['for']('react.call') : 0xeac8; -var REACT_RETURN_TYPE = hasSymbol ? Symbol['for']('react.return') : 0xeac9; -var REACT_PORTAL_TYPE = hasSymbol ? Symbol['for']('react.portal') : 0xeaca; -var REACT_FRAGMENT_TYPE = hasSymbol ? Symbol['for']('react.fragment') : 0xeacb; + ReactPropTypes.checkPropTypes = emptyFunction; + ReactPropTypes.PropTypes = ReactPropTypes; -var MAYBE_ITERATOR_SYMBOL = typeof Symbol === 'function' && Symbol.iterator; -var FAUX_ITERATOR_SYMBOL = '@@iterator'; + return ReactPropTypes; +}; -function getIteratorFn(maybeIterable) { - if (maybeIterable === null || typeof maybeIterable === 'undefined') { - return null; - } - var maybeIterator = MAYBE_ITERATOR_SYMBOL && maybeIterable[MAYBE_ITERATOR_SYMBOL] || maybeIterable[FAUX_ITERATOR_SYMBOL]; - if (typeof maybeIterator === 'function') { - return maybeIterator; - } - return null; -} -var getCurrentFiberStackAddendum$1 = ReactDebugCurrentFiber.getCurrentFiberStackAddendum; +/***/ }), +/* 25 */ +/***/ (function(module, exports, __webpack_require__) { +"use strict"; +/** @license React v16.7.0 + * react-dom.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ -{ - var didWarnAboutMaps = false; - /** - * Warn if there's no key explicitly set on dynamic arrays of children or - * object keys are not valid. This allows us to keep track of children between - * updates. - */ - var ownerHasKeyUseWarning = {}; - var ownerHasFunctionTypeWarning = {}; +/* + Modernizr 3.0.0pre (Custom Build) | MIT +*/ +var aa=__webpack_require__(1),n=__webpack_require__(6),ba=__webpack_require__(10);function ca(a,b,c,d,e,f,g,h){if(!a){a=void 0;if(void 0===b)a=Error("Minified exception occurred; use the non-minified dev environment for the full error message and additional helpful warnings.");else{var k=[c,d,e,f,g,h],l=0;a=Error(b.replace(/%s/g,function(){return k[l++]}));a.name="Invariant Violation"}a.framesToPop=1;throw a;}} +function t(a){for(var b=arguments.length-1,c="https://reactjs.org/docs/error-decoder.html?invariant="+a,d=0;dthis.eventPool.length&&this.eventPool.push(a)} +function jb(a){a.eventPool=[];a.getPooled=kb;a.release=lb}var mb=z.extend({data:null}),nb=z.extend({data:null}),ob=[9,13,27,32],pb=Sa&&"CompositionEvent"in window,qb=null;Sa&&"documentMode"in document&&(qb=document.documentMode); +var rb=Sa&&"TextEvent"in window&&!qb,sb=Sa&&(!pb||qb&&8=qb),tb=String.fromCharCode(32),ub={beforeInput:{phasedRegistrationNames:{bubbled:"onBeforeInput",captured:"onBeforeInputCapture"},dependencies:["compositionend","keypress","textInput","paste"]},compositionEnd:{phasedRegistrationNames:{bubbled:"onCompositionEnd",captured:"onCompositionEndCapture"},dependencies:"blur compositionend keydown keypress keyup mousedown".split(" ")},compositionStart:{phasedRegistrationNames:{bubbled:"onCompositionStart", +captured:"onCompositionStartCapture"},dependencies:"blur compositionstart keydown keypress keyup mousedown".split(" ")},compositionUpdate:{phasedRegistrationNames:{bubbled:"onCompositionUpdate",captured:"onCompositionUpdateCapture"},dependencies:"blur compositionupdate keydown keypress keyup mousedown".split(" ")}},vb=!1; +function wb(a,b){switch(a){case "keyup":return-1!==ob.indexOf(b.keyCode);case "keydown":return 229!==b.keyCode;case "keypress":case "mousedown":case "blur":return!0;default:return!1}}function xb(a){a=a.detail;return"object"===typeof a&&"data"in a?a.data:null}var yb=!1;function zb(a,b){switch(a){case "compositionend":return xb(b);case "keypress":if(32!==b.which)return null;vb=!0;return tb;case "textInput":return a=b.data,a===tb&&vb?null:a;default:return null}} +function Ab(a,b){if(yb)return"compositionend"===a||!pb&&wb(a,b)?(a=gb(),fb=eb=cb=null,yb=!1,a):null;switch(a){case "paste":return null;case "keypress":if(!(b.ctrlKey||b.altKey||b.metaKey)||b.ctrlKey&&b.altKey){if(b.char&&1b}return!1}function E(a,b,c,d,e){this.acceptsBooleans=2===b||3===b||4===b;this.attributeName=d;this.attributeNamespace=e;this.mustUseProperty=c;this.propertyName=a;this.type=b}var F={}; +"children dangerouslySetInnerHTML defaultValue defaultChecked innerHTML suppressContentEditableWarning suppressHydrationWarning style".split(" ").forEach(function(a){F[a]=new E(a,0,!1,a,null)});[["acceptCharset","accept-charset"],["className","class"],["htmlFor","for"],["httpEquiv","http-equiv"]].forEach(function(a){var b=a[0];F[b]=new E(b,1,!1,a[1],null)});["contentEditable","draggable","spellCheck","value"].forEach(function(a){F[a]=new E(a,2,!1,a.toLowerCase(),null)}); +["autoReverse","externalResourcesRequired","focusable","preserveAlpha"].forEach(function(a){F[a]=new E(a,2,!1,a,null)});"allowFullScreen async autoFocus autoPlay controls default defer disabled formNoValidate hidden loop noModule noValidate open playsInline readOnly required reversed scoped seamless itemScope".split(" ").forEach(function(a){F[a]=new E(a,3,!1,a.toLowerCase(),null)});["checked","multiple","muted","selected"].forEach(function(a){F[a]=new E(a,3,!0,a,null)}); +["capture","download"].forEach(function(a){F[a]=new E(a,4,!1,a,null)});["cols","rows","size","span"].forEach(function(a){F[a]=new E(a,6,!1,a,null)});["rowSpan","start"].forEach(function(a){F[a]=new E(a,5,!1,a.toLowerCase(),null)});var vc=/[\-:]([a-z])/g;function wc(a){return a[1].toUpperCase()} +"accent-height alignment-baseline arabic-form baseline-shift cap-height clip-path clip-rule color-interpolation color-interpolation-filters color-profile color-rendering dominant-baseline enable-background fill-opacity fill-rule flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-name glyph-orientation-horizontal glyph-orientation-vertical horiz-adv-x horiz-origin-x image-rendering letter-spacing lighting-color marker-end marker-mid marker-start overline-position overline-thickness paint-order panose-1 pointer-events rendering-intent shape-rendering stop-color stop-opacity strikethrough-position strikethrough-thickness stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width text-anchor text-decoration text-rendering underline-position underline-thickness unicode-bidi unicode-range units-per-em v-alphabetic v-hanging v-ideographic v-mathematical vector-effect vert-adv-y vert-origin-x vert-origin-y word-spacing writing-mode xmlns:xlink x-height".split(" ").forEach(function(a){var b=a.replace(vc, +wc);F[b]=new E(b,1,!1,a,null)});"xlink:actuate xlink:arcrole xlink:href xlink:role xlink:show xlink:title xlink:type".split(" ").forEach(function(a){var b=a.replace(vc,wc);F[b]=new E(b,1,!1,a,"http://www.w3.org/1999/xlink")});["xml:base","xml:lang","xml:space"].forEach(function(a){var b=a.replace(vc,wc);F[b]=new E(b,1,!1,a,"http://www.w3.org/XML/1998/namespace")});F.tabIndex=new E("tabIndex",1,!1,"tabindex",null); +function xc(a,b,c,d){var e=F.hasOwnProperty(b)?F[b]:null;var f=null!==e?0===e.type:d?!1:!(2Fd.length&&Fd.push(a)}}}var Ld={},Md=0,Nd="_reactListenersID"+(""+Math.random()).slice(2); +function Od(a){Object.prototype.hasOwnProperty.call(a,Nd)||(a[Nd]=Md++,Ld[a[Nd]]={});return Ld[a[Nd]]}function Pd(a){a=a||("undefined"!==typeof document?document:void 0);if("undefined"===typeof a)return null;try{return a.activeElement||a.body}catch(b){return a.body}}function Qd(a){for(;a&&a.firstChild;)a=a.firstChild;return a} +function Rd(a,b){var c=Qd(a);a=0;for(var d;c;){if(3===c.nodeType){d=a+c.textContent.length;if(a<=b&&d>=b)return{node:c,offset:b-a};a=d}a:{for(;c;){if(c.nextSibling){c=c.nextSibling;break a}c=c.parentNode}c=void 0}c=Qd(c)}}function Sd(a,b){return a&&b?a===b?!0:a&&3===a.nodeType?!1:b&&3===b.nodeType?Sd(a,b.parentNode):"contains"in a?a.contains(b):a.compareDocumentPosition?!!(a.compareDocumentPosition(b)&16):!1:!1} +function Td(){for(var a=window,b=Pd();b instanceof a.HTMLIFrameElement;){try{a=b.contentDocument.defaultView}catch(c){break}b=Pd(a.document)}return b}function Ud(a){var b=a&&a.nodeName&&a.nodeName.toLowerCase();return b&&("input"===b&&("text"===a.type||"search"===a.type||"tel"===a.type||"url"===a.type||"password"===a.type)||"textarea"===b||"true"===a.contentEditable)} +var Vd=Sa&&"documentMode"in document&&11>=document.documentMode,Wd={select:{phasedRegistrationNames:{bubbled:"onSelect",captured:"onSelectCapture"},dependencies:"blur contextmenu dragend focus keydown keyup mousedown mouseup selectionchange".split(" ")}},Xd=null,Yd=null,Zd=null,$d=!1; +function ae(a,b){var c=b.window===b?b.document:9===b.nodeType?b:b.ownerDocument;if($d||null==Xd||Xd!==Pd(c))return null;c=Xd;"selectionStart"in c&&Ud(c)?c={start:c.selectionStart,end:c.selectionEnd}:(c=(c.ownerDocument&&c.ownerDocument.defaultView||window).getSelection(),c={anchorNode:c.anchorNode,anchorOffset:c.anchorOffset,focusNode:c.focusNode,focusOffset:c.focusOffset});return Zd&&jd(Zd,c)?null:(Zd=c,a=z.getPooled(Wd.select,Yd,a,b),a.type="select",a.target=Xd,Ra(a),a)} +var be={eventTypes:Wd,extractEvents:function(a,b,c,d){var e=d.window===d?d.document:9===d.nodeType?d:d.ownerDocument,f;if(!(f=!e)){a:{e=Od(e);f=ta.onSelect;for(var g=0;g=b.length?void 0:t("93"),b=b[0]),c=b),null==c&&(c=""));a._wrapperState={initialValue:yc(c)}} +function ie(a,b){var c=yc(b.value),d=yc(b.defaultValue);null!=c&&(c=""+c,c!==a.value&&(a.value=c),null==b.defaultValue&&a.defaultValue!==c&&(a.defaultValue=c));null!=d&&(a.defaultValue=""+d)}function je(a){var b=a.textContent;b===a._wrapperState.initialValue&&(a.value=b)}var ke={html:"http://www.w3.org/1999/xhtml",mathml:"http://www.w3.org/1998/Math/MathML",svg:"http://www.w3.org/2000/svg"}; +function le(a){switch(a){case "svg":return"http://www.w3.org/2000/svg";case "math":return"http://www.w3.org/1998/Math/MathML";default:return"http://www.w3.org/1999/xhtml"}}function me(a,b){return null==a||"http://www.w3.org/1999/xhtml"===a?le(b):"http://www.w3.org/2000/svg"===a&&"foreignObject"===b?"http://www.w3.org/1999/xhtml":a} +var ne=void 0,oe=function(a){return"undefined"!==typeof MSApp&&MSApp.execUnsafeLocalFunction?function(b,c,d,e){MSApp.execUnsafeLocalFunction(function(){return a(b,c,d,e)})}:a}(function(a,b){if(a.namespaceURI!==ke.svg||"innerHTML"in a)a.innerHTML=b;else{ne=ne||document.createElement("div");ne.innerHTML=""+b+"";for(b=ne.firstChild;a.firstChild;)a.removeChild(a.firstChild);for(;b.firstChild;)a.appendChild(b.firstChild)}}); +function pe(a,b){if(b){var c=a.firstChild;if(c&&c===a.lastChild&&3===c.nodeType){c.nodeValue=b;return}}a.textContent=b} +var qe={animationIterationCount:!0,borderImageOutset:!0,borderImageSlice:!0,borderImageWidth:!0,boxFlex:!0,boxFlexGroup:!0,boxOrdinalGroup:!0,columnCount:!0,columns:!0,flex:!0,flexGrow:!0,flexPositive:!0,flexShrink:!0,flexNegative:!0,flexOrder:!0,gridArea:!0,gridRow:!0,gridRowEnd:!0,gridRowSpan:!0,gridRowStart:!0,gridColumn:!0,gridColumnEnd:!0,gridColumnSpan:!0,gridColumnStart:!0,fontWeight:!0,lineClamp:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,tabSize:!0,widows:!0,zIndex:!0,zoom:!0,fillOpacity:!0, +floodOpacity:!0,stopOpacity:!0,strokeDasharray:!0,strokeDashoffset:!0,strokeMiterlimit:!0,strokeOpacity:!0,strokeWidth:!0},re=["Webkit","ms","Moz","O"];Object.keys(qe).forEach(function(a){re.forEach(function(b){b=b+a.charAt(0).toUpperCase()+a.substring(1);qe[b]=qe[a]})});function se(a,b,c){return null==b||"boolean"===typeof b||""===b?"":c||"number"!==typeof b||0===b||qe.hasOwnProperty(a)&&qe[a]?(""+b).trim():b+"px"} +function te(a,b){a=a.style;for(var c in b)if(b.hasOwnProperty(c)){var d=0===c.indexOf("--"),e=se(c,b[c],d);"float"===c&&(c="cssFloat");d?a.setProperty(c,e):a[c]=e}}var ue=n({menuitem:!0},{area:!0,base:!0,br:!0,col:!0,embed:!0,hr:!0,img:!0,input:!0,keygen:!0,link:!0,meta:!0,param:!0,source:!0,track:!0,wbr:!0}); +function ve(a,b){b&&(ue[a]&&(null!=b.children||null!=b.dangerouslySetInnerHTML?t("137",a,""):void 0),null!=b.dangerouslySetInnerHTML&&(null!=b.children?t("60"):void 0,"object"===typeof b.dangerouslySetInnerHTML&&"__html"in b.dangerouslySetInnerHTML?void 0:t("61")),null!=b.style&&"object"!==typeof b.style?t("62",""):void 0)} +function we(a,b){if(-1===a.indexOf("-"))return"string"===typeof b.is;switch(a){case "annotation-xml":case "color-profile":case "font-face":case "font-face-src":case "font-face-uri":case "font-face-format":case "font-face-name":case "missing-glyph":return!1;default:return!0}} +function xe(a,b){a=9===a.nodeType||11===a.nodeType?a:a.ownerDocument;var c=Od(a);b=ta[b];for(var d=0;dJe||(a.current=Ie[Je],Ie[Je]=null,Je--)}function J(a,b){Je++;Ie[Je]=a.current;a.current=b}var Ke={},K={current:Ke},L={current:!1},Le=Ke; +function Me(a,b){var c=a.type.contextTypes;if(!c)return Ke;var d=a.stateNode;if(d&&d.__reactInternalMemoizedUnmaskedChildContext===b)return d.__reactInternalMemoizedMaskedChildContext;var e={},f;for(f in c)e[f]=b[f];d&&(a=a.stateNode,a.__reactInternalMemoizedUnmaskedChildContext=b,a.__reactInternalMemoizedMaskedChildContext=e);return e}function M(a){a=a.childContextTypes;return null!==a&&void 0!==a}function Ne(a){I(L,a);I(K,a)}function Oe(a){I(L,a);I(K,a)} +function Pe(a,b,c){K.current!==Ke?t("168"):void 0;J(K,b,a);J(L,c,a)}function Qe(a,b,c){var d=a.stateNode;a=b.childContextTypes;if("function"!==typeof d.getChildContext)return c;d=d.getChildContext();for(var e in d)e in a?void 0:t("108",mc(b)||"Unknown",e);return n({},c,d)}function Re(a){var b=a.stateNode;b=b&&b.__reactInternalMemoizedMergedChildContext||Ke;Le=K.current;J(K,b,a);J(L,L.current,a);return!0} +function Se(a,b,c){var d=a.stateNode;d?void 0:t("169");c?(b=Qe(a,b,Le),d.__reactInternalMemoizedMergedChildContext=b,I(L,a),I(K,a),J(K,b,a)):I(L,a);J(L,c,a)}var Te=null,Ue=null;function Ve(a){return function(b){try{return a(b)}catch(c){}}} +function We(a){if("undefined"===typeof __REACT_DEVTOOLS_GLOBAL_HOOK__)return!1;var b=__REACT_DEVTOOLS_GLOBAL_HOOK__;if(b.isDisabled||!b.supportsFiber)return!0;try{var c=b.inject(a);Te=Ve(function(a){return b.onCommitFiberRoot(c,a)});Ue=Ve(function(a){return b.onCommitFiberUnmount(c,a)})}catch(d){}return!0} +function Xe(a,b,c,d){this.tag=a;this.key=c;this.sibling=this.child=this.return=this.stateNode=this.type=this.elementType=null;this.index=0;this.ref=null;this.pendingProps=b;this.firstContextDependency=this.memoizedState=this.updateQueue=this.memoizedProps=null;this.mode=d;this.effectTag=0;this.lastEffect=this.firstEffect=this.nextEffect=null;this.childExpirationTime=this.expirationTime=0;this.alternate=null}function N(a,b,c,d){return new Xe(a,b,c,d)} +function Ye(a){a=a.prototype;return!(!a||!a.isReactComponent)}function Ze(a){if("function"===typeof a)return Ye(a)?1:0;if(void 0!==a&&null!==a){a=a.$$typeof;if(a===gc)return 11;if(a===ic)return 14}return 2} +function $e(a,b){var c=a.alternate;null===c?(c=N(a.tag,b,a.key,a.mode),c.elementType=a.elementType,c.type=a.type,c.stateNode=a.stateNode,c.alternate=a,a.alternate=c):(c.pendingProps=b,c.effectTag=0,c.nextEffect=null,c.firstEffect=null,c.lastEffect=null);c.childExpirationTime=a.childExpirationTime;c.expirationTime=a.expirationTime;c.child=a.child;c.memoizedProps=a.memoizedProps;c.memoizedState=a.memoizedState;c.updateQueue=a.updateQueue;c.firstContextDependency=a.firstContextDependency;c.sibling=a.sibling; +c.index=a.index;c.ref=a.ref;return c} +function af(a,b,c,d,e,f){var g=2;d=a;if("function"===typeof a)Ye(a)&&(g=1);else if("string"===typeof a)g=5;else a:switch(a){case ac:return bf(c.children,e,f,b);case fc:return cf(c,e|3,f,b);case bc:return cf(c,e|2,f,b);case cc:return a=N(12,c,b,e|4),a.elementType=cc,a.type=cc,a.expirationTime=f,a;case hc:return a=N(13,c,b,e),a.elementType=hc,a.type=hc,a.expirationTime=f,a;default:if("object"===typeof a&&null!==a)switch(a.$$typeof){case dc:g=10;break a;case ec:g=9;break a;case gc:g=11;break a;case ic:g= +14;break a;case jc:g=16;d=null;break a}t("130",null==a?a:typeof a,"")}b=N(g,c,b,e);b.elementType=a;b.type=d;b.expirationTime=f;return b}function bf(a,b,c,d){a=N(7,a,d,b);a.expirationTime=c;return a}function cf(a,b,c,d){a=N(8,a,d,b);b=0===(b&1)?bc:fc;a.elementType=b;a.type=b;a.expirationTime=c;return a}function df(a,b,c){a=N(6,a,null,b);a.expirationTime=c;return a} +function ef(a,b,c){b=N(4,null!==a.children?a.children:[],a.key,b);b.expirationTime=c;b.stateNode={containerInfo:a.containerInfo,pendingChildren:null,implementation:a.implementation};return b}function ff(a,b){a.didError=!1;var c=a.earliestPendingTime;0===c?a.earliestPendingTime=a.latestPendingTime=b:cb&&(a.latestPendingTime=b);gf(b,a)} +function hf(a,b){a.didError=!1;a.latestPingedTime>=b&&(a.latestPingedTime=0);var c=a.earliestPendingTime,d=a.latestPendingTime;c===b?a.earliestPendingTime=d===b?a.latestPendingTime=0:d:d===b&&(a.latestPendingTime=c);c=a.earliestSuspendedTime;d=a.latestSuspendedTime;0===c?a.earliestSuspendedTime=a.latestSuspendedTime=b:cb&&(a.latestSuspendedTime=b);gf(b,a)}function jf(a,b){var c=a.earliestPendingTime;a=a.earliestSuspendedTime;c>b&&(b=c);a>b&&(b=a);return b} +function gf(a,b){var c=b.earliestSuspendedTime,d=b.latestSuspendedTime,e=b.earliestPendingTime,f=b.latestPingedTime;e=0!==e?e:f;0===e&&(0===a||da&&(a=c);b.nextExpirationTimeToWorkOn=e;b.expirationTime=a}var kf=!1;function lf(a){return{baseState:a,firstUpdate:null,lastUpdate:null,firstCapturedUpdate:null,lastCapturedUpdate:null,firstEffect:null,lastEffect:null,firstCapturedEffect:null,lastCapturedEffect:null}} +function mf(a){return{baseState:a.baseState,firstUpdate:a.firstUpdate,lastUpdate:a.lastUpdate,firstCapturedUpdate:null,lastCapturedUpdate:null,firstEffect:null,lastEffect:null,firstCapturedEffect:null,lastCapturedEffect:null}}function nf(a){return{expirationTime:a,tag:0,payload:null,callback:null,next:null,nextEffect:null}}function of(a,b){null===a.lastUpdate?a.firstUpdate=a.lastUpdate=b:(a.lastUpdate.next=b,a.lastUpdate=b)} +function pf(a,b){var c=a.alternate;if(null===c){var d=a.updateQueue;var e=null;null===d&&(d=a.updateQueue=lf(a.memoizedState))}else d=a.updateQueue,e=c.updateQueue,null===d?null===e?(d=a.updateQueue=lf(a.memoizedState),e=c.updateQueue=lf(c.memoizedState)):d=a.updateQueue=mf(e):null===e&&(e=c.updateQueue=mf(d));null===e||d===e?of(d,b):null===d.lastUpdate||null===e.lastUpdate?(of(d,b),of(e,b)):(of(d,b),e.lastUpdate=b)} +function qf(a,b){var c=a.updateQueue;c=null===c?a.updateQueue=lf(a.memoizedState):rf(a,c);null===c.lastCapturedUpdate?c.firstCapturedUpdate=c.lastCapturedUpdate=b:(c.lastCapturedUpdate.next=b,c.lastCapturedUpdate=b)}function rf(a,b){var c=a.alternate;null!==c&&b===c.updateQueue&&(b=a.updateQueue=mf(b));return b} +function sf(a,b,c,d,e,f){switch(c.tag){case 1:return a=c.payload,"function"===typeof a?a.call(f,d,e):a;case 3:a.effectTag=a.effectTag&-2049|64;case 0:a=c.payload;e="function"===typeof a?a.call(f,d,e):a;if(null===e||void 0===e)break;return n({},d,e);case 2:kf=!0}return d} +function tf(a,b,c,d,e){kf=!1;b=rf(a,b);for(var f=b.baseState,g=null,h=0,k=b.firstUpdate,l=f;null!==k;){var m=k.expirationTime;mu?(p=m,m=null):p=m.sibling;var v=w(e,m,h[u],k);if(null===v){null===m&&(m=p);break}a&& +m&&null===v.alternate&&b(e,m);g=f(v,g,u);null===q?l=v:q.sibling=v;q=v;m=p}if(u===h.length)return c(e,m),l;if(null===m){for(;uu?(p=q,q=null):p=q.sibling;var A=w(e,q,v.value,k);if(null===A){q||(q=p);break}a&&q&&null===A.alternate&&b(e,q);g=f(A,g,u);null===m?l=A:m.sibling=A;m=A;q=p}if(v.done)return c(e,q),l;if(null===q){for(;!v.done;u++,v=h.next())v=r(e,v.value,k),null!==v&&(g=f(v,g,u),null===m?l=v:m.sibling=v,m=v);return l}for(q=d(e,q);!v.done;u++,v=h.next())v=y(q,e,u,v.value,k),null!==v&&(a&&null!==v.alternate&&q.delete(null===v.key?u: +v.key),g=f(v,g,u),null===m?l=v:m.sibling=v,m=v);a&&q.forEach(function(a){return b(e,a)});return l}return function(a,d,f,h){var k="object"===typeof f&&null!==f&&f.type===ac&&null===f.key;k&&(f=f.props.children);var l="object"===typeof f&&null!==f;if(l)switch(f.$$typeof){case Zb:a:{l=f.key;for(k=d;null!==k;){if(k.key===l)if(7===k.tag?f.type===ac:k.elementType===f.type){c(a,k.sibling);d=e(k,f.type===ac?f.props.children:f.props,h);d.ref=bg(a,k,f);d.return=a;a=d;break a}else{c(a,k);break}else b(a,k);k= +k.sibling}f.type===ac?(d=bf(f.props.children,a.mode,h,f.key),d.return=a,a=d):(h=af(f.type,f.key,f.props,null,a.mode,h),h.ref=bg(a,d,f),h.return=a,a=h)}return g(a);case $b:a:{for(k=f.key;null!==d;){if(d.key===k)if(4===d.tag&&d.stateNode.containerInfo===f.containerInfo&&d.stateNode.implementation===f.implementation){c(a,d.sibling);d=e(d,f.children||[],h);d.return=a;a=d;break a}else{c(a,d);break}else b(a,d);d=d.sibling}d=ef(f,a.mode,h);d.return=a;a=d}return g(a)}if("string"===typeof f||"number"===typeof f)return f= +""+f,null!==d&&6===d.tag?(c(a,d.sibling),d=e(d,f,h),d.return=a,a=d):(c(a,d),d=df(f,a.mode,h),d.return=a,a=d),g(a);if(ag(f))return B(a,d,f,h);if(lc(f))return R(a,d,f,h);l&&cg(a,f);if("undefined"===typeof f&&!k)switch(a.tag){case 1:case 0:h=a.type,t("152",h.displayName||h.name||"Component")}return c(a,d)}}var eg=dg(!0),fg=dg(!1),gg=null,hg=null,ig=!1; +function jg(a,b){var c=N(5,null,null,0);c.elementType="DELETED";c.type="DELETED";c.stateNode=b;c.return=a;c.effectTag=8;null!==a.lastEffect?(a.lastEffect.nextEffect=c,a.lastEffect=c):a.firstEffect=a.lastEffect=c}function kg(a,b){switch(a.tag){case 5:var c=a.type;b=1!==b.nodeType||c.toLowerCase()!==b.nodeName.toLowerCase()?null:b;return null!==b?(a.stateNode=b,!0):!1;case 6:return b=""===a.pendingProps||3!==b.nodeType?null:b,null!==b?(a.stateNode=b,!0):!1;default:return!1}} +function lg(a){if(ig){var b=hg;if(b){var c=b;if(!kg(a,b)){b=Ge(c);if(!b||!kg(a,b)){a.effectTag|=2;ig=!1;gg=a;return}jg(gg,c)}gg=a;hg=He(b)}else a.effectTag|=2,ig=!1,gg=a}}function mg(a){for(a=a.return;null!==a&&5!==a.tag&&3!==a.tag;)a=a.return;gg=a}function ng(a){if(a!==gg)return!1;if(!ig)return mg(a),ig=!0,!1;var b=a.type;if(5!==a.tag||"head"!==b&&"body"!==b&&!Ce(b,a.memoizedProps))for(b=hg;b;)jg(a,b),b=Ge(b);mg(a);hg=gg?Ge(a.stateNode):null;return!0}function og(){hg=gg=null;ig=!1}var pg=Xb.ReactCurrentOwner; +function Q(a,b,c,d){b.child=null===a?fg(b,null,c,d):eg(b,a.child,c,d)}function qg(a,b,c,d,e){c=c.render;var f=b.ref;Df(b,e);d=c(d,f);b.effectTag|=1;Q(a,b,d,e);return b.child} +function rg(a,b,c,d,e,f){if(null===a){var g=c.type;if("function"===typeof g&&!Ye(g)&&void 0===g.defaultProps&&null===c.compare&&void 0===c.defaultProps)return b.tag=15,b.type=g,sg(a,b,g,d,e,f);a=af(c.type,null,d,null,b.mode,f);a.ref=b.ref;a.return=b;return b.child=a}g=a.child;if(e=c)return zg(a,b,c);b=tg(a,b,c);return null!==b?b.sibling:null}}return tg(a,b,c)}b.expirationTime=0;switch(b.tag){case 2:d=b.elementType;null!== +a&&(a.alternate=null,b.alternate=null,b.effectTag|=2);a=b.pendingProps;var e=Me(b,K.current);Df(b,c);e=d(a,e);b.effectTag|=1;if("object"===typeof e&&null!==e&&"function"===typeof e.render&&void 0===e.$$typeof){b.tag=1;if(M(d)){var f=!0;Re(b)}else f=!1;b.memoizedState=null!==e.state&&void 0!==e.state?e.state:null;var g=d.getDerivedStateFromProps;"function"===typeof g&&Qf(b,d,g,a);e.updater=Vf;b.stateNode=e;e._reactInternalFiber=b;$f(b,d,a,c);b=xg(null,b,d,!0,f,c)}else b.tag=0,Q(null,b,e,c),b=b.child; +return b;case 16:e=b.elementType;null!==a&&(a.alternate=null,b.alternate=null,b.effectTag|=2);f=b.pendingProps;a=Nf(e);b.type=a;e=b.tag=Ze(a);f=P(a,f);g=void 0;switch(e){case 0:g=ug(null,b,a,f,c);break;case 1:g=wg(null,b,a,f,c);break;case 11:g=qg(null,b,a,f,c);break;case 14:g=rg(null,b,a,P(a.type,f),d,c);break;default:t("306",a,"")}return g;case 0:return d=b.type,e=b.pendingProps,e=b.elementType===d?e:P(d,e),ug(a,b,d,e,c);case 1:return d=b.type,e=b.pendingProps,e=b.elementType===d?e:P(d,e),wg(a,b, +d,e,c);case 3:yg(b);d=b.updateQueue;null===d?t("282"):void 0;e=b.memoizedState;e=null!==e?e.element:null;tf(b,d,b.pendingProps,null,c);d=b.memoizedState.element;if(d===e)og(),b=tg(a,b,c);else{e=b.stateNode;if(e=(null===a||null===a.child)&&e.hydrate)hg=He(b.stateNode.containerInfo),gg=b,e=ig=!0;e?(b.effectTag|=2,b.child=fg(b,null,d,c)):(Q(a,b,d,c),og());b=b.child}return b;case 5:return Lf(b),null===a&&lg(b),d=b.type,e=b.pendingProps,f=null!==a?a.memoizedProps:null,g=e.children,Ce(d,e)?g=null:null!== +f&&Ce(d,f)&&(b.effectTag|=16),vg(a,b),1!==c&&b.mode&1&&e.hidden?(b.expirationTime=1,b=null):(Q(a,b,g,c),b=b.child),b;case 6:return null===a&&lg(b),null;case 13:return zg(a,b,c);case 4:return Jf(b,b.stateNode.containerInfo),d=b.pendingProps,null===a?b.child=eg(b,null,d,c):Q(a,b,d,c),b.child;case 11:return d=b.type,e=b.pendingProps,e=b.elementType===d?e:P(d,e),qg(a,b,d,e,c);case 7:return Q(a,b,b.pendingProps,c),b.child;case 8:return Q(a,b,b.pendingProps.children,c),b.child;case 12:return Q(a,b,b.pendingProps.children, +c),b.child;case 10:a:{d=b.type._context;e=b.pendingProps;g=b.memoizedProps;f=e.value;Bf(b,f);if(null!==g){var h=g.value;f=h===f&&(0!==h||1/h===1/f)||h!==h&&f!==f?0:("function"===typeof d._calculateChangedBits?d._calculateChangedBits(h,f):1073741823)|0;if(0===f){if(g.children===e.children&&!L.current){b=tg(a,b,c);break a}}else for(g=b.child,null!==g&&(g.return=b);null!==g;){h=g.firstContextDependency;if(null!==h){do{if(h.context===d&&0!==(h.observedBits&f)){if(1===g.tag){var k=nf(c);k.tag=2;pf(g,k)}g.expirationTime< +c&&(g.expirationTime=c);k=g.alternate;null!==k&&k.expirationTime\x3c/script>",l=e.removeChild(e.firstChild)):"string"===typeof r.is?l=l.createElement(e,{is:r.is}):(l=l.createElement(e),"select"===e&&r.multiple&&(l.multiple=!0)):l=l.createElementNS(k,e);e=l;e[Ga]=m;e[Ha]=g;Cg(e,b,!1,!1);r=e;l=f;m=g;var w=h,y=we(l,m);switch(l){case "iframe":case "object":H("load", +r);h=m;break;case "video":case "audio":for(h=0;hg&&(g=e),h>g&&(g=h),f=f.sibling;b.childExpirationTime=g}if(null!==S)return S;null!==c&&0===(c.effectTag&1024)&&(null=== +c.firstEffect&&(c.firstEffect=a.firstEffect),null!==a.lastEffect&&(null!==c.lastEffect&&(c.lastEffect.nextEffect=a.firstEffect),c.lastEffect=a.lastEffect),1=y)r=0;else if(-1===r||y component higher in the tree to provide a loading indicator or placeholder to display."+ +nc(k))}fh=!0;l=wf(l,k);g=h;do{switch(g.tag){case 3:g.effectTag|=2048;g.expirationTime=f;f=Vg(g,l,f);qf(g,f);break a;case 1:if(m=l,r=g.type,w=g.stateNode,0===(g.effectTag&64)&&("function"===typeof r.getDerivedStateFromError||null!==w&&"function"===typeof w.componentDidCatch&&(null===Yg||!Yg.has(w)))){g.effectTag|=2048;g.expirationTime=f;f=Xg(g,m,f);qf(g,f);break a}}g=g.return}while(null!==g)}S=kh(e);continue}}}break}while(1);dh=!1;Af=zf=yf=ah.currentDispatcher=null;if(d)T=null,a.finishedWork=null; +else if(null!==S)a.finishedWork=null;else{d=a.current.alternate;null===d?t("281"):void 0;T=null;if(fh){e=a.latestPendingTime;f=a.latestSuspendedTime;g=a.latestPingedTime;if(0!==e&&eb?0:b)):(a.pendingCommitExpirationTime= +c,a.finishedWork=d)}}function Mg(a,b){for(var c=a.return;null!==c;){switch(c.tag){case 1:var d=c.stateNode;if("function"===typeof c.type.getDerivedStateFromError||"function"===typeof d.componentDidCatch&&(null===Yg||!Yg.has(d))){a=wf(b,a);a=Xg(c,a,1073741823);pf(c,a);Uf(c,1073741823);return}break;case 3:a=wf(b,a);a=Vg(c,a,1073741823);pf(c,a);Uf(c,1073741823);return}c=c.return}3===a.tag&&(c=wf(b,a),c=Vg(a,c,1073741823),pf(a,c),Uf(a,1073741823))} +function Sf(a,b){0!==ch?a=ch:dh?a=gh?1073741823:U:b.mode&1?(a=qh?1073741822-10*(((1073741822-a+15)/10|0)+1):1073741822-25*(((1073741822-a+500)/25|0)+1),null!==T&&a===U&&--a):a=1073741823;qh&&(0===rh||a=d){a.didError=!1;b=a.latestPingedTime;if(0===b||b>c)a.latestPingedTime=c;gf(c,a);c=a.expirationTime;0!==c&&sh(a,c)}} +function Tg(a,b){var c=a.stateNode;null!==c&&c.delete(b);b=Rf();b=Sf(b,a);a=th(a,b);null!==a&&(ff(a,b),b=a.expirationTime,0!==b&&sh(a,b))} +function th(a,b){a.expirationTimeU&&jh(),ff(a,b),dh&&!gh&&T===a||sh(a,a.expirationTime),uh>vh&&(uh=0,t("185")))}function wh(a,b,c,d,e){var f=ch;ch=1073741823;try{return a(b,c,d,e)}finally{ch=f}}var xh=null,W=null,yh=0,zh=void 0,X=!1,Ah=null,Y=0,rh=0,Bh=!1,Ch=null,Z=!1,Dh=!1,qh=!1,Eh=null,Fh=ba.unstable_now(),Gh=1073741822-(Fh/10|0),Hh=Gh,vh=50,uh=0,Ih=null;function Jh(){Gh=1073741822-((ba.unstable_now()-Fh)/10|0)} +function Kh(a,b){if(0!==yh){if(ba.expirationTime&&(a.expirationTime=b);X||(Z?Dh&&(Ah=a,Y=1073741823,Ph(a,1073741823,!1)):1073741823===b?Qh(1073741823,!1):Kh(a,b))} +function Oh(){var a=0,b=null;if(null!==W)for(var c=W,d=xh;null!==d;){var e=d.expirationTime;if(0===e){null===c||null===W?t("244"):void 0;if(d===d.nextScheduledRoot){xh=W=d.nextScheduledRoot=null;break}else if(d===xh)xh=e=d.nextScheduledRoot,W.nextScheduledRoot=e,d.nextScheduledRoot=null;else if(d===W){W=c;W.nextScheduledRoot=xh;d.nextScheduledRoot=null;break}else c.nextScheduledRoot=d.nextScheduledRoot,d.nextScheduledRoot=null;d=c.nextScheduledRoot}else{e>a&&(a=e,b=d);if(d===W)break;if(1073741823=== +a)break;c=d;d=d.nextScheduledRoot}}Ah=b;Y=a}var Rh=!1;function nh(){return Rh?!0:ba.unstable_shouldYield()?Rh=!0:!1}function Lh(){try{if(!nh()&&null!==xh){Jh();var a=xh;do{var b=a.expirationTime;0!==b&&Gh<=b&&(a.nextExpirationTimeToWorkOn=Gh);a=a.nextScheduledRoot}while(a!==xh)}Qh(0,!0)}finally{Rh=!1}} +function Qh(a,b){Oh();if(b)for(Jh(),Hh=Gh;null!==Ah&&0!==Y&&a<=Y&&!(Rh&&Gh>Y);)Ph(Ah,Y,Gh>Y),Oh(),Jh(),Hh=Gh;else for(;null!==Ah&&0!==Y&&a<=Y;)Ph(Ah,Y,!1),Oh();b&&(yh=0,zh=null);0!==Y&&Kh(Ah,Y);uh=0;Ih=null;if(null!==Eh)for(a=Eh,Eh=null,b=0;b=c&&(null===Eh?Eh=[d]:Eh.push(d),d._defer)){a.finishedWork=b;a.expirationTime=0;return}a.finishedWork=null;a===Ih?uh++:(Ih=a,uh=0);gh=dh=!0;a.current===b?t("177"):void 0;c=a.pendingCommitExpirationTime;0===c?t("261"):void 0;a.pendingCommitExpirationTime=0;d=b.expirationTime;var e=b.childExpirationTime;d=e>d?e:d;a.didError=!1;0===d?(a.earliestPendingTime=0,a.latestPendingTime=0,a.earliestSuspendedTime=0,a.latestSuspendedTime=0,a.latestPingedTime= +0):(dd?a.earliestPendingTime=a.latestPendingTime=0:a.earliestPendingTime>d&&(a.earliestPendingTime=a.latestPendingTime)),e=a.earliestSuspendedTime,0===e?ff(a,d):de&&ff(a,d));gf(0,a);ah.current=null;1q&&(u=q,q=G,G=u),u=Rd(x,G),A=Rd(x,q),u&&A&&(1!==p.rangeCount||p.anchorNode!==u.node||p.anchorOffset!==u.offset||p.focusNode!==A.node||p.focusOffset!==A.offset)&&(C=C.createRange(),C.setStart(u.node,u.offset),p.removeAllRanges(), +G>q?(p.addRange(C),p.extend(A.node,A.offset)):(C.setEnd(A.node,A.offset),p.addRange(C))))));C=[];for(p=x;p=p.parentNode;)1===p.nodeType&&C.push({element:p,left:p.scrollLeft,top:p.scrollTop});"function"===typeof x.focus&&x.focus();for(x=0;xFb?b:Fb;0===b&&(Yg= +null);a.expirationTime=b;a.finishedWork=null}function Wg(a){null===Ah?t("246"):void 0;Ah.expirationTime=0;Bh||(Bh=!0,Ch=a)}function Th(a,b){var c=Z;Z=!0;try{return a(b)}finally{(Z=c)||X||Qh(1073741823,!1)}}function Uh(a,b){if(Z&&!Dh){Dh=!0;try{return a(b)}finally{Dh=!1}}return a(b)}function Wh(a,b,c){if(qh)return a(b,c);Z||X||0===rh||(Qh(rh,!1),rh=0);var d=qh,e=Z;Z=qh=!0;try{return a(b,c)}finally{qh=d,(Z=e)||X||Qh(1073741823,!1)}} +function Xh(a,b,c,d,e){var f=b.current;a:if(c){c=c._reactInternalFiber;b:{2===kd(c)&&1===c.tag?void 0:t("170");var g=c;do{switch(g.tag){case 3:g=g.stateNode.context;break b;case 1:if(M(g.type)){g=g.stateNode.__reactInternalMemoizedMergedChildContext;break b}}g=g.return}while(null!==g);t("171");g=void 0}if(1===c.tag){var h=c.type;if(M(h)){c=Qe(c,h,g);break a}}c=g}else c=Ke;null===b.context?b.context=c:b.pendingContext=c;b=e;e=nf(d);e.payload={element:a};b=void 0===b?null:b;null!==b&&(e.callback=b); +Tf();pf(f,e);Uf(f,d);return d}function Yh(a,b,c,d){var e=b.current,f=Rf();e=Sf(f,e);return Xh(a,b,c,e,d)}function Zh(a){a=a.current;if(!a.child)return null;switch(a.child.tag){case 5:return a.child.stateNode;default:return a.child.stateNode}}function $h(a,b,c){var d=3=bh&&(b=bh-1);this._expirationTime=bh=b;this._root=a;this._callbacks=this._next=null;this._hasChildren=this._didComplete=!1;this._children=null;this._defer=!0}ai.prototype.render=function(a){this._defer?void 0:t("250");this._hasChildren=!0;this._children=a;var b=this._root._internalRoot,c=this._expirationTime,d=new bi;Xh(a,b,null,c,d._onCommit);return d}; +ai.prototype.then=function(a){if(this._didComplete)a();else{var b=this._callbacks;null===b&&(b=this._callbacks=[]);b.push(a)}}; +ai.prototype.commit=function(){var a=this._root._internalRoot,b=a.firstBatch;this._defer&&null!==b?void 0:t("251");if(this._hasChildren){var c=this._expirationTime;if(b!==this){this._hasChildren&&(c=this._expirationTime=b._expirationTime,this.render(this._children));for(var d=null,e=b;e!==this;)d=e,e=e._next;null===d?t("251"):void 0;d._next=e._next;this._next=b;a.firstBatch=this}this._defer=!1;Nh(a,c);b=this._next;this._next=null;b=a.firstBatch=b;null!==b&&b._hasChildren&&b.render(b._children)}else this._next= +null,this._defer=!1};ai.prototype._onComplete=function(){if(!this._didComplete){this._didComplete=!0;var a=this._callbacks;if(null!==a)for(var b=0;b=b;)c=d,d=d._next;a._next=d;null!==c&&(c._next=a)}return a};function di(a){return!(!a||1!==a.nodeType&&9!==a.nodeType&&11!==a.nodeType&&(8!==a.nodeType||" react-mount-point-unstable "!==a.nodeValue))}Kb=Th;Lb=Wh;Mb=function(){X||0===rh||(Qh(rh,!1),rh=0)}; +function ei(a,b){b||(b=a?9===a.nodeType?a.documentElement:a.firstChild:null,b=!(!b||1!==b.nodeType||!b.hasAttribute("data-reactroot")));if(!b)for(var c;c=a.lastChild;)a.removeChild(c);return new ci(a,!1,b)} +function fi(a,b,c,d,e){di(c)?void 0:t("200");var f=c._reactRootContainer;if(f){if("function"===typeof e){var g=e;e=function(){var a=Zh(f._internalRoot);g.call(a)}}null!=a?f.legacy_renderSubtreeIntoContainer(a,b,e):f.render(b,e)}else{f=c._reactRootContainer=ei(c,d);if("function"===typeof e){var h=e;e=function(){var a=Zh(f._internalRoot);h.call(a)}}Uh(function(){null!=a?f.legacy_renderSubtreeIntoContainer(a,b,e):f.render(b,e)})}return Zh(f._internalRoot)} +function gi(a,b){var c=2=b){d=a;break}a=a.next}while(a!==c);null===d?d=c:d===c&&(c=g,p());b=d.previous;b.next=d.previous=g;g.next=d;g.previous= +b}}function v(){if(-1===k&&null!==c&&1===c.priorityLevel){m=!0;try{do u();while(null!==c&&1===c.priorityLevel)}finally{m=!1,null!==c?p():n=!1}}}function t(a){m=!0;var b=f;f=a;try{if(a)for(;null!==c;){var d=exports.unstable_now();if(c.expirationTime<=d){do u();while(null!==c&&c.expirationTime<=d)}else break}else if(null!==c){do u();while(null!==c&&!w())}}finally{m=!1,f=b,null!==c?p():n=!1,v()}} +var x=Date,y="function"===typeof setTimeout?setTimeout:void 0,z="function"===typeof clearTimeout?clearTimeout:void 0,A="function"===typeof requestAnimationFrame?requestAnimationFrame:void 0,B="function"===typeof cancelAnimationFrame?cancelAnimationFrame:void 0,C,D;function E(a){C=A(function(b){z(D);a(b)});D=y(function(){B(C);a(exports.unstable_now())},100)} +if("object"===typeof performance&&"function"===typeof performance.now){var F=performance;exports.unstable_now=function(){return F.now()}}else exports.unstable_now=function(){return x.now()};var r,q,w,G=null;"undefined"!==typeof window?G=window:"undefined"!==typeof global&&(G=global); +if(G&&G._schedMock){var H=G._schedMock;r=H[0];q=H[1];w=H[2];exports.unstable_now=H[3]}else if("undefined"===typeof window||"function"!==typeof MessageChannel){var I=null,J=function(a){if(null!==I)try{I(a)}finally{I=null}};r=function(a){null!==I?setTimeout(r,0,a):(I=a,setTimeout(J,0,!1))};q=function(){I=null};w=function(){return!1}}else{"undefined"!==typeof console&&("function"!==typeof A&&console.error("This browser doesn't support requestAnimationFrame. Make sure that you load a polyfill in older browsers. https://fb.me/react-polyfills"), +"function"!==typeof B&&console.error("This browser doesn't support cancelAnimationFrame. Make sure that you load a polyfill in older browsers. https://fb.me/react-polyfills"));var K=null,L=!1,M=-1,N=!1,O=!1,P=0,R=33,S=33;w=function(){return P<=exports.unstable_now()};var T=new MessageChannel,U=T.port2;T.port1.onmessage=function(){L=!1;var a=K,b=M;K=null;M=-1;var d=exports.unstable_now(),e=!1;if(0>=P-d)if(-1!==b&&b<=d)e=!0;else{N||(N=!0,E(V));K=a;M=b;return}if(null!==a){O=!0;try{a(e)}finally{O=!1}}}; +var V=function(a){if(null!==K){E(V);var b=a-P+S;bb&&(b=8),S=bb?U.postMessage(void 0):N||(N=!0,E(V))};q=function(){K=null;L=!1;M=-1}}exports.unstable_ImmediatePriority=1;exports.unstable_UserBlockingPriority=2;exports.unstable_NormalPriority=3;exports.unstable_IdlePriority=5;exports.unstable_LowPriority=4; +exports.unstable_runWithPriority=function(a,b){switch(a){case 1:case 2:case 3:case 4:case 5:break;default:a=3}var d=h,e=k;h=a;k=exports.unstable_now();try{return b()}finally{h=d,k=e,v()}}; +exports.unstable_scheduleCallback=function(a,b){var d=-1!==k?k:exports.unstable_now();if("object"===typeof b&&null!==b&&"number"===typeof b.timeout)b=d+b.timeout;else switch(h){case 1:b=d+-1;break;case 2:b=d+250;break;case 5:b=d+1073741823;break;case 4:b=d+1E4;break;default:b=d+5E3}a={callback:a,priorityLevel:h,expirationTime:b,next:null,previous:null};if(null===c)c=a.next=a.previous=a,p();else{d=null;var e=c;do{if(e.expirationTime>b){d=e;break}e=e.next}while(e!==c);null===d?d=c:d===c&&(c=a,p()); +b=d.previous;b.next=d.previous=a;a.next=d;a.previous=b}return a};exports.unstable_cancelCallback=function(a){var b=a.next;if(null!==b){if(b===a)c=null;else{a===c&&(c=b);var d=a.previous;d.next=b;b.previous=d}a.next=a.previous=null}};exports.unstable_wrapCallback=function(a){var b=h;return function(){var d=h,e=k;h=b;k=exports.unstable_now();try{return a.apply(this,arguments)}finally{h=d,k=e,v()}}};exports.unstable_getCurrentPriorityLevel=function(){return h}; +exports.unstable_shouldYield=function(){return!f&&(null!==c&&c.expirationTime= expirationTime) { + // This callback expires at or after the continuation. We will insert + // the continuation *before* this callback. + nextAfterContinuation = node; + break; + } + node = node.next; + } while (node !== firstCallbackNode); + + if (nextAfterContinuation === null) { + // No equal or lower priority callback was found, which means the new + // callback is the lowest priority callback in the list. + nextAfterContinuation = firstCallbackNode; + } else if (nextAfterContinuation === firstCallbackNode) { + // The new callback is the highest priority callback in the list. + firstCallbackNode = continuationNode; + ensureHostCallbackIsScheduled(); + } + + var previous = nextAfterContinuation.previous; + previous.next = nextAfterContinuation.previous = continuationNode; + continuationNode.next = nextAfterContinuation; + continuationNode.previous = previous; } } - return mixedRef; } -function throwOnInvalidObjectType(returnFiber, newChild) { - if (returnFiber.type !== 'textarea') { - var addendum = ''; - { - addendum = ' If you meant to render a collection of children, use an array ' + 'instead.' + (getCurrentFiberStackAddendum$1() || ''); +function flushImmediateWork() { + if ( + // Confirm we've exited the outer most event handler + currentEventStartTime === -1 && firstCallbackNode !== null && firstCallbackNode.priorityLevel === ImmediatePriority) { + isExecutingCallback = true; + try { + do { + flushFirstCallback(); + } while ( + // Keep flushing until there are no more immediate callbacks + firstCallbackNode !== null && firstCallbackNode.priorityLevel === ImmediatePriority); + } finally { + isExecutingCallback = false; + if (firstCallbackNode !== null) { + // There's still work remaining. Request another callback. + ensureHostCallbackIsScheduled(); + } else { + isHostCallbackScheduled = false; + } } - invariant(false, 'Objects are not valid as a React child (found: %s).%s', Object.prototype.toString.call(newChild) === '[object Object]' ? 'object with keys {' + Object.keys(newChild).join(', ') + '}' : newChild, addendum); } } -function warnOnFunctionType() { - var currentComponentErrorInfo = 'Functions are not valid as a React child. This may happen if ' + 'you return a Component instead of from render. ' + 'Or maybe you meant to call this function rather than return it.' + (getCurrentFiberStackAddendum$1() || ''); +function flushWork(didTimeout) { + // Exit right away if we're currently paused - if (ownerHasFunctionTypeWarning[currentComponentErrorInfo]) { + if (enableSchedulerDebugging && isSchedulerPaused) { return; } - ownerHasFunctionTypeWarning[currentComponentErrorInfo] = true; - - warning(false, 'Functions are not valid as a React child. This may happen if ' + 'you return a Component instead of from render. ' + 'Or maybe you meant to call this function rather than return it.%s', getCurrentFiberStackAddendum$1() || ''); -} -// This wrapper function exists because I expect to clone the code in each path -// to be able to optimize each path individually by branching early. This needs -// a compiler or we can do it manually. Helpers that don't need this branching -// live outside of this function. -function ChildReconciler(shouldTrackSideEffects) { - function deleteChild(returnFiber, childToDelete) { - if (!shouldTrackSideEffects) { - // Noop. - return; + isExecutingCallback = true; + var previousDidTimeout = currentDidTimeout; + currentDidTimeout = didTimeout; + try { + if (didTimeout) { + // Flush all the expired callbacks without yielding. + while (firstCallbackNode !== null && !(enableSchedulerDebugging && isSchedulerPaused)) { + // TODO Wrap i nfeature flag + // Read the current time. Flush all the callbacks that expire at or + // earlier than that time. Then read the current time again and repeat. + // This optimizes for as few performance.now calls as possible. + var currentTime = exports.unstable_now(); + if (firstCallbackNode.expirationTime <= currentTime) { + do { + flushFirstCallback(); + } while (firstCallbackNode !== null && firstCallbackNode.expirationTime <= currentTime && !(enableSchedulerDebugging && isSchedulerPaused)); + continue; + } + break; + } + } else { + // Keep flushing callbacks until we run out of time in the frame. + if (firstCallbackNode !== null) { + do { + if (enableSchedulerDebugging && isSchedulerPaused) { + break; + } + flushFirstCallback(); + } while (firstCallbackNode !== null && !shouldYieldToHost()); + } } - // Deletions are added in reversed order so we add it to the front. - // At this point, the return fiber's effect list is empty except for - // deletions, so we can just append the deletion to the list. The remaining - // effects aren't added until the complete phase. Once we implement - // resuming, this may not be true. - var last = returnFiber.lastEffect; - if (last !== null) { - last.nextEffect = childToDelete; - returnFiber.lastEffect = childToDelete; + } finally { + isExecutingCallback = false; + currentDidTimeout = previousDidTimeout; + if (firstCallbackNode !== null) { + // There's still work remaining. Request another callback. + ensureHostCallbackIsScheduled(); } else { - returnFiber.firstEffect = returnFiber.lastEffect = childToDelete; + isHostCallbackScheduled = false; } - childToDelete.nextEffect = null; - childToDelete.effectTag = Deletion; + // Before exiting, flush all the immediate work that was scheduled. + flushImmediateWork(); } +} - function deleteRemainingChildren(returnFiber, currentFirstChild) { - if (!shouldTrackSideEffects) { - // Noop. - return null; - } - - // TODO: For the shouldClone case, this could be micro-optimized a bit by - // assuming that after the first child we've already added everything. - var childToDelete = currentFirstChild; - while (childToDelete !== null) { - deleteChild(returnFiber, childToDelete); - childToDelete = childToDelete.sibling; - } - return null; +function unstable_runWithPriority(priorityLevel, eventHandler) { + switch (priorityLevel) { + case ImmediatePriority: + case UserBlockingPriority: + case NormalPriority: + case LowPriority: + case IdlePriority: + break; + default: + priorityLevel = NormalPriority; } - function mapRemainingChildren(returnFiber, currentFirstChild) { - // Add the remaining children to a temporary map so that we can find them by - // keys quickly. Implicit (null) keys get added to this set with their index - var existingChildren = new Map(); + var previousPriorityLevel = currentPriorityLevel; + var previousEventStartTime = currentEventStartTime; + currentPriorityLevel = priorityLevel; + currentEventStartTime = exports.unstable_now(); - var existingChild = currentFirstChild; - while (existingChild !== null) { - if (existingChild.key !== null) { - existingChildren.set(existingChild.key, existingChild); - } else { - existingChildren.set(existingChild.index, existingChild); - } - existingChild = existingChild.sibling; - } - return existingChildren; - } + try { + return eventHandler(); + } finally { + currentPriorityLevel = previousPriorityLevel; + currentEventStartTime = previousEventStartTime; - function useFiber(fiber, pendingProps, expirationTime) { - // We currently set sibling to null and index to 0 here because it is easy - // to forget to do before returning it. E.g. for the single child case. - var clone = createWorkInProgress(fiber, pendingProps, expirationTime); - clone.index = 0; - clone.sibling = null; - return clone; + // Before exiting, flush all the immediate work that was scheduled. + flushImmediateWork(); } +} - function placeChild(newFiber, lastPlacedIndex, newIndex) { - newFiber.index = newIndex; - if (!shouldTrackSideEffects) { - // Noop. - return lastPlacedIndex; - } - var current = newFiber.alternate; - if (current !== null) { - var oldIndex = current.index; - if (oldIndex < lastPlacedIndex) { - // This is a move. - newFiber.effectTag = Placement; - return lastPlacedIndex; - } else { - // This item can stay in place. - return oldIndex; - } - } else { - // This is an insertion. - newFiber.effectTag = Placement; - return lastPlacedIndex; - } - } +function unstable_wrapCallback(callback) { + var parentPriorityLevel = currentPriorityLevel; + return function () { + // This is a fork of runWithPriority, inlined for performance. + var previousPriorityLevel = currentPriorityLevel; + var previousEventStartTime = currentEventStartTime; + currentPriorityLevel = parentPriorityLevel; + currentEventStartTime = exports.unstable_now(); - function placeSingleChild(newFiber) { - // This is simpler for the single child case. We only need to do a - // placement for inserting new children. - if (shouldTrackSideEffects && newFiber.alternate === null) { - newFiber.effectTag = Placement; + try { + return callback.apply(this, arguments); + } finally { + currentPriorityLevel = previousPriorityLevel; + currentEventStartTime = previousEventStartTime; + flushImmediateWork(); } - return newFiber; - } + }; +} - function updateTextNode(returnFiber, current, textContent, expirationTime) { - if (current === null || current.tag !== HostText) { - // Insert - var created = createFiberFromText(textContent, returnFiber.internalContextTag, expirationTime); - created['return'] = returnFiber; - return created; - } else { - // Update - var existing = useFiber(current, textContent, expirationTime); - existing['return'] = returnFiber; - return existing; +function unstable_scheduleCallback(callback, deprecated_options) { + var startTime = currentEventStartTime !== -1 ? currentEventStartTime : exports.unstable_now(); + + var expirationTime; + if (typeof deprecated_options === 'object' && deprecated_options !== null && typeof deprecated_options.timeout === 'number') { + // FIXME: Remove this branch once we lift expiration times out of React. + expirationTime = startTime + deprecated_options.timeout; + } else { + switch (currentPriorityLevel) { + case ImmediatePriority: + expirationTime = startTime + IMMEDIATE_PRIORITY_TIMEOUT; + break; + case UserBlockingPriority: + expirationTime = startTime + USER_BLOCKING_PRIORITY; + break; + case IdlePriority: + expirationTime = startTime + IDLE_PRIORITY; + break; + case LowPriority: + expirationTime = startTime + LOW_PRIORITY_TIMEOUT; + break; + case NormalPriority: + default: + expirationTime = startTime + NORMAL_PRIORITY_TIMEOUT; } } - function updateElement(returnFiber, current, element, expirationTime) { - if (current !== null && current.type === element.type) { - // Move based on index - var existing = useFiber(current, element.props, expirationTime); - existing.ref = coerceRef(current, element); - existing['return'] = returnFiber; - { - existing._debugSource = element._source; - existing._debugOwner = element._owner; + var newNode = { + callback: callback, + priorityLevel: currentPriorityLevel, + expirationTime: expirationTime, + next: null, + previous: null + }; + + // Insert the new callback into the list, ordered first by expiration, then + // by insertion. So the new callback is inserted any other callback with + // equal expiration. + if (firstCallbackNode === null) { + // This is the first callback in the list. + firstCallbackNode = newNode.next = newNode.previous = newNode; + ensureHostCallbackIsScheduled(); + } else { + var next = null; + var node = firstCallbackNode; + do { + if (node.expirationTime > expirationTime) { + // The new callback expires before this one. + next = node; + break; } - return existing; - } else { - // Insert - var created = createFiberFromElement(element, returnFiber.internalContextTag, expirationTime); - created.ref = coerceRef(current, element); - created['return'] = returnFiber; - return created; - } - } + node = node.next; + } while (node !== firstCallbackNode); - function updateCall(returnFiber, current, call, expirationTime) { - // TODO: Should this also compare handler to determine whether to reuse? - if (current === null || current.tag !== CallComponent) { - // Insert - var created = createFiberFromCall(call, returnFiber.internalContextTag, expirationTime); - created['return'] = returnFiber; - return created; - } else { - // Move based on index - var existing = useFiber(current, call, expirationTime); - existing['return'] = returnFiber; - return existing; + if (next === null) { + // No callback with a later expiration was found, which means the new + // callback has the latest expiration in the list. + next = firstCallbackNode; + } else if (next === firstCallbackNode) { + // The new callback has the earliest expiration in the entire list. + firstCallbackNode = newNode; + ensureHostCallbackIsScheduled(); } + + var previous = next.previous; + previous.next = next.previous = newNode; + newNode.next = next; + newNode.previous = previous; } - function updateReturn(returnFiber, current, returnNode, expirationTime) { - if (current === null || current.tag !== ReturnComponent) { - // Insert - var created = createFiberFromReturn(returnNode, returnFiber.internalContextTag, expirationTime); - created.type = returnNode.value; - created['return'] = returnFiber; - return created; - } else { - // Move based on index - var existing = useFiber(current, null, expirationTime); - existing.type = returnNode.value; - existing['return'] = returnFiber; - return existing; - } + return newNode; +} + +function unstable_pauseExecution() { + isSchedulerPaused = true; +} + +function unstable_continueExecution() { + isSchedulerPaused = false; + if (firstCallbackNode !== null) { + ensureHostCallbackIsScheduled(); } +} - function updatePortal(returnFiber, current, portal, expirationTime) { - if (current === null || current.tag !== HostPortal || current.stateNode.containerInfo !== portal.containerInfo || current.stateNode.implementation !== portal.implementation) { - // Insert - var created = createFiberFromPortal(portal, returnFiber.internalContextTag, expirationTime); - created['return'] = returnFiber; - return created; - } else { - // Update - var existing = useFiber(current, portal.children || [], expirationTime); - existing['return'] = returnFiber; - return existing; - } +function unstable_getFirstCallbackNode() { + return firstCallbackNode; +} + +function unstable_cancelCallback(callbackNode) { + var next = callbackNode.next; + if (next === null) { + // Already cancelled. + return; } - function updateFragment(returnFiber, current, fragment, expirationTime, key) { - if (current === null || current.tag !== Fragment) { - // Insert - var created = createFiberFromFragment(fragment, returnFiber.internalContextTag, expirationTime, key); - created['return'] = returnFiber; - return created; - } else { - // Update - var existing = useFiber(current, fragment, expirationTime); - existing['return'] = returnFiber; - return existing; + if (next === callbackNode) { + // This is the only scheduled callback. Clear the list. + firstCallbackNode = null; + } else { + // Remove the callback from its position in the list. + if (callbackNode === firstCallbackNode) { + firstCallbackNode = next; } + var previous = callbackNode.previous; + previous.next = next; + next.previous = previous; } - function createChild(returnFiber, newChild, expirationTime) { - if (typeof newChild === 'string' || typeof newChild === 'number') { - // Text nodes don't have keys. If the previous node is implicitly keyed - // we can continue to replace it without aborting even if it is not a text - // node. - var created = createFiberFromText('' + newChild, returnFiber.internalContextTag, expirationTime); - created['return'] = returnFiber; - return created; - } + callbackNode.next = callbackNode.previous = null; +} - if (typeof newChild === 'object' && newChild !== null) { - switch (newChild.$$typeof) { - case REACT_ELEMENT_TYPE: - { - if (newChild.type === REACT_FRAGMENT_TYPE) { - var _created = createFiberFromFragment(newChild.props.children, returnFiber.internalContextTag, expirationTime, newChild.key); - _created['return'] = returnFiber; - return _created; - } else { - var _created2 = createFiberFromElement(newChild, returnFiber.internalContextTag, expirationTime); - _created2.ref = coerceRef(null, newChild); - _created2['return'] = returnFiber; - return _created2; - } - } +function unstable_getCurrentPriorityLevel() { + return currentPriorityLevel; +} - case REACT_CALL_TYPE: - { - var _created3 = createFiberFromCall(newChild, returnFiber.internalContextTag, expirationTime); - _created3['return'] = returnFiber; - return _created3; - } +function unstable_shouldYield() { + return !currentDidTimeout && (firstCallbackNode !== null && firstCallbackNode.expirationTime < currentExpirationTime || shouldYieldToHost()); +} - case REACT_RETURN_TYPE: - { - var _created4 = createFiberFromReturn(newChild, returnFiber.internalContextTag, expirationTime); - _created4.type = newChild.value; - _created4['return'] = returnFiber; - return _created4; - } +// The remaining code is essentially a polyfill for requestIdleCallback. It +// works by scheduling a requestAnimationFrame, storing the time for the start +// of the frame, then scheduling a postMessage which gets scheduled after paint. +// Within the postMessage handler do as much work as possible until time + frame +// rate. By separating the idle call into a separate event tick we ensure that +// layout, paint and other browser work is counted against the available time. +// The frame rate is dynamically adjusted. - case REACT_PORTAL_TYPE: - { - var _created5 = createFiberFromPortal(newChild, returnFiber.internalContextTag, expirationTime); - _created5['return'] = returnFiber; - return _created5; - } - } +// We capture a local reference to any global, in case it gets polyfilled after +// this module is initially evaluated. We want to be using a +// consistent implementation. +var localDate = Date; + +// This initialization code may run even on server environments if a component +// just imports ReactDOM (e.g. for findDOMNode). Some environments might not +// have setTimeout or clearTimeout. However, we always expect them to be defined +// on the client. https://github.com/facebook/react/pull/13088 +var localSetTimeout = typeof setTimeout === 'function' ? setTimeout : undefined; +var localClearTimeout = typeof clearTimeout === 'function' ? clearTimeout : undefined; + +// We don't expect either of these to necessarily be defined, but we will error +// later if they are missing on the client. +var localRequestAnimationFrame = typeof requestAnimationFrame === 'function' ? requestAnimationFrame : undefined; +var localCancelAnimationFrame = typeof cancelAnimationFrame === 'function' ? cancelAnimationFrame : undefined; + +// requestAnimationFrame does not run when the tab is in the background. If +// we're backgrounded we prefer for that work to happen so that the page +// continues to load in the background. So we also schedule a 'setTimeout' as +// a fallback. +// TODO: Need a better heuristic for backgrounded work. +var ANIMATION_FRAME_TIMEOUT = 100; +var rAFID; +var rAFTimeoutID; +var requestAnimationFrameWithTimeout = function (callback) { + // schedule rAF and also a setTimeout + rAFID = localRequestAnimationFrame(function (timestamp) { + // cancel the setTimeout + localClearTimeout(rAFTimeoutID); + callback(timestamp); + }); + rAFTimeoutID = localSetTimeout(function () { + // cancel the requestAnimationFrame + localCancelAnimationFrame(rAFID); + callback(exports.unstable_now()); + }, ANIMATION_FRAME_TIMEOUT); +}; - if (isArray$1(newChild) || getIteratorFn(newChild)) { - var _created6 = createFiberFromFragment(newChild, returnFiber.internalContextTag, expirationTime, null); - _created6['return'] = returnFiber; - return _created6; - } +if (hasNativePerformanceNow) { + var Performance = performance; + exports.unstable_now = function () { + return Performance.now(); + }; +} else { + exports.unstable_now = function () { + return localDate.now(); + }; +} - throwOnInvalidObjectType(returnFiber, newChild); - } +var requestHostCallback; +var cancelHostCallback; +var shouldYieldToHost; - { - if (typeof newChild === 'function') { - warnOnFunctionType(); +var globalValue = null; +if (typeof window !== 'undefined') { + globalValue = window; +} else if (typeof global !== 'undefined') { + globalValue = global; +} + +if (globalValue && globalValue._schedMock) { + // Dynamic injection, only for testing purposes. + var globalImpl = globalValue._schedMock; + requestHostCallback = globalImpl[0]; + cancelHostCallback = globalImpl[1]; + shouldYieldToHost = globalImpl[2]; + exports.unstable_now = globalImpl[3]; +} else if ( +// If Scheduler runs in a non-DOM environment, it falls back to a naive +// implementation using setTimeout. +typeof window === 'undefined' || +// Check if MessageChannel is supported, too. +typeof MessageChannel !== 'function') { + // If this accidentally gets imported in a non-browser environment, e.g. JavaScriptCore, + // fallback to a naive implementation. + var _callback = null; + var _flushCallback = function (didTimeout) { + if (_callback !== null) { + try { + _callback(didTimeout); + } finally { + _callback = null; } } - - return null; + }; + requestHostCallback = function (cb, ms) { + if (_callback !== null) { + // Protect against re-entrancy. + setTimeout(requestHostCallback, 0, cb); + } else { + _callback = cb; + setTimeout(_flushCallback, 0, false); + } + }; + cancelHostCallback = function () { + _callback = null; + }; + shouldYieldToHost = function () { + return false; + }; +} else { + if (typeof console !== 'undefined') { + // TODO: Remove fb.me link + if (typeof localRequestAnimationFrame !== 'function') { + console.error("This browser doesn't support requestAnimationFrame. " + 'Make sure that you load a ' + 'polyfill in older browsers. https://fb.me/react-polyfills'); + } + if (typeof localCancelAnimationFrame !== 'function') { + console.error("This browser doesn't support cancelAnimationFrame. " + 'Make sure that you load a ' + 'polyfill in older browsers. https://fb.me/react-polyfills'); + } } - function updateSlot(returnFiber, oldFiber, newChild, expirationTime) { - // Update the fiber if the keys match, otherwise return null. + var scheduledHostCallback = null; + var isMessageEventScheduled = false; + var timeoutTime = -1; - var key = oldFiber !== null ? oldFiber.key : null; + var isAnimationFrameScheduled = false; - if (typeof newChild === 'string' || typeof newChild === 'number') { - // Text nodes don't have keys. If the previous node is implicitly keyed - // we can continue to replace it without aborting even if it is not a text - // node. - if (key !== null) { - return null; - } - return updateTextNode(returnFiber, oldFiber, '' + newChild, expirationTime); - } + var isFlushingHostCallback = false; - if (typeof newChild === 'object' && newChild !== null) { - switch (newChild.$$typeof) { - case REACT_ELEMENT_TYPE: - { - if (newChild.key === key) { - if (newChild.type === REACT_FRAGMENT_TYPE) { - return updateFragment(returnFiber, oldFiber, newChild.props.children, expirationTime, key); - } - return updateElement(returnFiber, oldFiber, newChild, expirationTime); - } else { - return null; - } - } + var frameDeadline = 0; + // We start out assuming that we run at 30fps but then the heuristic tracking + // will adjust this value to a faster fps if we get more frequent animation + // frames. + var previousFrameTime = 33; + var activeFrameTime = 33; - case REACT_CALL_TYPE: - { - if (newChild.key === key) { - return updateCall(returnFiber, oldFiber, newChild, expirationTime); - } else { - return null; - } - } + shouldYieldToHost = function () { + return frameDeadline <= exports.unstable_now(); + }; - case REACT_RETURN_TYPE: - { - // Returns don't have keys. If the previous node is implicitly keyed - // we can continue to replace it without aborting even if it is not a - // yield. - if (key === null) { - return updateReturn(returnFiber, oldFiber, newChild, expirationTime); - } else { - return null; - } - } + // We use the postMessage trick to defer idle work until after the repaint. + var channel = new MessageChannel(); + var port = channel.port2; + channel.port1.onmessage = function (event) { + isMessageEventScheduled = false; + + var prevScheduledCallback = scheduledHostCallback; + var prevTimeoutTime = timeoutTime; + scheduledHostCallback = null; + timeoutTime = -1; - case REACT_PORTAL_TYPE: - { - if (newChild.key === key) { - return updatePortal(returnFiber, oldFiber, newChild, expirationTime); - } else { - return null; - } - } - } + var currentTime = exports.unstable_now(); - if (isArray$1(newChild) || getIteratorFn(newChild)) { - if (key !== null) { - return null; + var didTimeout = false; + if (frameDeadline - currentTime <= 0) { + // There's no time left in this idle period. Check if the callback has + // a timeout and whether it's been exceeded. + if (prevTimeoutTime !== -1 && prevTimeoutTime <= currentTime) { + // Exceeded the timeout. Invoke the callback even though there's no + // time left. + didTimeout = true; + } else { + // No timeout. + if (!isAnimationFrameScheduled) { + // Schedule another animation callback so we retry later. + isAnimationFrameScheduled = true; + requestAnimationFrameWithTimeout(animationTick); } - - return updateFragment(returnFiber, oldFiber, newChild, expirationTime, null); + // Exit without invoking the callback. + scheduledHostCallback = prevScheduledCallback; + timeoutTime = prevTimeoutTime; + return; } - - throwOnInvalidObjectType(returnFiber, newChild); } - { - if (typeof newChild === 'function') { - warnOnFunctionType(); + if (prevScheduledCallback !== null) { + isFlushingHostCallback = true; + try { + prevScheduledCallback(didTimeout); + } finally { + isFlushingHostCallback = false; } } + }; - return null; - } - - function updateFromMap(existingChildren, returnFiber, newIdx, newChild, expirationTime) { - if (typeof newChild === 'string' || typeof newChild === 'number') { - // Text nodes don't have keys, so we neither have to check the old nor - // new node for the key. If both are text nodes, they match. - var matchedFiber = existingChildren.get(newIdx) || null; - return updateTextNode(returnFiber, matchedFiber, '' + newChild, expirationTime); + var animationTick = function (rafTime) { + if (scheduledHostCallback !== null) { + // Eagerly schedule the next animation callback at the beginning of the + // frame. If the scheduler queue is not empty at the end of the frame, it + // will continue flushing inside that callback. If the queue *is* empty, + // then it will exit immediately. Posting the callback at the start of the + // frame ensures it's fired within the earliest possible frame. If we + // waited until the end of the frame to post the callback, we risk the + // browser skipping a frame and not firing the callback until the frame + // after that. + requestAnimationFrameWithTimeout(animationTick); + } else { + // No pending work. Exit. + isAnimationFrameScheduled = false; + return; } - if (typeof newChild === 'object' && newChild !== null) { - switch (newChild.$$typeof) { - case REACT_ELEMENT_TYPE: - { - var _matchedFiber = existingChildren.get(newChild.key === null ? newIdx : newChild.key) || null; - if (newChild.type === REACT_FRAGMENT_TYPE) { - return updateFragment(returnFiber, _matchedFiber, newChild.props.children, expirationTime, newChild.key); - } - return updateElement(returnFiber, _matchedFiber, newChild, expirationTime); - } + var nextFrameTime = rafTime - frameDeadline + activeFrameTime; + if (nextFrameTime < activeFrameTime && previousFrameTime < activeFrameTime) { + if (nextFrameTime < 8) { + // Defensive coding. We don't support higher frame rates than 120hz. + // If the calculated frame time gets lower than 8, it is probably a bug. + nextFrameTime = 8; + } + // If one frame goes long, then the next one can be short to catch up. + // If two frames are short in a row, then that's an indication that we + // actually have a higher frame rate than what we're currently optimizing. + // We adjust our heuristic dynamically accordingly. For example, if we're + // running on 120hz display or 90hz VR display. + // Take the max of the two in case one of them was an anomaly due to + // missed frame deadlines. + activeFrameTime = nextFrameTime < previousFrameTime ? previousFrameTime : nextFrameTime; + } else { + previousFrameTime = nextFrameTime; + } + frameDeadline = rafTime + activeFrameTime; + if (!isMessageEventScheduled) { + isMessageEventScheduled = true; + port.postMessage(undefined); + } + }; - case REACT_CALL_TYPE: - { - var _matchedFiber2 = existingChildren.get(newChild.key === null ? newIdx : newChild.key) || null; - return updateCall(returnFiber, _matchedFiber2, newChild, expirationTime); - } + requestHostCallback = function (callback, absoluteTimeout) { + scheduledHostCallback = callback; + timeoutTime = absoluteTimeout; + if (isFlushingHostCallback || absoluteTimeout < 0) { + // Don't wait for the next frame. Continue working ASAP, in a new event. + port.postMessage(undefined); + } else if (!isAnimationFrameScheduled) { + // If rAF didn't already schedule one, we need to schedule a frame. + // TODO: If this rAF doesn't materialize because the browser throttles, we + // might want to still have setTimeout trigger rIC as a backup to ensure + // that we keep performing work. + isAnimationFrameScheduled = true; + requestAnimationFrameWithTimeout(animationTick); + } + }; - case REACT_RETURN_TYPE: - { - // Returns don't have keys, so we neither have to check the old nor - // new node for the key. If both are returns, they match. - var _matchedFiber3 = existingChildren.get(newIdx) || null; - return updateReturn(returnFiber, _matchedFiber3, newChild, expirationTime); - } + cancelHostCallback = function () { + scheduledHostCallback = null; + isMessageEventScheduled = false; + timeoutTime = -1; + }; +} - case REACT_PORTAL_TYPE: - { - var _matchedFiber4 = existingChildren.get(newChild.key === null ? newIdx : newChild.key) || null; - return updatePortal(returnFiber, _matchedFiber4, newChild, expirationTime); - } - } +exports.unstable_ImmediatePriority = ImmediatePriority; +exports.unstable_UserBlockingPriority = UserBlockingPriority; +exports.unstable_NormalPriority = NormalPriority; +exports.unstable_IdlePriority = IdlePriority; +exports.unstable_LowPriority = LowPriority; +exports.unstable_runWithPriority = unstable_runWithPriority; +exports.unstable_scheduleCallback = unstable_scheduleCallback; +exports.unstable_cancelCallback = unstable_cancelCallback; +exports.unstable_wrapCallback = unstable_wrapCallback; +exports.unstable_getCurrentPriorityLevel = unstable_getCurrentPriorityLevel; +exports.unstable_shouldYield = unstable_shouldYield; +exports.unstable_continueExecution = unstable_continueExecution; +exports.unstable_pauseExecution = unstable_pauseExecution; +exports.unstable_getFirstCallbackNode = unstable_getFirstCallbackNode; + })(); +} - if (isArray$1(newChild) || getIteratorFn(newChild)) { - var _matchedFiber5 = existingChildren.get(newIdx) || null; - return updateFragment(returnFiber, _matchedFiber5, newChild, expirationTime, null); - } +/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0), __webpack_require__(11))) - throwOnInvalidObjectType(returnFiber, newChild); - } +/***/ }), +/* 28 */ +/***/ (function(module, exports, __webpack_require__) { - { - if (typeof newChild === 'function') { - warnOnFunctionType(); - } - } +"use strict"; +/* WEBPACK VAR INJECTION */(function(process) {/** @license React v16.7.0 + * react-dom.development.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ - return null; - } - /** - * Warns if there is a duplicate or missing key - */ - function warnOnInvalidKey(child, knownKeys) { - { - if (typeof child !== 'object' || child === null) { - return knownKeys; - } - switch (child.$$typeof) { - case REACT_ELEMENT_TYPE: - case REACT_CALL_TYPE: - case REACT_PORTAL_TYPE: - warnForMissingKey(child); - var key = child.key; - if (typeof key !== 'string') { - break; - } - if (knownKeys === null) { - knownKeys = new Set(); - knownKeys.add(key); - break; - } - if (!knownKeys.has(key)) { - knownKeys.add(key); - break; - } - warning(false, 'Encountered two children with the same key, `%s`. ' + 'Keys should be unique so that components maintain their identity ' + 'across updates. Non-unique keys may cause children to be ' + 'duplicated and/or omitted — the behavior is unsupported and ' + 'could change in a future version.%s', key, getCurrentFiberStackAddendum$1()); - break; - default: - break; - } - } - return knownKeys; - } - function reconcileChildrenArray(returnFiber, currentFirstChild, newChildren, expirationTime) { - // This algorithm can't optimize by searching from boths ends since we - // don't have backpointers on fibers. I'm trying to see how far we can get - // with that model. If it ends up not being worth the tradeoffs, we can - // add it later. - // Even with a two ended optimization, we'd want to optimize for the case - // where there are few changes and brute force the comparison instead of - // going for the Map. It'd like to explore hitting that path first in - // forward-only mode and only go for the Map once we notice that we need - // lots of look ahead. This doesn't handle reversal as well as two ended - // search but that's unusual. Besides, for the two ended optimization to - // work on Iterables, we'd need to copy the whole set. - // In this first iteration, we'll just live with hitting the bad case - // (adding everything to a Map) in for every insert/move. +if (process.env.NODE_ENV !== "production") { + (function() { +'use strict'; - // If you change this code, also update reconcileChildrenIterator() which - // uses the same algorithm. +var React = __webpack_require__(1); +var _assign = __webpack_require__(6); +var checkPropTypes = __webpack_require__(8); +var scheduler = __webpack_require__(10); +var tracing = __webpack_require__(29); - { - // First, validate keys. - var knownKeys = null; - for (var i = 0; i < newChildren.length; i++) { - var child = newChildren[i]; - knownKeys = warnOnInvalidKey(child, knownKeys); - } - } +/** + * Use invariant() to assert state which your program assumes to be true. + * + * Provide sprintf-style format (only %s is supported) and arguments + * to provide information about what broke and what you were + * expecting. + * + * The invariant message will be stripped in production, but the invariant + * will remain to ensure logic does not differ in production. + */ - var resultingFirstChild = null; - var previousNewFiber = null; +var validateFormat = function () {}; - var oldFiber = currentFirstChild; - var lastPlacedIndex = 0; - var newIdx = 0; - var nextOldFiber = null; - for (; oldFiber !== null && newIdx < newChildren.length; newIdx++) { - if (oldFiber.index > newIdx) { - nextOldFiber = oldFiber; - oldFiber = null; - } else { - nextOldFiber = oldFiber.sibling; - } - var newFiber = updateSlot(returnFiber, oldFiber, newChildren[newIdx], expirationTime); - if (newFiber === null) { - // TODO: This breaks on empty slots like null children. That's - // unfortunate because it triggers the slow path all the time. We need - // a better way to communicate whether this was a miss or null, - // boolean, undefined, etc. - if (oldFiber === null) { - oldFiber = nextOldFiber; - } - break; - } - if (shouldTrackSideEffects) { - if (oldFiber && newFiber.alternate === null) { - // We matched the slot, but we didn't reuse the existing fiber, so we - // need to delete the existing child. - deleteChild(returnFiber, oldFiber); - } - } - lastPlacedIndex = placeChild(newFiber, lastPlacedIndex, newIdx); - if (previousNewFiber === null) { - // TODO: Move out of the loop. This only happens for the first run. - resultingFirstChild = newFiber; - } else { - // TODO: Defer siblings if we're not at the right index for this slot. - // I.e. if we had null values before, then we want to defer this - // for each null value. However, we also don't want to call updateSlot - // with the previous one. - previousNewFiber.sibling = newFiber; - } - previousNewFiber = newFiber; - oldFiber = nextOldFiber; +{ + validateFormat = function (format) { + if (format === undefined) { + throw new Error('invariant requires an error message argument'); } + }; +} - if (newIdx === newChildren.length) { - // We've reached the end of the new children. We can delete the rest. - deleteRemainingChildren(returnFiber, oldFiber); - return resultingFirstChild; - } +function invariant(condition, format, a, b, c, d, e, f) { + validateFormat(format); - if (oldFiber === null) { - // If we don't have any more existing children we can choose a fast path - // since the rest will all be insertions. - for (; newIdx < newChildren.length; newIdx++) { - var _newFiber = createChild(returnFiber, newChildren[newIdx], expirationTime); - if (!_newFiber) { - continue; - } - lastPlacedIndex = placeChild(_newFiber, lastPlacedIndex, newIdx); - if (previousNewFiber === null) { - // TODO: Move out of the loop. This only happens for the first run. - resultingFirstChild = _newFiber; - } else { - previousNewFiber.sibling = _newFiber; - } - previousNewFiber = _newFiber; - } - return resultingFirstChild; + if (!condition) { + var error = void 0; + if (format === undefined) { + error = new Error('Minified exception occurred; use the non-minified dev environment ' + 'for the full error message and additional helpful warnings.'); + } else { + var args = [a, b, c, d, e, f]; + var argIndex = 0; + error = new Error(format.replace(/%s/g, function () { + return args[argIndex++]; + })); + error.name = 'Invariant Violation'; } - // Add all children to a key map for quick lookups. - var existingChildren = mapRemainingChildren(returnFiber, oldFiber); + error.framesToPop = 1; // we don't care about invariant's own frame + throw error; + } +} - // Keep scanning and use the map to restore deleted items as moves. - for (; newIdx < newChildren.length; newIdx++) { - var _newFiber2 = updateFromMap(existingChildren, returnFiber, newIdx, newChildren[newIdx], expirationTime); - if (_newFiber2) { - if (shouldTrackSideEffects) { - if (_newFiber2.alternate !== null) { - // The new fiber is a work in progress, but if there exists a - // current, that means that we reused the fiber. We need to delete - // it from the child list so that we don't add it to the deletion - // list. - existingChildren['delete'](_newFiber2.key === null ? newIdx : _newFiber2.key); - } - } - lastPlacedIndex = placeChild(_newFiber2, lastPlacedIndex, newIdx); - if (previousNewFiber === null) { - resultingFirstChild = _newFiber2; - } else { - previousNewFiber.sibling = _newFiber2; - } - previousNewFiber = _newFiber2; - } - } +// Relying on the `invariant()` implementation lets us +// preserve the format and params in the www builds. - if (shouldTrackSideEffects) { - // Any existing children that weren't consumed above were deleted. We need - // to add them to the deletion list. - existingChildren.forEach(function (child) { - return deleteChild(returnFiber, child); - }); - } +!React ? invariant(false, 'ReactDOM was loaded before React. Make sure you load the React package before loading ReactDOM.') : void 0; - return resultingFirstChild; +var invokeGuardedCallbackImpl = function (name, func, context, a, b, c, d, e, f) { + var funcArgs = Array.prototype.slice.call(arguments, 3); + try { + func.apply(context, funcArgs); + } catch (error) { + this.onError(error); } +}; - function reconcileChildrenIterator(returnFiber, currentFirstChild, newChildrenIterable, expirationTime) { - // This is the same implementation as reconcileChildrenArray(), - // but using the iterator instead. +{ + // In DEV mode, we swap out invokeGuardedCallback for a special version + // that plays more nicely with the browser's DevTools. The idea is to preserve + // "Pause on exceptions" behavior. Because React wraps all user-provided + // functions in invokeGuardedCallback, and the production version of + // invokeGuardedCallback uses a try-catch, all user exceptions are treated + // like caught exceptions, and the DevTools won't pause unless the developer + // takes the extra step of enabling pause on caught exceptions. This is + // untintuitive, though, because even though React has caught the error, from + // the developer's perspective, the error is uncaught. + // + // To preserve the expected "Pause on exceptions" behavior, we don't use a + // try-catch in DEV. Instead, we synchronously dispatch a fake event to a fake + // DOM node, and call the user-provided callback from inside an event handler + // for that fake event. If the callback throws, the error is "captured" using + // a global event handler. But because the error happens in a different + // event loop context, it does not interrupt the normal program flow. + // Effectively, this gives us try-catch behavior without actually using + // try-catch. Neat! - var iteratorFn = getIteratorFn(newChildrenIterable); - !(typeof iteratorFn === 'function') ? invariant(false, 'An object is not an iterable. This error is likely caused by a bug in React. Please file an issue.') : void 0; + // Check that the browser supports the APIs we need to implement our special + // DEV version of invokeGuardedCallback + if (typeof window !== 'undefined' && typeof window.dispatchEvent === 'function' && typeof document !== 'undefined' && typeof document.createEvent === 'function') { + var fakeNode = document.createElement('react'); - { - // Warn about using Maps as children - if (typeof newChildrenIterable.entries === 'function') { - var possibleMap = newChildrenIterable; - if (possibleMap.entries === iteratorFn) { - warning(didWarnAboutMaps, 'Using Maps as children is unsupported and will likely yield ' + 'unexpected results. Convert it to a sequence/iterable of keyed ' + 'ReactElements instead.%s', getCurrentFiberStackAddendum$1()); - didWarnAboutMaps = true; - } - } + var invokeGuardedCallbackDev = function (name, func, context, a, b, c, d, e, f) { + // If document doesn't exist we know for sure we will crash in this method + // when we call document.createEvent(). However this can cause confusing + // errors: https://github.com/facebookincubator/create-react-app/issues/3482 + // So we preemptively throw with a better message instead. + !(typeof document !== 'undefined') ? invariant(false, 'The `document` global was defined when React was initialized, but is not defined anymore. This can happen in a test environment if a component schedules an update from an asynchronous callback, but the test has already finished running. To solve this, you can either unmount the component at the end of your test (and ensure that any asynchronous operations get canceled in `componentWillUnmount`), or you can change the test itself to be asynchronous.') : void 0; + var evt = document.createEvent('Event'); - // First, validate keys. - // We'll get a different iterator later for the main pass. - var _newChildren = iteratorFn.call(newChildrenIterable); - if (_newChildren) { - var knownKeys = null; - var _step = _newChildren.next(); - for (; !_step.done; _step = _newChildren.next()) { - var child = _step.value; - knownKeys = warnOnInvalidKey(child, knownKeys); - } - } - } + // Keeps track of whether the user-provided callback threw an error. We + // set this to true at the beginning, then set it to false right after + // calling the function. If the function errors, `didError` will never be + // set to false. This strategy works even if the browser is flaky and + // fails to call our global error handler, because it doesn't rely on + // the error event at all. + var didError = true; - var newChildren = iteratorFn.call(newChildrenIterable); - !(newChildren != null) ? invariant(false, 'An iterable object provided no iterator.') : void 0; + // Keeps track of the value of window.event so that we can reset it + // during the callback to let user code access window.event in the + // browsers that support it. + var windowEvent = window.event; - var resultingFirstChild = null; - var previousNewFiber = null; + // Keeps track of the descriptor of window.event to restore it after event + // dispatching: https://github.com/facebook/react/issues/13688 + var windowEventDescriptor = Object.getOwnPropertyDescriptor(window, 'event'); - var oldFiber = currentFirstChild; - var lastPlacedIndex = 0; - var newIdx = 0; - var nextOldFiber = null; + // Create an event handler for our fake event. We will synchronously + // dispatch our fake event using `dispatchEvent`. Inside the handler, we + // call the user-provided callback. + var funcArgs = Array.prototype.slice.call(arguments, 3); + function callCallback() { + // We immediately remove the callback from event listeners so that + // nested `invokeGuardedCallback` calls do not clash. Otherwise, a + // nested call would trigger the fake event handlers of any call higher + // in the stack. + fakeNode.removeEventListener(evtType, callCallback, false); - var step = newChildren.next(); - for (; oldFiber !== null && !step.done; newIdx++, step = newChildren.next()) { - if (oldFiber.index > newIdx) { - nextOldFiber = oldFiber; - oldFiber = null; - } else { - nextOldFiber = oldFiber.sibling; - } - var newFiber = updateSlot(returnFiber, oldFiber, step.value, expirationTime); - if (newFiber === null) { - // TODO: This breaks on empty slots like null children. That's - // unfortunate because it triggers the slow path all the time. We need - // a better way to communicate whether this was a miss or null, - // boolean, undefined, etc. - if (!oldFiber) { - oldFiber = nextOldFiber; - } - break; - } - if (shouldTrackSideEffects) { - if (oldFiber && newFiber.alternate === null) { - // We matched the slot, but we didn't reuse the existing fiber, so we - // need to delete the existing child. - deleteChild(returnFiber, oldFiber); + // We check for window.hasOwnProperty('event') to prevent the + // window.event assignment in both IE <= 10 as they throw an error + // "Member not found" in strict mode, and in Firefox which does not + // support window.event. + if (typeof window.event !== 'undefined' && window.hasOwnProperty('event')) { + window.event = windowEvent; } + + func.apply(context, funcArgs); + didError = false; } - lastPlacedIndex = placeChild(newFiber, lastPlacedIndex, newIdx); - if (previousNewFiber === null) { - // TODO: Move out of the loop. This only happens for the first run. - resultingFirstChild = newFiber; - } else { - // TODO: Defer siblings if we're not at the right index for this slot. - // I.e. if we had null values before, then we want to defer this - // for each null value. However, we also don't want to call updateSlot - // with the previous one. - previousNewFiber.sibling = newFiber; - } - previousNewFiber = newFiber; - oldFiber = nextOldFiber; - } - if (step.done) { - // We've reached the end of the new children. We can delete the rest. - deleteRemainingChildren(returnFiber, oldFiber); - return resultingFirstChild; - } + // Create a global error event handler. We use this to capture the value + // that was thrown. It's possible that this error handler will fire more + // than once; for example, if non-React code also calls `dispatchEvent` + // and a handler for that event throws. We should be resilient to most of + // those cases. Even if our error event handler fires more than once, the + // last error event is always used. If the callback actually does error, + // we know that the last error event is the correct one, because it's not + // possible for anything else to have happened in between our callback + // erroring and the code that follows the `dispatchEvent` call below. If + // the callback doesn't error, but the error event was fired, we know to + // ignore it because `didError` will be false, as described above. + var error = void 0; + // Use this to track whether the error event is ever called. + var didSetError = false; + var isCrossOriginError = false; - if (oldFiber === null) { - // If we don't have any more existing children we can choose a fast path - // since the rest will all be insertions. - for (; !step.done; newIdx++, step = newChildren.next()) { - var _newFiber3 = createChild(returnFiber, step.value, expirationTime); - if (_newFiber3 === null) { - continue; + function handleWindowError(event) { + error = event.error; + didSetError = true; + if (error === null && event.colno === 0 && event.lineno === 0) { + isCrossOriginError = true; } - lastPlacedIndex = placeChild(_newFiber3, lastPlacedIndex, newIdx); - if (previousNewFiber === null) { - // TODO: Move out of the loop. This only happens for the first run. - resultingFirstChild = _newFiber3; - } else { - previousNewFiber.sibling = _newFiber3; + if (event.defaultPrevented) { + // Some other error handler has prevented default. + // Browsers silence the error report if this happens. + // We'll remember this to later decide whether to log it or not. + if (error != null && typeof error === 'object') { + try { + error._suppressLogging = true; + } catch (inner) { + // Ignore. + } + } } - previousNewFiber = _newFiber3; } - return resultingFirstChild; - } - // Add all children to a key map for quick lookups. - var existingChildren = mapRemainingChildren(returnFiber, oldFiber); + // Create a fake event type. + var evtType = 'react-' + (name ? name : 'invokeguardedcallback'); - // Keep scanning and use the map to restore deleted items as moves. - for (; !step.done; newIdx++, step = newChildren.next()) { - var _newFiber4 = updateFromMap(existingChildren, returnFiber, newIdx, step.value, expirationTime); - if (_newFiber4 !== null) { - if (shouldTrackSideEffects) { - if (_newFiber4.alternate !== null) { - // The new fiber is a work in progress, but if there exists a - // current, that means that we reused the fiber. We need to delete - // it from the child list so that we don't add it to the deletion - // list. - existingChildren['delete'](_newFiber4.key === null ? newIdx : _newFiber4.key); - } - } - lastPlacedIndex = placeChild(_newFiber4, lastPlacedIndex, newIdx); - if (previousNewFiber === null) { - resultingFirstChild = _newFiber4; - } else { - previousNewFiber.sibling = _newFiber4; + // Attach our event handlers + window.addEventListener('error', handleWindowError); + fakeNode.addEventListener(evtType, callCallback, false); + + // Synchronously dispatch our fake event. If the user-provided function + // errors, it will trigger our global error handler. + evt.initEvent(evtType, false, false); + fakeNode.dispatchEvent(evt); + + if (windowEventDescriptor) { + Object.defineProperty(window, 'event', windowEventDescriptor); + } + + if (didError) { + if (!didSetError) { + // The callback errored, but the error event never fired. + error = new Error('An error was thrown inside one of your components, but React ' + "doesn't know what it was. This is likely due to browser " + 'flakiness. React does its best to preserve the "Pause on ' + 'exceptions" behavior of the DevTools, which requires some ' + "DEV-mode only tricks. It's possible that these don't work in " + 'your browser. Try triggering the error in production mode, ' + 'or switching to a modern browser. If you suspect that this is ' + 'actually an issue with React, please file an issue.'); + } else if (isCrossOriginError) { + error = new Error("A cross-origin error was thrown. React doesn't have access to " + 'the actual error object in development. ' + 'See https://fb.me/react-crossorigin-error for more information.'); } - previousNewFiber = _newFiber4; + this.onError(error); } - } - if (shouldTrackSideEffects) { - // Any existing children that weren't consumed above were deleted. We need - // to add them to the deletion list. - existingChildren.forEach(function (child) { - return deleteChild(returnFiber, child); - }); - } + // Remove our event listeners + window.removeEventListener('error', handleWindowError); + }; - return resultingFirstChild; + invokeGuardedCallbackImpl = invokeGuardedCallbackDev; } +} - function reconcileSingleTextNode(returnFiber, currentFirstChild, textContent, expirationTime) { - // There's no need to check for keys on text nodes since we don't have a - // way to define them. - if (currentFirstChild !== null && currentFirstChild.tag === HostText) { - // We already have an existing node so let's just update it and delete - // the rest. - deleteRemainingChildren(returnFiber, currentFirstChild.sibling); - var existing = useFiber(currentFirstChild, textContent, expirationTime); - existing['return'] = returnFiber; - return existing; - } - // The existing first child is not a text node so we need to create one - // and delete the existing ones. - deleteRemainingChildren(returnFiber, currentFirstChild); - var created = createFiberFromText(textContent, returnFiber.internalContextTag, expirationTime); - created['return'] = returnFiber; - return created; - } +var invokeGuardedCallbackImpl$1 = invokeGuardedCallbackImpl; - function reconcileSingleElement(returnFiber, currentFirstChild, element, expirationTime) { - var key = element.key; - var child = currentFirstChild; - while (child !== null) { - // TODO: If key === null and child.key === null, then this only applies to - // the first item in the list. - if (child.key === key) { - if (child.tag === Fragment ? element.type === REACT_FRAGMENT_TYPE : child.type === element.type) { - deleteRemainingChildren(returnFiber, child.sibling); - var existing = useFiber(child, element.type === REACT_FRAGMENT_TYPE ? element.props.children : element.props, expirationTime); - existing.ref = coerceRef(child, element); - existing['return'] = returnFiber; - { - existing._debugSource = element._source; - existing._debugOwner = element._owner; - } - return existing; - } else { - deleteRemainingChildren(returnFiber, child); - break; - } - } else { - deleteChild(returnFiber, child); - } - child = child.sibling; - } +// Used by Fiber to simulate a try-catch. +var hasError = false; +var caughtError = null; - if (element.type === REACT_FRAGMENT_TYPE) { - var created = createFiberFromFragment(element.props.children, returnFiber.internalContextTag, expirationTime, element.key); - created['return'] = returnFiber; - return created; - } else { - var _created7 = createFiberFromElement(element, returnFiber.internalContextTag, expirationTime); - _created7.ref = coerceRef(currentFirstChild, element); - _created7['return'] = returnFiber; - return _created7; - } +// Used by event system to capture/rethrow the first error. +var hasRethrowError = false; +var rethrowError = null; + +var reporter = { + onError: function (error) { + hasError = true; + caughtError = error; } +}; - function reconcileSingleCall(returnFiber, currentFirstChild, call, expirationTime) { - var key = call.key; - var child = currentFirstChild; - while (child !== null) { - // TODO: If key === null and child.key === null, then this only applies to - // the first item in the list. - if (child.key === key) { - if (child.tag === CallComponent) { - deleteRemainingChildren(returnFiber, child.sibling); - var existing = useFiber(child, call, expirationTime); - existing['return'] = returnFiber; - return existing; - } else { - deleteRemainingChildren(returnFiber, child); - break; - } - } else { - deleteChild(returnFiber, child); - } - child = child.sibling; - } - - var created = createFiberFromCall(call, returnFiber.internalContextTag, expirationTime); - created['return'] = returnFiber; - return created; - } +/** + * Call a function while guarding against errors that happens within it. + * Returns an error if it throws, otherwise null. + * + * In production, this is implemented using a try-catch. The reason we don't + * use a try-catch directly is so that we can swap out a different + * implementation in DEV mode. + * + * @param {String} name of the guard to use for logging or debugging + * @param {Function} func The function to invoke + * @param {*} context The context to use when calling the function + * @param {...*} args Arguments for function + */ +function invokeGuardedCallback(name, func, context, a, b, c, d, e, f) { + hasError = false; + caughtError = null; + invokeGuardedCallbackImpl$1.apply(reporter, arguments); +} - function reconcileSingleReturn(returnFiber, currentFirstChild, returnNode, expirationTime) { - // There's no need to check for keys on yields since they're stateless. - var child = currentFirstChild; - if (child !== null) { - if (child.tag === ReturnComponent) { - deleteRemainingChildren(returnFiber, child.sibling); - var existing = useFiber(child, null, expirationTime); - existing.type = returnNode.value; - existing['return'] = returnFiber; - return existing; - } else { - deleteRemainingChildren(returnFiber, child); - } +/** + * Same as invokeGuardedCallback, but instead of returning an error, it stores + * it in a global so it can be rethrown by `rethrowCaughtError` later. + * TODO: See if caughtError and rethrowError can be unified. + * + * @param {String} name of the guard to use for logging or debugging + * @param {Function} func The function to invoke + * @param {*} context The context to use when calling the function + * @param {...*} args Arguments for function + */ +function invokeGuardedCallbackAndCatchFirstError(name, func, context, a, b, c, d, e, f) { + invokeGuardedCallback.apply(this, arguments); + if (hasError) { + var error = clearCaughtError(); + if (!hasRethrowError) { + hasRethrowError = true; + rethrowError = error; } - - var created = createFiberFromReturn(returnNode, returnFiber.internalContextTag, expirationTime); - created.type = returnNode.value; - created['return'] = returnFiber; - return created; } +} - function reconcileSinglePortal(returnFiber, currentFirstChild, portal, expirationTime) { - var key = portal.key; - var child = currentFirstChild; - while (child !== null) { - // TODO: If key === null and child.key === null, then this only applies to - // the first item in the list. - if (child.key === key) { - if (child.tag === HostPortal && child.stateNode.containerInfo === portal.containerInfo && child.stateNode.implementation === portal.implementation) { - deleteRemainingChildren(returnFiber, child.sibling); - var existing = useFiber(child, portal.children || [], expirationTime); - existing['return'] = returnFiber; - return existing; - } else { - deleteRemainingChildren(returnFiber, child); - break; - } - } else { - deleteChild(returnFiber, child); - } - child = child.sibling; - } - - var created = createFiberFromPortal(portal, returnFiber.internalContextTag, expirationTime); - created['return'] = returnFiber; - return created; +/** + * During execution of guarded functions we will capture the first error which + * we will rethrow to be handled by the top level error handler. + */ +function rethrowCaughtError() { + if (hasRethrowError) { + var error = rethrowError; + hasRethrowError = false; + rethrowError = null; + throw error; } +} - // This API will tag the children with the side-effect of the reconciliation - // itself. They will be added to the side-effect list as we pass through the - // children and the parent. - function reconcileChildFibers(returnFiber, currentFirstChild, newChild, expirationTime) { - // This function is not recursive. - // If the top level item is an array, we treat it as a set of children, - // not as a fragment. Nested arrays on the other hand will be treated as - // fragment nodes. Recursion happens at the normal flow. - - // Handle top level unkeyed fragments as if they were arrays. - // This leads to an ambiguity between <>{[...]} and <>.... - // We treat the ambiguous cases above the same. - if (typeof newChild === 'object' && newChild !== null && newChild.type === REACT_FRAGMENT_TYPE && newChild.key === null) { - newChild = newChild.props.children; - } - - // Handle object types - var isObject = typeof newChild === 'object' && newChild !== null; +function hasCaughtError() { + return hasError; +} - if (isObject) { - switch (newChild.$$typeof) { - case REACT_ELEMENT_TYPE: - return placeSingleChild(reconcileSingleElement(returnFiber, currentFirstChild, newChild, expirationTime)); +function clearCaughtError() { + if (hasError) { + var error = caughtError; + hasError = false; + caughtError = null; + return error; + } else { + invariant(false, 'clearCaughtError was called but no error was captured. This error is likely caused by a bug in React. Please file an issue.'); + } +} - case REACT_CALL_TYPE: - return placeSingleChild(reconcileSingleCall(returnFiber, currentFirstChild, newChild, expirationTime)); - case REACT_RETURN_TYPE: - return placeSingleChild(reconcileSingleReturn(returnFiber, currentFirstChild, newChild, expirationTime)); - case REACT_PORTAL_TYPE: - return placeSingleChild(reconcileSinglePortal(returnFiber, currentFirstChild, newChild, expirationTime)); - } - } +/** + * Injectable ordering of event plugins. + */ +var eventPluginOrder = null; - if (typeof newChild === 'string' || typeof newChild === 'number') { - return placeSingleChild(reconcileSingleTextNode(returnFiber, currentFirstChild, '' + newChild, expirationTime)); - } +/** + * Injectable mapping from names to event plugin modules. + */ +var namesToPlugins = {}; - if (isArray$1(newChild)) { - return reconcileChildrenArray(returnFiber, currentFirstChild, newChild, expirationTime); +/** + * Recomputes the plugin list using the injected plugins and plugin ordering. + * + * @private + */ +function recomputePluginOrdering() { + if (!eventPluginOrder) { + // Wait until an `eventPluginOrder` is injected. + return; + } + for (var pluginName in namesToPlugins) { + var pluginModule = namesToPlugins[pluginName]; + var pluginIndex = eventPluginOrder.indexOf(pluginName); + !(pluginIndex > -1) ? invariant(false, 'EventPluginRegistry: Cannot inject event plugins that do not exist in the plugin ordering, `%s`.', pluginName) : void 0; + if (plugins[pluginIndex]) { + continue; } - - if (getIteratorFn(newChild)) { - return reconcileChildrenIterator(returnFiber, currentFirstChild, newChild, expirationTime); + !pluginModule.extractEvents ? invariant(false, 'EventPluginRegistry: Event plugins must implement an `extractEvents` method, but `%s` does not.', pluginName) : void 0; + plugins[pluginIndex] = pluginModule; + var publishedEvents = pluginModule.eventTypes; + for (var eventName in publishedEvents) { + !publishEventForPlugin(publishedEvents[eventName], pluginModule, eventName) ? invariant(false, 'EventPluginRegistry: Failed to publish event `%s` for plugin `%s`.', eventName, pluginName) : void 0; } + } +} - if (isObject) { - throwOnInvalidObjectType(returnFiber, newChild); - } +/** + * Publishes an event so that it can be dispatched by the supplied plugin. + * + * @param {object} dispatchConfig Dispatch configuration for the event. + * @param {object} PluginModule Plugin publishing the event. + * @return {boolean} True if the event was successfully published. + * @private + */ +function publishEventForPlugin(dispatchConfig, pluginModule, eventName) { + !!eventNameDispatchConfigs.hasOwnProperty(eventName) ? invariant(false, 'EventPluginHub: More than one plugin attempted to publish the same event name, `%s`.', eventName) : void 0; + eventNameDispatchConfigs[eventName] = dispatchConfig; - { - if (typeof newChild === 'function') { - warnOnFunctionType(); - } - } - if (typeof newChild === 'undefined') { - // If the new child is undefined, and the return fiber is a composite - // component, throw an error. If Fiber return types are disabled, - // we already threw above. - switch (returnFiber.tag) { - case ClassComponent: - { - { - var instance = returnFiber.stateNode; - if (instance.render._isMockFunction) { - // We allow auto-mocks to proceed as if they're returning null. - break; - } - } - } - // Intentionally fall through to the next case, which handles both - // functions and classes - // eslint-disable-next-lined no-fallthrough - case FunctionalComponent: - { - var Component = returnFiber.type; - invariant(false, '%s(...): Nothing was returned from render. This usually means a return statement is missing. Or, to render nothing, return null.', Component.displayName || Component.name || 'Component'); - } + var phasedRegistrationNames = dispatchConfig.phasedRegistrationNames; + if (phasedRegistrationNames) { + for (var phaseName in phasedRegistrationNames) { + if (phasedRegistrationNames.hasOwnProperty(phaseName)) { + var phasedRegistrationName = phasedRegistrationNames[phaseName]; + publishRegistrationName(phasedRegistrationName, pluginModule, eventName); } } - - // Remaining cases are all treated as empty. - return deleteRemainingChildren(returnFiber, currentFirstChild); + return true; + } else if (dispatchConfig.registrationName) { + publishRegistrationName(dispatchConfig.registrationName, pluginModule, eventName); + return true; } - - return reconcileChildFibers; + return false; } -var reconcileChildFibers = ChildReconciler(true); -var mountChildFibers = ChildReconciler(false); - -function cloneChildFibers(current, workInProgress) { - !(current === null || workInProgress.child === current.child) ? invariant(false, 'Resuming work not yet implemented.') : void 0; - - if (workInProgress.child === null) { - return; - } +/** + * Publishes a registration name that is used to identify dispatched events. + * + * @param {string} registrationName Registration name to add. + * @param {object} PluginModule Plugin publishing the event. + * @private + */ +function publishRegistrationName(registrationName, pluginModule, eventName) { + !!registrationNameModules[registrationName] ? invariant(false, 'EventPluginHub: More than one plugin attempted to publish the same registration name, `%s`.', registrationName) : void 0; + registrationNameModules[registrationName] = pluginModule; + registrationNameDependencies[registrationName] = pluginModule.eventTypes[eventName].dependencies; - var currentChild = workInProgress.child; - var newChild = createWorkInProgress(currentChild, currentChild.pendingProps, currentChild.expirationTime); - workInProgress.child = newChild; + { + var lowerCasedName = registrationName.toLowerCase(); + possibleRegistrationNames[lowerCasedName] = registrationName; - newChild['return'] = workInProgress; - while (currentChild.sibling !== null) { - currentChild = currentChild.sibling; - newChild = newChild.sibling = createWorkInProgress(currentChild, currentChild.pendingProps, currentChild.expirationTime); - newChild['return'] = workInProgress; + if (registrationName === 'onDoubleClick') { + possibleRegistrationNames.ondblclick = registrationName; + } } - newChild.sibling = null; } -{ - var warnedAboutStatelessRefs = {}; -} +/** + * Registers plugins so that they can extract and dispatch events. + * + * @see {EventPluginHub} + */ -var ReactFiberBeginWork = function (config, hostContext, hydrationContext, scheduleWork, computeExpirationForFiber) { - var shouldSetTextContent = config.shouldSetTextContent, - useSyncScheduling = config.useSyncScheduling, - shouldDeprioritizeSubtree = config.shouldDeprioritizeSubtree; - var pushHostContext = hostContext.pushHostContext, - pushHostContainer = hostContext.pushHostContainer; - var enterHydrationState = hydrationContext.enterHydrationState, - resetHydrationState = hydrationContext.resetHydrationState, - tryToClaimNextHydratableInstance = hydrationContext.tryToClaimNextHydratableInstance; +/** + * Ordered list of injected plugins. + */ +var plugins = []; - var _ReactFiberClassCompo = ReactFiberClassComponent(scheduleWork, computeExpirationForFiber, memoizeProps, memoizeState), - adoptClassInstance = _ReactFiberClassCompo.adoptClassInstance, - constructClassInstance = _ReactFiberClassCompo.constructClassInstance, - mountClassInstance = _ReactFiberClassCompo.mountClassInstance, - updateClassInstance = _ReactFiberClassCompo.updateClassInstance; +/** + * Mapping from event name to dispatch config + */ +var eventNameDispatchConfigs = {}; - // TODO: Remove this and use reconcileChildrenAtExpirationTime directly. +/** + * Mapping from registration name to plugin module + */ +var registrationNameModules = {}; +/** + * Mapping from registration name to event name + */ +var registrationNameDependencies = {}; - function reconcileChildren(current, workInProgress, nextChildren) { - reconcileChildrenAtExpirationTime(current, workInProgress, nextChildren, workInProgress.expirationTime); - } +/** + * Mapping from lowercase registration names to the properly cased version, + * used to warn in the case of missing event handlers. Available + * only in true. + * @type {Object} + */ +var possibleRegistrationNames = {}; +// Trust the developer to only use possibleRegistrationNames in true - function reconcileChildrenAtExpirationTime(current, workInProgress, nextChildren, renderExpirationTime) { - if (current === null) { - // If this is a fresh new component that hasn't been rendered yet, we - // won't update its child set by applying minimal side-effects. Instead, - // we will add them all to the child before it gets rendered. That means - // we can optimize this reconciliation pass by not tracking side-effects. - workInProgress.child = mountChildFibers(workInProgress, null, nextChildren, renderExpirationTime); - } else { - // If the current child is the same as the work in progress, it means that - // we haven't yet started any work on these children. Therefore, we use - // the clone algorithm to create a copy of all the current children. +/** + * Injects an ordering of plugins (by plugin name). This allows the ordering + * to be decoupled from injection of the actual plugins so that ordering is + * always deterministic regardless of packaging, on-the-fly injection, etc. + * + * @param {array} InjectedEventPluginOrder + * @internal + * @see {EventPluginHub.injection.injectEventPluginOrder} + */ +function injectEventPluginOrder(injectedEventPluginOrder) { + !!eventPluginOrder ? invariant(false, 'EventPluginRegistry: Cannot inject event plugin ordering more than once. You are likely trying to load more than one copy of React.') : void 0; + // Clone the ordering so it cannot be dynamically mutated. + eventPluginOrder = Array.prototype.slice.call(injectedEventPluginOrder); + recomputePluginOrdering(); +} - // If we had any progressed work already, that is invalid at this point so - // let's throw it out. - workInProgress.child = reconcileChildFibers(workInProgress, current.child, nextChildren, renderExpirationTime); +/** + * Injects plugins to be used by `EventPluginHub`. The plugin names must be + * in the ordering injected by `injectEventPluginOrder`. + * + * Plugins can be injected as part of page initialization or on-the-fly. + * + * @param {object} injectedNamesToPlugins Map from names to plugin modules. + * @internal + * @see {EventPluginHub.injection.injectEventPluginsByName} + */ +function injectEventPluginsByName(injectedNamesToPlugins) { + var isOrderingDirty = false; + for (var pluginName in injectedNamesToPlugins) { + if (!injectedNamesToPlugins.hasOwnProperty(pluginName)) { + continue; } - } - - function updateFragment(current, workInProgress) { - var nextChildren = workInProgress.pendingProps; - if (hasContextChanged()) { - // Normally we can bail out on props equality but if context has changed - // we don't do the bailout and we have to reuse existing props instead. - if (nextChildren === null) { - nextChildren = workInProgress.memoizedProps; - } - } else if (nextChildren === null || workInProgress.memoizedProps === nextChildren) { - return bailoutOnAlreadyFinishedWork(current, workInProgress); + var pluginModule = injectedNamesToPlugins[pluginName]; + if (!namesToPlugins.hasOwnProperty(pluginName) || namesToPlugins[pluginName] !== pluginModule) { + !!namesToPlugins[pluginName] ? invariant(false, 'EventPluginRegistry: Cannot inject two different event plugins using the same name, `%s`.', pluginName) : void 0; + namesToPlugins[pluginName] = pluginModule; + isOrderingDirty = true; } - reconcileChildren(current, workInProgress, nextChildren); - memoizeProps(workInProgress, nextChildren); - return workInProgress.child; } - - function markRef(current, workInProgress) { - var ref = workInProgress.ref; - if (ref !== null && (!current || current.ref !== ref)) { - // Schedule a Ref effect - workInProgress.effectTag |= Ref; - } + if (isOrderingDirty) { + recomputePluginOrdering(); } +} + +/** + * Similar to invariant but only logs a warning if the condition is not met. + * This can be used to log issues in development environments in critical + * paths. Removing the logging code for production environments will keep the + * same logic and follow the same code paths. + */ - function updateFunctionalComponent(current, workInProgress) { - var fn = workInProgress.type; - var nextProps = workInProgress.pendingProps; +var warningWithoutStack = function () {}; - var memoizedProps = workInProgress.memoizedProps; - if (hasContextChanged()) { - // Normally we can bail out on props equality but if context has changed - // we don't do the bailout and we have to reuse existing props instead. - if (nextProps === null) { - nextProps = memoizedProps; - } - } else { - if (nextProps === null || memoizedProps === nextProps) { - return bailoutOnAlreadyFinishedWork(current, workInProgress); - } - // TODO: consider bringing fn.shouldComponentUpdate() back. - // It used to be here. +{ + warningWithoutStack = function (condition, format) { + for (var _len = arguments.length, args = Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) { + args[_key - 2] = arguments[_key]; } - var unmaskedContext = getUnmaskedContext(workInProgress); - var context = getMaskedContext(workInProgress, unmaskedContext); + if (format === undefined) { + throw new Error('`warningWithoutStack(condition, format, ...args)` requires a warning ' + 'message argument'); + } + if (args.length > 8) { + // Check before the condition to catch violations early. + throw new Error('warningWithoutStack() currently supports at most 8 arguments.'); + } + if (condition) { + return; + } + if (typeof console !== 'undefined') { + var argsWithFormat = args.map(function (item) { + return '' + item; + }); + argsWithFormat.unshift('Warning: ' + format); - var nextChildren; + // We intentionally don't use spread (or .apply) directly because it + // breaks IE9: https://github.com/facebook/react/issues/13610 + Function.prototype.apply.call(console.error, console, argsWithFormat); + } + try { + // --- Welcome to debugging React --- + // This error was thrown as a convenience so that you can use this stack + // to find the callsite that caused this warning to fire. + var argIndex = 0; + var message = 'Warning: ' + format.replace(/%s/g, function () { + return args[argIndex++]; + }); + throw new Error(message); + } catch (x) {} + }; +} - { - ReactCurrentOwner.current = workInProgress; - ReactDebugCurrentFiber.setCurrentPhase('render'); - nextChildren = fn(nextProps, context); - ReactDebugCurrentFiber.setCurrentPhase(null); - } - // React DevTools reads this flag. - workInProgress.effectTag |= PerformedWork; - reconcileChildren(current, workInProgress, nextChildren); - memoizeProps(workInProgress, nextProps); - return workInProgress.child; - } +var warningWithoutStack$1 = warningWithoutStack; - function updateClassComponent(current, workInProgress, renderExpirationTime) { - // Push context providers early to prevent context stack mismatches. - // During mounting we don't know the child context yet as the instance doesn't exist. - // We will invalidate the child context in finishClassComponent() right after rendering. - var hasContext = pushContextProvider(workInProgress); +var getFiberCurrentPropsFromNode = null; +var getInstanceFromNode = null; +var getNodeFromInstance = null; - var shouldUpdate = void 0; - if (current === null) { - if (!workInProgress.stateNode) { - // In the initial pass we might need to construct the instance. - constructClassInstance(workInProgress, workInProgress.pendingProps); - mountClassInstance(workInProgress, renderExpirationTime); - shouldUpdate = true; - } else { - invariant(false, 'Resuming work not yet implemented.'); - // In a resume, we'll already have an instance we can reuse. - // shouldUpdate = resumeMountClassInstance(workInProgress, renderExpirationTime); - } - } else { - shouldUpdate = updateClassInstance(current, workInProgress, renderExpirationTime); - } - return finishClassComponent(current, workInProgress, shouldUpdate, hasContext); +function setComponentTree(getFiberCurrentPropsFromNodeImpl, getInstanceFromNodeImpl, getNodeFromInstanceImpl) { + getFiberCurrentPropsFromNode = getFiberCurrentPropsFromNodeImpl; + getInstanceFromNode = getInstanceFromNodeImpl; + getNodeFromInstance = getNodeFromInstanceImpl; + { + !(getNodeFromInstance && getInstanceFromNode) ? warningWithoutStack$1(false, 'EventPluginUtils.setComponentTree(...): Injected ' + 'module is missing getNodeFromInstance or getInstanceFromNode.') : void 0; } +} - function finishClassComponent(current, workInProgress, shouldUpdate, hasContext) { - // Refs should update even if shouldComponentUpdate returns false - markRef(current, workInProgress); - - if (!shouldUpdate) { - // Context providers should defer to sCU for rendering - if (hasContext) { - invalidateContextProvider(workInProgress, false); - } - - return bailoutOnAlreadyFinishedWork(current, workInProgress); - } +var validateEventDispatches = void 0; +{ + validateEventDispatches = function (event) { + var dispatchListeners = event._dispatchListeners; + var dispatchInstances = event._dispatchInstances; - var instance = workInProgress.stateNode; + var listenersIsArr = Array.isArray(dispatchListeners); + var listenersLen = listenersIsArr ? dispatchListeners.length : dispatchListeners ? 1 : 0; - // Rerender - ReactCurrentOwner.current = workInProgress; - var nextChildren = void 0; - { - ReactDebugCurrentFiber.setCurrentPhase('render'); - nextChildren = instance.render(); - if (debugRenderPhaseSideEffects) { - instance.render(); - } - ReactDebugCurrentFiber.setCurrentPhase(null); - } - // React DevTools reads this flag. - workInProgress.effectTag |= PerformedWork; - reconcileChildren(current, workInProgress, nextChildren); - // Memoize props and state using the values we just used to render. - // TODO: Restructure so we never read values from the instance. - memoizeState(workInProgress, instance.state); - memoizeProps(workInProgress, instance.props); + var instancesIsArr = Array.isArray(dispatchInstances); + var instancesLen = instancesIsArr ? dispatchInstances.length : dispatchInstances ? 1 : 0; - // The context might have changed so we need to recalculate it. - if (hasContext) { - invalidateContextProvider(workInProgress, true); - } + !(instancesIsArr === listenersIsArr && instancesLen === listenersLen) ? warningWithoutStack$1(false, 'EventPluginUtils: Invalid `event`.') : void 0; + }; +} - return workInProgress.child; - } +/** + * Dispatch the event to the listener. + * @param {SyntheticEvent} event SyntheticEvent to handle + * @param {function} listener Application-level callback + * @param {*} inst Internal component instance + */ +function executeDispatch(event, listener, inst) { + var type = event.type || 'unknown-event'; + event.currentTarget = getNodeFromInstance(inst); + invokeGuardedCallbackAndCatchFirstError(type, listener, undefined, event); + event.currentTarget = null; +} - function pushHostRootContext(workInProgress) { - var root = workInProgress.stateNode; - if (root.pendingContext) { - pushTopLevelContextObject(workInProgress, root.pendingContext, root.pendingContext !== root.context); - } else if (root.context) { - // Should always be set - pushTopLevelContextObject(workInProgress, root.context, false); - } - pushHostContainer(workInProgress, root.containerInfo); +/** + * Standard/simple iteration through an event's collected dispatches. + */ +function executeDispatchesInOrder(event) { + var dispatchListeners = event._dispatchListeners; + var dispatchInstances = event._dispatchInstances; + { + validateEventDispatches(event); } - - function updateHostRoot(current, workInProgress, renderExpirationTime) { - pushHostRootContext(workInProgress); - var updateQueue = workInProgress.updateQueue; - if (updateQueue !== null) { - var prevState = workInProgress.memoizedState; - var state = processUpdateQueue(current, workInProgress, updateQueue, null, null, renderExpirationTime); - if (prevState === state) { - // If the state is the same as before, that's a bailout because we had - // no work that expires at this time. - resetHydrationState(); - return bailoutOnAlreadyFinishedWork(current, workInProgress); - } - var element = state.element; - var root = workInProgress.stateNode; - if ((current === null || current.child === null) && root.hydrate && enterHydrationState(workInProgress)) { - // If we don't have any current children this might be the first pass. - // We always try to hydrate. If this isn't a hydration pass there won't - // be any children to hydrate which is effectively the same thing as - // not hydrating. - - // This is a bit of a hack. We track the host root as a placement to - // know that we're currently in a mounting state. That way isMounted - // works as expected. We must reset this before committing. - // TODO: Delete this when we delete isMounted and findDOMNode. - workInProgress.effectTag |= Placement; - - // Ensure that children mount into this root without tracking - // side-effects. This ensures that we don't store Placement effects on - // nodes that will be hydrated. - workInProgress.child = mountChildFibers(workInProgress, null, element, renderExpirationTime); - } else { - // Otherwise reset hydration state in case we aborted and resumed another - // root. - resetHydrationState(); - reconcileChildren(current, workInProgress, element); + if (Array.isArray(dispatchListeners)) { + for (var i = 0; i < dispatchListeners.length; i++) { + if (event.isPropagationStopped()) { + break; } - memoizeState(workInProgress, state); - return workInProgress.child; + // Listeners and Instances are two parallel arrays that are always in sync. + executeDispatch(event, dispatchListeners[i], dispatchInstances[i]); } - resetHydrationState(); - // If there is no update queue, that's a bailout because the root has no props. - return bailoutOnAlreadyFinishedWork(current, workInProgress); + } else if (dispatchListeners) { + executeDispatch(event, dispatchListeners, dispatchInstances); } + event._dispatchListeners = null; + event._dispatchInstances = null; +} - function updateHostComponent(current, workInProgress, renderExpirationTime) { - pushHostContext(workInProgress); - - if (current === null) { - tryToClaimNextHydratableInstance(workInProgress); - } +/** + * @see executeDispatchesInOrderStopAtTrueImpl + */ - var type = workInProgress.type; - var memoizedProps = workInProgress.memoizedProps; - var nextProps = workInProgress.pendingProps; - if (nextProps === null) { - nextProps = memoizedProps; - !(nextProps !== null) ? invariant(false, 'We should always have pending or current props. This error is likely caused by a bug in React. Please file an issue.') : void 0; - } - var prevProps = current !== null ? current.memoizedProps : null; - if (hasContextChanged()) { - // Normally we can bail out on props equality but if context has changed - // we don't do the bailout and we have to reuse existing props instead. - } else if (nextProps === null || memoizedProps === nextProps) { - return bailoutOnAlreadyFinishedWork(current, workInProgress); - } +/** + * Execution of a "direct" dispatch - there must be at most one dispatch + * accumulated on the event or it is considered an error. It doesn't really make + * sense for an event with multiple dispatches (bubbled) to keep track of the + * return values at each dispatch execution, but it does tend to make sense when + * dealing with "direct" dispatches. + * + * @return {*} The return value of executing the single dispatch. + */ - var nextChildren = nextProps.children; - var isDirectTextChild = shouldSetTextContent(type, nextProps); - if (isDirectTextChild) { - // We special case a direct text child of a host node. This is a common - // case. We won't handle it as a reified child. We will instead handle - // this in the host environment that also have access to this prop. That - // avoids allocating another HostText fiber and traversing it. - nextChildren = null; - } else if (prevProps && shouldSetTextContent(type, prevProps)) { - // If we're switching from a direct text child to a normal child, or to - // empty, we need to schedule the text content to be reset. - workInProgress.effectTag |= ContentReset; - } +/** + * @param {SyntheticEvent} event + * @return {boolean} True iff number of dispatches accumulated is greater than 0. + */ - markRef(current, workInProgress); +/** + * Accumulates items that must not be null or undefined into the first one. This + * is used to conserve memory by avoiding array allocations, and thus sacrifices + * API cleanness. Since `current` can be null before being passed in and not + * null after this function, make sure to assign it back to `current`: + * + * `a = accumulateInto(a, b);` + * + * This API should be sparingly used. Try `accumulate` for something cleaner. + * + * @return {*|array<*>} An accumulation of items. + */ - // Check the host config to see if the children are offscreen/hidden. - if (renderExpirationTime !== Never && !useSyncScheduling && shouldDeprioritizeSubtree(type, nextProps)) { - // Down-prioritize the children. - workInProgress.expirationTime = Never; - // Bailout and come back to this fiber later. - return null; - } +function accumulateInto(current, next) { + !(next != null) ? invariant(false, 'accumulateInto(...): Accumulated items must not be null or undefined.') : void 0; - reconcileChildren(current, workInProgress, nextChildren); - memoizeProps(workInProgress, nextProps); - return workInProgress.child; + if (current == null) { + return next; } - function updateHostText(current, workInProgress) { - if (current === null) { - tryToClaimNextHydratableInstance(workInProgress); - } - var nextProps = workInProgress.pendingProps; - if (nextProps === null) { - nextProps = workInProgress.memoizedProps; + // Both are not empty. Warning: Never call x.concat(y) when you are not + // certain that x is an Array (x could be a string with concat method). + if (Array.isArray(current)) { + if (Array.isArray(next)) { + current.push.apply(current, next); + return current; } - memoizeProps(workInProgress, nextProps); - // Nothing to do here. This is terminal. We'll do the completion step - // immediately after. - return null; + current.push(next); + return current; } - function mountIndeterminateComponent(current, workInProgress, renderExpirationTime) { - !(current === null) ? invariant(false, 'An indeterminate component should never have mounted. This error is likely caused by a bug in React. Please file an issue.') : void 0; - var fn = workInProgress.type; - var props = workInProgress.pendingProps; - var unmaskedContext = getUnmaskedContext(workInProgress); - var context = getMaskedContext(workInProgress, unmaskedContext); - - var value; - - { - if (fn.prototype && typeof fn.prototype.render === 'function') { - var componentName = getComponentName(workInProgress); - warning(false, "The <%s /> component appears to have a render method, but doesn't extend React.Component. " + 'This is likely to cause errors. Change %s to extend React.Component instead.', componentName, componentName); - } - ReactCurrentOwner.current = workInProgress; - value = fn(props, context); - } - // React DevTools reads this flag. - workInProgress.effectTag |= PerformedWork; - - if (typeof value === 'object' && value !== null && typeof value.render === 'function') { - // Proceed under the assumption that this is a class instance - workInProgress.tag = ClassComponent; - - // Push context providers early to prevent context stack mismatches. - // During mounting we don't know the child context yet as the instance doesn't exist. - // We will invalidate the child context in finishClassComponent() right after rendering. - var hasContext = pushContextProvider(workInProgress); - adoptClassInstance(workInProgress, value); - mountClassInstance(workInProgress, renderExpirationTime); - return finishClassComponent(current, workInProgress, true, hasContext); - } else { - // Proceed under the assumption that this is a functional component - workInProgress.tag = FunctionalComponent; - { - var Component = workInProgress.type; + if (Array.isArray(next)) { + // A bit too dangerous to mutate `next`. + return [current].concat(next); + } - if (Component) { - warning(!Component.childContextTypes, '%s(...): childContextTypes cannot be defined on a functional component.', Component.displayName || Component.name || 'Component'); - } - if (workInProgress.ref !== null) { - var info = ''; - var ownerName = ReactDebugCurrentFiber.getCurrentFiberOwnerName(); - if (ownerName) { - info += '\n\nCheck the render method of `' + ownerName + '`.'; - } + return [current, next]; +} - var warningKey = ownerName || workInProgress._debugID || ''; - var debugSource = workInProgress._debugSource; - if (debugSource) { - warningKey = debugSource.fileName + ':' + debugSource.lineNumber; - } - if (!warnedAboutStatelessRefs[warningKey]) { - warnedAboutStatelessRefs[warningKey] = true; - warning(false, 'Stateless function components cannot be given refs. ' + 'Attempts to access this ref will fail.%s%s', info, ReactDebugCurrentFiber.getCurrentFiberStackAddendum()); - } - } - } - reconcileChildren(current, workInProgress, value); - memoizeProps(workInProgress, props); - return workInProgress.child; - } +/** + * @param {array} arr an "accumulation" of items which is either an Array or + * a single item. Useful when paired with the `accumulate` module. This is a + * simple utility that allows us to reason about a collection of items, but + * handling the case when there is exactly one item (and we do not need to + * allocate an array). + * @param {function} cb Callback invoked with each element or a collection. + * @param {?} [scope] Scope used as `this` in a callback. + */ +function forEachAccumulated(arr, cb, scope) { + if (Array.isArray(arr)) { + arr.forEach(cb, scope); + } else if (arr) { + cb.call(scope, arr); } +} - function updateCallComponent(current, workInProgress, renderExpirationTime) { - var nextCall = workInProgress.pendingProps; - if (hasContextChanged()) { - // Normally we can bail out on props equality but if context has changed - // we don't do the bailout and we have to reuse existing props instead. - if (nextCall === null) { - nextCall = current && current.memoizedProps; - !(nextCall !== null) ? invariant(false, 'We should always have pending or current props. This error is likely caused by a bug in React. Please file an issue.') : void 0; - } - } else if (nextCall === null || workInProgress.memoizedProps === nextCall) { - nextCall = workInProgress.memoizedProps; - // TODO: When bailing out, we might need to return the stateNode instead - // of the child. To check it for work. - // return bailoutOnAlreadyFinishedWork(current, workInProgress); - } +/** + * Internal queue of events that have accumulated their dispatches and are + * waiting to have their dispatches executed. + */ +var eventQueue = null; - var nextChildren = nextCall.children; +/** + * Dispatches an event and releases it back into the pool, unless persistent. + * + * @param {?object} event Synthetic event to be dispatched. + * @private + */ +var executeDispatchesAndRelease = function (event) { + if (event) { + executeDispatchesInOrder(event); - // The following is a fork of reconcileChildrenAtExpirationTime but using - // stateNode to store the child. - if (current === null) { - workInProgress.stateNode = mountChildFibers(workInProgress, workInProgress.stateNode, nextChildren, renderExpirationTime); - } else { - workInProgress.stateNode = reconcileChildFibers(workInProgress, workInProgress.stateNode, nextChildren, renderExpirationTime); + if (!event.isPersistent()) { + event.constructor.release(event); } - - memoizeProps(workInProgress, nextCall); - // This doesn't take arbitrary time so we could synchronously just begin - // eagerly do the work of workInProgress.child as an optimization. - return workInProgress.stateNode; } +}; +var executeDispatchesAndReleaseTopLevel = function (e) { + return executeDispatchesAndRelease(e); +}; - function updatePortalComponent(current, workInProgress, renderExpirationTime) { - pushHostContainer(workInProgress, workInProgress.stateNode.containerInfo); - var nextChildren = workInProgress.pendingProps; - if (hasContextChanged()) { - // Normally we can bail out on props equality but if context has changed - // we don't do the bailout and we have to reuse existing props instead. - if (nextChildren === null) { - nextChildren = current && current.memoizedProps; - !(nextChildren != null) ? invariant(false, 'We should always have pending or current props. This error is likely caused by a bug in React. Please file an issue.') : void 0; - } - } else if (nextChildren === null || workInProgress.memoizedProps === nextChildren) { - return bailoutOnAlreadyFinishedWork(current, workInProgress); - } - - if (current === null) { - // Portals are special because we don't append the children during mount - // but at commit. Therefore we need to track insertions which the normal - // flow doesn't do during mount. This doesn't happen at the root because - // the root always starts with a "current" with a null child. - // TODO: Consider unifying this with how the root works. - workInProgress.child = reconcileChildFibers(workInProgress, null, nextChildren, renderExpirationTime); - memoizeProps(workInProgress, nextChildren); - } else { - reconcileChildren(current, workInProgress, nextChildren); - memoizeProps(workInProgress, nextChildren); - } - return workInProgress.child; - } +function isInteractive(tag) { + return tag === 'button' || tag === 'input' || tag === 'select' || tag === 'textarea'; +} - /* - function reuseChildrenEffects(returnFiber : Fiber, firstChild : Fiber) { - let child = firstChild; - do { - // Ensure that the first and last effect of the parent corresponds - // to the children's first and last effect. - if (!returnFiber.firstEffect) { - returnFiber.firstEffect = child.firstEffect; - } - if (child.lastEffect) { - if (returnFiber.lastEffect) { - returnFiber.lastEffect.nextEffect = child.firstEffect; - } - returnFiber.lastEffect = child.lastEffect; - } - } while (child = child.sibling); - } - */ - - function bailoutOnAlreadyFinishedWork(current, workInProgress) { - cancelWorkTimer(workInProgress); - - // TODO: We should ideally be able to bail out early if the children have no - // more work to do. However, since we don't have a separation of this - // Fiber's priority and its children yet - we don't know without doing lots - // of the same work we do anyway. Once we have that separation we can just - // bail out here if the children has no more work at this priority level. - // if (workInProgress.priorityOfChildren <= priorityLevel) { - // // If there are side-effects in these children that have not yet been - // // committed we need to ensure that they get properly transferred up. - // if (current && current.child !== workInProgress.child) { - // reuseChildrenEffects(workInProgress, child); - // } - // return null; - // } - - cloneChildFibers(current, workInProgress); - return workInProgress.child; - } +function shouldPreventMouseEvent(name, type, props) { + switch (name) { + case 'onClick': + case 'onClickCapture': + case 'onDoubleClick': + case 'onDoubleClickCapture': + case 'onMouseDown': + case 'onMouseDownCapture': + case 'onMouseMove': + case 'onMouseMoveCapture': + case 'onMouseUp': + case 'onMouseUpCapture': + return !!(props.disabled && isInteractive(type)); + default: + return false; + } +} + +/** + * This is a unified interface for event plugins to be installed and configured. + * + * Event plugins can implement the following properties: + * + * `extractEvents` {function(string, DOMEventTarget, string, object): *} + * Required. When a top-level event is fired, this method is expected to + * extract synthetic events that will in turn be queued and dispatched. + * + * `eventTypes` {object} + * Optional, plugins that fire events must publish a mapping of registration + * names that are used to register listeners. Values of this mapping must + * be objects that contain `registrationName` or `phasedRegistrationNames`. + * + * `executeDispatch` {function(object, function, string)} + * Optional, allows plugins to override how an event gets dispatched. By + * default, the listener is simply invoked. + * + * Each plugin that is injected into `EventsPluginHub` is immediately operable. + * + * @public + */ + +/** + * Methods for injecting dependencies. + */ +var injection = { + /** + * @param {array} InjectedEventPluginOrder + * @public + */ + injectEventPluginOrder: injectEventPluginOrder, - function bailoutOnLowPriority(current, workInProgress) { - cancelWorkTimer(workInProgress); + /** + * @param {object} injectedNamesToPlugins Map from names to plugin modules. + */ + injectEventPluginsByName: injectEventPluginsByName +}; - // TODO: Handle HostComponent tags here as well and call pushHostContext()? - // See PR 8590 discussion for context - switch (workInProgress.tag) { - case HostRoot: - pushHostRootContext(workInProgress); - break; - case ClassComponent: - pushContextProvider(workInProgress); - break; - case HostPortal: - pushHostContainer(workInProgress, workInProgress.stateNode.containerInfo); - break; - } - // TODO: What if this is currently in progress? - // How can that happen? How is this not being cloned? +/** + * @param {object} inst The instance, which is the source of events. + * @param {string} registrationName Name of listener (e.g. `onClick`). + * @return {?function} The stored callback. + */ +function getListener(inst, registrationName) { + var listener = void 0; + + // TODO: shouldPreventMouseEvent is DOM-specific and definitely should not + // live here; needs to be moved to a better place soon + var stateNode = inst.stateNode; + if (!stateNode) { + // Work in progress (ex: onload events in incremental mode). return null; } - - // TODO: Delete memoizeProps/State and move to reconcile/bailout instead - function memoizeProps(workInProgress, nextProps) { - workInProgress.memoizedProps = nextProps; + var props = getFiberCurrentPropsFromNode(stateNode); + if (!props) { + // Work in progress. + return null; } - - function memoizeState(workInProgress, nextState) { - workInProgress.memoizedState = nextState; - // Don't reset the updateQueue, in case there are pending updates. Resetting - // is handled by processUpdateQueue. + listener = props[registrationName]; + if (shouldPreventMouseEvent(registrationName, inst.type, props)) { + return null; } + !(!listener || typeof listener === 'function') ? invariant(false, 'Expected `%s` listener to be a function, instead got a value of `%s` type.', registrationName, typeof listener) : void 0; + return listener; +} - function beginWork(current, workInProgress, renderExpirationTime) { - if (workInProgress.expirationTime === NoWork || workInProgress.expirationTime > renderExpirationTime) { - return bailoutOnLowPriority(current, workInProgress); - } - - switch (workInProgress.tag) { - case IndeterminateComponent: - return mountIndeterminateComponent(current, workInProgress, renderExpirationTime); - case FunctionalComponent: - return updateFunctionalComponent(current, workInProgress); - case ClassComponent: - return updateClassComponent(current, workInProgress, renderExpirationTime); - case HostRoot: - return updateHostRoot(current, workInProgress, renderExpirationTime); - case HostComponent: - return updateHostComponent(current, workInProgress, renderExpirationTime); - case HostText: - return updateHostText(current, workInProgress); - case CallHandlerPhase: - // This is a restart. Reset the tag to the initial phase. - workInProgress.tag = CallComponent; - // Intentionally fall through since this is now the same. - case CallComponent: - return updateCallComponent(current, workInProgress, renderExpirationTime); - case ReturnComponent: - // A return component is just a placeholder, we can just run through the - // next one immediately. - return null; - case HostPortal: - return updatePortalComponent(current, workInProgress, renderExpirationTime); - case Fragment: - return updateFragment(current, workInProgress); - default: - invariant(false, 'Unknown unit of work tag. This error is likely caused by a bug in React. Please file an issue.'); +/** + * Allows registered plugins an opportunity to extract events from top-level + * native browser events. + * + * @return {*} An accumulation of synthetic events. + * @internal + */ +function extractEvents(topLevelType, targetInst, nativeEvent, nativeEventTarget) { + var events = null; + for (var i = 0; i < plugins.length; i++) { + // Not every plugin in the ordering may be loaded at runtime. + var possiblePlugin = plugins[i]; + if (possiblePlugin) { + var extractedEvents = possiblePlugin.extractEvents(topLevelType, targetInst, nativeEvent, nativeEventTarget); + if (extractedEvents) { + events = accumulateInto(events, extractedEvents); + } } } + return events; +} - function beginFailedWork(current, workInProgress, renderExpirationTime) { - // Push context providers here to avoid a push/pop context mismatch. - switch (workInProgress.tag) { - case ClassComponent: - pushContextProvider(workInProgress); - break; - case HostRoot: - pushHostRootContext(workInProgress); - break; - default: - invariant(false, 'Invalid type of work. This error is likely caused by a bug in React. Please file an issue.'); - } - - // Add an error effect so we can handle the error during the commit phase - workInProgress.effectTag |= Err; - - // This is a weird case where we do "resume" work — work that failed on - // our first attempt. Because we no longer have a notion of "progressed - // deletions," reset the child to the current child to make sure we delete - // it again. TODO: Find a better way to handle this, perhaps during a more - // general overhaul of error handling. - if (current === null) { - workInProgress.child = null; - } else if (workInProgress.child !== current.child) { - workInProgress.child = current.child; - } +function runEventsInBatch(events) { + if (events !== null) { + eventQueue = accumulateInto(eventQueue, events); + } - if (workInProgress.expirationTime === NoWork || workInProgress.expirationTime > renderExpirationTime) { - return bailoutOnLowPriority(current, workInProgress); - } + // Set `eventQueue` to null before processing it so that we can tell if more + // events get enqueued while processing. + var processingEventQueue = eventQueue; + eventQueue = null; - // If we don't bail out, we're going be recomputing our children so we need - // to drop our effect list. - workInProgress.firstEffect = null; - workInProgress.lastEffect = null; + if (!processingEventQueue) { + return; + } - // Unmount the current children as if the component rendered null - var nextChildren = null; - reconcileChildrenAtExpirationTime(current, workInProgress, nextChildren, renderExpirationTime); + forEachAccumulated(processingEventQueue, executeDispatchesAndReleaseTopLevel); + !!eventQueue ? invariant(false, 'processEventQueue(): Additional events were enqueued while processing an event queue. Support for this has not yet been implemented.') : void 0; + // This would be a good time to rethrow if any of the event handlers threw. + rethrowCaughtError(); +} - if (workInProgress.tag === ClassComponent) { - var instance = workInProgress.stateNode; - workInProgress.memoizedProps = instance.props; - workInProgress.memoizedState = instance.state; - } +function runExtractedEventsInBatch(topLevelType, targetInst, nativeEvent, nativeEventTarget) { + var events = extractEvents(topLevelType, targetInst, nativeEvent, nativeEventTarget); + runEventsInBatch(events); +} - return workInProgress.child; - } +var FunctionComponent = 0; +var ClassComponent = 1; +var IndeterminateComponent = 2; // Before we know whether it is function or class +var HostRoot = 3; // Root of a host tree. Could be nested inside another node. +var HostPortal = 4; // A subtree. Could be an entry point to a different renderer. +var HostComponent = 5; +var HostText = 6; +var Fragment = 7; +var Mode = 8; +var ContextConsumer = 9; +var ContextProvider = 10; +var ForwardRef = 11; +var Profiler = 12; +var SuspenseComponent = 13; +var MemoComponent = 14; +var SimpleMemoComponent = 15; +var LazyComponent = 16; +var IncompleteClassComponent = 17; - return { - beginWork: beginWork, - beginFailedWork: beginFailedWork - }; -}; +var randomKey = Math.random().toString(36).slice(2); +var internalInstanceKey = '__reactInternalInstance$' + randomKey; +var internalEventHandlersKey = '__reactEventHandlers$' + randomKey; -var ReactFiberCompleteWork = function (config, hostContext, hydrationContext) { - var createInstance = config.createInstance, - createTextInstance = config.createTextInstance, - appendInitialChild = config.appendInitialChild, - finalizeInitialChildren = config.finalizeInitialChildren, - prepareUpdate = config.prepareUpdate, - mutation = config.mutation, - persistence = config.persistence; - var getRootHostContainer = hostContext.getRootHostContainer, - popHostContext = hostContext.popHostContext, - getHostContext = hostContext.getHostContext, - popHostContainer = hostContext.popHostContainer; - var prepareToHydrateHostInstance = hydrationContext.prepareToHydrateHostInstance, - prepareToHydrateHostTextInstance = hydrationContext.prepareToHydrateHostTextInstance, - popHydrationState = hydrationContext.popHydrationState; - - - function markUpdate(workInProgress) { - // Tag the fiber with an update effect. This turns a Placement into - // an UpdateAndPlacement. - workInProgress.effectTag |= Update; - } +function precacheFiberNode(hostInst, node) { + node[internalInstanceKey] = hostInst; +} - function markRef(workInProgress) { - workInProgress.effectTag |= Ref; +/** + * Given a DOM node, return the closest ReactDOMComponent or + * ReactDOMTextComponent instance ancestor. + */ +function getClosestInstanceFromNode(node) { + if (node[internalInstanceKey]) { + return node[internalInstanceKey]; } - function appendAllReturns(returns, workInProgress) { - var node = workInProgress.stateNode; - if (node) { - node['return'] = workInProgress; - } - while (node !== null) { - if (node.tag === HostComponent || node.tag === HostText || node.tag === HostPortal) { - invariant(false, 'A call cannot have host component children.'); - } else if (node.tag === ReturnComponent) { - returns.push(node.type); - } else if (node.child !== null) { - node.child['return'] = node; - node = node.child; - continue; - } - while (node.sibling === null) { - if (node['return'] === null || node['return'] === workInProgress) { - return; - } - node = node['return']; - } - node.sibling['return'] = node['return']; - node = node.sibling; + while (!node[internalInstanceKey]) { + if (node.parentNode) { + node = node.parentNode; + } else { + // Top of the tree. This node must not be part of a React tree (or is + // unmounted, potentially). + return null; } } - function moveCallToHandlerPhase(current, workInProgress, renderExpirationTime) { - var call = workInProgress.memoizedProps; - !call ? invariant(false, 'Should be resolved by now. This error is likely caused by a bug in React. Please file an issue.') : void 0; - - // First step of the call has completed. Now we need to do the second. - // TODO: It would be nice to have a multi stage call represented by a - // single component, or at least tail call optimize nested ones. Currently - // that requires additional fields that we don't want to add to the fiber. - // So this requires nested handlers. - // Note: This doesn't mutate the alternate node. I don't think it needs to - // since this stage is reset for every pass. - workInProgress.tag = CallHandlerPhase; - - // Build up the returns. - // TODO: Compare this to a generator or opaque helpers like Children. - var returns = []; - appendAllReturns(returns, workInProgress); - var fn = call.handler; - var props = call.props; - var nextChildren = fn(props, returns); - - var currentFirstChild = current !== null ? current.child : null; - workInProgress.child = reconcileChildFibers(workInProgress, currentFirstChild, nextChildren, renderExpirationTime); - return workInProgress.child; + var inst = node[internalInstanceKey]; + if (inst.tag === HostComponent || inst.tag === HostText) { + // In Fiber, this will always be the deepest root. + return inst; } - function appendAllChildren(parent, workInProgress) { - // We only have the top Fiber that was created but we need recurse down its - // children to find all the terminal nodes. - var node = workInProgress.child; - while (node !== null) { - if (node.tag === HostComponent || node.tag === HostText) { - appendInitialChild(parent, node.stateNode); - } else if (node.tag === HostPortal) { - // If we have a portal child, then we don't want to traverse - // down its children. Instead, we'll get insertions from each child in - // the portal directly. - } else if (node.child !== null) { - node.child['return'] = node; - node = node.child; - continue; - } - if (node === workInProgress) { - return; - } - while (node.sibling === null) { - if (node['return'] === null || node['return'] === workInProgress) { - return; - } - node = node['return']; - } - node.sibling['return'] = node['return']; - node = node.sibling; - } - } + return null; +} - var updateHostContainer = void 0; - var updateHostComponent = void 0; - var updateHostText = void 0; - if (mutation) { - if (enableMutatingReconciler) { - // Mutation mode - updateHostContainer = function (workInProgress) { - // Noop - }; - updateHostComponent = function (current, workInProgress, updatePayload, type, oldProps, newProps, rootContainerInstance) { - // TODO: Type this specific to this type of component. - workInProgress.updateQueue = updatePayload; - // If the update payload indicates that there is a change or if there - // is a new ref we mark this as an update. All the work is done in commitWork. - if (updatePayload) { - markUpdate(workInProgress); - } - }; - updateHostText = function (current, workInProgress, oldText, newText) { - // If the text differs, mark it as an update. All the work in done in commitWork. - if (oldText !== newText) { - markUpdate(workInProgress); - } - }; - } else { - invariant(false, 'Mutating reconciler is disabled.'); - } - } else if (persistence) { - if (enablePersistentReconciler) { - // Persistent host tree mode - var cloneInstance = persistence.cloneInstance, - createContainerChildSet = persistence.createContainerChildSet, - appendChildToContainerChildSet = persistence.appendChildToContainerChildSet, - finalizeContainerChildren = persistence.finalizeContainerChildren; - - // An unfortunate fork of appendAllChildren because we have two different parent types. - - var appendAllChildrenToContainer = function (containerChildSet, workInProgress) { - // We only have the top Fiber that was created but we need recurse down its - // children to find all the terminal nodes. - var node = workInProgress.child; - while (node !== null) { - if (node.tag === HostComponent || node.tag === HostText) { - appendChildToContainerChildSet(containerChildSet, node.stateNode); - } else if (node.tag === HostPortal) { - // If we have a portal child, then we don't want to traverse - // down its children. Instead, we'll get insertions from each child in - // the portal directly. - } else if (node.child !== null) { - node.child['return'] = node; - node = node.child; - continue; - } - if (node === workInProgress) { - return; - } - while (node.sibling === null) { - if (node['return'] === null || node['return'] === workInProgress) { - return; - } - node = node['return']; - } - node.sibling['return'] = node['return']; - node = node.sibling; - } - }; - updateHostContainer = function (workInProgress) { - var portalOrRoot = workInProgress.stateNode; - var childrenUnchanged = workInProgress.firstEffect === null; - if (childrenUnchanged) { - // No changes, just reuse the existing instance. - } else { - var container = portalOrRoot.containerInfo; - var newChildSet = createContainerChildSet(container); - if (finalizeContainerChildren(container, newChildSet)) { - markUpdate(workInProgress); - } - portalOrRoot.pendingChildren = newChildSet; - // If children might have changed, we have to add them all to the set. - appendAllChildrenToContainer(newChildSet, workInProgress); - // Schedule an update on the container to swap out the container. - markUpdate(workInProgress); - } - }; - updateHostComponent = function (current, workInProgress, updatePayload, type, oldProps, newProps, rootContainerInstance) { - // If there are no effects associated with this node, then none of our children had any updates. - // This guarantees that we can reuse all of them. - var childrenUnchanged = workInProgress.firstEffect === null; - var currentInstance = current.stateNode; - if (childrenUnchanged && updatePayload === null) { - // No changes, just reuse the existing instance. - // Note that this might release a previous clone. - workInProgress.stateNode = currentInstance; - } else { - var recyclableInstance = workInProgress.stateNode; - var newInstance = cloneInstance(currentInstance, updatePayload, type, oldProps, newProps, workInProgress, childrenUnchanged, recyclableInstance); - if (finalizeInitialChildren(newInstance, type, newProps, rootContainerInstance)) { - markUpdate(workInProgress); - } - workInProgress.stateNode = newInstance; - if (childrenUnchanged) { - // If there are no other effects in this tree, we need to flag this node as having one. - // Even though we're not going to use it for anything. - // Otherwise parents won't know that there are new children to propagate upwards. - markUpdate(workInProgress); - } else { - // If children might have changed, we have to add them all to the set. - appendAllChildren(newInstance, workInProgress); - } - } - }; - updateHostText = function (current, workInProgress, oldText, newText) { - if (oldText !== newText) { - // If the text content differs, we'll create a new text instance for it. - var rootContainerInstance = getRootHostContainer(); - var currentHostContext = getHostContext(); - workInProgress.stateNode = createTextInstance(newText, rootContainerInstance, currentHostContext, workInProgress); - // We'll have to mark it as having an effect, even though we won't use the effect for anything. - // This lets the parents know that at least one of their children has changed. - markUpdate(workInProgress); - } - }; - } else { - invariant(false, 'Persistent reconciler is disabled.'); - } - } else { - if (enableNoopReconciler) { - // No host operations - updateHostContainer = function (workInProgress) { - // Noop - }; - updateHostComponent = function (current, workInProgress, updatePayload, type, oldProps, newProps, rootContainerInstance) { - // Noop - }; - updateHostText = function (current, workInProgress, oldText, newText) { - // Noop - }; +/** + * Given a DOM node, return the ReactDOMComponent or ReactDOMTextComponent + * instance, or null if the node was not rendered by this React. + */ +function getInstanceFromNode$1(node) { + var inst = node[internalInstanceKey]; + if (inst) { + if (inst.tag === HostComponent || inst.tag === HostText) { + return inst; } else { - invariant(false, 'Noop reconciler is disabled.'); + return null; } } + return null; +} - function completeWork(current, workInProgress, renderExpirationTime) { - // Get the latest props. - var newProps = workInProgress.pendingProps; - if (newProps === null) { - newProps = workInProgress.memoizedProps; - } else if (workInProgress.expirationTime !== Never || renderExpirationTime === Never) { - // Reset the pending props, unless this was a down-prioritization. - workInProgress.pendingProps = null; - } +/** + * Given a ReactDOMComponent or ReactDOMTextComponent, return the corresponding + * DOM node. + */ +function getNodeFromInstance$1(inst) { + if (inst.tag === HostComponent || inst.tag === HostText) { + // In Fiber this, is just the state node right now. We assume it will be + // a host component or host text. + return inst.stateNode; + } - switch (workInProgress.tag) { - case FunctionalComponent: - return null; - case ClassComponent: - { - // We are leaving this subtree, so pop context if any. - popContextProvider(workInProgress); - return null; - } - case HostRoot: - { - popHostContainer(workInProgress); - popTopLevelContextObject(workInProgress); - var fiberRoot = workInProgress.stateNode; - if (fiberRoot.pendingContext) { - fiberRoot.context = fiberRoot.pendingContext; - fiberRoot.pendingContext = null; - } + // Without this first invariant, passing a non-DOM-component triggers the next + // invariant for a missing parent, which is super confusing. + invariant(false, 'getNodeFromInstance: Invalid argument.'); +} - if (current === null || current.child === null) { - // If we hydrated, pop so that we can delete any remaining children - // that weren't hydrated. - popHydrationState(workInProgress); - // This resets the hacky state to fix isMounted before committing. - // TODO: Delete this when we delete isMounted and findDOMNode. - workInProgress.effectTag &= ~Placement; - } - updateHostContainer(workInProgress); - return null; - } - case HostComponent: - { - popHostContext(workInProgress); - var rootContainerInstance = getRootHostContainer(); - var type = workInProgress.type; - if (current !== null && workInProgress.stateNode != null) { - // If we have an alternate, that means this is an update and we need to - // schedule a side-effect to do the updates. - var oldProps = current.memoizedProps; - // If we get updated because one of our children updated, we don't - // have newProps so we'll have to reuse them. - // TODO: Split the update API as separate for the props vs. children. - // Even better would be if children weren't special cased at all tho. - var instance = workInProgress.stateNode; - var currentHostContext = getHostContext(); - var updatePayload = prepareUpdate(instance, type, oldProps, newProps, rootContainerInstance, currentHostContext); - - updateHostComponent(current, workInProgress, updatePayload, type, oldProps, newProps, rootContainerInstance); - - if (current.ref !== workInProgress.ref) { - markRef(workInProgress); - } - } else { - if (!newProps) { - !(workInProgress.stateNode !== null) ? invariant(false, 'We must have new props for new mounts. This error is likely caused by a bug in React. Please file an issue.') : void 0; - // This can happen when we abort work. - return null; - } +function getFiberCurrentPropsFromNode$1(node) { + return node[internalEventHandlersKey] || null; +} - var _currentHostContext = getHostContext(); - // TODO: Move createInstance to beginWork and keep it on a context - // "stack" as the parent. Then append children as we go in beginWork - // or completeWork depending on we want to add then top->down or - // bottom->up. Top->down is faster in IE11. - var wasHydrated = popHydrationState(workInProgress); - if (wasHydrated) { - // TODO: Move this and createInstance step into the beginPhase - // to consolidate. - if (prepareToHydrateHostInstance(workInProgress, rootContainerInstance, _currentHostContext)) { - // If changes to the hydrated node needs to be applied at the - // commit-phase we mark this as such. - markUpdate(workInProgress); - } - } else { - var _instance = createInstance(type, newProps, rootContainerInstance, _currentHostContext, workInProgress); +function updateFiberProps(node, props) { + node[internalEventHandlersKey] = props; +} - appendAllChildren(_instance, workInProgress); +function getParent(inst) { + do { + inst = inst.return; + // TODO: If this is a HostRoot we might want to bail out. + // That is depending on if we want nested subtrees (layers) to bubble + // events to their parent. We could also go through parentNode on the + // host node but that wouldn't work for React Native and doesn't let us + // do the portal feature. + } while (inst && inst.tag !== HostComponent); + if (inst) { + return inst; + } + return null; +} - // Certain renderers require commit-time effects for initial mount. - // (eg DOM renderer supports auto-focus for certain elements). - // Make sure such renderers get scheduled for later work. - if (finalizeInitialChildren(_instance, type, newProps, rootContainerInstance)) { - markUpdate(workInProgress); - } - workInProgress.stateNode = _instance; - } +/** + * Return the lowest common ancestor of A and B, or null if they are in + * different trees. + */ +function getLowestCommonAncestor(instA, instB) { + var depthA = 0; + for (var tempA = instA; tempA; tempA = getParent(tempA)) { + depthA++; + } + var depthB = 0; + for (var tempB = instB; tempB; tempB = getParent(tempB)) { + depthB++; + } - if (workInProgress.ref !== null) { - // If there is a ref on a host node we need to schedule a callback - markRef(workInProgress); - } - } - return null; - } - case HostText: - { - var newText = newProps; - if (current && workInProgress.stateNode != null) { - var oldText = current.memoizedProps; - // If we have an alternate, that means this is an update and we need - // to schedule a side-effect to do the updates. - updateHostText(current, workInProgress, oldText, newText); - } else { - if (typeof newText !== 'string') { - !(workInProgress.stateNode !== null) ? invariant(false, 'We must have new props for new mounts. This error is likely caused by a bug in React. Please file an issue.') : void 0; - // This can happen when we abort work. - return null; - } - var _rootContainerInstance = getRootHostContainer(); - var _currentHostContext2 = getHostContext(); - var _wasHydrated = popHydrationState(workInProgress); - if (_wasHydrated) { - if (prepareToHydrateHostTextInstance(workInProgress)) { - markUpdate(workInProgress); - } - } else { - workInProgress.stateNode = createTextInstance(newText, _rootContainerInstance, _currentHostContext2, workInProgress); - } - } - return null; - } - case CallComponent: - return moveCallToHandlerPhase(current, workInProgress, renderExpirationTime); - case CallHandlerPhase: - // Reset the tag to now be a first phase call. - workInProgress.tag = CallComponent; - return null; - case ReturnComponent: - // Does nothing. - return null; - case Fragment: - return null; - case HostPortal: - popHostContainer(workInProgress); - updateHostContainer(workInProgress); - return null; - // Error cases - case IndeterminateComponent: - invariant(false, 'An indeterminate component should have become determinate before completing. This error is likely caused by a bug in React. Please file an issue.'); - // eslint-disable-next-line no-fallthrough - default: - invariant(false, 'Unknown unit of work tag. This error is likely caused by a bug in React. Please file an issue.'); - } + // If A is deeper, crawl up. + while (depthA - depthB > 0) { + instA = getParent(instA); + depthA--; } - return { - completeWork: completeWork - }; -}; + // If B is deeper, crawl up. + while (depthB - depthA > 0) { + instB = getParent(instB); + depthB--; + } -var invokeGuardedCallback$2 = ReactErrorUtils.invokeGuardedCallback; -var hasCaughtError$1 = ReactErrorUtils.hasCaughtError; -var clearCaughtError$1 = ReactErrorUtils.clearCaughtError; + // Walk in lockstep until we find a match. + var depth = depthA; + while (depth--) { + if (instA === instB || instA === instB.alternate) { + return instA; + } + instA = getParent(instA); + instB = getParent(instB); + } + return null; +} +/** + * Return if A is an ancestor of B. + */ -var ReactFiberCommitWork = function (config, captureError) { - var getPublicInstance = config.getPublicInstance, - mutation = config.mutation, - persistence = config.persistence; +/** + * Return the parent instance of the passed-in instance. + */ - var callComponentWillUnmountWithTimer = function (current, instance) { - startPhaseTimer(current, 'componentWillUnmount'); - instance.props = current.memoizedProps; - instance.state = current.memoizedState; - instance.componentWillUnmount(); - stopPhaseTimer(); - }; - // Capture errors so they don't interrupt unmounting. - function safelyCallComponentWillUnmount(current, instance) { - { - invokeGuardedCallback$2(null, callComponentWillUnmountWithTimer, null, current, instance); - if (hasCaughtError$1()) { - var unmountError = clearCaughtError$1(); - captureError(current, unmountError); - } - } +/** + * Simulates the traversal of a two-phase, capture/bubble event dispatch. + */ +function traverseTwoPhase(inst, fn, arg) { + var path = []; + while (inst) { + path.push(inst); + inst = getParent(inst); } - - function safelyDetachRef(current) { - var ref = current.ref; - if (ref !== null) { - { - invokeGuardedCallback$2(null, ref, null, null); - if (hasCaughtError$1()) { - var refError = clearCaughtError$1(); - captureError(current, refError); - } - } - } + var i = void 0; + for (i = path.length; i-- > 0;) { + fn(path[i], 'captured', arg); } - - function commitLifeCycles(current, finishedWork) { - switch (finishedWork.tag) { - case ClassComponent: - { - var instance = finishedWork.stateNode; - if (finishedWork.effectTag & Update) { - if (current === null) { - startPhaseTimer(finishedWork, 'componentDidMount'); - instance.props = finishedWork.memoizedProps; - instance.state = finishedWork.memoizedState; - instance.componentDidMount(); - stopPhaseTimer(); - } else { - var prevProps = current.memoizedProps; - var prevState = current.memoizedState; - startPhaseTimer(finishedWork, 'componentDidUpdate'); - instance.props = finishedWork.memoizedProps; - instance.state = finishedWork.memoizedState; - instance.componentDidUpdate(prevProps, prevState); - stopPhaseTimer(); - } - } - var updateQueue = finishedWork.updateQueue; - if (updateQueue !== null) { - commitCallbacks(updateQueue, instance); - } - return; - } - case HostRoot: - { - var _updateQueue = finishedWork.updateQueue; - if (_updateQueue !== null) { - var _instance = finishedWork.child !== null ? finishedWork.child.stateNode : null; - commitCallbacks(_updateQueue, _instance); - } - return; - } - case HostComponent: - { - var _instance2 = finishedWork.stateNode; - - // Renderers may schedule work to be done after host components are mounted - // (eg DOM renderer may schedule auto-focus for inputs and form controls). - // These effects should only be committed when components are first mounted, - // aka when there is no current/alternate. - if (current === null && finishedWork.effectTag & Update) { - var type = finishedWork.type; - var props = finishedWork.memoizedProps; - commitMount(_instance2, type, props, finishedWork); - } - - return; - } - case HostText: - { - // We have no life-cycles associated with text. - return; - } - case HostPortal: - { - // We have no life-cycles associated with portals. - return; - } - default: - { - invariant(false, 'This unit of work tag should not have side-effects. This error is likely caused by a bug in React. Please file an issue.'); - } - } + for (i = 0; i < path.length; i++) { + fn(path[i], 'bubbled', arg); } +} - function commitAttachRef(finishedWork) { - var ref = finishedWork.ref; - if (ref !== null) { - var instance = finishedWork.stateNode; - switch (finishedWork.tag) { - case HostComponent: - ref(getPublicInstance(instance)); - break; - default: - ref(instance); - } +/** + * Traverses the ID hierarchy and invokes the supplied `cb` on any IDs that + * should would receive a `mouseEnter` or `mouseLeave` event. + * + * Does not invoke the callback on the nearest common ancestor because nothing + * "entered" or "left" that element. + */ +function traverseEnterLeave(from, to, fn, argFrom, argTo) { + var common = from && to ? getLowestCommonAncestor(from, to) : null; + var pathFrom = []; + while (true) { + if (!from) { + break; } - } - - function commitDetachRef(current) { - var currentRef = current.ref; - if (currentRef !== null) { - currentRef(null); + if (from === common) { + break; + } + var alternate = from.alternate; + if (alternate !== null && alternate === common) { + break; } + pathFrom.push(from); + from = getParent(from); } - - // User-originating errors (lifecycles and refs) should not interrupt - // deletion, so don't let them throw. Host-originating errors should - // interrupt deletion, so it's okay - function commitUnmount(current) { - if (typeof onCommitUnmount === 'function') { - onCommitUnmount(current); + var pathTo = []; + while (true) { + if (!to) { + break; } - - switch (current.tag) { - case ClassComponent: - { - safelyDetachRef(current); - var instance = current.stateNode; - if (typeof instance.componentWillUnmount === 'function') { - safelyCallComponentWillUnmount(current, instance); - } - return; - } - case HostComponent: - { - safelyDetachRef(current); - return; - } - case CallComponent: - { - commitNestedUnmounts(current.stateNode); - return; - } - case HostPortal: - { - // TODO: this is recursive. - // We are also not using this parent because - // the portal will get pushed immediately. - if (enableMutatingReconciler && mutation) { - unmountHostComponents(current); - } else if (enablePersistentReconciler && persistence) { - emptyPortalContainer(current); - } - return; - } + if (to === common) { + break; } + var _alternate = to.alternate; + if (_alternate !== null && _alternate === common) { + break; + } + pathTo.push(to); + to = getParent(to); + } + for (var i = 0; i < pathFrom.length; i++) { + fn(pathFrom[i], 'bubbled', argFrom); + } + for (var _i = pathTo.length; _i-- > 0;) { + fn(pathTo[_i], 'captured', argTo); } +} - function commitNestedUnmounts(root) { - // While we're inside a removed host node we don't want to call - // removeChild on the inner nodes because they're removed by the top - // call anyway. We also want to call componentWillUnmount on all - // composites before this host node is removed from the tree. Therefore - var node = root; - while (true) { - commitUnmount(node); - // Visit children because they may contain more composite or host nodes. - // Skip portals because commitUnmount() currently visits them recursively. - if (node.child !== null && ( - // If we use mutation we drill down into portals using commitUnmount above. - // If we don't use mutation we drill down into portals here instead. - !mutation || node.tag !== HostPortal)) { - node.child['return'] = node; - node = node.child; - continue; - } - if (node === root) { - return; - } - while (node.sibling === null) { - if (node['return'] === null || node['return'] === root) { - return; - } - node = node['return']; - } - node.sibling['return'] = node['return']; - node = node.sibling; - } +/** + * Some event types have a notion of different registration names for different + * "phases" of propagation. This finds listeners by a given phase. + */ +function listenerAtPhase(inst, event, propagationPhase) { + var registrationName = event.dispatchConfig.phasedRegistrationNames[propagationPhase]; + return getListener(inst, registrationName); +} + +/** + * A small set of propagation patterns, each of which will accept a small amount + * of information, and generate a set of "dispatch ready event objects" - which + * are sets of events that have already been annotated with a set of dispatched + * listener functions/ids. The API is designed this way to discourage these + * propagation strategies from actually executing the dispatches, since we + * always want to collect the entire set of dispatches before executing even a + * single one. + */ + +/** + * Tags a `SyntheticEvent` with dispatched listeners. Creating this function + * here, allows us to not have to bind or create functions for each event. + * Mutating the event's members allows us to not have to create a wrapping + * "dispatch" object that pairs the event with the listener. + */ +function accumulateDirectionalDispatches(inst, phase, event) { + { + !inst ? warningWithoutStack$1(false, 'Dispatching inst must not be null') : void 0; + } + var listener = listenerAtPhase(inst, event, phase); + if (listener) { + event._dispatchListeners = accumulateInto(event._dispatchListeners, listener); + event._dispatchInstances = accumulateInto(event._dispatchInstances, inst); + } +} + +/** + * Collect dispatches (must be entirely collected before dispatching - see unit + * tests). Lazily allocate the array to conserve memory. We must loop through + * each event and perform the traversal for each one. We cannot perform a + * single traversal for the entire collection of events because each event may + * have a different target. + */ +function accumulateTwoPhaseDispatchesSingle(event) { + if (event && event.dispatchConfig.phasedRegistrationNames) { + traverseTwoPhase(event._targetInst, accumulateDirectionalDispatches, event); } +} - function detachFiber(current) { - // Cut off the return pointers to disconnect it from the tree. Ideally, we - // should clear the child pointer of the parent alternate to let this - // get GC:ed but we don't know which for sure which parent is the current - // one so we'll settle for GC:ing the subtree of this child. This child - // itself will be GC:ed when the parent updates the next time. - current['return'] = null; - current.child = null; - if (current.alternate) { - current.alternate.child = null; - current.alternate['return'] = null; +/** + * Accumulates without regard to direction, does not look for phased + * registration names. Same as `accumulateDirectDispatchesSingle` but without + * requiring that the `dispatchMarker` be the same as the dispatched ID. + */ +function accumulateDispatches(inst, ignoredDirection, event) { + if (inst && event && event.dispatchConfig.registrationName) { + var registrationName = event.dispatchConfig.registrationName; + var listener = getListener(inst, registrationName); + if (listener) { + event._dispatchListeners = accumulateInto(event._dispatchListeners, listener); + event._dispatchInstances = accumulateInto(event._dispatchInstances, inst); } } +} - if (!mutation) { - var commitContainer = void 0; - if (persistence) { - var replaceContainerChildren = persistence.replaceContainerChildren, - createContainerChildSet = persistence.createContainerChildSet; +/** + * Accumulates dispatches on an `SyntheticEvent`, but only for the + * `dispatchMarker`. + * @param {SyntheticEvent} event + */ +function accumulateDirectDispatchesSingle(event) { + if (event && event.dispatchConfig.registrationName) { + accumulateDispatches(event._targetInst, null, event); + } +} - var emptyPortalContainer = function (current) { - var portal = current.stateNode; - var containerInfo = portal.containerInfo; +function accumulateTwoPhaseDispatches(events) { + forEachAccumulated(events, accumulateTwoPhaseDispatchesSingle); +} - var emptyChildSet = createContainerChildSet(containerInfo); - replaceContainerChildren(containerInfo, emptyChildSet); - }; - commitContainer = function (finishedWork) { - switch (finishedWork.tag) { - case ClassComponent: - { - return; - } - case HostComponent: - { - return; - } - case HostText: - { - return; - } - case HostRoot: - case HostPortal: - { - var portalOrRoot = finishedWork.stateNode; - var containerInfo = portalOrRoot.containerInfo, - _pendingChildren = portalOrRoot.pendingChildren; - replaceContainerChildren(containerInfo, _pendingChildren); - return; - } - default: - { - invariant(false, 'This unit of work tag should not have side-effects. This error is likely caused by a bug in React. Please file an issue.'); - } - } - }; - } else { - commitContainer = function (finishedWork) { - // Noop - }; - } - if (enablePersistentReconciler || enableNoopReconciler) { - return { - commitResetTextContent: function (finishedWork) {}, - commitPlacement: function (finishedWork) {}, - commitDeletion: function (current) { - // Detach refs and call componentWillUnmount() on the whole subtree. - commitNestedUnmounts(current); - detachFiber(current); - }, - commitWork: function (current, finishedWork) { - commitContainer(finishedWork); - }, - commitLifeCycles: commitLifeCycles, - commitAttachRef: commitAttachRef, - commitDetachRef: commitDetachRef - }; - } else if (persistence) { - invariant(false, 'Persistent reconciler is disabled.'); - } else { - invariant(false, 'Noop reconciler is disabled.'); - } - } - var commitMount = mutation.commitMount, - commitUpdate = mutation.commitUpdate, - resetTextContent = mutation.resetTextContent, - commitTextUpdate = mutation.commitTextUpdate, - appendChild = mutation.appendChild, - appendChildToContainer = mutation.appendChildToContainer, - insertBefore = mutation.insertBefore, - insertInContainerBefore = mutation.insertInContainerBefore, - removeChild = mutation.removeChild, - removeChildFromContainer = mutation.removeChildFromContainer; +function accumulateEnterLeaveDispatches(leave, enter, from, to) { + traverseEnterLeave(from, to, accumulateDispatches, leave, enter); +} +function accumulateDirectDispatches(events) { + forEachAccumulated(events, accumulateDirectDispatchesSingle); +} - function getHostParentFiber(fiber) { - var parent = fiber['return']; - while (parent !== null) { - if (isHostParent(parent)) { - return parent; - } - parent = parent['return']; - } - invariant(false, 'Expected to find a host parent. This error is likely caused by a bug in React. Please file an issue.'); - } +var canUseDOM = !!(typeof window !== 'undefined' && window.document && window.document.createElement); - function isHostParent(fiber) { - return fiber.tag === HostComponent || fiber.tag === HostRoot || fiber.tag === HostPortal; - } +// Do not uses the below two methods directly! +// Instead use constants exported from DOMTopLevelEventTypes in ReactDOM. +// (It is the only module that is allowed to access these methods.) - function getHostSibling(fiber) { - // We're going to search forward into the tree until we find a sibling host - // node. Unfortunately, if multiple insertions are done in a row we have to - // search past them. This leads to exponential search for the next sibling. - var node = fiber; - siblings: while (true) { - // If we didn't find anything, let's try the next sibling. - while (node.sibling === null) { - if (node['return'] === null || isHostParent(node['return'])) { - // If we pop out of the root or hit the parent the fiber we are the - // last sibling. - return null; - } - node = node['return']; - } - node.sibling['return'] = node['return']; - node = node.sibling; - while (node.tag !== HostComponent && node.tag !== HostText) { - // If it is not host node and, we might have a host node inside it. - // Try to search down until we find one. - if (node.effectTag & Placement) { - // If we don't have a child, try the siblings instead. - continue siblings; - } - // If we don't have a child, try the siblings instead. - // We also skip portals because they are not part of this host tree. - if (node.child === null || node.tag === HostPortal) { - continue siblings; - } else { - node.child['return'] = node; - node = node.child; - } - } - // Check if this host node is stable or about to be placed. - if (!(node.effectTag & Placement)) { - // Found it! - return node.stateNode; - } - } - } +function unsafeCastStringToDOMTopLevelType(topLevelType) { + return topLevelType; +} - function commitPlacement(finishedWork) { - // Recursively insert all host nodes into the parent. - var parentFiber = getHostParentFiber(finishedWork); - var parent = void 0; - var isContainer = void 0; - switch (parentFiber.tag) { - case HostComponent: - parent = parentFiber.stateNode; - isContainer = false; - break; - case HostRoot: - parent = parentFiber.stateNode.containerInfo; - isContainer = true; - break; - case HostPortal: - parent = parentFiber.stateNode.containerInfo; - isContainer = true; - break; - default: - invariant(false, 'Invalid host parent fiber. This error is likely caused by a bug in React. Please file an issue.'); - } - if (parentFiber.effectTag & ContentReset) { - // Reset the text content of the parent before doing any insertions - resetTextContent(parent); - // Clear ContentReset from the effect tag - parentFiber.effectTag &= ~ContentReset; - } +function unsafeCastDOMTopLevelTypeToString(topLevelType) { + return topLevelType; +} - var before = getHostSibling(finishedWork); - // We only have the top Fiber that was inserted but we need recurse down its - // children to find all the terminal nodes. - var node = finishedWork; - while (true) { - if (node.tag === HostComponent || node.tag === HostText) { - if (before) { - if (isContainer) { - insertInContainerBefore(parent, node.stateNode, before); - } else { - insertBefore(parent, node.stateNode, before); - } - } else { - if (isContainer) { - appendChildToContainer(parent, node.stateNode); - } else { - appendChild(parent, node.stateNode); - } - } - } else if (node.tag === HostPortal) { - // If the insertion itself is a portal, then we don't want to traverse - // down its children. Instead, we'll get insertions from each child in - // the portal directly. - } else if (node.child !== null) { - node.child['return'] = node; - node = node.child; - continue; - } - if (node === finishedWork) { - return; - } - while (node.sibling === null) { - if (node['return'] === null || node['return'] === finishedWork) { - return; - } - node = node['return']; - } - node.sibling['return'] = node['return']; - node = node.sibling; - } - } +/** + * Generate a mapping of standard vendor prefixes using the defined style property and event name. + * + * @param {string} styleProp + * @param {string} eventName + * @returns {object} + */ +function makePrefixMap(styleProp, eventName) { + var prefixes = {}; - function unmountHostComponents(current) { - // We only have the top Fiber that was inserted but we need recurse down its - var node = current; + prefixes[styleProp.toLowerCase()] = eventName.toLowerCase(); + prefixes['Webkit' + styleProp] = 'webkit' + eventName; + prefixes['Moz' + styleProp] = 'moz' + eventName; - // Each iteration, currentParent is populated with node's host parent if not - // currentParentIsValid. - var currentParentIsValid = false; - var currentParent = void 0; - var currentParentIsContainer = void 0; + return prefixes; +} - while (true) { - if (!currentParentIsValid) { - var parent = node['return']; - findParent: while (true) { - !(parent !== null) ? invariant(false, 'Expected to find a host parent. This error is likely caused by a bug in React. Please file an issue.') : void 0; - switch (parent.tag) { - case HostComponent: - currentParent = parent.stateNode; - currentParentIsContainer = false; - break findParent; - case HostRoot: - currentParent = parent.stateNode.containerInfo; - currentParentIsContainer = true; - break findParent; - case HostPortal: - currentParent = parent.stateNode.containerInfo; - currentParentIsContainer = true; - break findParent; - } - parent = parent['return']; - } - currentParentIsValid = true; - } +/** + * A list of event names to a configurable list of vendor prefixes. + */ +var vendorPrefixes = { + animationend: makePrefixMap('Animation', 'AnimationEnd'), + animationiteration: makePrefixMap('Animation', 'AnimationIteration'), + animationstart: makePrefixMap('Animation', 'AnimationStart'), + transitionend: makePrefixMap('Transition', 'TransitionEnd') +}; - if (node.tag === HostComponent || node.tag === HostText) { - commitNestedUnmounts(node); - // After all the children have unmounted, it is now safe to remove the - // node from the tree. - if (currentParentIsContainer) { - removeChildFromContainer(currentParent, node.stateNode); - } else { - removeChild(currentParent, node.stateNode); - } - // Don't visit children because we already visited them. - } else if (node.tag === HostPortal) { - // When we go into a portal, it becomes the parent to remove from. - // We will reassign it back when we pop the portal on the way up. - currentParent = node.stateNode.containerInfo; - // Visit children because portals might contain host components. - if (node.child !== null) { - node.child['return'] = node; - node = node.child; - continue; - } - } else { - commitUnmount(node); - // Visit children because we may find more host components below. - if (node.child !== null) { - node.child['return'] = node; - node = node.child; - continue; - } - } - if (node === current) { - return; - } - while (node.sibling === null) { - if (node['return'] === null || node['return'] === current) { - return; - } - node = node['return']; - if (node.tag === HostPortal) { - // When we go out of the portal, we need to restore the parent. - // Since we don't keep a stack of them, we will search for it. - currentParentIsValid = false; - } - } - node.sibling['return'] = node['return']; - node = node.sibling; - } - } +/** + * Event names that have already been detected and prefixed (if applicable). + */ +var prefixedEventNames = {}; - function commitDeletion(current) { - // Recursively delete all host nodes from the parent. - // Detach refs and call componentWillUnmount() on the whole subtree. - unmountHostComponents(current); - detachFiber(current); - } +/** + * Element to check for prefixes on. + */ +var style = {}; - function commitWork(current, finishedWork) { - switch (finishedWork.tag) { - case ClassComponent: - { - return; - } - case HostComponent: - { - var instance = finishedWork.stateNode; - if (instance != null) { - // Commit the work prepared earlier. - var newProps = finishedWork.memoizedProps; - // For hydration we reuse the update path but we treat the oldProps - // as the newProps. The updatePayload will contain the real change in - // this case. - var oldProps = current !== null ? current.memoizedProps : newProps; - var type = finishedWork.type; - // TODO: Type the updateQueue to be specific to host components. - var updatePayload = finishedWork.updateQueue; - finishedWork.updateQueue = null; - if (updatePayload !== null) { - commitUpdate(instance, updatePayload, type, oldProps, newProps, finishedWork); - } - } - return; - } - case HostText: - { - !(finishedWork.stateNode !== null) ? invariant(false, 'This should have a text node initialized. This error is likely caused by a bug in React. Please file an issue.') : void 0; - var textInstance = finishedWork.stateNode; - var newText = finishedWork.memoizedProps; - // For hydration we reuse the update path but we treat the oldProps - // as the newProps. The updatePayload will contain the real change in - // this case. - var oldText = current !== null ? current.memoizedProps : newText; - commitTextUpdate(textInstance, oldText, newText); - return; - } - case HostRoot: - { - return; - } - default: - { - invariant(false, 'This unit of work tag should not have side-effects. This error is likely caused by a bug in React. Please file an issue.'); - } - } +/** + * Bootstrap if a DOM exists. + */ +if (canUseDOM) { + style = document.createElement('div').style; + + // On some platforms, in particular some releases of Android 4.x, + // the un-prefixed "animation" and "transition" properties are defined on the + // style object but the events that fire will still be prefixed, so we need + // to check if the un-prefixed events are usable, and if not remove them from the map. + if (!('AnimationEvent' in window)) { + delete vendorPrefixes.animationend.animation; + delete vendorPrefixes.animationiteration.animation; + delete vendorPrefixes.animationstart.animation; } - function commitResetTextContent(current) { - resetTextContent(current.stateNode); + // Same as above + if (!('TransitionEvent' in window)) { + delete vendorPrefixes.transitionend.transition; } +} - if (enableMutatingReconciler) { - return { - commitResetTextContent: commitResetTextContent, - commitPlacement: commitPlacement, - commitDeletion: commitDeletion, - commitWork: commitWork, - commitLifeCycles: commitLifeCycles, - commitAttachRef: commitAttachRef, - commitDetachRef: commitDetachRef - }; - } else { - invariant(false, 'Mutating reconciler is disabled.'); +/** + * Attempts to determine the correct vendor prefixed event name. + * + * @param {string} eventName + * @returns {string} + */ +function getVendorPrefixedEventName(eventName) { + if (prefixedEventNames[eventName]) { + return prefixedEventNames[eventName]; + } else if (!vendorPrefixes[eventName]) { + return eventName; } -}; -var NO_CONTEXT = {}; + var prefixMap = vendorPrefixes[eventName]; -var ReactFiberHostContext = function (config) { - var getChildHostContext = config.getChildHostContext, - getRootHostContext = config.getRootHostContext; + for (var styleProp in prefixMap) { + if (prefixMap.hasOwnProperty(styleProp) && styleProp in style) { + return prefixedEventNames[eventName] = prefixMap[styleProp]; + } + } + return eventName; +} - var contextStackCursor = createCursor(NO_CONTEXT); - var contextFiberStackCursor = createCursor(NO_CONTEXT); - var rootInstanceStackCursor = createCursor(NO_CONTEXT); +/** + * To identify top level events in ReactDOM, we use constants defined by this + * module. This is the only module that uses the unsafe* methods to express + * that the constants actually correspond to the browser event names. This lets + * us save some bundle size by avoiding a top level type -> event name map. + * The rest of ReactDOM code should import top level types from this file. + */ +var TOP_ABORT = unsafeCastStringToDOMTopLevelType('abort'); +var TOP_ANIMATION_END = unsafeCastStringToDOMTopLevelType(getVendorPrefixedEventName('animationend')); +var TOP_ANIMATION_ITERATION = unsafeCastStringToDOMTopLevelType(getVendorPrefixedEventName('animationiteration')); +var TOP_ANIMATION_START = unsafeCastStringToDOMTopLevelType(getVendorPrefixedEventName('animationstart')); +var TOP_BLUR = unsafeCastStringToDOMTopLevelType('blur'); +var TOP_CAN_PLAY = unsafeCastStringToDOMTopLevelType('canplay'); +var TOP_CAN_PLAY_THROUGH = unsafeCastStringToDOMTopLevelType('canplaythrough'); +var TOP_CANCEL = unsafeCastStringToDOMTopLevelType('cancel'); +var TOP_CHANGE = unsafeCastStringToDOMTopLevelType('change'); +var TOP_CLICK = unsafeCastStringToDOMTopLevelType('click'); +var TOP_CLOSE = unsafeCastStringToDOMTopLevelType('close'); +var TOP_COMPOSITION_END = unsafeCastStringToDOMTopLevelType('compositionend'); +var TOP_COMPOSITION_START = unsafeCastStringToDOMTopLevelType('compositionstart'); +var TOP_COMPOSITION_UPDATE = unsafeCastStringToDOMTopLevelType('compositionupdate'); +var TOP_CONTEXT_MENU = unsafeCastStringToDOMTopLevelType('contextmenu'); +var TOP_COPY = unsafeCastStringToDOMTopLevelType('copy'); +var TOP_CUT = unsafeCastStringToDOMTopLevelType('cut'); +var TOP_DOUBLE_CLICK = unsafeCastStringToDOMTopLevelType('dblclick'); +var TOP_AUX_CLICK = unsafeCastStringToDOMTopLevelType('auxclick'); +var TOP_DRAG = unsafeCastStringToDOMTopLevelType('drag'); +var TOP_DRAG_END = unsafeCastStringToDOMTopLevelType('dragend'); +var TOP_DRAG_ENTER = unsafeCastStringToDOMTopLevelType('dragenter'); +var TOP_DRAG_EXIT = unsafeCastStringToDOMTopLevelType('dragexit'); +var TOP_DRAG_LEAVE = unsafeCastStringToDOMTopLevelType('dragleave'); +var TOP_DRAG_OVER = unsafeCastStringToDOMTopLevelType('dragover'); +var TOP_DRAG_START = unsafeCastStringToDOMTopLevelType('dragstart'); +var TOP_DROP = unsafeCastStringToDOMTopLevelType('drop'); +var TOP_DURATION_CHANGE = unsafeCastStringToDOMTopLevelType('durationchange'); +var TOP_EMPTIED = unsafeCastStringToDOMTopLevelType('emptied'); +var TOP_ENCRYPTED = unsafeCastStringToDOMTopLevelType('encrypted'); +var TOP_ENDED = unsafeCastStringToDOMTopLevelType('ended'); +var TOP_ERROR = unsafeCastStringToDOMTopLevelType('error'); +var TOP_FOCUS = unsafeCastStringToDOMTopLevelType('focus'); +var TOP_GOT_POINTER_CAPTURE = unsafeCastStringToDOMTopLevelType('gotpointercapture'); +var TOP_INPUT = unsafeCastStringToDOMTopLevelType('input'); +var TOP_INVALID = unsafeCastStringToDOMTopLevelType('invalid'); +var TOP_KEY_DOWN = unsafeCastStringToDOMTopLevelType('keydown'); +var TOP_KEY_PRESS = unsafeCastStringToDOMTopLevelType('keypress'); +var TOP_KEY_UP = unsafeCastStringToDOMTopLevelType('keyup'); +var TOP_LOAD = unsafeCastStringToDOMTopLevelType('load'); +var TOP_LOAD_START = unsafeCastStringToDOMTopLevelType('loadstart'); +var TOP_LOADED_DATA = unsafeCastStringToDOMTopLevelType('loadeddata'); +var TOP_LOADED_METADATA = unsafeCastStringToDOMTopLevelType('loadedmetadata'); +var TOP_LOST_POINTER_CAPTURE = unsafeCastStringToDOMTopLevelType('lostpointercapture'); +var TOP_MOUSE_DOWN = unsafeCastStringToDOMTopLevelType('mousedown'); +var TOP_MOUSE_MOVE = unsafeCastStringToDOMTopLevelType('mousemove'); +var TOP_MOUSE_OUT = unsafeCastStringToDOMTopLevelType('mouseout'); +var TOP_MOUSE_OVER = unsafeCastStringToDOMTopLevelType('mouseover'); +var TOP_MOUSE_UP = unsafeCastStringToDOMTopLevelType('mouseup'); +var TOP_PASTE = unsafeCastStringToDOMTopLevelType('paste'); +var TOP_PAUSE = unsafeCastStringToDOMTopLevelType('pause'); +var TOP_PLAY = unsafeCastStringToDOMTopLevelType('play'); +var TOP_PLAYING = unsafeCastStringToDOMTopLevelType('playing'); +var TOP_POINTER_CANCEL = unsafeCastStringToDOMTopLevelType('pointercancel'); +var TOP_POINTER_DOWN = unsafeCastStringToDOMTopLevelType('pointerdown'); + + +var TOP_POINTER_MOVE = unsafeCastStringToDOMTopLevelType('pointermove'); +var TOP_POINTER_OUT = unsafeCastStringToDOMTopLevelType('pointerout'); +var TOP_POINTER_OVER = unsafeCastStringToDOMTopLevelType('pointerover'); +var TOP_POINTER_UP = unsafeCastStringToDOMTopLevelType('pointerup'); +var TOP_PROGRESS = unsafeCastStringToDOMTopLevelType('progress'); +var TOP_RATE_CHANGE = unsafeCastStringToDOMTopLevelType('ratechange'); +var TOP_RESET = unsafeCastStringToDOMTopLevelType('reset'); +var TOP_SCROLL = unsafeCastStringToDOMTopLevelType('scroll'); +var TOP_SEEKED = unsafeCastStringToDOMTopLevelType('seeked'); +var TOP_SEEKING = unsafeCastStringToDOMTopLevelType('seeking'); +var TOP_SELECTION_CHANGE = unsafeCastStringToDOMTopLevelType('selectionchange'); +var TOP_STALLED = unsafeCastStringToDOMTopLevelType('stalled'); +var TOP_SUBMIT = unsafeCastStringToDOMTopLevelType('submit'); +var TOP_SUSPEND = unsafeCastStringToDOMTopLevelType('suspend'); +var TOP_TEXT_INPUT = unsafeCastStringToDOMTopLevelType('textInput'); +var TOP_TIME_UPDATE = unsafeCastStringToDOMTopLevelType('timeupdate'); +var TOP_TOGGLE = unsafeCastStringToDOMTopLevelType('toggle'); +var TOP_TOUCH_CANCEL = unsafeCastStringToDOMTopLevelType('touchcancel'); +var TOP_TOUCH_END = unsafeCastStringToDOMTopLevelType('touchend'); +var TOP_TOUCH_MOVE = unsafeCastStringToDOMTopLevelType('touchmove'); +var TOP_TOUCH_START = unsafeCastStringToDOMTopLevelType('touchstart'); +var TOP_TRANSITION_END = unsafeCastStringToDOMTopLevelType(getVendorPrefixedEventName('transitionend')); +var TOP_VOLUME_CHANGE = unsafeCastStringToDOMTopLevelType('volumechange'); +var TOP_WAITING = unsafeCastStringToDOMTopLevelType('waiting'); +var TOP_WHEEL = unsafeCastStringToDOMTopLevelType('wheel'); + +// List of events that need to be individually attached to media elements. +// Note that events in this list will *not* be listened to at the top level +// unless they're explicitly whitelisted in `ReactBrowserEventEmitter.listenTo`. +var mediaEventTypes = [TOP_ABORT, TOP_CAN_PLAY, TOP_CAN_PLAY_THROUGH, TOP_DURATION_CHANGE, TOP_EMPTIED, TOP_ENCRYPTED, TOP_ENDED, TOP_ERROR, TOP_LOADED_DATA, TOP_LOADED_METADATA, TOP_LOAD_START, TOP_PAUSE, TOP_PLAY, TOP_PLAYING, TOP_PROGRESS, TOP_RATE_CHANGE, TOP_SEEKED, TOP_SEEKING, TOP_STALLED, TOP_SUSPEND, TOP_TIME_UPDATE, TOP_VOLUME_CHANGE, TOP_WAITING]; + +function getRawEventName(topLevelType) { + return unsafeCastDOMTopLevelTypeToString(topLevelType); +} - function requiredContext(c) { - !(c !== NO_CONTEXT) ? invariant(false, 'Expected host context to exist. This error is likely caused by a bug in React. Please file an issue.') : void 0; - return c; - } +/** + * These variables store information about text content of a target node, + * allowing comparison of content before and after a given event. + * + * Identify the node where selection currently begins, then observe + * both its text content and its current position in the DOM. Since the + * browser may natively replace the target node during composition, we can + * use its position to find its replacement. + * + * + */ - function getRootHostContainer() { - var rootInstance = requiredContext(rootInstanceStackCursor.current); - return rootInstance; - } +var root = null; +var startText = null; +var fallbackText = null; - function pushHostContainer(fiber, nextRootInstance) { - // Push current root instance onto the stack; - // This allows us to reset root when portals are popped. - push(rootInstanceStackCursor, nextRootInstance, fiber); +function initialize(nativeEventTarget) { + root = nativeEventTarget; + startText = getText(); + return true; +} - var nextRootContext = getRootHostContext(nextRootInstance); +function reset() { + root = null; + startText = null; + fallbackText = null; +} - // Track the context and the Fiber that provided it. - // This enables us to pop only Fibers that provide unique contexts. - push(contextFiberStackCursor, fiber, fiber); - push(contextStackCursor, nextRootContext, fiber); +function getData() { + if (fallbackText) { + return fallbackText; } - function popHostContainer(fiber) { - pop(contextStackCursor, fiber); - pop(contextFiberStackCursor, fiber); - pop(rootInstanceStackCursor, fiber); - } + var start = void 0; + var startValue = startText; + var startLength = startValue.length; + var end = void 0; + var endValue = getText(); + var endLength = endValue.length; - function getHostContext() { - var context = requiredContext(contextStackCursor.current); - return context; + for (start = 0; start < startLength; start++) { + if (startValue[start] !== endValue[start]) { + break; + } } - function pushHostContext(fiber) { - var rootInstance = requiredContext(rootInstanceStackCursor.current); - var context = requiredContext(contextStackCursor.current); - var nextContext = getChildHostContext(context, fiber.type, rootInstance); - - // Don't push this Fiber's context unless it's unique. - if (context === nextContext) { - return; + var minEnd = startLength - start; + for (end = 1; end <= minEnd; end++) { + if (startValue[startLength - end] !== endValue[endLength - end]) { + break; } - - // Track the context and the Fiber that provided it. - // This enables us to pop only Fibers that provide unique contexts. - push(contextFiberStackCursor, fiber, fiber); - push(contextStackCursor, nextContext, fiber); } - function popHostContext(fiber) { - // Do not pop unless this Fiber provided the current context. - // pushHostContext() only pushes Fibers that provide unique contexts. - if (contextFiberStackCursor.current !== fiber) { - return; - } + var sliceTail = end > 1 ? 1 - end : undefined; + fallbackText = endValue.slice(start, sliceTail); + return fallbackText; +} - pop(contextStackCursor, fiber); - pop(contextFiberStackCursor, fiber); +function getText() { + if ('value' in root) { + return root.value; } + return root.textContent; +} - function resetHostContainer() { - contextStackCursor.current = NO_CONTEXT; - rootInstanceStackCursor.current = NO_CONTEXT; - } +/* eslint valid-typeof: 0 */ - return { - getHostContext: getHostContext, - getRootHostContainer: getRootHostContainer, - popHostContainer: popHostContainer, - popHostContext: popHostContext, - pushHostContainer: pushHostContainer, - pushHostContext: pushHostContext, - resetHostContainer: resetHostContainer - }; +var EVENT_POOL_SIZE = 10; + +/** + * @interface Event + * @see http://www.w3.org/TR/DOM-Level-3-Events/ + */ +var EventInterface = { + type: null, + target: null, + // currentTarget is set when dispatching; no use in copying it here + currentTarget: function () { + return null; + }, + eventPhase: null, + bubbles: null, + cancelable: null, + timeStamp: function (event) { + return event.timeStamp || Date.now(); + }, + defaultPrevented: null, + isTrusted: null }; -var ReactFiberHydrationContext = function (config) { - var shouldSetTextContent = config.shouldSetTextContent, - hydration = config.hydration; +function functionThatReturnsTrue() { + return true; +} - // If this doesn't have hydration mode. +function functionThatReturnsFalse() { + return false; +} - if (!hydration) { - return { - enterHydrationState: function () { - return false; - }, - resetHydrationState: function () {}, - tryToClaimNextHydratableInstance: function () {}, - prepareToHydrateHostInstance: function () { - invariant(false, 'Expected prepareToHydrateHostInstance() to never be called. This error is likely caused by a bug in React. Please file an issue.'); - }, - prepareToHydrateHostTextInstance: function () { - invariant(false, 'Expected prepareToHydrateHostTextInstance() to never be called. This error is likely caused by a bug in React. Please file an issue.'); - }, - popHydrationState: function (fiber) { - return false; - } - }; +/** + * Synthetic events are dispatched by event plugins, typically in response to a + * top-level event delegation handler. + * + * These systems should generally use pooling to reduce the frequency of garbage + * collection. The system should check `isPersistent` to determine whether the + * event should be released into the pool after being dispatched. Users that + * need a persisted event should invoke `persist`. + * + * Synthetic events (and subclasses) implement the DOM Level 3 Events API by + * normalizing browser quirks. Subclasses do not necessarily have to implement a + * DOM interface; custom application-specific events can also subclass this. + * + * @param {object} dispatchConfig Configuration used to dispatch this event. + * @param {*} targetInst Marker identifying the event target. + * @param {object} nativeEvent Native browser event. + * @param {DOMEventTarget} nativeEventTarget Target node. + */ +function SyntheticEvent(dispatchConfig, targetInst, nativeEvent, nativeEventTarget) { + { + // these have a getter/setter for warnings + delete this.nativeEvent; + delete this.preventDefault; + delete this.stopPropagation; + delete this.isDefaultPrevented; + delete this.isPropagationStopped; } - var canHydrateInstance = hydration.canHydrateInstance, - canHydrateTextInstance = hydration.canHydrateTextInstance, - getNextHydratableSibling = hydration.getNextHydratableSibling, - getFirstHydratableChild = hydration.getFirstHydratableChild, - hydrateInstance = hydration.hydrateInstance, - hydrateTextInstance = hydration.hydrateTextInstance, - didNotMatchHydratedContainerTextInstance = hydration.didNotMatchHydratedContainerTextInstance, - didNotMatchHydratedTextInstance = hydration.didNotMatchHydratedTextInstance, - didNotHydrateContainerInstance = hydration.didNotHydrateContainerInstance, - didNotHydrateInstance = hydration.didNotHydrateInstance, - didNotFindHydratableContainerInstance = hydration.didNotFindHydratableContainerInstance, - didNotFindHydratableContainerTextInstance = hydration.didNotFindHydratableContainerTextInstance, - didNotFindHydratableInstance = hydration.didNotFindHydratableInstance, - didNotFindHydratableTextInstance = hydration.didNotFindHydratableTextInstance; - - // The deepest Fiber on the stack involved in a hydration context. - // This may have been an insertion or a hydration. - - var hydrationParentFiber = null; - var nextHydratableInstance = null; - var isHydrating = false; - - function enterHydrationState(fiber) { - var parentInstance = fiber.stateNode.containerInfo; - nextHydratableInstance = getFirstHydratableChild(parentInstance); - hydrationParentFiber = fiber; - isHydrating = true; - return true; - } + this.dispatchConfig = dispatchConfig; + this._targetInst = targetInst; + this.nativeEvent = nativeEvent; - function deleteHydratableInstance(returnFiber, instance) { + var Interface = this.constructor.Interface; + for (var propName in Interface) { + if (!Interface.hasOwnProperty(propName)) { + continue; + } { - switch (returnFiber.tag) { - case HostRoot: - didNotHydrateContainerInstance(returnFiber.stateNode.containerInfo, instance); - break; - case HostComponent: - didNotHydrateInstance(returnFiber.type, returnFiber.memoizedProps, returnFiber.stateNode, instance); - break; - } + delete this[propName]; // this has a getter/setter for warnings } - - var childToDelete = createFiberFromHostInstanceForDeletion(); - childToDelete.stateNode = instance; - childToDelete['return'] = returnFiber; - childToDelete.effectTag = Deletion; - - // This might seem like it belongs on progressedFirstDeletion. However, - // these children are not part of the reconciliation list of children. - // Even if we abort and rereconcile the children, that will try to hydrate - // again and the nodes are still in the host tree so these will be - // recreated. - if (returnFiber.lastEffect !== null) { - returnFiber.lastEffect.nextEffect = childToDelete; - returnFiber.lastEffect = childToDelete; + var normalize = Interface[propName]; + if (normalize) { + this[propName] = normalize(nativeEvent); } else { - returnFiber.firstEffect = returnFiber.lastEffect = childToDelete; - } - } - - function insertNonHydratedInstance(returnFiber, fiber) { - fiber.effectTag |= Placement; - { - switch (returnFiber.tag) { - case HostRoot: - { - var parentContainer = returnFiber.stateNode.containerInfo; - switch (fiber.tag) { - case HostComponent: - var type = fiber.type; - var props = fiber.pendingProps; - didNotFindHydratableContainerInstance(parentContainer, type, props); - break; - case HostText: - var text = fiber.pendingProps; - didNotFindHydratableContainerTextInstance(parentContainer, text); - break; - } - break; - } - case HostComponent: - { - var parentType = returnFiber.type; - var parentProps = returnFiber.memoizedProps; - var parentInstance = returnFiber.stateNode; - switch (fiber.tag) { - case HostComponent: - var _type = fiber.type; - var _props = fiber.pendingProps; - didNotFindHydratableInstance(parentType, parentProps, parentInstance, _type, _props); - break; - case HostText: - var _text = fiber.pendingProps; - didNotFindHydratableTextInstance(parentType, parentProps, parentInstance, _text); - break; - } - break; - } - default: - return; + if (propName === 'target') { + this.target = nativeEventTarget; + } else { + this[propName] = nativeEvent[propName]; } } } - function tryHydrate(fiber, nextInstance) { - switch (fiber.tag) { - case HostComponent: - { - var type = fiber.type; - var props = fiber.pendingProps; - var instance = canHydrateInstance(nextInstance, type, props); - if (instance !== null) { - fiber.stateNode = instance; - return true; - } - return false; - } - case HostText: - { - var text = fiber.pendingProps; - var textInstance = canHydrateTextInstance(nextInstance, text); - if (textInstance !== null) { - fiber.stateNode = textInstance; - return true; - } - return false; - } - default: - return false; - } + var defaultPrevented = nativeEvent.defaultPrevented != null ? nativeEvent.defaultPrevented : nativeEvent.returnValue === false; + if (defaultPrevented) { + this.isDefaultPrevented = functionThatReturnsTrue; + } else { + this.isDefaultPrevented = functionThatReturnsFalse; } + this.isPropagationStopped = functionThatReturnsFalse; + return this; +} - function tryToClaimNextHydratableInstance(fiber) { - if (!isHydrating) { - return; - } - var nextInstance = nextHydratableInstance; - if (!nextInstance) { - // Nothing to hydrate. Make it an insertion. - insertNonHydratedInstance(hydrationParentFiber, fiber); - isHydrating = false; - hydrationParentFiber = fiber; +_assign(SyntheticEvent.prototype, { + preventDefault: function () { + this.defaultPrevented = true; + var event = this.nativeEvent; + if (!event) { return; } - if (!tryHydrate(fiber, nextInstance)) { - // If we can't hydrate this instance let's try the next one. - // We use this as a heuristic. It's based on intuition and not data so it - // might be flawed or unnecessary. - nextInstance = getNextHydratableSibling(nextInstance); - if (!nextInstance || !tryHydrate(fiber, nextInstance)) { - // Nothing to hydrate. Make it an insertion. - insertNonHydratedInstance(hydrationParentFiber, fiber); - isHydrating = false; - hydrationParentFiber = fiber; - return; - } - // We matched the next one, we'll now assume that the first one was - // superfluous and we'll delete it. Since we can't eagerly delete it - // we'll have to schedule a deletion. To do that, this node needs a dummy - // fiber associated with it. - deleteHydratableInstance(hydrationParentFiber, nextHydratableInstance); + + if (event.preventDefault) { + event.preventDefault(); + } else if (typeof event.returnValue !== 'unknown') { + event.returnValue = false; } - hydrationParentFiber = fiber; - nextHydratableInstance = getFirstHydratableChild(nextInstance); - } + this.isDefaultPrevented = functionThatReturnsTrue; + }, - function prepareToHydrateHostInstance(fiber, rootContainerInstance, hostContext) { - var instance = fiber.stateNode; - var updatePayload = hydrateInstance(instance, fiber.type, fiber.memoizedProps, rootContainerInstance, hostContext, fiber); - // TODO: Type this specific to this type of component. - fiber.updateQueue = updatePayload; - // If the update payload indicates that there is a change or if there - // is a new ref we mark this as an update. - if (updatePayload !== null) { - return true; + stopPropagation: function () { + var event = this.nativeEvent; + if (!event) { + return; } - return false; - } - function prepareToHydrateHostTextInstance(fiber) { - var textInstance = fiber.stateNode; - var textContent = fiber.memoizedProps; - var shouldUpdate = hydrateTextInstance(textInstance, textContent, fiber); - { - if (shouldUpdate) { - // We assume that prepareToHydrateHostTextInstance is called in a context where the - // hydration parent is the parent host component of this host text. - var returnFiber = hydrationParentFiber; - if (returnFiber !== null) { - switch (returnFiber.tag) { - case HostRoot: - { - var parentContainer = returnFiber.stateNode.containerInfo; - didNotMatchHydratedContainerTextInstance(parentContainer, textInstance, textContent); - break; - } - case HostComponent: - { - var parentType = returnFiber.type; - var parentProps = returnFiber.memoizedProps; - var parentInstance = returnFiber.stateNode; - didNotMatchHydratedTextInstance(parentType, parentProps, parentInstance, textInstance, textContent); - break; - } - } - } - } + if (event.stopPropagation) { + event.stopPropagation(); + } else if (typeof event.cancelBubble !== 'unknown') { + // The ChangeEventPlugin registers a "propertychange" event for + // IE. This event does not support bubbling or cancelling, and + // any references to cancelBubble throw "Member not found". A + // typeof check of "unknown" circumvents this issue (and is also + // IE specific). + event.cancelBubble = true; } - return shouldUpdate; - } - function popToNextHostParent(fiber) { - var parent = fiber['return']; - while (parent !== null && parent.tag !== HostComponent && parent.tag !== HostRoot) { - parent = parent['return']; - } - hydrationParentFiber = parent; - } + this.isPropagationStopped = functionThatReturnsTrue; + }, - function popHydrationState(fiber) { - if (fiber !== hydrationParentFiber) { - // We're deeper than the current hydration context, inside an inserted - // tree. - return false; - } - if (!isHydrating) { - // If we're not currently hydrating but we're in a hydration context, then - // we were an insertion and now need to pop up reenter hydration of our - // siblings. - popToNextHostParent(fiber); - isHydrating = true; - return false; - } + /** + * We release all dispatched `SyntheticEvent`s after each event loop, adding + * them back into the pool. This allows a way to hold onto a reference that + * won't be added back into the pool. + */ + persist: function () { + this.isPersistent = functionThatReturnsTrue; + }, - var type = fiber.type; + /** + * Checks if this event should be released back into the pool. + * + * @return {boolean} True if this should not be released, false otherwise. + */ + isPersistent: functionThatReturnsFalse, - // If we have any remaining hydratable nodes, we need to delete them now. - // We only do this deeper than head and body since they tend to have random - // other nodes in them. We also ignore components with pure text content in - // side of them. - // TODO: Better heuristic. - if (fiber.tag !== HostComponent || type !== 'head' && type !== 'body' && !shouldSetTextContent(type, fiber.memoizedProps)) { - var nextInstance = nextHydratableInstance; - while (nextInstance) { - deleteHydratableInstance(fiber, nextInstance); - nextInstance = getNextHydratableSibling(nextInstance); + /** + * `PooledClass` looks for `destructor` on each instance it releases. + */ + destructor: function () { + var Interface = this.constructor.Interface; + for (var propName in Interface) { + { + Object.defineProperty(this, propName, getPooledWarningPropertyDefinition(propName, Interface[propName])); } } - - popToNextHostParent(fiber); - nextHydratableInstance = hydrationParentFiber ? getNextHydratableSibling(fiber.stateNode) : null; - return true; + this.dispatchConfig = null; + this._targetInst = null; + this.nativeEvent = null; + this.isDefaultPrevented = functionThatReturnsFalse; + this.isPropagationStopped = functionThatReturnsFalse; + this._dispatchListeners = null; + this._dispatchInstances = null; + { + Object.defineProperty(this, 'nativeEvent', getPooledWarningPropertyDefinition('nativeEvent', null)); + Object.defineProperty(this, 'isDefaultPrevented', getPooledWarningPropertyDefinition('isDefaultPrevented', functionThatReturnsFalse)); + Object.defineProperty(this, 'isPropagationStopped', getPooledWarningPropertyDefinition('isPropagationStopped', functionThatReturnsFalse)); + Object.defineProperty(this, 'preventDefault', getPooledWarningPropertyDefinition('preventDefault', function () {})); + Object.defineProperty(this, 'stopPropagation', getPooledWarningPropertyDefinition('stopPropagation', function () {})); + } } +}); - function resetHydrationState() { - hydrationParentFiber = null; - nextHydratableInstance = null; - isHydrating = false; - } +SyntheticEvent.Interface = EventInterface; - return { - enterHydrationState: enterHydrationState, - resetHydrationState: resetHydrationState, - tryToClaimNextHydratableInstance: tryToClaimNextHydratableInstance, - prepareToHydrateHostInstance: prepareToHydrateHostInstance, - prepareToHydrateHostTextInstance: prepareToHydrateHostTextInstance, - popHydrationState: popHydrationState - }; -}; +/** + * Helper to reduce boilerplate when creating subclasses. + */ +SyntheticEvent.extend = function (Interface) { + var Super = this; -// This lets us hook into Fiber to debug what it's doing. -// See https://github.com/facebook/react/pull/8033. -// This is not part of the public API, not even for React DevTools. -// You may only inject a debugTool if you work on React Fiber itself. -var ReactFiberInstrumentation = { - debugTool: null -}; + var E = function () {}; + E.prototype = Super.prototype; + var prototype = new E(); -var ReactFiberInstrumentation_1 = ReactFiberInstrumentation; + function Class() { + return Super.apply(this, arguments); + } + _assign(prototype, Class.prototype); + Class.prototype = prototype; + Class.prototype.constructor = Class; -var defaultShowDialog = function (capturedError) { - return true; + Class.Interface = _assign({}, Super.Interface, Interface); + Class.extend = Super.extend; + addEventPoolingTo(Class); + + return Class; }; -var showDialog = defaultShowDialog; +addEventPoolingTo(SyntheticEvent); -function logCapturedError(capturedError) { - var logError = showDialog(capturedError); +/** + * Helper to nullify syntheticEvent instance properties when destructing + * + * @param {String} propName + * @param {?object} getVal + * @return {object} defineProperty object + */ +function getPooledWarningPropertyDefinition(propName, getVal) { + var isFunction = typeof getVal === 'function'; + return { + configurable: true, + set: set, + get: get + }; - // Allow injected showDialog() to prevent default console.error logging. - // This enables renderers like ReactNative to better manage redbox behavior. - if (logError === false) { - return; + function set(val) { + var action = isFunction ? 'setting the method' : 'setting the property'; + warn(action, 'This is effectively a no-op'); + return val; } - var error = capturedError.error; - var suppressLogging = error && error.suppressReactErrorLogging; - if (suppressLogging) { - return; + function get() { + var action = isFunction ? 'accessing the method' : 'accessing the property'; + var result = isFunction ? 'This is a no-op function' : 'This is set to null'; + warn(action, result); + return getVal; } - { - var componentName = capturedError.componentName, - componentStack = capturedError.componentStack, - errorBoundaryName = capturedError.errorBoundaryName, - errorBoundaryFound = capturedError.errorBoundaryFound, - willRetry = capturedError.willRetry; - - - var componentNameMessage = componentName ? 'The above error occurred in the <' + componentName + '> component:' : 'The above error occurred in one of your React components:'; + function warn(action, result) { + var warningCondition = false; + !warningCondition ? warningWithoutStack$1(false, "This synthetic event is reused for performance reasons. If you're seeing this, " + "you're %s `%s` on a released/nullified synthetic event. %s. " + 'If you must keep the original synthetic event around, use event.persist(). ' + 'See https://fb.me/react-event-pooling for more information.', action, propName, result) : void 0; + } +} - var errorBoundaryMessage = void 0; - // errorBoundaryFound check is sufficient; errorBoundaryName check is to satisfy Flow. - if (errorBoundaryFound && errorBoundaryName) { - if (willRetry) { - errorBoundaryMessage = 'React will try to recreate this component tree from scratch ' + ('using the error boundary you provided, ' + errorBoundaryName + '.'); - } else { - errorBoundaryMessage = 'This error was initially handled by the error boundary ' + errorBoundaryName + '.\n' + 'Recreating the tree from scratch failed so React will unmount the tree.'; - } - } else { - errorBoundaryMessage = 'Consider adding an error boundary to your tree to customize error handling behavior.\n' + 'Visit https://fb.me/react-error-boundaries to learn more about error boundaries.'; - } - var combinedMessage = '' + componentNameMessage + componentStack + '\n\n' + ('' + errorBoundaryMessage); +function getPooledEvent(dispatchConfig, targetInst, nativeEvent, nativeInst) { + var EventConstructor = this; + if (EventConstructor.eventPool.length) { + var instance = EventConstructor.eventPool.pop(); + EventConstructor.call(instance, dispatchConfig, targetInst, nativeEvent, nativeInst); + return instance; + } + return new EventConstructor(dispatchConfig, targetInst, nativeEvent, nativeInst); +} - // In development, we provide our own message with just the component stack. - // We don't include the original error message and JS stack because the browser - // has already printed it. Even if the application swallows the error, it is still - // displayed by the browser thanks to the DEV-only fake event trick in ReactErrorUtils. - console.error(combinedMessage); +function releasePooledEvent(event) { + var EventConstructor = this; + !(event instanceof EventConstructor) ? invariant(false, 'Trying to release an event instance into a pool of a different type.') : void 0; + event.destructor(); + if (EventConstructor.eventPool.length < EVENT_POOL_SIZE) { + EventConstructor.eventPool.push(event); } } -var invokeGuardedCallback$1 = ReactErrorUtils.invokeGuardedCallback; -var hasCaughtError = ReactErrorUtils.hasCaughtError; -var clearCaughtError = ReactErrorUtils.clearCaughtError; +function addEventPoolingTo(EventConstructor) { + EventConstructor.eventPool = []; + EventConstructor.getPooled = getPooledEvent; + EventConstructor.release = releasePooledEvent; +} +/** + * @interface Event + * @see http://www.w3.org/TR/DOM-Level-3-Events/#events-compositionevents + */ +var SyntheticCompositionEvent = SyntheticEvent.extend({ + data: null +}); -{ - var didWarnAboutStateTransition = false; - var didWarnSetStateChildContext = false; - var didWarnStateUpdateForUnmountedComponent = {}; +/** + * @interface Event + * @see http://www.w3.org/TR/2013/WD-DOM-Level-3-Events-20131105 + * /#events-inputevents + */ +var SyntheticInputEvent = SyntheticEvent.extend({ + data: null +}); - var warnAboutUpdateOnUnmounted = function (fiber) { - var componentName = getComponentName(fiber) || 'ReactClass'; - if (didWarnStateUpdateForUnmountedComponent[componentName]) { - return; - } - warning(false, 'Can only update a mounted or mounting ' + 'component. This usually means you called setState, replaceState, ' + 'or forceUpdate on an unmounted component. This is a no-op.\n\nPlease ' + 'check the code for the %s component.', componentName); - didWarnStateUpdateForUnmountedComponent[componentName] = true; - }; +var END_KEYCODES = [9, 13, 27, 32]; // Tab, Return, Esc, Space +var START_KEYCODE = 229; - var warnAboutInvalidUpdates = function (instance) { - switch (ReactDebugCurrentFiber.phase) { - case 'getChildContext': - if (didWarnSetStateChildContext) { - return; - } - warning(false, 'setState(...): Cannot call setState() inside getChildContext()'); - didWarnSetStateChildContext = true; - break; - case 'render': - if (didWarnAboutStateTransition) { - return; - } - warning(false, 'Cannot update during an existing state transition (such as within ' + "`render` or another component's constructor). Render methods should " + 'be a pure function of props and state; constructor side-effects are ' + 'an anti-pattern, but can be moved to `componentWillMount`.'); - didWarnAboutStateTransition = true; - break; - } - }; +var canUseCompositionEvent = canUseDOM && 'CompositionEvent' in window; + +var documentMode = null; +if (canUseDOM && 'documentMode' in document) { + documentMode = document.documentMode; } -var ReactFiberScheduler = function (config) { - var hostContext = ReactFiberHostContext(config); - var hydrationContext = ReactFiberHydrationContext(config); - var popHostContainer = hostContext.popHostContainer, - popHostContext = hostContext.popHostContext, - resetHostContainer = hostContext.resetHostContainer; - - var _ReactFiberBeginWork = ReactFiberBeginWork(config, hostContext, hydrationContext, scheduleWork, computeExpirationForFiber), - beginWork = _ReactFiberBeginWork.beginWork, - beginFailedWork = _ReactFiberBeginWork.beginFailedWork; - - var _ReactFiberCompleteWo = ReactFiberCompleteWork(config, hostContext, hydrationContext), - completeWork = _ReactFiberCompleteWo.completeWork; - - var _ReactFiberCommitWork = ReactFiberCommitWork(config, captureError), - commitResetTextContent = _ReactFiberCommitWork.commitResetTextContent, - commitPlacement = _ReactFiberCommitWork.commitPlacement, - commitDeletion = _ReactFiberCommitWork.commitDeletion, - commitWork = _ReactFiberCommitWork.commitWork, - commitLifeCycles = _ReactFiberCommitWork.commitLifeCycles, - commitAttachRef = _ReactFiberCommitWork.commitAttachRef, - commitDetachRef = _ReactFiberCommitWork.commitDetachRef; - - var now = config.now, - scheduleDeferredCallback = config.scheduleDeferredCallback, - cancelDeferredCallback = config.cancelDeferredCallback, - useSyncScheduling = config.useSyncScheduling, - prepareForCommit = config.prepareForCommit, - resetAfterCommit = config.resetAfterCommit; - - // Represents the current time in ms. - - var startTime = now(); - var mostRecentCurrentTime = msToExpirationTime(0); - - // Represents the expiration time that incoming updates should use. (If this - // is NoWork, use the default strategy: async updates in async mode, sync - // updates in sync mode.) - var expirationContext = NoWork; - - var isWorking = false; - - // The next work in progress fiber that we're currently working on. - var nextUnitOfWork = null; - var nextRoot = null; - // The time at which we're currently rendering work. - var nextRenderExpirationTime = NoWork; - - // The next fiber with an effect that we're currently committing. - var nextEffect = null; - - // Keep track of which fibers have captured an error that need to be handled. - // Work is removed from this collection after componentDidCatch is called. - var capturedErrors = null; - // Keep track of which fibers have failed during the current batch of work. - // This is a different set than capturedErrors, because it is not reset until - // the end of the batch. This is needed to propagate errors correctly if a - // subtree fails more than once. - var failedBoundaries = null; - // Error boundaries that captured an error during the current commit. - var commitPhaseBoundaries = null; - var firstUncaughtError = null; - var didFatal = false; +// Webkit offers a very useful `textInput` event that can be used to +// directly represent `beforeInput`. The IE `textinput` event is not as +// useful, so we don't use it. +var canUseTextInputEvent = canUseDOM && 'TextEvent' in window && !documentMode; - var isCommitting = false; - var isUnmounting = false; +// In IE9+, we have access to composition events, but the data supplied +// by the native compositionend event may be incorrect. Japanese ideographic +// spaces, for instance (\u3000) are not recorded correctly. +var useFallbackCompositionData = canUseDOM && (!canUseCompositionEvent || documentMode && documentMode > 8 && documentMode <= 11); - // Used for performance tracking. - var interruptedBy = null; +var SPACEBAR_CODE = 32; +var SPACEBAR_CHAR = String.fromCharCode(SPACEBAR_CODE); - function resetContextStack() { - // Reset the stack - reset$1(); - // Reset the cursors - resetContext(); - resetHostContainer(); +// Events and their corresponding property names. +var eventTypes = { + beforeInput: { + phasedRegistrationNames: { + bubbled: 'onBeforeInput', + captured: 'onBeforeInputCapture' + }, + dependencies: [TOP_COMPOSITION_END, TOP_KEY_PRESS, TOP_TEXT_INPUT, TOP_PASTE] + }, + compositionEnd: { + phasedRegistrationNames: { + bubbled: 'onCompositionEnd', + captured: 'onCompositionEndCapture' + }, + dependencies: [TOP_BLUR, TOP_COMPOSITION_END, TOP_KEY_DOWN, TOP_KEY_PRESS, TOP_KEY_UP, TOP_MOUSE_DOWN] + }, + compositionStart: { + phasedRegistrationNames: { + bubbled: 'onCompositionStart', + captured: 'onCompositionStartCapture' + }, + dependencies: [TOP_BLUR, TOP_COMPOSITION_START, TOP_KEY_DOWN, TOP_KEY_PRESS, TOP_KEY_UP, TOP_MOUSE_DOWN] + }, + compositionUpdate: { + phasedRegistrationNames: { + bubbled: 'onCompositionUpdate', + captured: 'onCompositionUpdateCapture' + }, + dependencies: [TOP_BLUR, TOP_COMPOSITION_UPDATE, TOP_KEY_DOWN, TOP_KEY_PRESS, TOP_KEY_UP, TOP_MOUSE_DOWN] } +}; - function commitAllHostEffects() { - while (nextEffect !== null) { - { - ReactDebugCurrentFiber.setCurrentFiber(nextEffect); - } - recordEffect(); +// Track whether we've ever handled a keypress on the space key. +var hasSpaceKeypress = false; - var effectTag = nextEffect.effectTag; - if (effectTag & ContentReset) { - commitResetTextContent(nextEffect); - } +/** + * Return whether a native keypress event is assumed to be a command. + * This is required because Firefox fires `keypress` events for key commands + * (cut, copy, select-all, etc.) even though no character is inserted. + */ +function isKeypressCommand(nativeEvent) { + return (nativeEvent.ctrlKey || nativeEvent.altKey || nativeEvent.metaKey) && + // ctrlKey && altKey is equivalent to AltGr, and is not a command. + !(nativeEvent.ctrlKey && nativeEvent.altKey); +} - if (effectTag & Ref) { - var current = nextEffect.alternate; - if (current !== null) { - commitDetachRef(current); - } - } +/** + * Translate native top level events into event types. + * + * @param {string} topLevelType + * @return {object} + */ +function getCompositionEventType(topLevelType) { + switch (topLevelType) { + case TOP_COMPOSITION_START: + return eventTypes.compositionStart; + case TOP_COMPOSITION_END: + return eventTypes.compositionEnd; + case TOP_COMPOSITION_UPDATE: + return eventTypes.compositionUpdate; + } +} - // The following switch statement is only concerned about placement, - // updates, and deletions. To avoid needing to add a case for every - // possible bitmap value, we remove the secondary effects from the - // effect tag and switch on that value. - var primaryEffectTag = effectTag & ~(Callback | Err | ContentReset | Ref | PerformedWork); - switch (primaryEffectTag) { - case Placement: - { - commitPlacement(nextEffect); - // Clear the "placement" from effect tag so that we know that this is inserted, before - // any life-cycles like componentDidMount gets called. - // TODO: findDOMNode doesn't rely on this any more but isMounted - // does and isMounted is deprecated anyway so we should be able - // to kill this. - nextEffect.effectTag &= ~Placement; - break; - } - case PlacementAndUpdate: - { - // Placement - commitPlacement(nextEffect); - // Clear the "placement" from effect tag so that we know that this is inserted, before - // any life-cycles like componentDidMount gets called. - nextEffect.effectTag &= ~Placement; - - // Update - var _current = nextEffect.alternate; - commitWork(_current, nextEffect); - break; - } - case Update: - { - var _current2 = nextEffect.alternate; - commitWork(_current2, nextEffect); - break; - } - case Deletion: - { - isUnmounting = true; - commitDeletion(nextEffect); - isUnmounting = false; - break; - } - } - nextEffect = nextEffect.nextEffect; - } +/** + * Does our fallback best-guess model think this event signifies that + * composition has begun? + * + * @param {string} topLevelType + * @param {object} nativeEvent + * @return {boolean} + */ +function isFallbackCompositionStart(topLevelType, nativeEvent) { + return topLevelType === TOP_KEY_DOWN && nativeEvent.keyCode === START_KEYCODE; +} - { - ReactDebugCurrentFiber.resetCurrentFiber(); - } +/** + * Does our fallback mode think that this event is the end of composition? + * + * @param {string} topLevelType + * @param {object} nativeEvent + * @return {boolean} + */ +function isFallbackCompositionEnd(topLevelType, nativeEvent) { + switch (topLevelType) { + case TOP_KEY_UP: + // Command keys insert or clear IME input. + return END_KEYCODES.indexOf(nativeEvent.keyCode) !== -1; + case TOP_KEY_DOWN: + // Expect IME keyCode on each keydown. If we get any other + // code we must have exited earlier. + return nativeEvent.keyCode !== START_KEYCODE; + case TOP_KEY_PRESS: + case TOP_MOUSE_DOWN: + case TOP_BLUR: + // Events are not possible without cancelling IME. + return true; + default: + return false; } +} - function commitAllLifeCycles() { - while (nextEffect !== null) { - var effectTag = nextEffect.effectTag; +/** + * Google Input Tools provides composition data via a CustomEvent, + * with the `data` property populated in the `detail` object. If this + * is available on the event object, use it. If not, this is a plain + * composition event and we have nothing special to extract. + * + * @param {object} nativeEvent + * @return {?string} + */ +function getDataFromCustomEvent(nativeEvent) { + var detail = nativeEvent.detail; + if (typeof detail === 'object' && 'data' in detail) { + return detail.data; + } + return null; +} - if (effectTag & (Update | Callback)) { - recordEffect(); - var current = nextEffect.alternate; - commitLifeCycles(current, nextEffect); - } +/** + * Check if a composition event was triggered by Korean IME. + * Our fallback mode does not work well with IE's Korean IME, + * so just use native composition events when Korean IME is used. + * Although CompositionEvent.locale property is deprecated, + * it is available in IE, where our fallback mode is enabled. + * + * @param {object} nativeEvent + * @return {boolean} + */ +function isUsingKoreanIME(nativeEvent) { + return nativeEvent.locale === 'ko'; +} - if (effectTag & Ref) { - recordEffect(); - commitAttachRef(nextEffect); - } +// Track the current IME composition status, if any. +var isComposing = false; - if (effectTag & Err) { - recordEffect(); - commitErrorHandling(nextEffect); - } +/** + * @return {?object} A SyntheticCompositionEvent. + */ +function extractCompositionEvent(topLevelType, targetInst, nativeEvent, nativeEventTarget) { + var eventType = void 0; + var fallbackData = void 0; - var next = nextEffect.nextEffect; - // Ensure that we clean these up so that we don't accidentally keep them. - // I'm not actually sure this matters because we can't reset firstEffect - // and lastEffect since they're on every node, not just the effectful - // ones. So we have to clean everything as we reuse nodes anyway. - nextEffect.nextEffect = null; - // Ensure that we reset the effectTag here so that we can rely on effect - // tags to reason about the current life-cycle. - nextEffect = next; + if (canUseCompositionEvent) { + eventType = getCompositionEventType(topLevelType); + } else if (!isComposing) { + if (isFallbackCompositionStart(topLevelType, nativeEvent)) { + eventType = eventTypes.compositionStart; } + } else if (isFallbackCompositionEnd(topLevelType, nativeEvent)) { + eventType = eventTypes.compositionEnd; } - function commitRoot(finishedWork) { - // We keep track of this so that captureError can collect any boundaries - // that capture an error during the commit phase. The reason these aren't - // local to this function is because errors that occur during cWU are - // captured elsewhere, to prevent the unmount from being interrupted. - isWorking = true; - isCommitting = true; - startCommitTimer(); - - var root = finishedWork.stateNode; - !(root.current !== finishedWork) ? invariant(false, 'Cannot commit the same tree as before. This is probably a bug related to the return field. This error is likely caused by a bug in React. Please file an issue.') : void 0; - root.isReadyForCommit = false; - - // Reset this to null before calling lifecycles - ReactCurrentOwner.current = null; - - var firstEffect = void 0; - if (finishedWork.effectTag > PerformedWork) { - // A fiber's effect list consists only of its children, not itself. So if - // the root has an effect, we need to add it to the end of the list. The - // resulting list is the set that would belong to the root's parent, if - // it had one; that is, all the effects in the tree including the root. - if (finishedWork.lastEffect !== null) { - finishedWork.lastEffect.nextEffect = finishedWork; - firstEffect = finishedWork.firstEffect; - } else { - firstEffect = finishedWork; + if (!eventType) { + return null; + } + + if (useFallbackCompositionData && !isUsingKoreanIME(nativeEvent)) { + // The current composition is stored statically and must not be + // overwritten while composition continues. + if (!isComposing && eventType === eventTypes.compositionStart) { + isComposing = initialize(nativeEventTarget); + } else if (eventType === eventTypes.compositionEnd) { + if (isComposing) { + fallbackData = getData(); } - } else { - // There is no effect on the root. - firstEffect = finishedWork.firstEffect; } + } - prepareForCommit(); + var event = SyntheticCompositionEvent.getPooled(eventType, targetInst, nativeEvent, nativeEventTarget); - // Commit all the side-effects within a tree. We'll do this in two passes. - // The first pass performs all the host insertions, updates, deletions and - // ref unmounts. - nextEffect = firstEffect; - startCommitHostEffectsTimer(); - while (nextEffect !== null) { - var didError = false; - var _error = void 0; - { - invokeGuardedCallback$1(null, commitAllHostEffects, null); - if (hasCaughtError()) { - didError = true; - _error = clearCaughtError(); - } - } - if (didError) { - !(nextEffect !== null) ? invariant(false, 'Should have next effect. This error is likely caused by a bug in React. Please file an issue.') : void 0; - captureError(nextEffect, _error); - // Clean-up - if (nextEffect !== null) { - nextEffect = nextEffect.nextEffect; - } - } + if (fallbackData) { + // Inject data generated from fallback path into the synthetic event. + // This matches the property of native CompositionEventInterface. + event.data = fallbackData; + } else { + var customData = getDataFromCustomEvent(nativeEvent); + if (customData !== null) { + event.data = customData; } - stopCommitHostEffectsTimer(); - - resetAfterCommit(); + } - // The work-in-progress tree is now the current tree. This must come after - // the first pass of the commit phase, so that the previous tree is still - // current during componentWillUnmount, but before the second pass, so that - // the finished work is current during componentDidMount/Update. - root.current = finishedWork; + accumulateTwoPhaseDispatches(event); + return event; +} - // In the second pass we'll perform all life-cycles and ref callbacks. - // Life-cycles happen as a separate pass so that all placements, updates, - // and deletions in the entire tree have already been invoked. - // This pass also triggers any renderer-specific initial effects. - nextEffect = firstEffect; - startCommitLifeCyclesTimer(); - while (nextEffect !== null) { - var _didError = false; - var _error2 = void 0; - { - invokeGuardedCallback$1(null, commitAllLifeCycles, null); - if (hasCaughtError()) { - _didError = true; - _error2 = clearCaughtError(); - } - } - if (_didError) { - !(nextEffect !== null) ? invariant(false, 'Should have next effect. This error is likely caused by a bug in React. Please file an issue.') : void 0; - captureError(nextEffect, _error2); - if (nextEffect !== null) { - nextEffect = nextEffect.nextEffect; - } +/** + * @param {TopLevelType} topLevelType Number from `TopLevelType`. + * @param {object} nativeEvent Native browser event. + * @return {?string} The string corresponding to this `beforeInput` event. + */ +function getNativeBeforeInputChars(topLevelType, nativeEvent) { + switch (topLevelType) { + case TOP_COMPOSITION_END: + return getDataFromCustomEvent(nativeEvent); + case TOP_KEY_PRESS: + /** + * If native `textInput` events are available, our goal is to make + * use of them. However, there is a special case: the spacebar key. + * In Webkit, preventing default on a spacebar `textInput` event + * cancels character insertion, but it *also* causes the browser + * to fall back to its default spacebar behavior of scrolling the + * page. + * + * Tracking at: + * https://code.google.com/p/chromium/issues/detail?id=355103 + * + * To avoid this issue, use the keypress event as if no `textInput` + * event is available. + */ + var which = nativeEvent.which; + if (which !== SPACEBAR_CODE) { + return null; } - } - - isCommitting = false; - isWorking = false; - stopCommitLifeCyclesTimer(); - stopCommitTimer(); - if (typeof onCommitRoot === 'function') { - onCommitRoot(finishedWork.stateNode); - } - if (true && ReactFiberInstrumentation_1.debugTool) { - ReactFiberInstrumentation_1.debugTool.onCommitWork(finishedWork); - } - // If we caught any errors during this commit, schedule their boundaries - // to update. - if (commitPhaseBoundaries) { - commitPhaseBoundaries.forEach(scheduleErrorRecovery); - commitPhaseBoundaries = null; - } + hasSpaceKeypress = true; + return SPACEBAR_CHAR; - if (firstUncaughtError !== null) { - var _error3 = firstUncaughtError; - firstUncaughtError = null; - onUncaughtError(_error3); - } + case TOP_TEXT_INPUT: + // Record the characters to be added to the DOM. + var chars = nativeEvent.data; - var remainingTime = root.current.expirationTime; + // If it's a spacebar character, assume that we have already handled + // it at the keypress level and bail immediately. Android Chrome + // doesn't give us keycodes, so we need to ignore it. + if (chars === SPACEBAR_CHAR && hasSpaceKeypress) { + return null; + } - if (remainingTime === NoWork) { - capturedErrors = null; - failedBoundaries = null; - } + return chars; - return remainingTime; + default: + // For other native event types, do nothing. + return null; } +} - function resetExpirationTime(workInProgress, renderTime) { - if (renderTime !== Never && workInProgress.expirationTime === Never) { - // The children of this component are hidden. Don't bubble their - // expiration times. - return; - } - - // Check for pending updates. - var newExpirationTime = getUpdateExpirationTime(workInProgress); - - // TODO: Calls need to visit stateNode - - // Bubble up the earliest expiration time. - var child = workInProgress.child; - while (child !== null) { - if (child.expirationTime !== NoWork && (newExpirationTime === NoWork || newExpirationTime > child.expirationTime)) { - newExpirationTime = child.expirationTime; - } - child = child.sibling; +/** + * For browsers that do not provide the `textInput` event, extract the + * appropriate string to use for SyntheticInputEvent. + * + * @param {number} topLevelType Number from `TopLevelEventTypes`. + * @param {object} nativeEvent Native browser event. + * @return {?string} The fallback string for this `beforeInput` event. + */ +function getFallbackBeforeInputChars(topLevelType, nativeEvent) { + // If we are currently composing (IME) and using a fallback to do so, + // try to extract the composed characters from the fallback object. + // If composition event is available, we extract a string only at + // compositionevent, otherwise extract it at fallback events. + if (isComposing) { + if (topLevelType === TOP_COMPOSITION_END || !canUseCompositionEvent && isFallbackCompositionEnd(topLevelType, nativeEvent)) { + var chars = getData(); + reset(); + isComposing = false; + return chars; } - workInProgress.expirationTime = newExpirationTime; + return null; } - function completeUnitOfWork(workInProgress) { - while (true) { - // The current, flushed, state of this fiber is the alternate. - // Ideally nothing should rely on this, but relying on it here - // means that we don't need an additional field on the work in - // progress. - var current = workInProgress.alternate; - { - ReactDebugCurrentFiber.setCurrentFiber(workInProgress); - } - var next = completeWork(current, workInProgress, nextRenderExpirationTime); - { - ReactDebugCurrentFiber.resetCurrentFiber(); + switch (topLevelType) { + case TOP_PASTE: + // If a paste event occurs after a keypress, throw out the input + // chars. Paste events should not lead to BeforeInput events. + return null; + case TOP_KEY_PRESS: + /** + * As of v27, Firefox may fire keypress events even when no character + * will be inserted. A few possibilities: + * + * - `which` is `0`. Arrow keys, Esc key, etc. + * + * - `which` is the pressed key code, but no char is available. + * Ex: 'AltGr + d` in Polish. There is no modified character for + * this key combination and no character is inserted into the + * document, but FF fires the keypress for char code `100` anyway. + * No `input` event will occur. + * + * - `which` is the pressed key code, but a command combination is + * being used. Ex: `Cmd+C`. No character is inserted, and no + * `input` event will occur. + */ + if (!isKeypressCommand(nativeEvent)) { + // IE fires the `keypress` event when a user types an emoji via + // Touch keyboard of Windows. In such a case, the `char` property + // holds an emoji character like `\uD83D\uDE0A`. Because its length + // is 2, the property `which` does not represent an emoji correctly. + // In such a case, we directly return the `char` property instead of + // using `which`. + if (nativeEvent.char && nativeEvent.char.length > 1) { + return nativeEvent.char; + } else if (nativeEvent.which) { + return String.fromCharCode(nativeEvent.which); + } } + return null; + case TOP_COMPOSITION_END: + return useFallbackCompositionData && !isUsingKoreanIME(nativeEvent) ? null : nativeEvent.data; + default: + return null; + } +} - var returnFiber = workInProgress['return']; - var siblingFiber = workInProgress.sibling; - - resetExpirationTime(workInProgress, nextRenderExpirationTime); - - if (next !== null) { - stopWorkTimer(workInProgress); - if (true && ReactFiberInstrumentation_1.debugTool) { - ReactFiberInstrumentation_1.debugTool.onCompleteWork(workInProgress); - } - // If completing this work spawned new work, do that next. We'll come - // back here again. - return next; - } - - if (returnFiber !== null) { - // Append all the effects of the subtree and this fiber onto the effect - // list of the parent. The completion order of the children affects the - // side-effect order. - if (returnFiber.firstEffect === null) { - returnFiber.firstEffect = workInProgress.firstEffect; - } - if (workInProgress.lastEffect !== null) { - if (returnFiber.lastEffect !== null) { - returnFiber.lastEffect.nextEffect = workInProgress.firstEffect; - } - returnFiber.lastEffect = workInProgress.lastEffect; - } - - // If this fiber had side-effects, we append it AFTER the children's - // side-effects. We can perform certain side-effects earlier if - // needed, by doing multiple passes over the effect list. We don't want - // to schedule our own side-effect on our own list because if end up - // reusing children we'll schedule this effect onto itself since we're - // at the end. - var effectTag = workInProgress.effectTag; - // Skip both NoWork and PerformedWork tags when creating the effect list. - // PerformedWork effect is read by React DevTools but shouldn't be committed. - if (effectTag > PerformedWork) { - if (returnFiber.lastEffect !== null) { - returnFiber.lastEffect.nextEffect = workInProgress; - } else { - returnFiber.firstEffect = workInProgress; - } - returnFiber.lastEffect = workInProgress; - } - } - - stopWorkTimer(workInProgress); - if (true && ReactFiberInstrumentation_1.debugTool) { - ReactFiberInstrumentation_1.debugTool.onCompleteWork(workInProgress); - } +/** + * Extract a SyntheticInputEvent for `beforeInput`, based on either native + * `textInput` or fallback behavior. + * + * @return {?object} A SyntheticInputEvent. + */ +function extractBeforeInputEvent(topLevelType, targetInst, nativeEvent, nativeEventTarget) { + var chars = void 0; - if (siblingFiber !== null) { - // If there is more work to do in this returnFiber, do that next. - return siblingFiber; - } else if (returnFiber !== null) { - // If there's no more work in this returnFiber. Complete the returnFiber. - workInProgress = returnFiber; - continue; - } else { - // We've reached the root. - var root = workInProgress.stateNode; - root.isReadyForCommit = true; - return null; - } - } + if (canUseTextInputEvent) { + chars = getNativeBeforeInputChars(topLevelType, nativeEvent); + } else { + chars = getFallbackBeforeInputChars(topLevelType, nativeEvent); + } - // Without this explicit null return Flow complains of invalid return type - // TODO Remove the above while(true) loop - // eslint-disable-next-line no-unreachable + // If no characters are being inserted, no BeforeInput event should + // be fired. + if (!chars) { return null; } - function performUnitOfWork(workInProgress) { - // The current, flushed, state of this fiber is the alternate. - // Ideally nothing should rely on this, but relying on it here - // means that we don't need an additional field on the work in - // progress. - var current = workInProgress.alternate; - - // See if beginning this work spawns more work. - startWorkTimer(workInProgress); - { - ReactDebugCurrentFiber.setCurrentFiber(workInProgress); - } - - var next = beginWork(current, workInProgress, nextRenderExpirationTime); - { - ReactDebugCurrentFiber.resetCurrentFiber(); - } - if (true && ReactFiberInstrumentation_1.debugTool) { - ReactFiberInstrumentation_1.debugTool.onBeginWork(workInProgress); - } + var event = SyntheticInputEvent.getPooled(eventTypes.beforeInput, targetInst, nativeEvent, nativeEventTarget); - if (next === null) { - // If this doesn't spawn new work, complete the current work. - next = completeUnitOfWork(workInProgress); - } + event.data = chars; + accumulateTwoPhaseDispatches(event); + return event; +} - ReactCurrentOwner.current = null; +/** + * Create an `onBeforeInput` event to match + * http://www.w3.org/TR/2013/WD-DOM-Level-3-Events-20131105/#events-inputevents. + * + * This event plugin is based on the native `textInput` event + * available in Chrome, Safari, Opera, and IE. This event fires after + * `onKeyPress` and `onCompositionEnd`, but before `onInput`. + * + * `beforeInput` is spec'd but not implemented in any browsers, and + * the `input` event does not provide any useful information about what has + * actually been added, contrary to the spec. Thus, `textInput` is the best + * available event to identify the characters that have actually been inserted + * into the target node. + * + * This plugin is also responsible for emitting `composition` events, thus + * allowing us to share composition fallback code for both `beforeInput` and + * `composition` event types. + */ +var BeforeInputEventPlugin = { + eventTypes: eventTypes, - return next; - } + extractEvents: function (topLevelType, targetInst, nativeEvent, nativeEventTarget) { + var composition = extractCompositionEvent(topLevelType, targetInst, nativeEvent, nativeEventTarget); - function performFailedUnitOfWork(workInProgress) { - // The current, flushed, state of this fiber is the alternate. - // Ideally nothing should rely on this, but relying on it here - // means that we don't need an additional field on the work in - // progress. - var current = workInProgress.alternate; + var beforeInput = extractBeforeInputEvent(topLevelType, targetInst, nativeEvent, nativeEventTarget); - // See if beginning this work spawns more work. - startWorkTimer(workInProgress); - { - ReactDebugCurrentFiber.setCurrentFiber(workInProgress); - } - var next = beginFailedWork(current, workInProgress, nextRenderExpirationTime); - { - ReactDebugCurrentFiber.resetCurrentFiber(); - } - if (true && ReactFiberInstrumentation_1.debugTool) { - ReactFiberInstrumentation_1.debugTool.onBeginWork(workInProgress); + if (composition === null) { + return beforeInput; } - if (next === null) { - // If this doesn't spawn new work, complete the current work. - next = completeUnitOfWork(workInProgress); + if (beforeInput === null) { + return composition; } - ReactCurrentOwner.current = null; - - return next; + return [composition, beforeInput]; } +}; - function workLoop(expirationTime) { - if (capturedErrors !== null) { - // If there are unhandled errors, switch to the slow work loop. - // TODO: How to avoid this check in the fast path? Maybe the renderer - // could keep track of which roots have unhandled errors and call a - // forked version of renderRoot. - slowWorkLoopThatChecksForFailedWork(expirationTime); - return; - } - if (nextRenderExpirationTime === NoWork || nextRenderExpirationTime > expirationTime) { - return; - } +// Use to restore controlled state after a change event has fired. - if (nextRenderExpirationTime <= mostRecentCurrentTime) { - // Flush all expired work. - while (nextUnitOfWork !== null) { - nextUnitOfWork = performUnitOfWork(nextUnitOfWork); - } - } else { - // Flush asynchronous work until the deadline runs out of time. - while (nextUnitOfWork !== null && !shouldYield()) { - nextUnitOfWork = performUnitOfWork(nextUnitOfWork); - } - } +var restoreImpl = null; +var restoreTarget = null; +var restoreQueue = null; + +function restoreStateOfTarget(target) { + // We perform this translation at the end of the event loop so that we + // always receive the correct fiber here + var internalInstance = getInstanceFromNode(target); + if (!internalInstance) { + // Unmounted + return; } + !(typeof restoreImpl === 'function') ? invariant(false, 'setRestoreImplementation() needs to be called to handle a target for controlled events. This error is likely caused by a bug in React. Please file an issue.') : void 0; + var props = getFiberCurrentPropsFromNode(internalInstance.stateNode); + restoreImpl(internalInstance.stateNode, internalInstance.type, props); +} - function slowWorkLoopThatChecksForFailedWork(expirationTime) { - if (nextRenderExpirationTime === NoWork || nextRenderExpirationTime > expirationTime) { - return; - } +function setRestoreImplementation(impl) { + restoreImpl = impl; +} - if (nextRenderExpirationTime <= mostRecentCurrentTime) { - // Flush all expired work. - while (nextUnitOfWork !== null) { - if (hasCapturedError(nextUnitOfWork)) { - // Use a forked version of performUnitOfWork - nextUnitOfWork = performFailedUnitOfWork(nextUnitOfWork); - } else { - nextUnitOfWork = performUnitOfWork(nextUnitOfWork); - } - } +function enqueueStateRestore(target) { + if (restoreTarget) { + if (restoreQueue) { + restoreQueue.push(target); } else { - // Flush asynchronous work until the deadline runs out of time. - while (nextUnitOfWork !== null && !shouldYield()) { - if (hasCapturedError(nextUnitOfWork)) { - // Use a forked version of performUnitOfWork - nextUnitOfWork = performFailedUnitOfWork(nextUnitOfWork); - } else { - nextUnitOfWork = performUnitOfWork(nextUnitOfWork); - } - } + restoreQueue = [target]; } + } else { + restoreTarget = target; } +} - function renderRootCatchBlock(root, failedWork, boundary, expirationTime) { - // We're going to restart the error boundary that captured the error. - // Conceptually, we're unwinding the stack. We need to unwind the - // context stack, too. - unwindContexts(failedWork, boundary); - - // Restart the error boundary using a forked version of - // performUnitOfWork that deletes the boundary's children. The entire - // failed subree will be unmounted. During the commit phase, a special - // lifecycle method is called on the error boundary, which triggers - // a re-render. - nextUnitOfWork = performFailedUnitOfWork(boundary); +function needsStateRestore() { + return restoreTarget !== null || restoreQueue !== null; +} - // Continue working. - workLoop(expirationTime); +function restoreStateIfNeeded() { + if (!restoreTarget) { + return; } + var target = restoreTarget; + var queuedTargets = restoreQueue; + restoreTarget = null; + restoreQueue = null; - function renderRoot(root, expirationTime) { - !!isWorking ? invariant(false, 'renderRoot was called recursively. This error is likely caused by a bug in React. Please file an issue.') : void 0; - isWorking = true; - - // We're about to mutate the work-in-progress tree. If the root was pending - // commit, it no longer is: we'll need to complete it again. - root.isReadyForCommit = false; - - // Check if we're starting from a fresh stack, or if we're resuming from - // previously yielded work. - if (root !== nextRoot || expirationTime !== nextRenderExpirationTime || nextUnitOfWork === null) { - // Reset the stack and start working from the root. - resetContextStack(); - nextRoot = root; - nextRenderExpirationTime = expirationTime; - nextUnitOfWork = createWorkInProgress(nextRoot.current, null, expirationTime); - } - - startWorkLoopTimer(nextUnitOfWork); - - var didError = false; - var error = null; - { - invokeGuardedCallback$1(null, workLoop, null, expirationTime); - if (hasCaughtError()) { - didError = true; - error = clearCaughtError(); - } + restoreStateOfTarget(target); + if (queuedTargets) { + for (var i = 0; i < queuedTargets.length; i++) { + restoreStateOfTarget(queuedTargets[i]); } + } +} - // An error was thrown during the render phase. - while (didError) { - if (didFatal) { - // This was a fatal error. Don't attempt to recover from it. - firstUncaughtError = error; - break; - } - - var failedWork = nextUnitOfWork; - if (failedWork === null) { - // An error was thrown but there's no current unit of work. This can - // happen during the commit phase if there's a bug in the renderer. - didFatal = true; - continue; - } - - // "Capture" the error by finding the nearest boundary. If there is no - // error boundary, we use the root. - var boundary = captureError(failedWork, error); - !(boundary !== null) ? invariant(false, 'Should have found an error boundary. This error is likely caused by a bug in React. Please file an issue.') : void 0; +// Used as a way to call batchedUpdates when we don't have a reference to +// the renderer. Such as when we're dispatching events or if third party +// libraries need to call batchedUpdates. Eventually, this API will go away when +// everything is batched by default. We'll then have a similar API to opt-out of +// scheduled work and instead do synchronous work. - if (didFatal) { - // The error we just captured was a fatal error. This happens - // when the error propagates to the root more than once. - continue; - } +// Defaults +var _batchedUpdatesImpl = function (fn, bookkeeping) { + return fn(bookkeeping); +}; +var _interactiveUpdatesImpl = function (fn, a, b) { + return fn(a, b); +}; +var _flushInteractiveUpdatesImpl = function () {}; - didError = false; - error = null; - { - invokeGuardedCallback$1(null, renderRootCatchBlock, null, root, failedWork, boundary, expirationTime); - if (hasCaughtError()) { - didError = true; - error = clearCaughtError(); - continue; - } - } - // We're finished working. Exit the error loop. - break; +var isBatching = false; +function batchedUpdates(fn, bookkeeping) { + if (isBatching) { + // If we are currently inside another batch, we need to wait until it + // fully completes before restoring state. + return fn(bookkeeping); + } + isBatching = true; + try { + return _batchedUpdatesImpl(fn, bookkeeping); + } finally { + // Here we wait until all updates have propagated, which is important + // when using controlled components within layers: + // https://github.com/facebook/react/issues/1698 + // Then we restore state of any controlled component. + isBatching = false; + var controlledComponentsHavePendingUpdates = needsStateRestore(); + if (controlledComponentsHavePendingUpdates) { + // If a controlled event was fired, we may need to restore the state of + // the DOM node back to the controlled value. This is necessary when React + // bails out of the update without touching the DOM. + _flushInteractiveUpdatesImpl(); + restoreStateIfNeeded(); } + } +} - var uncaughtError = firstUncaughtError; +function interactiveUpdates(fn, a, b) { + return _interactiveUpdatesImpl(fn, a, b); +} - // We're done performing work. Time to clean up. - stopWorkLoopTimer(interruptedBy); - interruptedBy = null; - isWorking = false; - didFatal = false; - firstUncaughtError = null; - if (uncaughtError !== null) { - onUncaughtError(uncaughtError); - } - return root.isReadyForCommit ? root.current.alternate : null; - } +function setBatchingImplementation(batchedUpdatesImpl, interactiveUpdatesImpl, flushInteractiveUpdatesImpl) { + _batchedUpdatesImpl = batchedUpdatesImpl; + _interactiveUpdatesImpl = interactiveUpdatesImpl; + _flushInteractiveUpdatesImpl = flushInteractiveUpdatesImpl; +} - // Returns the boundary that captured the error, or null if the error is ignored - function captureError(failedWork, error) { - // It is no longer valid because we exited the user code. - ReactCurrentOwner.current = null; - { - ReactDebugCurrentFiber.resetCurrentFiber(); - } +/** + * @see http://www.whatwg.org/specs/web-apps/current-work/multipage/the-input-element.html#input-type-attr-summary + */ +var supportedInputTypes = { + color: true, + date: true, + datetime: true, + 'datetime-local': true, + email: true, + month: true, + number: true, + password: true, + range: true, + search: true, + tel: true, + text: true, + time: true, + url: true, + week: true +}; - // Search for the nearest error boundary. - var boundary = null; +function isTextInputElement(elem) { + var nodeName = elem && elem.nodeName && elem.nodeName.toLowerCase(); - // Passed to logCapturedError() - var errorBoundaryFound = false; - var willRetry = false; - var errorBoundaryName = null; + if (nodeName === 'input') { + return !!supportedInputTypes[elem.type]; + } - // Host containers are a special case. If the failed work itself is a host - // container, then it acts as its own boundary. In all other cases, we - // ignore the work itself and only search through the parents. - if (failedWork.tag === HostRoot) { - boundary = failedWork; + if (nodeName === 'textarea') { + return true; + } - if (isFailedBoundary(failedWork)) { - // If this root already failed, there must have been an error when - // attempting to unmount it. This is a worst-case scenario and - // should only be possible if there's a bug in the renderer. - didFatal = true; - } - } else { - var node = failedWork['return']; - while (node !== null && boundary === null) { - if (node.tag === ClassComponent) { - var instance = node.stateNode; - if (typeof instance.componentDidCatch === 'function') { - errorBoundaryFound = true; - errorBoundaryName = getComponentName(node); - - // Found an error boundary! - boundary = node; - willRetry = true; - } - } else if (node.tag === HostRoot) { - // Treat the root like a no-op error boundary - boundary = node; - } + return false; +} - if (isFailedBoundary(node)) { - // This boundary is already in a failed state. +/** + * HTML nodeType values that represent the type of the node + */ - // If we're currently unmounting, that means this error was - // thrown while unmounting a failed subtree. We should ignore - // the error. - if (isUnmounting) { - return null; - } +var ELEMENT_NODE = 1; +var TEXT_NODE = 3; +var COMMENT_NODE = 8; +var DOCUMENT_NODE = 9; +var DOCUMENT_FRAGMENT_NODE = 11; - // If we're in the commit phase, we should check to see if - // this boundary already captured an error during this commit. - // This case exists because multiple errors can be thrown during - // a single commit without interruption. - if (commitPhaseBoundaries !== null && (commitPhaseBoundaries.has(node) || node.alternate !== null && commitPhaseBoundaries.has(node.alternate))) { - // If so, we should ignore this error. - return null; - } +/** + * Gets the target node from a native browser event by accounting for + * inconsistencies in browser DOM APIs. + * + * @param {object} nativeEvent Native browser event. + * @return {DOMEventTarget} Target node. + */ +function getEventTarget(nativeEvent) { + // Fallback to nativeEvent.srcElement for IE9 + // https://github.com/facebook/react/issues/12506 + var target = nativeEvent.target || nativeEvent.srcElement || window; - // The error should propagate to the next boundary -— we keep looking. - boundary = null; - willRetry = false; - } + // Normalize SVG element events #4963 + if (target.correspondingUseElement) { + target = target.correspondingUseElement; + } - node = node['return']; - } - } + // Safari may fire events on text nodes (Node.TEXT_NODE is 3). + // @see http://www.quirksmode.org/js/events_properties.html + return target.nodeType === TEXT_NODE ? target.parentNode : target; +} - if (boundary !== null) { - // Add to the collection of failed boundaries. This lets us know that - // subsequent errors in this subtree should propagate to the next boundary. - if (failedBoundaries === null) { - failedBoundaries = new Set(); - } - failedBoundaries.add(boundary); +/** + * Checks if an event is supported in the current execution environment. + * + * NOTE: This will not work correctly for non-generic events such as `change`, + * `reset`, `load`, `error`, and `select`. + * + * Borrows from Modernizr. + * + * @param {string} eventNameSuffix Event name, e.g. "click". + * @return {boolean} True if the event is supported. + * @internal + * @license Modernizr 3.0.0pre (Custom Build) | MIT + */ +function isEventSupported(eventNameSuffix) { + if (!canUseDOM) { + return false; + } - // This method is unsafe outside of the begin and complete phases. - // We might be in the commit phase when an error is captured. - // The risk is that the return path from this Fiber may not be accurate. - // That risk is acceptable given the benefit of providing users more context. - var _componentStack = getStackAddendumByWorkInProgressFiber(failedWork); - var _componentName = getComponentName(failedWork); + var eventName = 'on' + eventNameSuffix; + var isSupported = eventName in document; - // Add to the collection of captured errors. This is stored as a global - // map of errors and their component stack location keyed by the boundaries - // that capture them. We mostly use this Map as a Set; it's a Map only to - // avoid adding a field to Fiber to store the error. - if (capturedErrors === null) { - capturedErrors = new Map(); - } + if (!isSupported) { + var element = document.createElement('div'); + element.setAttribute(eventName, 'return;'); + isSupported = typeof element[eventName] === 'function'; + } - var capturedError = { - componentName: _componentName, - componentStack: _componentStack, - error: error, - errorBoundary: errorBoundaryFound ? boundary.stateNode : null, - errorBoundaryFound: errorBoundaryFound, - errorBoundaryName: errorBoundaryName, - willRetry: willRetry - }; + return isSupported; +} - capturedErrors.set(boundary, capturedError); +function isCheckable(elem) { + var type = elem.type; + var nodeName = elem.nodeName; + return nodeName && nodeName.toLowerCase() === 'input' && (type === 'checkbox' || type === 'radio'); +} - try { - logCapturedError(capturedError); - } catch (e) { - // Prevent cycle if logCapturedError() throws. - // A cycle may still occur if logCapturedError renders a component that throws. - var suppressLogging = e && e.suppressReactErrorLogging; - if (!suppressLogging) { - console.error(e); - } - } +function getTracker(node) { + return node._valueTracker; +} - // If we're in the commit phase, defer scheduling an update on the - // boundary until after the commit is complete - if (isCommitting) { - if (commitPhaseBoundaries === null) { - commitPhaseBoundaries = new Set(); - } - commitPhaseBoundaries.add(boundary); - } else { - // Otherwise, schedule an update now. - // TODO: Is this actually necessary during the render phase? Is it - // possible to unwind and continue rendering at the same priority, - // without corrupting internal state? - scheduleErrorRecovery(boundary); - } - return boundary; - } else if (firstUncaughtError === null) { - // If no boundary is found, we'll need to throw the error - firstUncaughtError = error; - } - return null; - } +function detachTracker(node) { + node._valueTracker = null; +} - function hasCapturedError(fiber) { - // TODO: capturedErrors should store the boundary instance, to avoid needing - // to check the alternate. - return capturedErrors !== null && (capturedErrors.has(fiber) || fiber.alternate !== null && capturedErrors.has(fiber.alternate)); +function getValueFromNode(node) { + var value = ''; + if (!node) { + return value; } - function isFailedBoundary(fiber) { - // TODO: failedBoundaries should store the boundary instance, to avoid - // needing to check the alternate. - return failedBoundaries !== null && (failedBoundaries.has(fiber) || fiber.alternate !== null && failedBoundaries.has(fiber.alternate)); + if (isCheckable(node)) { + value = node.checked ? 'true' : 'false'; + } else { + value = node.value; } - function commitErrorHandling(effectfulFiber) { - var capturedError = void 0; - if (capturedErrors !== null) { - capturedError = capturedErrors.get(effectfulFiber); - capturedErrors['delete'](effectfulFiber); - if (capturedError == null) { - if (effectfulFiber.alternate !== null) { - effectfulFiber = effectfulFiber.alternate; - capturedError = capturedErrors.get(effectfulFiber); - capturedErrors['delete'](effectfulFiber); - } - } - } + return value; +} - !(capturedError != null) ? invariant(false, 'No error for given unit of work. This error is likely caused by a bug in React. Please file an issue.') : void 0; +function trackValueOnNode(node) { + var valueField = isCheckable(node) ? 'checked' : 'value'; + var descriptor = Object.getOwnPropertyDescriptor(node.constructor.prototype, valueField); - switch (effectfulFiber.tag) { - case ClassComponent: - var instance = effectfulFiber.stateNode; + var currentValue = '' + node[valueField]; - var info = { - componentStack: capturedError.componentStack - }; + // if someone has already defined a value or Safari, then bail + // and don't track value will cause over reporting of changes, + // but it's better then a hard failure + // (needed for certain tests that spyOn input values and Safari) + if (node.hasOwnProperty(valueField) || typeof descriptor === 'undefined' || typeof descriptor.get !== 'function' || typeof descriptor.set !== 'function') { + return; + } + var get = descriptor.get, + set = descriptor.set; - // Allow the boundary to handle the error, usually by scheduling - // an update to itself - instance.componentDidCatch(capturedError.error, info); - return; - case HostRoot: - if (firstUncaughtError === null) { - firstUncaughtError = capturedError.error; - } - return; - default: - invariant(false, 'Invalid type of work. This error is likely caused by a bug in React. Please file an issue.'); + Object.defineProperty(node, valueField, { + configurable: true, + get: function () { + return get.call(this); + }, + set: function (value) { + currentValue = '' + value; + set.call(this, value); } - } + }); + // We could've passed this the first time + // but it triggers a bug in IE11 and Edge 14/15. + // Calling defineProperty() again should be equivalent. + // https://github.com/facebook/react/issues/11768 + Object.defineProperty(node, valueField, { + enumerable: descriptor.enumerable + }); - function unwindContexts(from, to) { - var node = from; - while (node !== null) { - switch (node.tag) { - case ClassComponent: - popContextProvider(node); - break; - case HostComponent: - popHostContext(node); - break; - case HostRoot: - popHostContainer(node); - break; - case HostPortal: - popHostContainer(node); - break; - } - if (node === to || node.alternate === to) { - stopFailedWorkTimer(node); - break; - } else { - stopWorkTimer(node); - } - node = node['return']; + var tracker = { + getValue: function () { + return currentValue; + }, + setValue: function (value) { + currentValue = '' + value; + }, + stopTracking: function () { + detachTracker(node); + delete node[valueField]; } - } + }; + return tracker; +} - function computeAsyncExpiration() { - // Given the current clock time, returns an expiration time. We use rounding - // to batch like updates together. - // Should complete within ~1000ms. 1200ms max. - var currentTime = recalculateCurrentTime(); - var expirationMs = 1000; - var bucketSizeMs = 200; - return computeExpirationBucket(currentTime, expirationMs, bucketSizeMs); +function track(node) { + if (getTracker(node)) { + return; } - function computeExpirationForFiber(fiber) { - var expirationTime = void 0; - if (expirationContext !== NoWork) { - // An explicit expiration context was set; - expirationTime = expirationContext; - } else if (isWorking) { - if (isCommitting) { - // Updates that occur during the commit phase should have sync priority - // by default. - expirationTime = Sync; - } else { - // Updates during the render phase should expire at the same time as - // the work that is being rendered. - expirationTime = nextRenderExpirationTime; - } - } else { - // No explicit expiration context was set, and we're not currently - // performing work. Calculate a new expiration time. - if (useSyncScheduling && !(fiber.internalContextTag & AsyncUpdates)) { - // This is a sync update - expirationTime = Sync; - } else { - // This is an async update - expirationTime = computeAsyncExpiration(); - } - } - return expirationTime; - } + // TODO: Once it's just Fiber we can move this to node._wrapperState + node._valueTracker = trackValueOnNode(node); +} - function scheduleWork(fiber, expirationTime) { - return scheduleWorkImpl(fiber, expirationTime, false); +function updateValueIfChanged(node) { + if (!node) { + return false; } - function checkRootNeedsClearing(root, fiber, expirationTime) { - if (!isWorking && root === nextRoot && expirationTime < nextRenderExpirationTime) { - // Restart the root from the top. - if (nextUnitOfWork !== null) { - // This is an interruption. (Used for performance tracking.) - interruptedBy = fiber; - } - nextRoot = null; - nextUnitOfWork = null; - nextRenderExpirationTime = NoWork; - } + var tracker = getTracker(node); + // if there is no tracker at this point it's unlikely + // that trying again will succeed + if (!tracker) { + return true; } - function scheduleWorkImpl(fiber, expirationTime, isErrorRecovery) { - recordScheduleUpdate(); + var lastValue = tracker.getValue(); + var nextValue = getValueFromNode(node); + if (nextValue !== lastValue) { + tracker.setValue(nextValue); + return true; + } + return false; +} - { - if (!isErrorRecovery && fiber.tag === ClassComponent) { - var instance = fiber.stateNode; - warnAboutInvalidUpdates(instance); - } - } +var ReactSharedInternals = React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED; - var node = fiber; - while (node !== null) { - // Walk the parent path to the root and update each node's - // expiration time. - if (node.expirationTime === NoWork || node.expirationTime > expirationTime) { - node.expirationTime = expirationTime; - } - if (node.alternate !== null) { - if (node.alternate.expirationTime === NoWork || node.alternate.expirationTime > expirationTime) { - node.alternate.expirationTime = expirationTime; - } - } - if (node['return'] === null) { - if (node.tag === HostRoot) { - var root = node.stateNode; +var BEFORE_SLASH_RE = /^(.*)[\\\/]/; - checkRootNeedsClearing(root, fiber, expirationTime); - requestWork(root, expirationTime); - checkRootNeedsClearing(root, fiber, expirationTime); - } else { - { - if (!isErrorRecovery && fiber.tag === ClassComponent) { - warnAboutUpdateOnUnmounted(fiber); - } +var describeComponentFrame = function (name, source, ownerName) { + var sourceInfo = ''; + if (source) { + var path = source.fileName; + var fileName = path.replace(BEFORE_SLASH_RE, ''); + { + // In DEV, include code for a common special case: + // prefer "folder/index.js" instead of just "index.js". + if (/^index\./.test(fileName)) { + var match = path.match(BEFORE_SLASH_RE); + if (match) { + var pathBeforeSlash = match[1]; + if (pathBeforeSlash) { + var folderName = pathBeforeSlash.replace(BEFORE_SLASH_RE, ''); + fileName = folderName + '/' + fileName; } - return; } } - node = node['return']; } + sourceInfo = ' (at ' + fileName + ':' + source.lineNumber + ')'; + } else if (ownerName) { + sourceInfo = ' (created by ' + ownerName + ')'; } + return '\n in ' + (name || 'Unknown') + sourceInfo; +}; - function scheduleErrorRecovery(fiber) { - scheduleWorkImpl(fiber, Sync, true); - } +// The Symbol used to tag the ReactElement-like types. If there is no native Symbol +// nor polyfill, then a plain number is used for performance. +var hasSymbol = typeof Symbol === 'function' && Symbol.for; + +var REACT_ELEMENT_TYPE = hasSymbol ? Symbol.for('react.element') : 0xeac7; +var REACT_PORTAL_TYPE = hasSymbol ? Symbol.for('react.portal') : 0xeaca; +var REACT_FRAGMENT_TYPE = hasSymbol ? Symbol.for('react.fragment') : 0xeacb; +var REACT_STRICT_MODE_TYPE = hasSymbol ? Symbol.for('react.strict_mode') : 0xeacc; +var REACT_PROFILER_TYPE = hasSymbol ? Symbol.for('react.profiler') : 0xead2; +var REACT_PROVIDER_TYPE = hasSymbol ? Symbol.for('react.provider') : 0xeacd; +var REACT_CONTEXT_TYPE = hasSymbol ? Symbol.for('react.context') : 0xeace; + +var REACT_CONCURRENT_MODE_TYPE = hasSymbol ? Symbol.for('react.concurrent_mode') : 0xeacf; +var REACT_FORWARD_REF_TYPE = hasSymbol ? Symbol.for('react.forward_ref') : 0xead0; +var REACT_SUSPENSE_TYPE = hasSymbol ? Symbol.for('react.suspense') : 0xead1; +var REACT_MEMO_TYPE = hasSymbol ? Symbol.for('react.memo') : 0xead3; +var REACT_LAZY_TYPE = hasSymbol ? Symbol.for('react.lazy') : 0xead4; - function recalculateCurrentTime() { - // Subtract initial time so it fits inside 32bits - var ms = now() - startTime; - mostRecentCurrentTime = msToExpirationTime(ms); - return mostRecentCurrentTime; - } +var MAYBE_ITERATOR_SYMBOL = typeof Symbol === 'function' && Symbol.iterator; +var FAUX_ITERATOR_SYMBOL = '@@iterator'; - function deferredUpdates(fn) { - var previousExpirationContext = expirationContext; - expirationContext = computeAsyncExpiration(); - try { - return fn(); - } finally { - expirationContext = previousExpirationContext; - } +function getIteratorFn(maybeIterable) { + if (maybeIterable === null || typeof maybeIterable !== 'object') { + return null; } - - function syncUpdates(fn) { - var previousExpirationContext = expirationContext; - expirationContext = Sync; - try { - return fn(); - } finally { - expirationContext = previousExpirationContext; - } + var maybeIterator = MAYBE_ITERATOR_SYMBOL && maybeIterable[MAYBE_ITERATOR_SYMBOL] || maybeIterable[FAUX_ITERATOR_SYMBOL]; + if (typeof maybeIterator === 'function') { + return maybeIterator; } + return null; +} - // TODO: Everything below this is written as if it has been lifted to the - // renderers. I'll do this in a follow-up. - - // Linked-list of roots - var firstScheduledRoot = null; - var lastScheduledRoot = null; - - var callbackExpirationTime = NoWork; - var callbackID = -1; - var isRendering = false; - var nextFlushedRoot = null; - var nextFlushedExpirationTime = NoWork; - var deadlineDidExpire = false; - var hasUnhandledError = false; - var unhandledError = null; - var deadline = null; - - var isBatchingUpdates = false; - var isUnbatchingUpdates = false; +var Pending = 0; +var Resolved = 1; +var Rejected = 2; - // Use these to prevent an infinite loop of nested updates - var NESTED_UPDATE_LIMIT = 1000; - var nestedUpdateCount = 0; +function refineResolvedLazyComponent(lazyComponent) { + return lazyComponent._status === Resolved ? lazyComponent._result : null; +} - var timeHeuristicForUnitOfWork = 1; +function getWrappedName(outerType, innerType, wrapperName) { + var functionName = innerType.displayName || innerType.name || ''; + return outerType.displayName || (functionName !== '' ? wrapperName + '(' + functionName + ')' : wrapperName); +} - function scheduleCallbackWithExpiration(expirationTime) { - if (callbackExpirationTime !== NoWork) { - // A callback is already scheduled. Check its expiration time (timeout). - if (expirationTime > callbackExpirationTime) { - // Existing callback has sufficient timeout. Exit. - return; - } else { - // Existing callback has insufficient timeout. Cancel and schedule a - // new one. - cancelDeferredCallback(callbackID); - } - // The request callback timer is already running. Don't start a new one. - } else { - startRequestCallbackTimer(); +function getComponentName(type) { + if (type == null) { + // Host root, text node or just invalid type. + return null; + } + { + if (typeof type.tag === 'number') { + warningWithoutStack$1(false, 'Received an unexpected object in getComponentName(). ' + 'This is likely a bug in React. Please file an issue.'); } - - // Compute a timeout for the given expiration time. - var currentMs = now() - startTime; - var expirationMs = expirationTimeToMs(expirationTime); - var timeout = expirationMs - currentMs; - - callbackExpirationTime = expirationTime; - callbackID = scheduleDeferredCallback(performAsyncWork, { timeout: timeout }); } - - // requestWork is called by the scheduler whenever a root receives an update. - // It's up to the renderer to call renderRoot at some point in the future. - function requestWork(root, expirationTime) { - if (nestedUpdateCount > NESTED_UPDATE_LIMIT) { - invariant(false, 'Maximum update depth exceeded. This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate. React limits the number of nested updates to prevent infinite loops.'); + if (typeof type === 'function') { + return type.displayName || type.name || null; + } + if (typeof type === 'string') { + return type; + } + switch (type) { + case REACT_CONCURRENT_MODE_TYPE: + return 'ConcurrentMode'; + case REACT_FRAGMENT_TYPE: + return 'Fragment'; + case REACT_PORTAL_TYPE: + return 'Portal'; + case REACT_PROFILER_TYPE: + return 'Profiler'; + case REACT_STRICT_MODE_TYPE: + return 'StrictMode'; + case REACT_SUSPENSE_TYPE: + return 'Suspense'; + } + if (typeof type === 'object') { + switch (type.$$typeof) { + case REACT_CONTEXT_TYPE: + return 'Context.Consumer'; + case REACT_PROVIDER_TYPE: + return 'Context.Provider'; + case REACT_FORWARD_REF_TYPE: + return getWrappedName(type, type.render, 'ForwardRef'); + case REACT_MEMO_TYPE: + return getComponentName(type.type); + case REACT_LAZY_TYPE: + { + var thenable = type; + var resolvedThenable = refineResolvedLazyComponent(thenable); + if (resolvedThenable) { + return getComponentName(resolvedThenable); + } + } } + } + return null; +} - // Add the root to the schedule. - // Check if this root is already part of the schedule. - if (root.nextScheduledRoot === null) { - // This root is not already scheduled. Add it. - root.remainingExpirationTime = expirationTime; - if (lastScheduledRoot === null) { - firstScheduledRoot = lastScheduledRoot = root; - root.nextScheduledRoot = root; - } else { - lastScheduledRoot.nextScheduledRoot = root; - lastScheduledRoot = root; - lastScheduledRoot.nextScheduledRoot = firstScheduledRoot; - } - } else { - // This root is already scheduled, but its priority may have increased. - var remainingExpirationTime = root.remainingExpirationTime; - if (remainingExpirationTime === NoWork || expirationTime < remainingExpirationTime) { - // Update the priority. - root.remainingExpirationTime = expirationTime; - } - } - - if (isRendering) { - // Prevent reentrancy. Remaining work will be scheduled at the end of - // the currently rendering batch. - return; - } - - if (isBatchingUpdates) { - // Flush work at the end of the batch. - if (isUnbatchingUpdates) { - // ...unless we're inside unbatchedUpdates, in which case we should - // flush it now. - nextFlushedRoot = root; - nextFlushedExpirationTime = Sync; - performWorkOnRoot(nextFlushedRoot, nextFlushedExpirationTime); - } - return; - } - - // TODO: Get rid of Sync and use current time? - if (expirationTime === Sync) { - performWork(Sync, null); - } else { - scheduleCallbackWithExpiration(expirationTime); - } - } - - function findHighestPriorityRoot() { - var highestPriorityWork = NoWork; - var highestPriorityRoot = null; - - if (lastScheduledRoot !== null) { - var previousScheduledRoot = lastScheduledRoot; - var root = firstScheduledRoot; - while (root !== null) { - var remainingExpirationTime = root.remainingExpirationTime; - if (remainingExpirationTime === NoWork) { - // This root no longer has work. Remove it from the scheduler. - - // TODO: This check is redudant, but Flow is confused by the branch - // below where we set lastScheduledRoot to null, even though we break - // from the loop right after. - !(previousScheduledRoot !== null && lastScheduledRoot !== null) ? invariant(false, 'Should have a previous and last root. This error is likely caused by a bug in React. Please file an issue.') : void 0; - if (root === root.nextScheduledRoot) { - // This is the only root in the list. - root.nextScheduledRoot = null; - firstScheduledRoot = lastScheduledRoot = null; - break; - } else if (root === firstScheduledRoot) { - // This is the first root in the list. - var next = root.nextScheduledRoot; - firstScheduledRoot = next; - lastScheduledRoot.nextScheduledRoot = next; - root.nextScheduledRoot = null; - } else if (root === lastScheduledRoot) { - // This is the last root in the list. - lastScheduledRoot = previousScheduledRoot; - lastScheduledRoot.nextScheduledRoot = firstScheduledRoot; - root.nextScheduledRoot = null; - break; - } else { - previousScheduledRoot.nextScheduledRoot = root.nextScheduledRoot; - root.nextScheduledRoot = null; - } - root = previousScheduledRoot.nextScheduledRoot; - } else { - if (highestPriorityWork === NoWork || remainingExpirationTime < highestPriorityWork) { - // Update the priority, if it's higher - highestPriorityWork = remainingExpirationTime; - highestPriorityRoot = root; - } - if (root === lastScheduledRoot) { - break; - } - previousScheduledRoot = root; - root = root.nextScheduledRoot; - } - } - } - - // If the next root is the same as the previous root, this is a nested - // update. To prevent an infinite loop, increment the nested update count. - var previousFlushedRoot = nextFlushedRoot; - if (previousFlushedRoot !== null && previousFlushedRoot === highestPriorityRoot) { - nestedUpdateCount++; - } else { - // Reset whenever we switch roots. - nestedUpdateCount = 0; - } - nextFlushedRoot = highestPriorityRoot; - nextFlushedExpirationTime = highestPriorityWork; - } +var ReactDebugCurrentFrame = ReactSharedInternals.ReactDebugCurrentFrame; - function performAsyncWork(dl) { - performWork(NoWork, dl); - } - - function performWork(minExpirationTime, dl) { - deadline = dl; - - // Keep working on roots until there's no more work, or until the we reach - // the deadline. - findHighestPriorityRoot(); - - if (enableUserTimingAPI && deadline !== null) { - var didExpire = nextFlushedExpirationTime < recalculateCurrentTime(); - stopRequestCallbackTimer(didExpire); - } - - while (nextFlushedRoot !== null && nextFlushedExpirationTime !== NoWork && (minExpirationTime === NoWork || nextFlushedExpirationTime <= minExpirationTime) && !deadlineDidExpire) { - performWorkOnRoot(nextFlushedRoot, nextFlushedExpirationTime); - // Find the next highest priority work. - findHighestPriorityRoot(); - } - - // We're done flushing work. Either we ran out of time in this callback, - // or there's no more work left with sufficient priority. - - // If we're inside a callback, set this to false since we just completed it. - if (deadline !== null) { - callbackExpirationTime = NoWork; - callbackID = -1; - } - // If there's work left over, schedule a new callback. - if (nextFlushedExpirationTime !== NoWork) { - scheduleCallbackWithExpiration(nextFlushedExpirationTime); - } - - // Clean-up. - deadline = null; - deadlineDidExpire = false; - nestedUpdateCount = 0; - - if (hasUnhandledError) { - var _error4 = unhandledError; - unhandledError = null; - hasUnhandledError = false; - throw _error4; - } - } - - function performWorkOnRoot(root, expirationTime) { - !!isRendering ? invariant(false, 'performWorkOnRoot was called recursively. This error is likely caused by a bug in React. Please file an issue.') : void 0; - - isRendering = true; - - // Check if this is async work or sync/expired work. - // TODO: Pass current time as argument to renderRoot, commitRoot - if (expirationTime <= recalculateCurrentTime()) { - // Flush sync work. - var finishedWork = root.finishedWork; - if (finishedWork !== null) { - // This root is already complete. We can commit it. - root.finishedWork = null; - root.remainingExpirationTime = commitRoot(finishedWork); - } else { - root.finishedWork = null; - finishedWork = renderRoot(root, expirationTime); - if (finishedWork !== null) { - // We've completed the root. Commit it. - root.remainingExpirationTime = commitRoot(finishedWork); - } - } - } else { - // Flush async work. - var _finishedWork = root.finishedWork; - if (_finishedWork !== null) { - // This root is already complete. We can commit it. - root.finishedWork = null; - root.remainingExpirationTime = commitRoot(_finishedWork); - } else { - root.finishedWork = null; - _finishedWork = renderRoot(root, expirationTime); - if (_finishedWork !== null) { - // We've completed the root. Check the deadline one more time - // before committing. - if (!shouldYield()) { - // Still time left. Commit the root. - root.remainingExpirationTime = commitRoot(_finishedWork); - } else { - // There's no time left. Mark this root as complete. We'll come - // back and commit it later. - root.finishedWork = _finishedWork; - } - } +function describeFiber(fiber) { + switch (fiber.tag) { + case HostRoot: + case HostPortal: + case HostText: + case Fragment: + case ContextProvider: + case ContextConsumer: + return ''; + default: + var owner = fiber._debugOwner; + var source = fiber._debugSource; + var name = getComponentName(fiber.type); + var ownerName = null; + if (owner) { + ownerName = getComponentName(owner.type); } - } - - isRendering = false; + return describeComponentFrame(name, source, ownerName); } +} - // When working on async work, the reconciler asks the renderer if it should - // yield execution. For DOM, we implement this with requestIdleCallback. - function shouldYield() { - if (deadline === null) { - return false; - } - if (deadline.timeRemaining() > timeHeuristicForUnitOfWork) { - // Disregard deadline.didTimeout. Only expired work should be flushed - // during a timeout. This path is only hit for non-expired work. - return false; - } - deadlineDidExpire = true; - return true; - } +function getStackByFiberInDevAndProd(workInProgress) { + var info = ''; + var node = workInProgress; + do { + info += describeFiber(node); + node = node.return; + } while (node); + return info; +} - // TODO: Not happy about this hook. Conceptually, renderRoot should return a - // tuple of (isReadyForCommit, didError, error) - function onUncaughtError(error) { - !(nextFlushedRoot !== null) ? invariant(false, 'Should be working on a root. This error is likely caused by a bug in React. Please file an issue.') : void 0; - // Unschedule this root so we don't work on it again until there's - // another update. - nextFlushedRoot.remainingExpirationTime = NoWork; - if (!hasUnhandledError) { - hasUnhandledError = true; - unhandledError = error; - } - } +var current = null; +var phase = null; - // TODO: Batching should be implemented at the renderer level, not inside - // the reconciler. - function batchedUpdates(fn, a) { - var previousIsBatchingUpdates = isBatchingUpdates; - isBatchingUpdates = true; - try { - return fn(a); - } finally { - isBatchingUpdates = previousIsBatchingUpdates; - if (!isBatchingUpdates && !isRendering) { - performWork(Sync, null); - } +function getCurrentFiberOwnerNameInDevOrNull() { + { + if (current === null) { + return null; } - } - - // TODO: Batching should be implemented at the renderer level, not inside - // the reconciler. - function unbatchedUpdates(fn) { - if (isBatchingUpdates && !isUnbatchingUpdates) { - isUnbatchingUpdates = true; - try { - return fn(); - } finally { - isUnbatchingUpdates = false; - } + var owner = current._debugOwner; + if (owner !== null && typeof owner !== 'undefined') { + return getComponentName(owner.type); } - return fn(); } + return null; +} - // TODO: Batching should be implemented at the renderer level, not within - // the reconciler. - function flushSync(fn) { - var previousIsBatchingUpdates = isBatchingUpdates; - isBatchingUpdates = true; - try { - return syncUpdates(fn); - } finally { - isBatchingUpdates = previousIsBatchingUpdates; - !!isRendering ? invariant(false, 'flushSync was called from inside a lifecycle method. It cannot be called when React is already rendering.') : void 0; - performWork(Sync, null); +function getCurrentFiberStackInDev() { + { + if (current === null) { + return ''; } + // Safe because if current fiber exists, we are reconciling, + // and it is guaranteed to be the work-in-progress version. + return getStackByFiberInDevAndProd(current); } - - return { - computeAsyncExpiration: computeAsyncExpiration, - computeExpirationForFiber: computeExpirationForFiber, - scheduleWork: scheduleWork, - batchedUpdates: batchedUpdates, - unbatchedUpdates: unbatchedUpdates, - flushSync: flushSync, - deferredUpdates: deferredUpdates - }; -}; - -{ - var didWarnAboutNestedUpdates = false; + return ''; } -// 0 is PROD, 1 is DEV. -// Might add PROFILE later. - - -function getContextForSubtree(parentComponent) { - if (!parentComponent) { - return emptyObject; +function resetCurrentFiber() { + { + ReactDebugCurrentFrame.getCurrentStack = null; + current = null; + phase = null; } - - var fiber = get(parentComponent); - var parentContext = findCurrentUnmaskedContext(fiber); - return isContextProvider(fiber) ? processChildContext(fiber, parentContext) : parentContext; } -var ReactFiberReconciler$1 = function (config) { - var getPublicInstance = config.getPublicInstance; - - var _ReactFiberScheduler = ReactFiberScheduler(config), - computeAsyncExpiration = _ReactFiberScheduler.computeAsyncExpiration, - computeExpirationForFiber = _ReactFiberScheduler.computeExpirationForFiber, - scheduleWork = _ReactFiberScheduler.scheduleWork, - batchedUpdates = _ReactFiberScheduler.batchedUpdates, - unbatchedUpdates = _ReactFiberScheduler.unbatchedUpdates, - flushSync = _ReactFiberScheduler.flushSync, - deferredUpdates = _ReactFiberScheduler.deferredUpdates; - - function scheduleTopLevelUpdate(current, element, callback) { - { - if (ReactDebugCurrentFiber.phase === 'render' && ReactDebugCurrentFiber.current !== null && !didWarnAboutNestedUpdates) { - didWarnAboutNestedUpdates = true; - warning(false, 'Render methods should be a pure function of props and state; ' + 'triggering nested component updates from render is not allowed. ' + 'If necessary, trigger nested updates in componentDidUpdate.\n\n' + 'Check the render method of %s.', getComponentName(ReactDebugCurrentFiber.current) || 'Unknown'); - } - } - - callback = callback === undefined ? null : callback; - { - warning(callback === null || typeof callback === 'function', 'render(...): Expected the last optional `callback` argument to be a ' + 'function. Instead received: %s.', callback); - } - - var expirationTime = void 0; - // Check if the top-level element is an async wrapper component. If so, - // treat updates to the root as async. This is a bit weird but lets us - // avoid a separate `renderAsync` API. - if (enableAsyncSubtreeAPI && element != null && element.type != null && element.type.prototype != null && element.type.prototype.unstable_isAsyncReactComponent === true) { - expirationTime = computeAsyncExpiration(); - } else { - expirationTime = computeExpirationForFiber(current); - } - - var update = { - expirationTime: expirationTime, - partialState: { element: element }, - callback: callback, - isReplace: false, - isForced: false, - nextCallback: null, - next: null - }; - insertUpdateIntoFiber(current, update); - scheduleWork(current, expirationTime); - } - - function findHostInstance(fiber) { - var hostFiber = findCurrentHostFiber(fiber); - if (hostFiber === null) { - return null; - } - return hostFiber.stateNode; +function setCurrentFiber(fiber) { + { + ReactDebugCurrentFrame.getCurrentStack = getCurrentFiberStackInDev; + current = fiber; + phase = null; } - - return { - createContainer: function (containerInfo, hydrate) { - return createFiberRoot(containerInfo, hydrate); - }, - updateContainer: function (element, container, parentComponent, callback) { - // TODO: If this is a nested container, this won't be the root. - var current = container.current; - - { - if (ReactFiberInstrumentation_1.debugTool) { - if (current.alternate === null) { - ReactFiberInstrumentation_1.debugTool.onMountContainer(container); - } else if (element === null) { - ReactFiberInstrumentation_1.debugTool.onUnmountContainer(container); - } else { - ReactFiberInstrumentation_1.debugTool.onUpdateContainer(container); - } - } - } - - var context = getContextForSubtree(parentComponent); - if (container.context === null) { - container.context = context; - } else { - container.pendingContext = context; - } - - scheduleTopLevelUpdate(current, element, callback); - }, - - - batchedUpdates: batchedUpdates, - - unbatchedUpdates: unbatchedUpdates, - - deferredUpdates: deferredUpdates, - - flushSync: flushSync, - - getPublicRootInstance: function (container) { - var containerFiber = container.current; - if (!containerFiber.child) { - return null; - } - switch (containerFiber.child.tag) { - case HostComponent: - return getPublicInstance(containerFiber.child.stateNode); - default: - return containerFiber.child.stateNode; - } - }, - - - findHostInstance: findHostInstance, - - findHostInstanceWithNoPortals: function (fiber) { - var hostFiber = findCurrentHostFiberWithNoPortals(fiber); - if (hostFiber === null) { - return null; - } - return hostFiber.stateNode; - }, - injectIntoDevTools: function (devToolsConfig) { - var findFiberByHostInstance = devToolsConfig.findFiberByHostInstance; - - return injectInternals(_assign({}, devToolsConfig, { - findHostInstanceByFiber: function (fiber) { - return findHostInstance(fiber); - }, - findFiberByHostInstance: function (instance) { - if (!findFiberByHostInstance) { - // Might not be implemented by the renderer. - return null; - } - return findFiberByHostInstance(instance); - } - })); - } - }; -}; - -var ReactFiberReconciler$2 = Object.freeze({ - default: ReactFiberReconciler$1 -}); - -var ReactFiberReconciler$3 = ( ReactFiberReconciler$2 && ReactFiberReconciler$1 ) || ReactFiberReconciler$2; - -// TODO: bundle Flow types with the package. - - - -// TODO: decide on the top-level export form. -// This is hacky but makes it work with both Rollup and Jest. -var reactReconciler = ReactFiberReconciler$3['default'] ? ReactFiberReconciler$3['default'] : ReactFiberReconciler$3; - -function createPortal$1(children, containerInfo, -// TODO: figure out the API for cross-renderer implementation. -implementation) { - var key = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null; - - return { - // This tag allow us to uniquely identify this as a React Portal - $$typeof: REACT_PORTAL_TYPE, - key: key == null ? null : '' + key, - children: children, - containerInfo: containerInfo, - implementation: implementation - }; } -// TODO: this is special because it gets imported during build. - -var ReactVersion = '16.2.0'; - -// a requestAnimationFrame, storing the time for the start of the frame, then -// scheduling a postMessage which gets scheduled after paint. Within the -// postMessage handler do as much work as possible until time + frame rate. -// By separating the idle call into a separate event tick we ensure that -// layout, paint and other browser work is counted against the available time. -// The frame rate is dynamically adjusted. - -{ - if (ExecutionEnvironment.canUseDOM && typeof requestAnimationFrame !== 'function') { - warning(false, 'React depends on requestAnimationFrame. Make sure that you load a ' + 'polyfill in older browsers. http://fb.me/react-polyfills'); +function setCurrentPhase(lifeCyclePhase) { + { + phase = lifeCyclePhase; } } -var hasNativePerformanceNow = typeof performance === 'object' && typeof performance.now === 'function'; - -var now = void 0; -if (hasNativePerformanceNow) { - now = function () { - return performance.now(); - }; -} else { - now = function () { - return Date.now(); - }; -} - -// TODO: There's no way to cancel, because Fiber doesn't atm. -var rIC = void 0; -var cIC = void 0; - -if (!ExecutionEnvironment.canUseDOM) { - rIC = function (frameCallback) { - return setTimeout(function () { - frameCallback({ - timeRemaining: function () { - return Infinity; - } - }); - }); - }; - cIC = function (timeoutID) { - clearTimeout(timeoutID); - }; -} else if (typeof requestIdleCallback !== 'function' || typeof cancelIdleCallback !== 'function') { - // Polyfill requestIdleCallback and cancelIdleCallback - - var scheduledRICCallback = null; - var isIdleScheduled = false; - var timeoutTime = -1; - - var isAnimationFrameScheduled = false; - - var frameDeadline = 0; - // We start out assuming that we run at 30fps but then the heuristic tracking - // will adjust this value to a faster fps if we get more frequent animation - // frames. - var previousFrameTime = 33; - var activeFrameTime = 33; +/** + * Similar to invariant but only logs a warning if the condition is not met. + * This can be used to log issues in development environments in critical + * paths. Removing the logging code for production environments will keep the + * same logic and follow the same code paths. + */ - var frameDeadlineObject; - if (hasNativePerformanceNow) { - frameDeadlineObject = { - didTimeout: false, - timeRemaining: function () { - // We assume that if we have a performance timer that the rAF callback - // gets a performance timer value. Not sure if this is always true. - var remaining = frameDeadline - performance.now(); - return remaining > 0 ? remaining : 0; - } - }; - } else { - frameDeadlineObject = { - didTimeout: false, - timeRemaining: function () { - // Fallback to Date.now() - var remaining = frameDeadline - Date.now(); - return remaining > 0 ? remaining : 0; - } - }; - } +var warning = warningWithoutStack$1; - // We use the postMessage trick to defer idle work until after the repaint. - var messageKey = '__reactIdleCallback$' + Math.random().toString(36).slice(2); - var idleTick = function (event) { - if (event.source !== window || event.data !== messageKey) { +{ + warning = function (condition, format) { + if (condition) { return; } + var ReactDebugCurrentFrame = ReactSharedInternals.ReactDebugCurrentFrame; + var stack = ReactDebugCurrentFrame.getStackAddendum(); + // eslint-disable-next-line react-internal/warning-and-invariant-args - isIdleScheduled = false; - - var currentTime = now(); - if (frameDeadline - currentTime <= 0) { - // There's no time left in this idle period. Check if the callback has - // a timeout and whether it's been exceeded. - if (timeoutTime !== -1 && timeoutTime <= currentTime) { - // Exceeded the timeout. Invoke the callback even though there's no - // time left. - frameDeadlineObject.didTimeout = true; - } else { - // No timeout. - if (!isAnimationFrameScheduled) { - // Schedule another animation callback so we retry later. - isAnimationFrameScheduled = true; - requestAnimationFrame(animationTick); - } - // Exit without invoking the callback. - return; - } - } else { - // There's still time left in this idle period. - frameDeadlineObject.didTimeout = false; + for (var _len = arguments.length, args = Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) { + args[_key - 2] = arguments[_key]; } - timeoutTime = -1; - var callback = scheduledRICCallback; - scheduledRICCallback = null; - if (callback !== null) { - callback(frameDeadlineObject); - } + warningWithoutStack$1.apply(undefined, [false, format + '%s'].concat(args, [stack])); }; - // Assumes that we have addEventListener in this environment. Might need - // something better for old IE. - window.addEventListener('message', idleTick, false); +} - var animationTick = function (rafTime) { - isAnimationFrameScheduled = false; - var nextFrameTime = rafTime - frameDeadline + activeFrameTime; - if (nextFrameTime < activeFrameTime && previousFrameTime < activeFrameTime) { - if (nextFrameTime < 8) { - // Defensive coding. We don't support higher frame rates than 120hz. - // If we get lower than that, it is probably a bug. - nextFrameTime = 8; - } - // If one frame goes long, then the next one can be short to catch up. - // If two frames are short in a row, then that's an indication that we - // actually have a higher frame rate than what we're currently optimizing. - // We adjust our heuristic dynamically accordingly. For example, if we're - // running on 120hz display or 90hz VR display. - // Take the max of the two in case one of them was an anomaly due to - // missed frame deadlines. - activeFrameTime = nextFrameTime < previousFrameTime ? previousFrameTime : nextFrameTime; - } else { - previousFrameTime = nextFrameTime; - } - frameDeadline = rafTime + activeFrameTime; - if (!isIdleScheduled) { - isIdleScheduled = true; - window.postMessage(messageKey, '*'); - } - }; +var warning$1 = warning; - rIC = function (callback, options) { - // This assumes that we only schedule one callback at a time because that's - // how Fiber uses it. - scheduledRICCallback = callback; - if (options != null && typeof options.timeout === 'number') { - timeoutTime = now() + options.timeout; - } - if (!isAnimationFrameScheduled) { - // If rAF didn't already schedule one, we need to schedule a frame. - // TODO: If this rAF doesn't materialize because the browser throttles, we - // might want to still have setTimeout trigger rIC as a backup to ensure - // that we keep performing work. - isAnimationFrameScheduled = true; - requestAnimationFrame(animationTick); - } - return 0; - }; +// A reserved attribute. +// It is handled by React separately and shouldn't be written to the DOM. +var RESERVED = 0; - cIC = function () { - scheduledRICCallback = null; - isIdleScheduled = false; - timeoutTime = -1; - }; -} else { - rIC = window.requestIdleCallback; - cIC = window.cancelIdleCallback; -} +// A simple string attribute. +// Attributes that aren't in the whitelist are presumed to have this type. +var STRING = 1; -/** - * Forked from fbjs/warning: - * https://github.com/facebook/fbjs/blob/e66ba20ad5be433eb54423f2b097d829324d9de6/packages/fbjs/src/__forks__/warning.js - * - * Only change is we use console.warn instead of console.error, - * and do nothing when 'console' is not supported. - * This really simplifies the code. - * --- - * Similar to invariant but only logs a warning if the condition is not met. - * This can be used to log issues in development environments in critical - * paths. Removing the logging code for production environments will keep the - * same logic and follow the same code paths. - */ +// A string attribute that accepts booleans in React. In HTML, these are called +// "enumerated" attributes with "true" and "false" as possible values. +// When true, it should be set to a "true" string. +// When false, it should be set to a "false" string. +var BOOLEANISH_STRING = 2; -var lowPriorityWarning = function () {}; +// A real boolean attribute. +// When true, it should be present (set either to an empty string or its name). +// When false, it should be omitted. +var BOOLEAN = 3; -{ - var printWarning = function (format) { - for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { - args[_key - 1] = arguments[_key]; - } +// An attribute that can be used as a flag as well as with a value. +// When true, it should be present (set either to an empty string or its name). +// When false, it should be omitted. +// For any other value, should be present with that value. +var OVERLOADED_BOOLEAN = 4; - var argIndex = 0; - var message = 'Warning: ' + format.replace(/%s/g, function () { - return args[argIndex++]; - }); - if (typeof console !== 'undefined') { - console.warn(message); - } - try { - // --- Welcome to debugging React --- - // This error was thrown as a convenience so that you can use this stack - // to find the callsite that caused this warning to fire. - throw new Error(message); - } catch (x) {} - }; +// An attribute that must be numeric or parse as a numeric. +// When falsy, it should be removed. +var NUMERIC = 5; - lowPriorityWarning = function (condition, format) { - if (format === undefined) { - throw new Error('`warning(condition, format, ...args)` requires a warning ' + 'message argument'); - } - if (!condition) { - for (var _len2 = arguments.length, args = Array(_len2 > 2 ? _len2 - 2 : 0), _key2 = 2; _key2 < _len2; _key2++) { - args[_key2 - 2] = arguments[_key2]; - } +// An attribute that must be positive numeric or parse as a positive numeric. +// When falsy, it should be removed. +var POSITIVE_NUMERIC = 6; - printWarning.apply(undefined, [format].concat(args)); - } - }; -} +/* eslint-disable max-len */ +var ATTRIBUTE_NAME_START_CHAR = ':A-Z_a-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02FF\\u0370-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D\\u2070-\\u218F\\u2C00-\\u2FEF\\u3001-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFFD'; +/* eslint-enable max-len */ +var ATTRIBUTE_NAME_CHAR = ATTRIBUTE_NAME_START_CHAR + '\\-.0-9\\u00B7\\u0300-\\u036F\\u203F-\\u2040'; -var lowPriorityWarning$1 = lowPriorityWarning; -// isAttributeNameSafe() is currently duplicated in DOMMarkupOperations. -// TODO: Find a better place for this. +var ROOT_ATTRIBUTE_NAME = 'data-reactroot'; var VALID_ATTRIBUTE_NAME_REGEX = new RegExp('^[' + ATTRIBUTE_NAME_START_CHAR + '][' + ATTRIBUTE_NAME_CHAR + ']*$'); + +var hasOwnProperty = Object.prototype.hasOwnProperty; var illegalAttributeNameCache = {}; var validatedAttributeNameCache = {}; + function isAttributeNameSafe(attributeName) { - if (validatedAttributeNameCache.hasOwnProperty(attributeName)) { + if (hasOwnProperty.call(validatedAttributeNameCache, attributeName)) { return true; } - if (illegalAttributeNameCache.hasOwnProperty(attributeName)) { + if (hasOwnProperty.call(illegalAttributeNameCache, attributeName)) { return false; } if (VALID_ATTRIBUTE_NAME_REGEX.test(attributeName)) { @@ -62422,81 +54996,281 @@ function isAttributeNameSafe(attributeName) { } illegalAttributeNameCache[attributeName] = true; { - warning(false, 'Invalid attribute name: `%s`', attributeName); + warning$1(false, 'Invalid attribute name: `%s`', attributeName); } return false; } -// shouldIgnoreValue() is currently duplicated in DOMMarkupOperations. -// TODO: Find a better place for this. -function shouldIgnoreValue(propertyInfo, value) { - return value == null || propertyInfo.hasBooleanValue && !value || propertyInfo.hasNumericValue && isNaN(value) || propertyInfo.hasPositiveNumericValue && value < 1 || propertyInfo.hasOverloadedBooleanValue && value === false; +function shouldIgnoreAttribute(name, propertyInfo, isCustomComponentTag) { + if (propertyInfo !== null) { + return propertyInfo.type === RESERVED; + } + if (isCustomComponentTag) { + return false; + } + if (name.length > 2 && (name[0] === 'o' || name[0] === 'O') && (name[1] === 'n' || name[1] === 'N')) { + return true; + } + return false; } -/** - * Operations for dealing with DOM properties. - */ +function shouldRemoveAttributeWithWarning(name, value, propertyInfo, isCustomComponentTag) { + if (propertyInfo !== null && propertyInfo.type === RESERVED) { + return false; + } + switch (typeof value) { + case 'function': + // $FlowIssue symbol is perfectly valid here + case 'symbol': + // eslint-disable-line + return true; + case 'boolean': + { + if (isCustomComponentTag) { + return false; + } + if (propertyInfo !== null) { + return !propertyInfo.acceptsBooleans; + } else { + var prefix = name.toLowerCase().slice(0, 5); + return prefix !== 'data-' && prefix !== 'aria-'; + } + } + default: + return false; + } +} + +function shouldRemoveAttribute(name, value, propertyInfo, isCustomComponentTag) { + if (value === null || typeof value === 'undefined') { + return true; + } + if (shouldRemoveAttributeWithWarning(name, value, propertyInfo, isCustomComponentTag)) { + return true; + } + if (isCustomComponentTag) { + return false; + } + if (propertyInfo !== null) { + switch (propertyInfo.type) { + case BOOLEAN: + return !value; + case OVERLOADED_BOOLEAN: + return value === false; + case NUMERIC: + return isNaN(value); + case POSITIVE_NUMERIC: + return isNaN(value) || value < 1; + } + } + return false; +} + +function getPropertyInfo(name) { + return properties.hasOwnProperty(name) ? properties[name] : null; +} + +function PropertyInfoRecord(name, type, mustUseProperty, attributeName, attributeNamespace) { + this.acceptsBooleans = type === BOOLEANISH_STRING || type === BOOLEAN || type === OVERLOADED_BOOLEAN; + this.attributeName = attributeName; + this.attributeNamespace = attributeNamespace; + this.mustUseProperty = mustUseProperty; + this.propertyName = name; + this.type = type; +} +// When adding attributes to this list, be sure to also add them to +// the `possibleStandardNames` module to ensure casing and incorrect +// name warnings. +var properties = {}; + +// These props are reserved by React. They shouldn't be written to the DOM. +['children', 'dangerouslySetInnerHTML', +// TODO: This prevents the assignment of defaultValue to regular +// elements (not just inputs). Now that ReactDOMInput assigns to the +// defaultValue property -- do we need this? +'defaultValue', 'defaultChecked', 'innerHTML', 'suppressContentEditableWarning', 'suppressHydrationWarning', 'style'].forEach(function (name) { + properties[name] = new PropertyInfoRecord(name, RESERVED, false, // mustUseProperty + name, // attributeName + null); +} // attributeNamespace +); + +// A few React string attributes have a different name. +// This is a mapping from React prop names to the attribute names. +[['acceptCharset', 'accept-charset'], ['className', 'class'], ['htmlFor', 'for'], ['httpEquiv', 'http-equiv']].forEach(function (_ref) { + var name = _ref[0], + attributeName = _ref[1]; + + properties[name] = new PropertyInfoRecord(name, STRING, false, // mustUseProperty + attributeName, // attributeName + null); +} // attributeNamespace +); + +// These are "enumerated" HTML attributes that accept "true" and "false". +// In React, we let users pass `true` and `false` even though technically +// these aren't boolean attributes (they are coerced to strings). +['contentEditable', 'draggable', 'spellCheck', 'value'].forEach(function (name) { + properties[name] = new PropertyInfoRecord(name, BOOLEANISH_STRING, false, // mustUseProperty + name.toLowerCase(), // attributeName + null); +} // attributeNamespace +); + +// These are "enumerated" SVG attributes that accept "true" and "false". +// In React, we let users pass `true` and `false` even though technically +// these aren't boolean attributes (they are coerced to strings). +// Since these are SVG attributes, their attribute names are case-sensitive. +['autoReverse', 'externalResourcesRequired', 'focusable', 'preserveAlpha'].forEach(function (name) { + properties[name] = new PropertyInfoRecord(name, BOOLEANISH_STRING, false, // mustUseProperty + name, // attributeName + null); +} // attributeNamespace +); + +// These are HTML boolean attributes. +['allowFullScreen', 'async', +// Note: there is a special case that prevents it from being written to the DOM +// on the client side because the browsers are inconsistent. Instead we call focus(). +'autoFocus', 'autoPlay', 'controls', 'default', 'defer', 'disabled', 'formNoValidate', 'hidden', 'loop', 'noModule', 'noValidate', 'open', 'playsInline', 'readOnly', 'required', 'reversed', 'scoped', 'seamless', +// Microdata +'itemScope'].forEach(function (name) { + properties[name] = new PropertyInfoRecord(name, BOOLEAN, false, // mustUseProperty + name.toLowerCase(), // attributeName + null); +} // attributeNamespace +); + +// These are the few React props that we set as DOM properties +// rather than attributes. These are all booleans. +['checked', +// Note: `option.selected` is not updated if `select.multiple` is +// disabled with `removeAttribute`. We have special logic for handling this. +'multiple', 'muted', 'selected'].forEach(function (name) { + properties[name] = new PropertyInfoRecord(name, BOOLEAN, true, // mustUseProperty + name, // attributeName + null); +} // attributeNamespace +); + +// These are HTML attributes that are "overloaded booleans": they behave like +// booleans, but can also accept a string value. +['capture', 'download'].forEach(function (name) { + properties[name] = new PropertyInfoRecord(name, OVERLOADED_BOOLEAN, false, // mustUseProperty + name, // attributeName + null); +} // attributeNamespace +); + +// These are HTML attributes that must be positive numbers. +['cols', 'rows', 'size', 'span'].forEach(function (name) { + properties[name] = new PropertyInfoRecord(name, POSITIVE_NUMERIC, false, // mustUseProperty + name, // attributeName + null); +} // attributeNamespace +); + +// These are HTML attributes that must be numbers. +['rowSpan', 'start'].forEach(function (name) { + properties[name] = new PropertyInfoRecord(name, NUMERIC, false, // mustUseProperty + name.toLowerCase(), // attributeName + null); +} // attributeNamespace +); + +var CAMELIZE = /[\-\:]([a-z])/g; +var capitalize = function (token) { + return token[1].toUpperCase(); +}; +// This is a list of all SVG attributes that need special casing, namespacing, +// or boolean value assignment. Regular attributes that just accept strings +// and have the same names are omitted, just like in the HTML whitelist. +// Some of these attributes can be hard to find. This list was created by +// scrapping the MDN documentation. +['accent-height', 'alignment-baseline', 'arabic-form', 'baseline-shift', 'cap-height', 'clip-path', 'clip-rule', 'color-interpolation', 'color-interpolation-filters', 'color-profile', 'color-rendering', 'dominant-baseline', 'enable-background', 'fill-opacity', 'fill-rule', 'flood-color', 'flood-opacity', 'font-family', 'font-size', 'font-size-adjust', 'font-stretch', 'font-style', 'font-variant', 'font-weight', 'glyph-name', 'glyph-orientation-horizontal', 'glyph-orientation-vertical', 'horiz-adv-x', 'horiz-origin-x', 'image-rendering', 'letter-spacing', 'lighting-color', 'marker-end', 'marker-mid', 'marker-start', 'overline-position', 'overline-thickness', 'paint-order', 'panose-1', 'pointer-events', 'rendering-intent', 'shape-rendering', 'stop-color', 'stop-opacity', 'strikethrough-position', 'strikethrough-thickness', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'text-anchor', 'text-decoration', 'text-rendering', 'underline-position', 'underline-thickness', 'unicode-bidi', 'unicode-range', 'units-per-em', 'v-alphabetic', 'v-hanging', 'v-ideographic', 'v-mathematical', 'vector-effect', 'vert-adv-y', 'vert-origin-x', 'vert-origin-y', 'word-spacing', 'writing-mode', 'xmlns:xlink', 'x-height'].forEach(function (attributeName) { + var name = attributeName.replace(CAMELIZE, capitalize); + properties[name] = new PropertyInfoRecord(name, STRING, false, // mustUseProperty + attributeName, null); +} // attributeNamespace +); + +// String SVG attributes with the xlink namespace. +['xlink:actuate', 'xlink:arcrole', 'xlink:href', 'xlink:role', 'xlink:show', 'xlink:title', 'xlink:type'].forEach(function (attributeName) { + var name = attributeName.replace(CAMELIZE, capitalize); + properties[name] = new PropertyInfoRecord(name, STRING, false, // mustUseProperty + attributeName, 'http://www.w3.org/1999/xlink'); +}); +// String SVG attributes with the xml namespace. +['xml:base', 'xml:lang', 'xml:space'].forEach(function (attributeName) { + var name = attributeName.replace(CAMELIZE, capitalize); + properties[name] = new PropertyInfoRecord(name, STRING, false, // mustUseProperty + attributeName, 'http://www.w3.org/XML/1998/namespace'); +}); +// Special case: this attribute exists both in HTML and SVG. +// Its "tabindex" attribute name is case-sensitive in SVG so we can't just use +// its React `tabIndex` name, like we do for attributes that exist only in HTML. +properties.tabIndex = new PropertyInfoRecord('tabIndex', STRING, false, // mustUseProperty +'tabindex', // attributeName +null); /** * Get the value for a property on a node. Only used in DEV for SSR validation. * The "expected" argument is used as a hint of what the expected value is. * Some properties have multiple equivalent values. */ -function getValueForProperty(node, name, expected) { +function getValueForProperty(node, name, expected, propertyInfo) { { - var propertyInfo = getPropertyInfo(name); - if (propertyInfo) { - var mutationMethod = propertyInfo.mutationMethod; - if (mutationMethod || propertyInfo.mustUseProperty) { - return node[propertyInfo.propertyName]; - } else { - var attributeName = propertyInfo.attributeName; + if (propertyInfo.mustUseProperty) { + var propertyName = propertyInfo.propertyName; - var stringValue = null; + return node[propertyName]; + } else { + var attributeName = propertyInfo.attributeName; - if (propertyInfo.hasOverloadedBooleanValue) { - if (node.hasAttribute(attributeName)) { - var value = node.getAttribute(attributeName); - if (value === '') { - return true; - } - if (shouldIgnoreValue(propertyInfo, expected)) { - return value; - } - if (value === '' + expected) { - return expected; - } - return value; + var stringValue = null; + + if (propertyInfo.type === OVERLOADED_BOOLEAN) { + if (node.hasAttribute(attributeName)) { + var value = node.getAttribute(attributeName); + if (value === '') { + return true; } - } else if (node.hasAttribute(attributeName)) { - if (shouldIgnoreValue(propertyInfo, expected)) { - // We had an attribute but shouldn't have had one, so read it - // for the error message. - return node.getAttribute(attributeName); + if (shouldRemoveAttribute(name, expected, propertyInfo, false)) { + return value; } - if (propertyInfo.hasBooleanValue) { - // If this was a boolean, it doesn't matter what the value is - // the fact that we have it is the same as the expected. + if (value === '' + expected) { return expected; } - // Even if this property uses a namespace we use getAttribute - // because we assume its namespaced name is the same as our config. - // To use getAttributeNS we need the local name which we don't have - // in our config atm. - stringValue = node.getAttribute(attributeName); + return value; } - - if (shouldIgnoreValue(propertyInfo, expected)) { - return stringValue === null ? expected : stringValue; - } else if (stringValue === '' + expected) { + } else if (node.hasAttribute(attributeName)) { + if (shouldRemoveAttribute(name, expected, propertyInfo, false)) { + // We had an attribute but shouldn't have had one, so read it + // for the error message. + return node.getAttribute(attributeName); + } + if (propertyInfo.type === BOOLEAN) { + // If this was a boolean, it doesn't matter what the value is + // the fact that we have it is the same as the expected. return expected; - } else { - return stringValue; } + // Even if this property uses a namespace we use getAttribute + // because we assume its namespaced name is the same as our config. + // To use getAttributeNS we need the local name which we don't have + // in our config atm. + stringValue = node.getAttribute(attributeName); + } + + if (shouldRemoveAttribute(name, expected, propertyInfo, false)) { + return stringValue === null ? expected : stringValue; + } else if (stringValue === '' + expected) { + return expected; + } else { + return stringValue; } } } @@ -62530,100 +55304,97 @@ function getValueForAttribute(node, name, expected) { * @param {string} name * @param {*} value */ -function setValueForProperty(node, name, value) { +function setValueForProperty(node, name, value, isCustomComponentTag) { var propertyInfo = getPropertyInfo(name); - - if (propertyInfo && shouldSetAttribute(name, value)) { - var mutationMethod = propertyInfo.mutationMethod; - if (mutationMethod) { - mutationMethod(node, value); - } else if (shouldIgnoreValue(propertyInfo, value)) { - deleteValueForProperty(node, name); - return; - } else if (propertyInfo.mustUseProperty) { - // Contrary to `setAttribute`, object properties are properly - // `toString`ed by IE8/9. - node[propertyInfo.propertyName] = value; - } else { - var attributeName = propertyInfo.attributeName; - var namespace = propertyInfo.attributeNamespace; - // `setAttribute` with objects becomes only `[object]` in IE8/9, - // ('' + value) makes it output the correct toString()-value. - if (namespace) { - node.setAttributeNS(namespace, attributeName, '' + value); - } else if (propertyInfo.hasBooleanValue || propertyInfo.hasOverloadedBooleanValue && value === true) { - node.setAttribute(attributeName, ''); + if (shouldIgnoreAttribute(name, propertyInfo, isCustomComponentTag)) { + return; + } + if (shouldRemoveAttribute(name, value, propertyInfo, isCustomComponentTag)) { + value = null; + } + // If the prop isn't in the special list, treat it as a simple attribute. + if (isCustomComponentTag || propertyInfo === null) { + if (isAttributeNameSafe(name)) { + var _attributeName = name; + if (value === null) { + node.removeAttribute(_attributeName); } else { - node.setAttribute(attributeName, '' + value); + node.setAttribute(_attributeName, '' + value); } } - } else { - setValueForAttribute(node, name, shouldSetAttribute(name, value) ? value : null); return; } + var mustUseProperty = propertyInfo.mustUseProperty; - { - - } -} + if (mustUseProperty) { + var propertyName = propertyInfo.propertyName; + + if (value === null) { + var type = propertyInfo.type; -function setValueForAttribute(node, name, value) { - if (!isAttributeNameSafe(name)) { + node[propertyName] = type === BOOLEAN ? false : ''; + } else { + // Contrary to `setAttribute`, object properties are properly + // `toString`ed by IE8/9. + node[propertyName] = value; + } return; } - if (value == null) { - node.removeAttribute(name); + // The rest are treated as attributes with special cases. + var attributeName = propertyInfo.attributeName, + attributeNamespace = propertyInfo.attributeNamespace; + + if (value === null) { + node.removeAttribute(attributeName); } else { - node.setAttribute(name, '' + value); - } + var _type = propertyInfo.type; - { - + var attributeValue = void 0; + if (_type === BOOLEAN || _type === OVERLOADED_BOOLEAN && value === true) { + attributeValue = ''; + } else { + // `setAttribute` with objects becomes only `[object]` in IE8/9, + // ('' + value) makes it output the correct toString()-value. + attributeValue = '' + value; + } + if (attributeNamespace) { + node.setAttributeNS(attributeNamespace, attributeName, attributeValue); + } else { + node.setAttribute(attributeName, attributeValue); + } } } -/** - * Deletes an attributes from a node. - * - * @param {DOMElement} node - * @param {string} name - */ -function deleteValueForAttribute(node, name) { - node.removeAttribute(name); +// Flow does not allow string concatenation of most non-string types. To work +// around this limitation, we use an opaque type that can only be obtained by +// passing the value through getToStringValue first. +function toString(value) { + return '' + value; } -/** - * Deletes the value for a property on a node. - * - * @param {DOMElement} node - * @param {string} name - */ -function deleteValueForProperty(node, name) { - var propertyInfo = getPropertyInfo(name); - if (propertyInfo) { - var mutationMethod = propertyInfo.mutationMethod; - if (mutationMethod) { - mutationMethod(node, undefined); - } else if (propertyInfo.mustUseProperty) { - var propName = propertyInfo.propertyName; - if (propertyInfo.hasBooleanValue) { - node[propName] = false; - } else { - node[propName] = ''; - } - } else { - node.removeAttribute(propertyInfo.attributeName); - } - } else { - node.removeAttribute(name); +function getToStringValue(value) { + switch (typeof value) { + case 'boolean': + case 'number': + case 'object': + case 'string': + case 'undefined': + return value; + default: + // function, symbol are assigned as empty strings + return ''; } } +var ReactDebugCurrentFrame$1 = null; + var ReactControlledValuePropTypes = { checkPropTypes: null }; { + ReactDebugCurrentFrame$1 = ReactSharedInternals.ReactDebugCurrentFrame; + var hasReadOnlyValue = { button: true, checkbox: true, @@ -62636,13 +55407,13 @@ var ReactControlledValuePropTypes = { var propTypes = { value: function (props, propName, componentName) { - if (!props[propName] || hasReadOnlyValue[props.type] || props.onChange || props.readOnly || props.disabled) { + if (hasReadOnlyValue[props.type] || props.onChange || props.readOnly || props.disabled || props[propName] == null) { return null; } return new Error('You provided a `value` prop to a form field without an ' + '`onChange` handler. This will render a read-only field. If ' + 'the field should be mutable use `defaultValue`. Otherwise, ' + 'set either `onChange` or `readOnly`.'); }, checked: function (props, propName, componentName) { - if (!props[propName] || props.onChange || props.readOnly || props.disabled) { + if (props.onChange || props.readOnly || props.disabled || props[propName] == null) { return null; } return new Error('You provided a `checked` prop to a form field without an ' + '`onChange` handler. This will render a read-only field. If ' + 'the field should be mutable use `defaultChecked`. Otherwise, ' + 'set either `onChange` or `readOnly`.'); @@ -62653,27 +55424,68 @@ var ReactControlledValuePropTypes = { * Provide a linked `value` attribute for controlled forms. You should not use * this outside of the ReactDOM controlled form components. */ - ReactControlledValuePropTypes.checkPropTypes = function (tagName, props, getStack) { - checkPropTypes(propTypes, props, 'prop', tagName, getStack); + ReactControlledValuePropTypes.checkPropTypes = function (tagName, props) { + checkPropTypes(propTypes, props, 'prop', tagName, ReactDebugCurrentFrame$1.getStackAddendum); }; } -// TODO: direct imports like some-package/src/* are bad. Fix me. -var getCurrentFiberOwnerName$2 = ReactDebugCurrentFiber.getCurrentFiberOwnerName; -var getCurrentFiberStackAddendum$3 = ReactDebugCurrentFiber.getCurrentFiberStackAddendum; +var enableUserTimingAPI = true; -var didWarnValueDefaultValue = false; -var didWarnCheckedDefaultChecked = false; -var didWarnControlledToUncontrolled = false; -var didWarnUncontrolledToControlled = false; +var enableHooks = false; +// Helps identify side effects in begin-phase lifecycle hooks and setState reducers: +var debugRenderPhaseSideEffects = false; -function isControlled(props) { - var usesChecked = props.type === 'checkbox' || props.type === 'radio'; - return usesChecked ? props.checked != null : props.value != null; -} +// In some cases, StrictMode should also double-render lifecycles. +// This can be confusing for tests though, +// And it can be bad for performance in production. +// This feature flag can be used to control the behavior: +var debugRenderPhaseSideEffectsForStrictMode = true; -/** - * Implements an host component that allows setting these optional +// To preserve the "Pause on caught exceptions" behavior of the debugger, we +// replay the begin phase of a failed component inside invokeGuardedCallback. +var replayFailedUnitOfWorkWithInvokeGuardedCallback = true; + +// Warn about deprecated, async-unsafe lifecycles; relates to RFC #6: +var warnAboutDeprecatedLifecycles = false; + +// Gather advanced timing metrics for Profiler subtrees. +var enableProfilerTimer = true; + +// Trace which interactions trigger each commit. +var enableSchedulerTracing = true; + +// Only used in www builds. + // TODO: true? Here it might just be false. + +// Only used in www builds. + + +// Only used in www builds. + + +// React Fire: prevent the value and checked attributes from syncing +// with their related DOM properties +var disableInputAttributeSyncing = false; + +// These APIs will no longer be "unstable" in the upcoming 16.7 release, +// Control this behavior with a flag to support 16.6 minor releases in the meanwhile. +var enableStableConcurrentModeAPIs = false; + +var warnAboutShorthandPropertyCollision = false; + +// TODO: direct imports like some-package/src/* are bad. Fix me. +var didWarnValueDefaultValue = false; +var didWarnCheckedDefaultChecked = false; +var didWarnControlledToUncontrolled = false; +var didWarnUncontrolledToControlled = false; + +function isControlled(props) { + var usesChecked = props.type === 'checkbox' || props.type === 'radio'; + return usesChecked ? props.checked != null : props.value != null; +} + +/** + * Implements an host component that allows setting these optional * props: `checked`, `value`, `defaultChecked`, and `defaultValue`. * * If `checked` or `value` are not supplied (or null/undefined), user actions @@ -62691,24 +55503,12 @@ function isControlled(props) { function getHostProps(element, props) { var node = element; - var value = props.value; var checked = props.checked; - var hostProps = _assign({ - // Make sure we set .type before any other properties (setting .value - // before .type means .value is lost in IE11 and below) - type: undefined, - // Make sure we set .step before .value (setting .value before .step - // means .value is rounded on mount, based upon step precision) - step: undefined, - // Make sure we set .min & .max before .value (to ensure proper order - // in corner cases such as min or max deriving from value, e.g. Issue #7170) - min: undefined, - max: undefined - }, props, { + var hostProps = _assign({}, props, { defaultChecked: undefined, defaultValue: undefined, - value: value != null ? value : node._wrapperState.initialValue, + value: undefined, checked: checked != null ? checked : node._wrapperState.initialChecked }); @@ -62717,23 +55517,24 @@ function getHostProps(element, props) { function initWrapperState(element, props) { { - ReactControlledValuePropTypes.checkPropTypes('input', props, getCurrentFiberStackAddendum$3); + ReactControlledValuePropTypes.checkPropTypes('input', props); if (props.checked !== undefined && props.defaultChecked !== undefined && !didWarnCheckedDefaultChecked) { - warning(false, '%s contains an input of type %s with both checked and defaultChecked props. ' + 'Input elements must be either controlled or uncontrolled ' + '(specify either the checked prop, or the defaultChecked prop, but not ' + 'both). Decide between using a controlled or uncontrolled input ' + 'element and remove one of these props. More info: ' + 'https://fb.me/react-controlled-components', getCurrentFiberOwnerName$2() || 'A component', props.type); + warning$1(false, '%s contains an input of type %s with both checked and defaultChecked props. ' + 'Input elements must be either controlled or uncontrolled ' + '(specify either the checked prop, or the defaultChecked prop, but not ' + 'both). Decide between using a controlled or uncontrolled input ' + 'element and remove one of these props. More info: ' + 'https://fb.me/react-controlled-components', getCurrentFiberOwnerNameInDevOrNull() || 'A component', props.type); didWarnCheckedDefaultChecked = true; } if (props.value !== undefined && props.defaultValue !== undefined && !didWarnValueDefaultValue) { - warning(false, '%s contains an input of type %s with both value and defaultValue props. ' + 'Input elements must be either controlled or uncontrolled ' + '(specify either the value prop, or the defaultValue prop, but not ' + 'both). Decide between using a controlled or uncontrolled input ' + 'element and remove one of these props. More info: ' + 'https://fb.me/react-controlled-components', getCurrentFiberOwnerName$2() || 'A component', props.type); + warning$1(false, '%s contains an input of type %s with both value and defaultValue props. ' + 'Input elements must be either controlled or uncontrolled ' + '(specify either the value prop, or the defaultValue prop, but not ' + 'both). Decide between using a controlled or uncontrolled input ' + 'element and remove one of these props. More info: ' + 'https://fb.me/react-controlled-components', getCurrentFiberOwnerNameInDevOrNull() || 'A component', props.type); didWarnValueDefaultValue = true; } } - var defaultValue = props.defaultValue; var node = element; + var defaultValue = props.defaultValue == null ? '' : props.defaultValue; + node._wrapperState = { initialChecked: props.checked != null ? props.checked : props.defaultChecked, - initialValue: props.value != null ? props.value : defaultValue, + initialValue: getToStringValue(props.value != null ? props.value : defaultValue), controlled: isControlled(props) }; } @@ -62742,98 +55543,150 @@ function updateChecked(element, props) { var node = element; var checked = props.checked; if (checked != null) { - setValueForProperty(node, 'checked', checked); + setValueForProperty(node, 'checked', checked, false); } } function updateWrapper(element, props) { var node = element; { - var controlled = isControlled(props); + var _controlled = isControlled(props); - if (!node._wrapperState.controlled && controlled && !didWarnUncontrolledToControlled) { - warning(false, 'A component is changing an uncontrolled input of type %s to be controlled. ' + 'Input elements should not switch from uncontrolled to controlled (or vice versa). ' + 'Decide between using a controlled or uncontrolled input ' + 'element for the lifetime of the component. More info: https://fb.me/react-controlled-components%s', props.type, getCurrentFiberStackAddendum$3()); + if (!node._wrapperState.controlled && _controlled && !didWarnUncontrolledToControlled) { + warning$1(false, 'A component is changing an uncontrolled input of type %s to be controlled. ' + 'Input elements should not switch from uncontrolled to controlled (or vice versa). ' + 'Decide between using a controlled or uncontrolled input ' + 'element for the lifetime of the component. More info: https://fb.me/react-controlled-components', props.type); didWarnUncontrolledToControlled = true; } - if (node._wrapperState.controlled && !controlled && !didWarnControlledToUncontrolled) { - warning(false, 'A component is changing a controlled input of type %s to be uncontrolled. ' + 'Input elements should not switch from controlled to uncontrolled (or vice versa). ' + 'Decide between using a controlled or uncontrolled input ' + 'element for the lifetime of the component. More info: https://fb.me/react-controlled-components%s', props.type, getCurrentFiberStackAddendum$3()); + if (node._wrapperState.controlled && !_controlled && !didWarnControlledToUncontrolled) { + warning$1(false, 'A component is changing a controlled input of type %s to be uncontrolled. ' + 'Input elements should not switch from controlled to uncontrolled (or vice versa). ' + 'Decide between using a controlled or uncontrolled input ' + 'element for the lifetime of the component. More info: https://fb.me/react-controlled-components', props.type); didWarnControlledToUncontrolled = true; } } updateChecked(element, props); - var value = props.value; + var value = getToStringValue(props.value); + var type = props.type; + if (value != null) { - if (value === 0 && node.value === '') { - node.value = '0'; - // Note: IE9 reports a number inputs as 'text', so check props instead. - } else if (props.type === 'number') { - // Simulate `input.valueAsNumber`. IE9 does not support it - var valueAsNumber = parseFloat(node.value) || 0; - - if ( + if (type === 'number') { + if (value === 0 && node.value === '' || + // We explicitly want to coerce to number here if possible. // eslint-disable-next-line - value != valueAsNumber || - // eslint-disable-next-line - value == valueAsNumber && node.value != value) { - // Cast `value` to a string to ensure the value is set correctly. While - // browsers typically do this as necessary, jsdom doesn't. - node.value = '' + value; + node.value != value) { + node.value = toString(value); } - } else if (node.value !== '' + value) { - // Cast `value` to a string to ensure the value is set correctly. While - // browsers typically do this as necessary, jsdom doesn't. - node.value = '' + value; + } else if (node.value !== toString(value)) { + node.value = toString(value); + } + } else if (type === 'submit' || type === 'reset') { + // Submit/reset inputs need the attribute removed completely to avoid + // blank-text buttons. + node.removeAttribute('value'); + return; + } + + if (disableInputAttributeSyncing) { + // When not syncing the value attribute, React only assigns a new value + // whenever the defaultValue React prop has changed. When not present, + // React does nothing + if (props.hasOwnProperty('defaultValue')) { + setDefaultValue(node, props.type, getToStringValue(props.defaultValue)); } } else { - if (props.value == null && props.defaultValue != null) { - // In Chrome, assigning defaultValue to certain input types triggers input validation. - // For number inputs, the display value loses trailing decimal points. For email inputs, - // Chrome raises "The specified value is not a valid email address". - // - // Here we check to see if the defaultValue has actually changed, avoiding these problems - // when the user is inputting text - // - // https://github.com/facebook/react/issues/7253 - if (node.defaultValue !== '' + props.defaultValue) { - node.defaultValue = '' + props.defaultValue; - } + // When syncing the value attribute, the value comes from a cascade of + // properties: + // 1. The value React property + // 2. The defaultValue React property + // 3. Otherwise there should be no change + if (props.hasOwnProperty('value')) { + setDefaultValue(node, props.type, value); + } else if (props.hasOwnProperty('defaultValue')) { + setDefaultValue(node, props.type, getToStringValue(props.defaultValue)); + } + } + + if (disableInputAttributeSyncing) { + // When not syncing the checked attribute, the attribute is directly + // controllable from the defaultValue React property. It needs to be + // updated as new props come in. + if (props.defaultChecked == null) { + node.removeAttribute('checked'); + } else { + node.defaultChecked = !!props.defaultChecked; } + } else { + // When syncing the checked attribute, it only changes when it needs + // to be removed, such as transitioning from a checkbox into a text input if (props.checked == null && props.defaultChecked != null) { node.defaultChecked = !!props.defaultChecked; } } } -function postMountWrapper(element, props) { +function postMountWrapper(element, props, isHydrating) { var node = element; - // Detach value from defaultValue. We won't do anything if we're working on - // submit or reset inputs as those values & defaultValues are linked. They - // are not resetable nodes so this operation doesn't matter and actually - // removes browser-default values (eg "Submit Query") when no value is - // provided. + // Do not assign value if it is already set. This prevents user text input + // from being lost during SSR hydration. + if (props.hasOwnProperty('value') || props.hasOwnProperty('defaultValue')) { + var type = props.type; + var isButton = type === 'submit' || type === 'reset'; - switch (props.type) { - case 'submit': - case 'reset': - break; - case 'color': - case 'date': - case 'datetime': - case 'datetime-local': - case 'month': - case 'time': - case 'week': - // This fixes the no-show issue on iOS Safari and Android Chrome: - // https://github.com/facebook/react/issues/7233 - node.value = ''; - node.value = node.defaultValue; - break; - default: - node.value = node.value; - break; + // Avoid setting value attribute on submit/reset inputs as it overrides the + // default value provided by the browser. See: #12872 + if (isButton && (props.value === undefined || props.value === null)) { + return; + } + + var _initialValue = toString(node._wrapperState.initialValue); + + // Do not assign value if it is already set. This prevents user text input + // from being lost during SSR hydration. + if (!isHydrating) { + if (disableInputAttributeSyncing) { + var value = getToStringValue(props.value); + + // When not syncing the value attribute, the value property points + // directly to the React prop. Only assign it if it exists. + if (value != null) { + // Always assign on buttons so that it is possible to assign an + // empty string to clear button text. + // + // Otherwise, do not re-assign the value property if is empty. This + // potentially avoids a DOM write and prevents Firefox (~60.0.1) from + // prematurely marking required inputs as invalid. Equality is compared + // to the current value in case the browser provided value is not an + // empty string. + if (isButton || value !== node.value) { + node.value = toString(value); + } + } + } else { + // When syncing the value attribute, the value property should use + // the wrapperState._initialValue property. This uses: + // + // 1. The value React property when present + // 2. The defaultValue React property when present + // 3. An empty string + if (_initialValue !== node.value) { + node.value = _initialValue; + } + } + } + + if (disableInputAttributeSyncing) { + // When not syncing the value attribute, assign the value attribute + // directly from the defaultValue React property (when present) + var defaultValue = getToStringValue(props.defaultValue); + if (defaultValue != null) { + node.defaultValue = toString(defaultValue); + } + } else { + // Otherwise, the value attribute is synchronized to the property, + // so we assign defaultValue to the same thing as the value property + // assignment step above. + node.defaultValue = _initialValue; + } } // Normally, we'd just do `node.checked = node.checked` upon initial mount, less this bug @@ -62845,14 +55698,40 @@ function postMountWrapper(element, props) { if (name !== '') { node.name = ''; } - node.defaultChecked = !node.defaultChecked; - node.defaultChecked = !node.defaultChecked; + + if (disableInputAttributeSyncing) { + // When not syncing the checked attribute, the checked property + // never gets assigned. It must be manually set. We don't want + // to do this when hydrating so that existing user input isn't + // modified + if (!isHydrating) { + updateChecked(element, props); + } + + // Only assign the checked attribute if it is defined. This saves + // a DOM write when controlling the checked attribute isn't needed + // (text inputs, submit/reset) + if (props.hasOwnProperty('defaultChecked')) { + node.defaultChecked = !node.defaultChecked; + node.defaultChecked = !!props.defaultChecked; + } + } else { + // When syncing the checked attribute, both the checked property and + // attribute are assigned at the same time using defaultChecked. This uses: + // + // 1. The checked React property when present + // 2. The defaultChecked React property when present + // 3. Otherwise, false + node.defaultChecked = !node.defaultChecked; + node.defaultChecked = !!node._wrapperState.initialChecked; + } + if (name !== '') { node.name = name; } } -function restoreControlledState$1(element, props) { +function restoreControlledState(element, props) { var node = element; updateWrapper(node, props); updateNamedCousins(node, props); @@ -62900,986 +55779,3173 @@ function updateNamedCousins(rootNode, props) { } } -function flattenChildren(children) { - var content = ''; - - // Flatten children and warn if they aren't strings or numbers; - // invalid types are ignored. - // We can silently skip them because invalid DOM nesting warning - // catches these cases in Fiber. - React.Children.forEach(children, function (child) { - if (child == null) { - return; - } - if (typeof child === 'string' || typeof child === 'number') { - content += child; +// In Chrome, assigning defaultValue to certain input types triggers input validation. +// For number inputs, the display value loses trailing decimal points. For email inputs, +// Chrome raises "The specified value is not a valid email address". +// +// Here we check to see if the defaultValue has actually changed, avoiding these problems +// when the user is inputting text +// +// https://github.com/facebook/react/issues/7253 +function setDefaultValue(node, type, value) { + if ( + // Focused number inputs synchronize on blur. See ChangeEventPlugin.js + type !== 'number' || node.ownerDocument.activeElement !== node) { + if (value == null) { + node.defaultValue = toString(node._wrapperState.initialValue); + } else if (node.defaultValue !== toString(value)) { + node.defaultValue = toString(value); } - }); - - return content; + } } +var eventTypes$1 = { + change: { + phasedRegistrationNames: { + bubbled: 'onChange', + captured: 'onChangeCapture' + }, + dependencies: [TOP_BLUR, TOP_CHANGE, TOP_CLICK, TOP_FOCUS, TOP_INPUT, TOP_KEY_DOWN, TOP_KEY_UP, TOP_SELECTION_CHANGE] + } +}; + +function createAndAccumulateChangeEvent(inst, nativeEvent, target) { + var event = SyntheticEvent.getPooled(eventTypes$1.change, inst, nativeEvent, target); + event.type = 'change'; + // Flag this event loop as needing state restore. + enqueueStateRestore(target); + accumulateTwoPhaseDispatches(event); + return event; +} /** - * Implements an