PageSourceSearch

https://www.eolas.co.jp/wp-content/plugins/wpvr/public/lib/videojs-vr/videojs-vr.js?ver=1

js eolas.co.jp collected 2026-10-04 00:59:03 UTC 1,384,429 bytes, 52,731 lines download raw bytes

1/*! @name videojs-vr @version 1.7.2 @license Apache-2.0 */
2(function (global, factory) {
3	typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('global/window'), require('global/document'), require('video.js')) :
4	typeof define === 'function' && define.amd ? define(['global/window', 'global/document', 'video.js'], factory) :
5	(global = global || self, global.videojsVr = factory(global.window, global.document, global.videojs));
6  }(this, (function (window$1, document$1, videojs) { 'use strict';
7  
8	window$1 = window$1 && window$1.hasOwnProperty('default') ? window$1['default'] : window$1;
9	document$1 = document$1 && document$1.hasOwnProperty('default') ? document$1['default'] : document$1;
10	videojs = videojs && videojs.hasOwnProperty('default') ? videojs['default'] : videojs;
11  
12	function _assertThisInitialized(self) {
13	  if (self === void 0) {
14		throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
15	  }
16  
17	  return self;
18	}
19  
20	var assertThisInitialized = _assertThisInitialized;
21  
22	function _inheritsLoose(subClass, superClass) {
23	  subClass.prototype = Object.create(superClass.prototype);
24	  subClass.prototype.constructor = subClass;
25	  subClass.__proto__ = superClass;
26	}
27  
28	var inheritsLoose = _inheritsLoose;
29  
30	var version = "1.7.2";
31  
32	var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
33  
34	function unwrapExports (x) {
35		return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
36	}
37  
38	function createCommonjsModule(fn, module) {
39		return module = { exports: {} }, fn(module, module.exports), module.exports;
40	}
41  
42	var webvrPolyfill = createCommonjsModule(function (module, exports) {
43	/**
44	 * @license
45	 * webvr-polyfill
46	 * Copyright (c) 2015-2017 Google
47	 * Licensed under the Apache License, Version 2.0 (the "License");
48	 * you may not use this file except in compliance with the License.
49	 * You may obtain a copy of the License at
50	 *
51	 * http://www.apache.org/licenses/LICENSE-2.0
52	 *
53	 * Unless required by applicable law or agreed to in writing, software
54	 * distributed under the License is distributed on an "AS IS" BASIS,
55	 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
56	 * See the License for the specific language governing permissions and
57	 * limitations under the License.
58	 */
59  
60	/**
61	 * @license
62	 * cardboard-vr-display
63	 * Copyright (c) 2015-2017 Google
64	 * Licensed under the Apache License, Version 2.0 (the "License");
65	 * you may not use this file except in compliance with the License.
66	 * You may obtain a copy of the License at
67	 *
68	 * http://www.apache.org/licenses/LICENSE-2.0
69	 *
70	 * Unless required by applicable law or agreed to in writing, software
71	 * distributed under the License is distributed on an "AS IS" BASIS,
72	 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
73	 * See the License for the specific language governing permissions and
74	 * limitations under the License.
75	 */
76  
77	/**
78	 * @license
79	 * webvr-polyfill-dpdb 
80	 * Copyright (c) 2017 Google
81	 * Licensed under the Apache License, Version 2.0 (the "License");
82	 * you may not use this file except in compliance with the License.
83	 * You may obtain a copy of the License at
84	 *
85	 * http://www.apache.org/licenses/LICENSE-2.0
86	 *
87	 * Unless required by applicable law or agreed to in writing, software
88	 * distributed under the License is distributed on an "AS IS" BASIS,
89	 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
90	 * See the License for the specific language governing permissions and
91	 * limitations under the License.
92	 */
93  
94	/**
95	 * @license
96	 * wglu-preserve-state
97	 * Copyright (c) 2016, Brandon Jones.
98	 *
99	 * Permission is hereby granted, free of charge, to any person obtaining a copy
100	 * of this software and associated documentation files (the "Software"), to deal
101	 * in the Software without restriction, including without limitation the rights
102	 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
103	 * copies of the Software, and to permit persons to whom the Software is
104	 * furnished to do so, subject to the following conditions:
105	 *
106	 * The above copyright notice and this permission notice shall be included in
107	 * all copies or substantial portions of the Software.
108	 *
109	 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
110	 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
111	 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
112	 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
113	 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
114	 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
115	 * THE SOFTWARE.
116	 */
117  
118	/**
119	 * @license
120	 * nosleep.js
121	 * Copyright (c) 2017, Rich Tibbett
122	 *
123	 * Permission is hereby granted, free of charge, to any person obtaining a copy
124	 * of this software and associated documentation files (the "Software"), to deal
125	 * in the Software without restriction, including without limitation the rights
126	 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
127	 * copies of the Software, and to permit persons to whom the Software is
128	 * furnished to do so, subject to the following conditions:
129	 *
130	 * The above copyright notice and this permission notice shall be included in
131	 * all copies or substantial portions of the Software.
132	 *
133	 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
134	 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
135	 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
136	 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
137	 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
138	 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
139	 * THE SOFTWARE.
140	 */
141  
142	(function (global, factory) {
143		 module.exports = factory() ;
144	}(commonjsGlobal, (function () {
145	var commonjsGlobal$1 = typeof window !== 'undefined' ? window : typeof commonjsGlobal !== 'undefined' ? commonjsGlobal : typeof self !== 'undefined' ? self : {};
146  
147  
148  
149	function unwrapExports (x) {
150		return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
151	}
152  
153	function createCommonjsModule(fn, module) {
154		return module = { exports: {} }, fn(module, module.exports), module.exports;
155	}
156  
157	var race = function race(promises) {
158	  if (Promise.race) {
159		return Promise.race(promises);
160	  }
161	  return new Promise(function (resolve, reject) {
162		for (var i = 0; i < promises.length; i++) {
163		  promises[i].then(resolve, reject);
164		}
165	  });
166	};
167  
168	var isMobile = function isMobile() {
169	  return (/Android/i.test(navigator.userAgent) || /iPhone|iPad|iPod/i.test(navigator.userAgent)
170	  );
171	};
172	var copyArray = function copyArray(source, dest) {
173	  for (var i = 0, n = source.length; i < n; i++) {
174		dest[i] = source[i];
175	  }
176	};
177	var extend = function extend(dest, src) {
178	  for (var key in src) {
179		if (src.hasOwnProperty(key)) {
180		  dest[key] = src[key];
181		}
182	  }
183	  return dest;
184	};
185  
186	var cardboardVrDisplay = createCommonjsModule(function (module, exports
186) {
187	/**
188	 * @license
189	 * cardboard-vr-display
190	 * Copyright (c) 2015-2017 Google
191	 * Licensed under the Apache License, Version 2.0 (the "License");
192	 * you may not use this file except in compliance with the License.
193	 * You may obtain a copy of the License at
194	 *
195	 * http://www.apache.org/licenses/LICENSE-2.0
196	 *
197	 * Unless required by applicable law or agreed to in writing, software
198	 * distributed under the License is distributed on an "AS IS" BASIS,
199	 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200	 * See the License for the specific language governing permissions and
201	 * limitations under the License.
202	 */
203	/**
204	 * @license
205	 * gl-preserve-state
206	 * Copyright (c) 2016, Brandon Jones.
207	 *
208	 * Permission is hereby granted, free of charge, to any person obtaining a copy
209	 * of this software and associated documentation files (the "Software"), to deal
210	 * in the Software without restriction, including without limitation the rights
211	 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
212	 * copies of the Software, and to permit persons to whom the Software is
213	 * furnished to do so, subject to the following conditions:
214	 *
215	 * The above copyright notice and this permission notice shall be included in
216	 * all copies or substantial portions of the Software.
217	 *
218	 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
219	 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
220	 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
221	 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
222	 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
223	 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
224	 * THE SOFTWARE.
225	 */
226	/**
227	 * @license
228	 * webvr-polyfill-dpdb
229	 * Copyright (c) 2015-2017 Google
230	 * Licensed under the Apache License, Version 2.0 (the "License");
231	 * you may not use this file except in compliance with the License.
232	 * You may obtain a copy of the License at
233	 *
234	 * http://www.apache.org/licenses/LICENSE-2.0
235	 *
236	 * Unless required by applicable law or agreed to in writing, software
237	 * distributed under the License is distributed on an "AS IS" BASIS,
238	 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
239	 * See the License for the specific language governing permissions and
240	 * limitations under the License.
241	 */
242	/**
243	 * @license
244	 * nosleep.js
245	 * Copyright (c) 2017, Rich Tibbett
246	 *
247	 * Permission is hereby granted, free of charge, to any person obtaining a copy
248	 * of this software and associated documentation files (the "Software"), to deal
249	 * in the Software without restriction, including without limitation the rights
250	 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
251	 * copies of the Software, and to permit persons to whom the Software is
252	 * furnished to do so, subject to the following conditions:
253	 *
254	 * The above copyright notice and this permission notice shall be included in
255	 * all copies or substantial portions of the Software.
256	 *
257	 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
258	 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
259	 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
260	 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
261	 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
262	 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
263	 * THE SOFTWARE.
264	 */
265	(function (global, factory) {
266		module.exports = factory();
267	}(commonjsGlobal$1, (function () { var classCallCheck = function (instance, Constructor) {
268	  if (!(instance instanceof Constructor)) {
269		throw new TypeError("Cannot call a class as a function");
270	  }
271	};
272	var createClass = function () {
273	  function defineProperties(target, props) {
274		for (var i = 0; i < props.length; i++) {
275		  var descriptor = props[i];
276		  descriptor.enumerable = descriptor.enumerable || false;
277		  descriptor.configurable = true;
278		  if ("value" in descriptor) descriptor.writable = true;
vendor: 26,977 bytes, lines 279-1033
279		  Object.defineProperty(target, descriptor.key, descriptor);
280		}
281	  }
282	  return function (Constructor, protoProps, staticProps) {
283		if (protoProps) defineProperties(Constructor.prototype, protoProps);
284		if (staticProps) defineProperties(Constructor, staticProps);
285		return Constructor;
286	  };
287	}();
288	var slicedToArray = function () {
289	  function sliceIterator(arr, i) {
290		var _arr = [];
291		var _n = true;
292		var _d = false;
293		var _e = undefined;
294		try {
295		  for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) {
296			_arr.push(_s.value);
297			if (i && _arr.length === i) break;
298		  }
299		} catch (err) {
300		  _d = true;
301		  _e = err;
302		} finally {
303		  try {
304			if (!_n && _i["return"]) _i["return"]();
305		  } finally {
306			if (_d) throw _e;
307		  }
308		}
309		return _arr;
310	  }
311	  return function (arr, i) {
312		if (Array.isArray(arr)) {
313		  return arr;
314		} else if (Symbol.iterator in Object(arr)) {
315		  return sliceIterator(arr, i);
316		} else {
317		  throw new TypeError("Invalid attempt to destructure non-iterable instance");
318		}
319	  };
320	}();
321	var MIN_TIMESTEP = 0.001;
322	var MAX_TIMESTEP = 1;
323	var base64 = function base64(mimeType, _base) {
324	  return 'data:' + mimeType + ';base64,' + _base;
325	};
326	var lerp = function lerp(a, b, t) {
327	  return a + (b - a) * t;
328	};
329	var isIOS = function () {
330	  var isIOS = /iPad|iPhone|iPod/.test(navigator.platform);
331	  return function () {
332		return isIOS;
333	  };
334	}();
335	var isWebViewAndroid = function () {
336	  var isWebViewAndroid = navigator.userAgent.indexOf('Version') !== -1 && navigator.userAgent.indexOf('Android') !== -1 && navigator.userAgent.indexOf('Chrome') !== -1;
337	  return function () {
338		return isWebViewAndroid;
339	  };
340	}();
341	var isSafari = function () {
342	  var isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
343	  return function () {
344		return isSafari;
345	  };
346	}();
347	var isFirefoxAndroid = function () {
348	  var isFirefoxAndroid = navigator.userAgent.indexOf('Firefox') !== -1 && navigator.userAgent.indexOf('Android') !== -1;
349	  return function () {
350		return isFirefoxAndroid;
351	  };
352	}();
353	var getChromeVersion = function () {
354	  var match = navigator.userAgent.match(/.*Chrome\/([0-9]+)/);
355	  var value = match ? parseInt(match[1], 10) : null;
356	  return function () {
357		return value;
358	  };
359	}();
360	var isChromeWithoutDeviceMotion = function () {
361	  var value = false;
362	  if (getChromeVersion() === 65) {
363		var match = navigator.userAgent.match(/.*Chrome\/([0-9\.]*)/);
364		if (match) {
365		  var _match$1$split = match[1].split('.'),
366			  _match$1$split2 = slicedToArray(_match$1$split, 4),
367			  major = _match$1$split2[0],
368			  minor = _match$1$split2[1],
369			  branch = _match$1$split2[2],
370			  build = _match$1$split2[3];
371		  value = parseInt(branch, 10) === 3325 && parseInt(build, 10) < 148;
372		}
373	  }
374	  return function () {
375		return value;
376	  };
377	}();
378	var isR7 = function () {
379	  var isR7 = navigator.userAgent.indexOf('R7 Build') !== -1;
380	  return function () {
381		return isR7;
382	  };
383	}();
384	var isLandscapeMode = function isLandscapeMode() {
385	  var rtn = window.orientation == 90 || window.orientation == -90;
386	  return isR7() ? !rtn : rtn;
387	};
388	var isTimestampDeltaValid = function isTimestampDeltaValid(timestampDeltaS) {
389	  if (isNaN(timestampDeltaS)) {
390		return false;
391	  }
392	  if (timestampDeltaS <= MIN_TIMESTEP) {
393		return false;
394	  }
395	  if (timestampDeltaS > MAX_TIMESTEP) {
396		return false;
397	  }
398	  return true;
399	};
400	var getScreenWidth = function getScreenWidth() {
401	  return Math.max(window.screen.width, window.screen.height) * window.devicePixelRatio;
402	};
403	var getScreenHeight = function getScreenHeight() {
404	  return Math.min(window.screen.width, window.screen.height) * window.devicePixelRatio;
405	};
406	var requestFullscreen = function requestFullscreen(element) {
407	  if (isWebViewAndroid()) {
408		return false;
409	  }
410	  if (element.requestFullscreen) {
411		element.requestFullscreen();
412	  } else if (element.webkitRequestFullscreen) {
413		element.webkitRequestFullscreen();
414	  } else if (element.mozRequestFullScreen) {
415		element.mozRequestFullScreen();
416	  } else if (element.msRequestFullscreen) {
417		element.msRequestFullscreen();
418	  } else {
419		return false;
420	  }
421	  return true;
422	};
423	var exitFullscreen = function exitFullscreen() {
424	  if (document.exitFullscreen) {
425		document.exitFullscreen();
426	  } else if (document.webkitExitFullscreen) {
427		document.webkitExitFullscreen();
428	  } else if (document.mozCancelFullScreen) {
429		document.mozCancelFullScreen();
430	  } else if (document.msExitFullscreen) {
431		document.msExitFullscreen();
432	  } else {
433		return false;
434	  }
435	  return true;
436	};
437	var getFullscreenElement = function getFullscreenElement() {
438	  return document.fullscreenElement || document.webkitFullscreenElement || document.mozFullScreenElement || document.msFullscreenElement;
439	};
440	var linkProgram = function linkProgram(gl, vertexSource, fragmentSource, attribLocationMap) {
441	  var vertexShader = gl.createShader(gl.VERTEX_SHADER);
442	  gl.shaderSource(vertexShader, vertexSource);
443	  gl.compileShader(vertexShader);
444	  var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
445	  gl.shaderSource(fragmentShader, fragmentSource);
446	  gl.compileShader(fragmentShader);
447	  var program = gl.createProgram();
448	  gl.attachShader(program, vertexShader);
449	  gl.attachShader(program, fragmentShader);
450	  for (var attribName in attribLocationMap) {
451		gl.bindAttribLocation(program, attribLocationMap[attribName], attribName);
452	  }gl.linkProgram(program);
453	  gl.deleteShader(vertexShader);
454	  gl.deleteShader(fragmentShader);
455	  return program;
456	};
457	var getProgramUniforms = function getProgramUniforms(gl, program) {
458	  var uniforms = {};
459	  var uniformCount = gl.getProgramParameter(program, gl.ACTIVE_UNIFORMS);
460	  var uniformName = '';
461	  for (var i = 0; i < uniformCount; i++) {
462		var uniformInfo = gl.getActiveUniform(program, i);
463		uniformName = uniformInfo.name.replace('[0]', '');
464		uniforms[uniformName] = gl.getUniformLocation(program, uniformName);
465	  }
466	  return uniforms;
467	};
468	var orthoMatrix = function orthoMatrix(out, left, right, bottom, top, near, far) {
469	  var lr = 1 / (left - right),
470		  bt = 1 / (bottom - top),
471		  nf = 1 / (near - far);
472	  out[0] = -2 * lr;
473	  out[1] = 0;
474	  out[2] = 0;
475	  out[3] = 0;
476	  out[4] = 0;
477	  out[5] = -2 * bt;
478	  out[6] = 0;
479	  out[7] = 0;
480	  out[8] = 0;
481	  out[9] = 0;
482	  out[10] = 2 * nf;
483	  out[11] = 0;
484	  out[12] = (left + right) * lr;
485	  out[13] = (top + bottom) * bt;
486	  out[14] = (far + near) * nf;
487	  out[15] = 1;
488	  return out;
489	};
490	var isMobile = function isMobile() {
491	  var check = false;
492	  (function (a) {
493		if (/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(a) || /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0, 4))) check = true;
494	  })(navigator.userAgent || navigator.vendor || window.opera);
495	  return check;
496	};
497	var extend = function extend(dest, src) {
498	  for (var key in src) {
499		if (src.hasOwnProperty(key)) {
500		  dest[key] = src[key];
501		}
502	  }
503	  return dest;
504	};
505	var safariCssSizeWorkaround = function safariCssSizeWorkaround(canvas) {
506	  if (isIOS()) {
507		var width = canvas.style.width;
508		var height = canvas.style.height;
509		canvas.style.width = parseInt(width) + 1 + 'px';
510		canvas.style.height = parseInt(height) + 'px';
511		setTimeout(function () {
512		  canvas.style.width = width;
513		  canvas.style.height = height;
514		}, 100);
515	  }
516	  window.canvas = canvas;
517	};
518	var frameDataFromPose = function () {
519	  var piOver180 = Math.PI / 180.0;
520	  var rad45 = Math.PI * 0.25;
521	  function mat4_perspectiveFromFieldOfView(out, fov, near, far) {
522		var upTan = Math.tan(fov ? fov.upDegrees * piOver180 : rad45),
523			downTan = Math.tan(fov ? fov.downDegrees * piOver180 : rad45),
524			leftTan = Math.tan(fov ? fov.leftDegrees * piOver180 : rad45),
525			rightTan = Math.tan(fov ? fov.rightDegrees * piOver180 : rad45),
526			xScale = 2.0 / (leftTan + rightTan),
527			yScale = 2.0 / (upTan + downTan);
528		out[0] = xScale;
529		out[1] = 0.0;
530		out[2] = 0.0;
531		out[3] = 0.0;
532		out[4] = 0.0;
533		out[5] = yScale;
534		out[6] = 0.0;
535		out[7] = 0.0;
536		out[8] = -((leftTan - rightTan) * xScale * 0.5);
537		out[9] = (upTan - downTan) * yScale * 0.5;
538		out[10] = far / (near - far);
539		out[11] = -1.0;
540		out[12] = 0.0;
541		out[13] = 0.0;
542		out[14] = far * near / (near - far);
543		out[15] = 0.0;
544		return out;
545	  }
546	  function mat4_fromRotationTranslation(out, q, v) {
547		var x = q[0],
548			y = q[1],
549			z = q[2],
550			w = q[3],
551			x2 = x + x,
552			y2 = y + y,
553			z2 = z + z,
554			xx = x * x2,
555			xy = x * y2,
556			xz = x * z2,
557			yy = y * y2,
558			yz = y * z2,
559			zz = z * z2,
560			wx = w * x2,
561			wy = w * y2,
562			wz = w * z2;
563		out[0] = 1 - (yy + zz);
564		out[1] = xy + wz;
565		out[2] = xz - wy;
566		out[3] = 0;
567		out[4] = xy - wz;
568		out[5] = 1 - (xx + zz);
569		out[6] = yz + wx;
570		out[7] = 0;
571		out[8] = xz + wy;
572		out[9] = yz - wx;
573		out[10] = 1 - (xx + yy);
574		out[11] = 0;
575		out[12] = v[0];
576		out[13] = v[1];
577		out[14] = v[2];
578		out[15] = 1;
579		return out;
580	  }
581	  function mat4_translate(out, a, v) {
582		var x = v[0],
583			y = v[1],
584			z = v[2],
585			a00,
586			a01,
587			a02,
588			a03,
589			a10,
590			a11,
591			a12,
592			a13,
593			a20,
594			a21,
595			a22,
596			a23;
597		if (a === out) {
598		  out[12] = a[0] * x + a[4] * y + a[8] * z + a[12];
599		  out[13] = a[1] * x + a[5] * y + a[9] * z + a[13];
600		  out[14] = a[2] * x + a[6] * y + a[10] * z + a[14];
601		  out[15] = a[3] * x + a[7] * y + a[11] * z + a[15];
602		} else {
603		  a00 = a[0];a01 = a[1];a02 = a[2];a03 = a[3];
604		  a10 = a[4];a11 = a[5];a12 = a[6];a13 = a[7];
605		  a20 = a[8];a21 = a[9];a22 = a[10];a23 = a[11];
606		  out[0] = a00;out[1] = a01;out[2] = a02;out[3] = a03;
607		  out[4] = a10;out[5] = a11;out[6] = a12;out[7] = a13;
608		  out[8] = a20;out[9] = a21;out[10] = a22;out[11] = a23;
609		  out[12] = a00 * x + a10 * y + a20 * z + a[12];
610		  out[13] = a01 * x + a11 * y + a21 * z + a[13];
611		  out[14] = a02 * x + a12 * y + a22 * z + a[14];
612		  out[15] = a03 * x + a13 * y + a23 * z + a[15];
613		}
614		return out;
615	  }
616	  function mat4_invert(out, a) {
617		var a00 = a[0],
618			a01 = a[1],
619			a02 = a[2],
620			a03 = a[3],
621			a10 = a[4],
622			a11 = a[5],
623			a12 = a[6],
624			a13 = a[7],
625			a20 = a[8],
626			a21 = a[9],
627			a22 = a[10],
628			a23 = a[11],
629			a30 = a[12],
630			a31 = a[13],
631			a32 = a[14],
632			a33 = a[15],
633			b00 = a00 * a11 - a01 * a10,
634			b01 = a00 * a12 - a02 * a10,
635			b02 = a00 * a13 - a03 * a10,
636			b03 = a01 * a12 - a02 * a11,
637			b04 = a01 * a13 - a03 * a11,
638			b05 = a02 * a13 - a03 * a12,
639			b06 = a20 * a31 - a21 * a30,
640			b07 = a20 * a32 - a22 * a30,
641			b08 = a20 * a33 - a23 * a30,
642			b09 = a21 * a32 - a22 * a31,
643			b10 = a21 * a33 - a23 * a31,
644			b11 = a22 * a33 - a23 * a32,
645		det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
646		if (!det) {
647		  return null;
648		}
649		det = 1.0 / det;
650		out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det;
651		out[1] = (a02 * b10 - a01 * b11 - a03 * b09) * det;
652		out[2] = (a31 * b05 - a32 * b04 + a33 * b03) * det;
653		out[3] = (a22 * b04 - a21 * b05 - a23 * b03) * det;
654		out[4] = (a12 * b08 - a10 * b11 - a13 * b07) * det;
655		out[5] = (a00 * b11 - a02 * b08 + a03 * b07) * det;
656		out[6] = (a32 * b02 - a30 * b05 - a33 * b01) * det;
657		out[7] = (a20 * b05 - a22 * b02 + a23 * b01) * det;
658		out[8] = (a10 * b10 - a11 * b08 + a13 * b06) * det;
659		out[9] = (a01 * b08 - a00 * b10 - a03 * b06) * det;
660		out[10] = (a30 * b04 - a31 * b02 + a33 * b00) * det;
661		out[11] = (a21 * b02 - a20 * b04 - a23 * b00) * det;
662		out[12] = (a11 * b07 - a10 * b09 - a12 * b06) * det;
663		out[13] = (a00 * b09 - a01 * b07 + a02 * b06) * det;
664		out[14] = (a31 * b01 - a30 * b03 - a32 * b00) * det;
665		out[15] = (a20 * b03 - a21 * b01 + a22 * b00) * det;
666		return out;
667	  }
668	  var defaultOrientation = new Float32Array([0, 0, 0, 1]);
669	  var defaultPosition = new Float32Array([0, 0, 0]);
670	  function updateEyeMatrices(projection, view, pose, fov, offset, vrDisplay) {
671		mat4_perspectiveFromFieldOfView(projection, fov || null, vrDisplay.depthNear, vrDisplay.depthFar);
672		var orientation = pose.orientation || defaultOrientation;
673		var position = pose.position || defaultPosition;
674		mat4_fromRotationTranslation(view, orientation, position);
675		if (offset) mat4_translate(view, view, offset);
676		mat4_invert(view, view);
677	  }
678	  return function (frameData, pose, vrDisplay) {
679		if (!frameData || !pose) return false;
680		frameData.pose = pose;
681		frameData.timestamp = pose.timestamp;
682		updateEyeMatrices(frameData.leftProjectionMatrix, frameData.leftViewMatrix, pose, vrDisplay._getFieldOfView("left"), vrDisplay._getEyeOffset("left"), vrDisplay);
683		updateEyeMatrices(frameData.rightProjectionMatrix, frameData.rightViewMatrix, pose, vrDisplay._getFieldOfView("right"), vrDisplay._getEyeOffset("right"), vrDisplay);
684		return true;
685	  };
686	}();
687	var isInsideCrossOriginIFrame = function isInsideCrossOriginIFrame() {
688	  var isFramed = window.self !== window.top;
689	  var refOrigin = getOriginFromUrl(document.referrer);
690	  var thisOrigin = getOriginFromUrl(window.location.href);
691	  return isFramed && refOrigin !== thisOrigin;
692	};
693	var getOriginFromUrl = function getOriginFromUrl(url) {
694	  var domainIdx;
695	  var protoSepIdx = url.indexOf("://");
696	  if (protoSepIdx !== -1) {
697		domainIdx = protoSepIdx + 3;
698	  } else {
699		domainIdx = 0;
700	  }
701	  var domainEndIdx = url.indexOf('/', domainIdx);
702	  if (domainEndIdx === -1) {
703		domainEndIdx = url.length;
704	  }
705	  return url.substring(0, domainEndIdx);
706	};
707	var getQuaternionAngle = function getQuaternionAngle(quat) {
708	  if (quat.w > 1) {
709		console.warn('getQuaternionAngle: w > 1');
710		return 0;
711	  }
712	  var angle = 2 * Math.acos(quat.w);
713	  return angle;
714	};
715	var warnOnce = function () {
716	  var observedWarnings = {};
717	  return function (key, message) {
718		if (observedWarnings[key] === undefined) {
719		  console.warn('webvr-polyfill: ' + message);
720		  observedWarnings[key] = true;
721		}
722	  };
723	}();
724	var deprecateWarning = function deprecateWarning(deprecated, suggested) {
725	  var alternative = suggested ? 'Please use ' + suggested + ' instead.' : '';
726	  warnOnce(deprecated, deprecated + ' has been deprecated. ' + 'This may not work on native WebVR displays. ' + alternative);
727	};
728	function WGLUPreserveGLState(gl, bindings, callback) {
729	  if (!bindings) {
730		callback(gl);
731		return;
732	  }
733	  var boundValues = [];
734	  var activeTexture = null;
735	  for (var i = 0; i < bindings.length; ++i) {
736		var binding = bindings[i];
737		switch (binding) {
738		  case gl.TEXTURE_BINDING_2D:
739		  case gl.TEXTURE_BINDING_CUBE_MAP:
740			var textureUnit = bindings[++i];
741			if (textureUnit < gl.TEXTURE0 || textureUnit > gl.TEXTURE31) {
742			  console.error("TEXTURE_BINDING_2D or TEXTURE_BINDING_CUBE_MAP must be followed by a valid texture unit");
743			  boundValues.push(null, null);
744			  break;
745			}
746			if (!activeTexture) {
747			  activeTexture = gl.getParameter(gl.ACTIVE_TEXTURE);
748			}
749			gl.activeTexture(textureUnit);
750			boundValues.push(gl.getParameter(binding), null);
751			break;
752		  case gl.ACTIVE_TEXTURE:
753			activeTexture = gl.getParameter(gl.ACTIVE_TEXTURE);
754			boundValues.push(null);
755			break;
756		  default:
757			boundValues.push(gl.getParameter(binding));
758			break;
759		}
760	  }
761	  callback(gl);
762	  for (var i = 0; i < bindings.length; ++i) {
763		var binding = bindings[i];
764		var boundValue = boundValues[i];
765		switch (binding) {
766		  case gl.ACTIVE_TEXTURE:
767			break;
768		  case gl.ARRAY_BUFFER_BINDING:
769			gl.bindBuffer(gl.ARRAY_BUFFER, boundValue);
770			break;
771		  case gl.COLOR_CLEAR_VALUE:
772			gl.clearColor(boundValue[0], boundValue[1], boundValue[2], boundValue[3]);
773			break;
774		  case gl.COLOR_WRITEMASK:
775			gl.colorMask(boundValue[0], boundValue[1], boundValue[2], boundValue[3]);
776			break;
777		  case gl.CURRENT_PROGRAM:
778			gl.useProgram(boundValue);
779			break;
780		  case gl.ELEMENT_ARRAY_BUFFER_BINDING:
781			gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, boundValue);
782			break;
783		  case gl.FRAMEBUFFER_BINDING:
784			gl.bindFramebuffer(gl.FRAMEBUFFER, boundValue);
785			break;
786		  case gl.RENDERBUFFER_BINDING:
787			gl.bindRenderbuffer(gl.RENDERBUFFER, boundValue);
788			break;
789		  case gl.TEXTURE_BINDING_2D:
790			var textureUnit = bindings[++i];
791			if (textureUnit < gl.TEXTURE0 || textureUnit > gl.TEXTURE31)
792			  break;
793			gl.activeTexture(textureUnit);
794			gl.bindTexture(gl.TEXTURE_2D, boundValue);
795			break;
796		  case gl.TEXTURE_BINDING_CUBE_MAP:
797			var textureUnit = bindings[++i];
798			if (textureUnit < gl.TEXTURE0 || textureUnit > gl.TEXTURE31)
799			  break;
800			gl.activeTexture(textureUnit);
801			gl.bindTexture(gl.TEXTURE_CUBE_MAP, boundValue);
802			break;
803		  case gl.VIEWPORT:
804			gl.viewport(boundValue[0], boundValue[1], boundValue[2], boundValue[3]);
805			break;
806		  case gl.BLEND:
807		  case gl.CULL_FACE:
808		  case gl.DEPTH_TEST:
809		  case gl.SCISSOR_TEST:
810		  case gl.STENCIL_TEST:
811			if (boundValue) {
812			  gl.enable(binding);
813			} else {
814			  gl.disable(binding);
815			}
816			break;
817		  default:
818			console.log("No GL restore behavior for 0x" + binding.toString(16));
819			break;
820		}
821		if (activeTexture) {
822		  gl.activeTexture(activeTexture);
823		}
824	  }
825	}
826	var glPreserveState = WGLUPreserveGLState;
827	var distortionVS = ['attribute vec2 position;', 'attribute vec3 texCoord;', 'varying vec2 vTexCoord;', 'uniform vec4 viewportOffsetScale[2];', 'void main() {', '  vec4 viewport = viewportOffsetScale[int(texCoord.z)];', '  vTexCoord = (texCoord.xy * viewport.zw) + viewport.xy;', '  gl_Position = vec4( position, 1.0, 1.0 );', '}'].join('\n');
828	var distortionFS = ['precision mediump float;', 'uniform sampler2D diffuse;', 'varying vec2 vTexCoord;', 'void main() {', '  gl_FragColor = texture2D(diffuse, vTexCoord);', '}'].join('\n');
829	function CardboardDistorter(gl, cardboardUI, bufferScale, dirtySubmitFrameBindings) {
830	  this.gl = gl;
831	  this.cardboardUI = cardboardUI;
832	  this.bufferScale = bufferScale;
833	  this.dirtySubmitFrameBindings = dirtySubmitFrameBindings;
834	  this.ctxAttribs = gl.getContextAttributes();
835	  this.meshWidth = 20;
836	  this.meshHeight = 20;
837	  this.bufferWidth = gl.drawingBufferWidth;
838	  this.bufferHeight = gl.drawingBufferHeight;
839	  this.realBindFramebuffer = gl.bindFramebuffer;
840	  this.realEnable = gl.enable;
841	  this.realDisable = gl.disable;
842	  this.realColorMask = gl.colorMask;
843	  this.realClearColor = gl.clearColor;
844	  this.realViewport = gl.viewport;
845	  if (!isIOS()) {
846		this.realCanvasWidth = Object.getOwnPropertyDescriptor(gl.canvas.__proto__, 'width');
847		this.realCanvasHeight = Object.getOwnPropertyDescriptor(gl.canvas.__proto__, 'height');
848	  }
849	  this.isPatched = false;
850	  this.lastBoundFramebuffer = null;
851	  this.cullFace = false;
852	  this.depthTest = false;
853	  this.blend = false;
854	  this.scissorTest = false;
855	  this.stencilTest = false;
856	  this.viewport = [0, 0, 0, 0];
857	  this.colorMask = [true, true, true, true];
858	  this.clearColor = [0, 0, 0, 0];
859	  this.attribs = {
860		position: 0,
861		texCoord: 1
862	  };
863	  this.program = linkProgram(gl, distortionVS, distortionFS, this.attribs);
864	  this.uniforms = getProgramUniforms(gl, this.program);
865	  this.viewportOffsetScale = new Float32Array(8);
866	  this.setTextureBounds();
867	  this.vertexBuffer = gl.createBuffer();
868	  this.indexBuffer = gl.createBuffer();
869	  this.indexCount = 0;
870	  this.renderTarget = gl.createTexture();
871	  this.framebuffer = gl.createFramebuffer();
872	  this.depthStencilBuffer = null;
873	  this.depthBuffer = null;
874	  this.stencilBuffer = null;
875	  if (this.ctxAttribs.depth && this.ctxAttribs.stencil) {
876		this.depthStencilBuffer = gl.createRenderbuffer();
877	  } else if (this.ctxAttribs.depth) {
878		this.depthBuffer = gl.createRenderbuffer();
879	  } else if (this.ctxAttribs.stencil) {
880		this.stencilBuffer = gl.createRenderbuffer();
881	  }
882	  this.patch();
883	  this.onResize();
884	}
885	CardboardDistorter.prototype.destroy = function () {
886	  var gl = this.gl;
887	  this.unpatch();
888	  gl.deleteProgram(this.program);
889	  gl.deleteBuffer(this.vertexBuffer);
890	  gl.deleteBuffer(this.indexBuffer);
891	  gl.deleteTexture(this.renderTarget);
892	  gl.deleteFramebuffer(this.framebuffer);
893	  if (this.depthStencilBuffer) {
894		gl.deleteRenderbuffer(this.depthStencilBuffer);
895	  }
896	  if (this.depthBuffer) {
897		gl.deleteRenderbuffer(this.depthBuffer);
898	  }
899	  if (this.stencilBuffer) {
900		gl.deleteRenderbuffer(this.stencilBuffer);
901	  }
902	  if (this.cardboardUI) {
903		this.cardboardUI.destroy();
904	  }
905	};
906	CardboardDistorter.prototype.onResize = function () {
907	  var gl = this.gl;
908	  var self = this;
909	  var glState = [gl.RENDERBUFFER_BINDING, gl.TEXTURE_BINDING_2D, gl.TEXTURE0];
910	  glPreserveState(gl, glState, function (gl) {
911		self.realBindFramebuffer.call(gl, gl.FRAMEBUFFER, null);
912		if (self.scissorTest) {
913		  self.realDisable.call(gl, gl.SCISSOR_TEST);
914		}
915		self.realColorMask.call(gl, true, true, true, true);
916		self.realViewport.call(gl, 0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
917		self.realClearColor.call(gl, 0, 0, 0, 1);
918		gl.clear(gl.COLOR_BUFFER_BIT);
919		self.realBindFramebuffer.call(gl, gl.FRAMEBUFFER, self.framebuffer);
920		gl.bindTexture(gl.TEXTURE_2D, self.renderTarget);
921		gl.texImage2D(gl.TEXTURE_2D, 0, self.ctxAttribs.alpha ? gl.RGBA : gl.RGB, self.bufferWidth, self.bufferHeight, 0, self.ctxAttribs.alpha ? gl.RGBA : gl.RGB, gl.UNSIGNED_BYTE, null);
922		gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
923		gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
924		gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
925		gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
926		gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, self.renderTarget, 0);
927		if (self.ctxAttribs.depth && self.ctxAttribs.stencil) {
928		  gl.bindRenderbuffer(gl.RENDERBUFFER, self.depthStencilBuffer);
929		  gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_STENCIL, self.bufferWidth, self.bufferHeight);
930		  gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.RENDERBUFFER, self.depthStencilBuffer);
931		} else if (self.ctxAttribs.depth) {
932		  gl.bindRenderbuffer(gl.RENDERBUFFER, self.depthBuffer);
933		  gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, self.bufferWidth, self.bufferHeight);
934		  gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, self.depthBuffer);
935		} else if (self.ctxAttribs.stencil) {
936		  gl.bindRenderbuffer(gl.RENDERBUFFER, self.stencilBuffer);
937		  gl.renderbufferStorage(gl.RENDERBUFFER, gl.STENCIL_INDEX8, self.bufferWidth, self.bufferHeight);
938		  gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.RENDERBUFFER, self.stencilBuffer);
939		}
940		if (!gl.checkFramebufferStatus(gl.FRAMEBUFFER) === gl.FRAMEBUFFER_COMPLETE) {
941		  console.error('Framebuffer incomplete!');
942		}
943		self.realBindFramebuffer.call(gl, gl.FRAMEBUFFER, self.lastBoundFramebuffer);
944		if (self.scissorTest) {
945		  self.realEnable.call(gl, gl.SCISSOR_TEST);
946		}
947		self.realColorMask.apply(gl, self.colorMask);
948		self.realViewport.apply(gl, self.viewport);
949		self.realClearColor.apply(gl, self.clearColor);
950	  });
951	  if (this.cardboardUI) {
952		this.cardboardUI.onResize();
953	  }
954	};
955	CardboardDistorter.prototype.patch = function () {
956	  if (this.isPatched) {
957		return;
958	  }
959	  var self = this;
960	  var canvas = this.gl.canvas;
961	  var gl = this.gl;
962	  if (!isIOS()) {
963		canvas.width = getScreenWidth() * this.bufferScale;
964		canvas.height = getScreenHeight() * this.bufferScale;
965		Object.defineProperty(canvas, 'width', {
966		  configurable: true,
967		  enumerable: true,
968		  get: function get() {
969			return self.bufferWidth;
970		  },
971		  set: function set(value) {
972			self.bufferWidth = value;
973			self.realCanvasWidth.set.call(canvas, value);
974			self.onResize();
975		  }
976		});
977		Object.defineProperty(canvas, 'height', {
978		  configurable: true,
979		  enumerable: true,
980		  get: function get() {
981			return self.bufferHeight;
982		  },
983		  set: function set(value) {
984			self.bufferHeight = value;
985			self.realCanvasHeight.set.call(canvas, value);
986			self.onResize();
987		  }
988		});
989	  }
990	  this.lastBoundFramebuffer = gl.getParameter(gl.FRAMEBUFFER_BINDING);
991	  if (this.lastBoundFramebuffer == null) {
992		this.lastBoundFramebuffer = this.framebuffer;
993		this.gl.bindFramebuffer(gl.FRAMEBUFFER, this.framebuffer);
994	  }
995	  this.gl.bindFramebuffer = function (target, framebuffer) {
996		self.lastBoundFramebuffer = framebuffer ? framebuffer : self.framebuffer;
997		self.realBindFramebuffer.call(gl, target, self.lastBoundFramebuffer);
998	  };
999	  this.cullFace = gl.getParameter(gl.CULL_FACE);
1000	  this.depthTest = gl.getParameter(gl.DEPTH_TEST);
1001	  this.blend = gl.getParameter(gl.BLEND);
1002	  this.scissorTest = gl.getParameter(gl.SCISSOR_TEST);
1003	  this.stencilTest = gl.getParameter(gl.STENCIL_TEST);
1004	  gl.enable = function (pname) {
1005		switch (pname) {
1006		  case gl.CULL_FACE:
1007			self.cullFace = true;break;
1008		  case gl.DEPTH_TEST:
1009			self.depthTest = true;break;
1010		  case gl.BLEND:
1011			self.blend = true;break;
1012		  case gl.SCISSOR_TEST:
1013			self.scissorTest = true;break;
1014		  case gl.STENCIL_TEST:
1015			self.stencilTest = true;break;
1016		}
1017		self.realEnable.call(gl, pname);
1018	  };
1019	  gl.disable = function (pname) {
1020		switch (pname) {
1021		  case gl.CULL_FACE:
1022			self.cullFace = false;break;
1023		  case gl.DEPTH_TEST:
1024			self.depthTest = false;break;
1025		  case gl.BLEND:
1026			self.blend = false;break;
1027		  case gl.SCISSOR_TEST:
1028			self.scissorTest = false;break;
1029		  case gl.STENCIL_TEST:
1030			self.stencilTest = false;break;
1031		}
1032		self.realDisable.call(gl, pname);
1033	  };
vendor: 13,898 bytes, lines 1034-1398
1034	  this.colorMask = gl.getParameter(gl.COLOR_WRITEMASK);
1035	  gl.colorMask = function (r, g, b, a) {
1036		self.colorMask[0] = r;
1037		self.colorMask[1] = g;
1038		self.colorMask[2] = b;
1039		self.colorMask[3] = a;
1040		self.realColorMask.call(gl, r, g, b, a);
1041	  };
1042	  this.clearColor = gl.getParameter(gl.COLOR_CLEAR_VALUE);
1043	  gl.clearColor = function (r, g, b, a) {
1044		self.clearColor[0] = r;
1045		self.clearColor[1] = g;
1046		self.clearColor[2] = b;
1047		self.clearColor[3] = a;
1048		self.realClearColor.call(gl, r, g, b, a);
1049	  };
1050	  this.viewport = gl.getParameter(gl.VIEWPORT);
1051	  gl.viewport = function (x, y, w, h) {
1052		self.viewport[0] = x;
1053		self.viewport[1] = y;
1054		self.viewport[2] = w;
1055		self.viewport[3] = h;
1056		self.realViewport.call(gl, x, y, w, h);
1057	  };
1058	  this.isPatched = true;
1059	  safariCssSizeWorkaround(canvas);
1060	};
1061	CardboardDistorter.prototype.unpatch = function () {
1062	  if (!this.isPatched) {
1063		return;
1064	  }
1065	  var gl = this.gl;
1066	  var canvas = this.gl.canvas;
1067	  if (!isIOS()) {
1068		Object.defineProperty(canvas, 'width', this.realCanvasWidth);
1069		Object.defineProperty(canvas, 'height', this.realCanvasHeight);
1070	  }
1071	  canvas.width = this.bufferWidth;
1072	  canvas.height = this.bufferHeight;
1073	  gl.bindFramebuffer = this.realBindFramebuffer;
1074	  gl.enable = this.realEnable;
1075	  gl.disable = this.realDisable;
1076	  gl.colorMask = this.realColorMask;
1077	  gl.clearColor = this.realClearColor;
1078	  gl.viewport = this.realViewport;
1079	  if (this.lastBoundFramebuffer == this.framebuffer) {
1080		gl.bindFramebuffer(gl.FRAMEBUFFER, null);
1081	  }
1082	  this.isPatched = false;
1083	  setTimeout(function () {
1084		safariCssSizeWorkaround(canvas);
1085	  }, 1);
1086	};
1087	CardboardDistorter.prototype.setTextureBounds = function (leftBounds, rightBounds) {
1088	  if (!leftBounds) {
1089		leftBounds = [0, 0, 0.5, 1];
1090	  }
1091	  if (!rightBounds) {
1092		rightBounds = [0.5, 0, 0.5, 1];
1093	  }
1094	  this.viewportOffsetScale[0] = leftBounds[0];
1095	  this.viewportOffsetScale[1] = leftBounds[1];
1096	  this.viewportOffsetScale[2] = leftBounds[2];
1097	  this.viewportOffsetScale[3] = leftBounds[3];
1098	  this.viewportOffsetScale[4] = rightBounds[0];
1099	  this.viewportOffsetScale[5] = rightBounds[1];
1100	  this.viewportOffsetScale[6] = rightBounds[2];
1101	  this.viewportOffsetScale[7] = rightBounds[3];
1102	};
1103	CardboardDistorter.prototype.submitFrame = function () {
1104	  var gl = this.gl;
1105	  var self = this;
1106	  var glState = [];
1107	  if (!this.dirtySubmitFrameBindings) {
1108		glState.push(gl.CURRENT_PROGRAM, gl.ARRAY_BUFFER_BINDING, gl.ELEMENT_ARRAY_BUFFER_BINDING, gl.TEXTURE_BINDING_2D, gl.TEXTURE0);
1109	  }
1110	  glPreserveState(gl, glState, function (gl) {
1111		self.realBindFramebuffer.call(gl, gl.FRAMEBUFFER, null);
1112		if (self.cullFace) {
1113		  self.realDisable.call(gl, gl.CULL_FACE);
1114		}
1115		if (self.depthTest) {
1116		  self.realDisable.call(gl, gl.DEPTH_TEST);
1117		}
1118		if (self.blend) {
1119		  self.realDisable.call(gl, gl.BLEND);
1120		}
1121		if (self.scissorTest) {
1122		  self.realDisable.call(gl, gl.SCISSOR_TEST);
1123		}
1124		if (self.stencilTest) {
1125		  self.realDisable.call(gl, gl.STENCIL_TEST);
1126		}
1127		self.realColorMask.call(gl, true, true, true, true);
1128		self.realViewport.call(gl, 0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
1129		if (self.ctxAttribs.alpha || isIOS()) {
1130		  self.realClearColor.call(gl, 0, 0, 0, 1);
1131		  gl.clear(gl.COLOR_BUFFER_BIT);
1132		}
1133		gl.useProgram(self.program);
1134		gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, self.indexBuffer);
1135		gl.bindBuffer(gl.ARRAY_BUFFER, self.vertexBuffer);
1136		gl.enableVertexAttribArray(self.attribs.position);
1137		gl.enableVertexAttribArray(self.attribs.texCoord);
1138		gl.vertexAttribPointer(self.attribs.position, 2, gl.FLOAT, false, 20, 0);
1139		gl.vertexAttribPointer(self.attribs.texCoord, 3, gl.FLOAT, false, 20, 8);
1140		gl.activeTexture(gl.TEXTURE0);
1141		gl.uniform1i(self.uniforms.diffuse, 0);
1142		gl.bindTexture(gl.TEXTURE_2D, self.renderTarget);
1143		gl.uniform4fv(self.uniforms.viewportOffsetScale, self.viewportOffsetScale);
1144		gl.drawElements(gl.TRIANGLES, self.indexCount, gl.UNSIGNED_SHORT, 0);
1145		if (self.cardboardUI) {
1146		  self.cardboardUI.renderNoState();
1147		}
1148		self.realBindFramebuffer.call(self.gl, gl.FRAMEBUFFER, self.framebuffer);
1149		if (!self.ctxAttribs.preserveDrawingBuffer) {
1150		  self.realClearColor.call(gl, 0, 0, 0, 0);
1151		  gl.clear(gl.COLOR_BUFFER_BIT);
1152		}
1153		if (!self.dirtySubmitFrameBindings) {
1154		  self.realBindFramebuffer.call(gl, gl.FRAMEBUFFER, self.lastBoundFramebuffer);
1155		}
1156		if (self.cullFace) {
1157		  self.realEnable.call(gl, gl.CULL_FACE);
1158		}
1159		if (self.depthTest) {
1160		  self.realEnable.call(gl, gl.DEPTH_TEST);
1161		}
1162		if (self.blend) {
1163		  self.realEnable.call(gl, gl.BLEND);
1164		}
1165		if (self.scissorTest) {
1166		  self.realEnable.call(gl, gl.SCISSOR_TEST);
1167		}
1168		if (self.stencilTest) {
1169		  self.realEnable.call(gl, gl.STENCIL_TEST);
1170		}
1171		self.realColorMask.apply(gl, self.colorMask);
1172		self.realViewport.apply(gl, self.viewport);
1173		if (self.ctxAttribs.alpha || !self.ctxAttribs.preserveDrawingBuffer) {
1174		  self.realClearColor.apply(gl, self.clearColor);
1175		}
1176	  });
1177	  if (isIOS()) {
1178		var canvas = gl.canvas;
1179		if (canvas.width != self.bufferWidth || canvas.height != self.bufferHeight) {
1180		  self.bufferWidth = canvas.width;
1181		  self.bufferHeight = canvas.height;
1182		  self.onResize();
1183		}
1184	  }
1185	};
1186	CardboardDistorter.prototype.updateDeviceInfo = function (deviceInfo) {
1187	  var gl = this.gl;
1188	  var self = this;
1189	  var glState = [gl.ARRAY_BUFFER_BINDING, gl.ELEMENT_ARRAY_BUFFER_BINDING];
1190	  glPreserveState(gl, glState, function (gl) {
1191		var vertices = self.computeMeshVertices_(self.meshWidth, self.meshHeight, deviceInfo);
1192		gl.bindBuffer(gl.ARRAY_BUFFER, self.vertexBuffer);
1193		gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
1194		if (!self.indexCount) {
1195		  var indices = self.computeMeshIndices_(self.meshWidth, self.meshHeight);
1196		  gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, self.indexBuffer);
1197		  gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW);
1198		  self.indexCount = indices.length;
1199		}
1200	  });
1201	};
1202	CardboardDistorter.prototype.computeMeshVertices_ = function (width, height, deviceInfo) {
1203	  var vertices = new Float32Array(2 * width * height * 5);
1204	  var lensFrustum = deviceInfo.getLeftEyeVisibleTanAngles();
1205	  var noLensFrustum = deviceInfo.getLeftEyeNoLensTanAngles();
1206	  var viewport = deviceInfo.getLeftEyeVisibleScreenRect(noLensFrustum);
1207	  var vidx = 0;
1208	  for (var e = 0; e < 2; e++) {
1209		for (var j = 0; j < height; j++) {
1210		  for (var i = 0; i < width; i++, vidx++) {
1211			var u = i / (width - 1);
1212			var v = j / (height - 1);
1213			var s = u;
1214			var t = v;
1215			var x = lerp(lensFrustum[0], lensFrustum[2], u);
1216			var y = lerp(lensFrustum[3], lensFrustum[1], v);
1217			var d = Math.sqrt(x * x + y * y);
1218			var r = deviceInfo.distortion.distortInverse(d);
1219			var p = x * r / d;
1220			var q = y * r / d;
1221			u = (p - noLensFrustum[0]) / (noLensFrustum[2] - noLensFrustum[0]);
1222			v = (q - noLensFrustum[3]) / (noLensFrustum[1] - noLensFrustum[3]);
1223			u = (viewport.x + u * viewport.width - 0.5) * 2.0;
1224			v = (viewport.y + v * viewport.height - 0.5) * 2.0;
1225			vertices[vidx * 5 + 0] = u;
1226			vertices[vidx * 5 + 1] = v;
1227			vertices[vidx * 5 + 2] = s;
1228			vertices[vidx * 5 + 3] = t;
1229			vertices[vidx * 5 + 4] = e;
1230		  }
1231		}
1232		var w = lensFrustum[2] - lensFrustum[0];
1233		lensFrustum[0] = -(w + lensFrustum[0]);
1234		lensFrustum[2] = w - lensFrustum[2];
1235		w = noLensFrustum[2] - noLensFrustum[0];
1236		noLensFrustum[0] = -(w + noLensFrustum[0]);
1237		noLensFrustum[2] = w - noLensFrustum[2];
1238		viewport.x = 1 - (viewport.x + viewport.width);
1239	  }
1240	  return vertices;
1241	};
1242	CardboardDistorter.prototype.computeMeshIndices_ = function (width, height) {
1243	  var indices = new Uint16Array(2 * (width - 1) * (height - 1) * 6);
1244	  var halfwidth = width / 2;
1245	  var halfheight = height / 2;
1246	  var vidx = 0;
1247	  var iidx = 0;
1248	  for (var e = 0; e < 2; e++) {
1249		for (var j = 0; j < height; j++) {
1250		  for (var i = 0; i < width; i++, vidx++) {
1251			if (i == 0 || j == 0) continue;
1252			if (i <= halfwidth == j <= halfheight) {
1253			  indices[iidx++] = vidx;
1254			  indices[iidx++] = vidx - width - 1;
1255			  indices[iidx++] = vidx - width;
1256			  indices[iidx++] = vidx - width - 1;
1257			  indices[iidx++] = vidx;
1258			  indices[iidx++] = vidx - 1;
1259			} else {
1260			  indices[iidx++] = vidx - 1;
1261			  indices[iidx++] = vidx - width;
1262			  indices[iidx++] = vidx;
1263			  indices[iidx++] = vidx - width;
1264			  indices[iidx++] = vidx - 1;
1265			  indices[iidx++] = vidx - width - 1;
1266			}
1267		  }
1268		}
1269	  }
1270	  return indices;
1271	};
1272	CardboardDistorter.prototype.getOwnPropertyDescriptor_ = function (proto, attrName) {
1273	  var descriptor = Object.getOwnPropertyDescriptor(proto, attrName);
1274	  if (descriptor.get === undefined || descriptor.set === undefined) {
1275		descriptor.configurable = true;
1276		descriptor.enumerable = true;
1277		descriptor.get = function () {
1278		  return this.getAttribute(attrName);
1279		};
1280		descriptor.set = function (val) {
1281		  this.setAttribute(attrName, val);
1282		};
1283	  }
1284	  return descriptor;
1285	};
1286	var uiVS = ['attribute vec2 position;', 'uniform mat4 projectionMat;', 'void main() {', '  gl_Position = projectionMat * vec4( position, -1.0, 1.0 );', '}'].join('\n');
1287	var uiFS = ['precision mediump float;', 'uniform vec4 color;', 'void main() {', '  gl_FragColor = color;', '}'].join('\n');
1288	var DEG2RAD = Math.PI / 180.0;
1289	var kAnglePerGearSection = 60;
1290	var kOuterRimEndAngle = 12;
1291	var kInnerRimBeginAngle = 20;
1292	var kOuterRadius = 1;
1293	var kMiddleRadius = 0.75;
1294	var kInnerRadius = 0.3125;
1295	var kCenterLineThicknessDp = 4;
1296	var kButtonWidthDp = 28;
1297	var kTouchSlopFactor = 1.5;
1298	function CardboardUI(gl) {
1299	  this.gl = gl;
1300	  this.attribs = {
1301		position: 0
1302	  };
1303	  this.program = linkProgram(gl, uiVS, uiFS, this.attribs);
1304	  this.uniforms = getProgramUniforms(gl, this.program);
1305	  this.vertexBuffer = gl.createBuffer();
1306	  this.gearOffset = 0;
1307	  this.gearVertexCount = 0;
1308	  this.arrowOffset = 0;
1309	  this.arrowVertexCount = 0;
1310	  this.projMat = new Float32Array(16);
1311	  this.listener = null;
1312	  this.onResize();
1313	}
1314	CardboardUI.prototype.destroy = function () {
1315	  var gl = this.gl;
1316	  if (this.listener) {
1317		gl.canvas.removeEventListener('click', this.listener, false);
1318	  }
1319	  gl.deleteProgram(this.program);
1320	  gl.deleteBuffer(this.vertexBuffer);
1321	};
1322	CardboardUI.prototype.listen = function (optionsCallback, backCallback) {
1323	  var canvas = this.gl.canvas;
1324	  this.listener = function (event) {
1325		var midline = canvas.clientWidth / 2;
1326		var buttonSize = kButtonWidthDp * kTouchSlopFactor;
1327		if (event.clientX > midline - buttonSize && event.clientX < midline + buttonSize && event.clientY > canvas.clientHeight - buttonSize) {
1328		  optionsCallback(event);
1329		}
1330		else if (event.clientX < buttonSize && event.clientY < buttonSize) {
1331			backCallback(event);
1332		  }
1333	  };
1334	  canvas.addEventListener('click', this.listener, false);
1335	};
1336	CardboardUI.prototype.onResize = function () {
1337	  var gl = this.gl;
1338	  var self = this;
1339	  var glState = [gl.ARRAY_BUFFER_BINDING];
1340	  glPreserveState(gl, glState, function (gl) {
1341		var vertices = [];
1342		var midline = gl.drawingBufferWidth / 2;
1343		var physicalPixels = Math.max(screen.width, screen.height) * window.devicePixelRatio;
1344		var scalingRatio = gl.drawingBufferWidth / physicalPixels;
1345		var dps = scalingRatio * window.devicePixelRatio;
1346		var lineWidth = kCenterLineThicknessDp * dps / 2;
1347		var buttonSize = kButtonWidthDp * kTouchSlopFactor * dps;
1348		var buttonScale = kButtonWidthDp * dps / 2;
1349		var buttonBorder = (kButtonWidthDp * kTouchSlopFactor - kButtonWidthDp) * dps;
1350		vertices.push(midline - lineWidth, buttonSize);
1351		vertices.push(midline - lineWidth, gl.drawingBufferHeight);
1352		vertices.push(midline + lineWidth, buttonSize);
1353		vertices.push(midline + lineWidth, gl.drawingBufferHeight);
1354		self.gearOffset = vertices.length / 2;
1355		function addGearSegment(theta, r) {
1356		  var angle = (90 - theta) * DEG2RAD;
1357		  var x = Math.cos(angle);
1358		  var y = Math.sin(angle);
1359		  vertices.push(kInnerRadius * x * buttonScale + midline, kInnerRadius * y * buttonScale + buttonScale);
1360		  vertices.push(r * x * buttonScale + midline, r * y * buttonScale + buttonScale);
1361		}
1362		for (var i = 0; i <= 6; i++) {
1363		  var segmentTheta = i * kAnglePerGearSection;
1364		  addGearSegment(segmentTheta, kOuterRadius);
1365		  addGearSegment(segmentTheta + kOuterRimEndAngle, kOuterRadius);
1366		  addGearSegment(segmentTheta + kInnerRimBeginAngle, kMiddleRadius);
1367		  addGearSegment(segmentTheta + (kAnglePerGearSection - kInnerRimBeginAngle), kMiddleRadius);
1368		  addGearSegment(segmentTheta + (kAnglePerGearSection - kOuterRimEndAngle), kOuterRadius);
1369		}
1370		self.gearVertexCount = vertices.length / 2 - self.gearOffset;
1371		self.arrowOffset = vertices.length / 2;
1372		function addArrowVertex(x, y) {
1373		  vertices.push(buttonBorder + x, gl.drawingBufferHeight - buttonBorder - y);
1374		}
1375		var angledLineWidth = lineWidth / Math.sin(45 * DEG2RAD);
1376		addArrowVertex(0, buttonScale);
1377		addArrowVertex(buttonScale, 0);
1378		addArrowVertex(buttonScale + angledLineWidth, angledLineWidth);
1379		addArrowVertex(angledLineWidth, buttonScale + angledLineWidth);
1380		addArrowVertex(angledLineWidth, buttonScale - angledLineWidth);
1381		addArrowVertex(0, buttonScale);
1382		addArrowVertex(buttonScale, buttonScale * 2);
1383		addArrowVertex(buttonScale + angledLineWidth, buttonScale * 2 - angledLineWidth);
1384		addArrowVertex(angledLineWidth, buttonScale - angledLineWidth);
1385		addArrowVertex(0, buttonScale);
1386		addArrowVertex(angledLineWidth, buttonScale - lineWidth);
1387		addArrowVertex(kButtonWidthDp * dps, buttonScale - lineWidth);
1388		addArrowVertex(angledLineWidth, buttonScale + lineWidth);
1389		addArrowVertex(kButtonWidthDp * dps, buttonScale + lineWidth);
1390		self.arrowVertexCount = vertices.length / 2 - self.arrowOffset;
1391		gl.bindBuffer(gl.ARRAY_BUFFER, self.vertexBuffer);
1392		gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
1393	  });
1394	};
1395	CardboardUI.prototype.render = function () {
1396	  var gl = this.gl;
1397	  var self = this;
1398	  var glState = [gl.CULL_FACE, gl.DEPTH_TEST, gl.BLEND, gl.SCISSOR_TEST, gl.STENCIL_TEST, gl.COLOR_WRITEMA
vendor: 18,151 bytes, lines 1398-1928
1398SK, gl.VIEWPORT, gl.CURRENT_PROGRAM, gl.ARRAY_BUFFER_BINDING];
1399	  glPreserveState(gl, glState, function (gl) {
1400		gl.disable(gl.CULL_FACE);
1401		gl.disable(gl.DEPTH_TEST);
1402		gl.disable(gl.BLEND);
1403		gl.disable(gl.SCISSOR_TEST);
1404		gl.disable(gl.STENCIL_TEST);
1405		gl.colorMask(true, true, true, true);
1406		gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
1407		self.renderNoState();
1408	  });
1409	};
1410	CardboardUI.prototype.renderNoState = function () {
1411	  var gl = this.gl;
1412	  gl.useProgram(this.program);
1413	  gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer);
1414	  gl.enableVertexAttribArray(this.attribs.position);
1415	  gl.vertexAttribPointer(this.attribs.position, 2, gl.FLOAT, false, 8, 0);
1416	  gl.uniform4f(this.uniforms.color, 1.0, 1.0, 1.0, 1.0);
1417	  orthoMatrix(this.projMat, 0, gl.drawingBufferWidth, 0, gl.drawingBufferHeight, 0.1, 1024.0);
1418	  gl.uniformMatrix4fv(this.uniforms.projectionMat, false, this.projMat);
1419	  gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
1420	  gl.drawArrays(gl.TRIANGLE_STRIP, this.gearOffset, this.gearVertexCount);
1421	  gl.drawArrays(gl.TRIANGLE_STRIP, this.arrowOffset, this.arrowVertexCount);
1422	};
1423	function Distortion(coefficients) {
1424	  this.coefficients = coefficients;
1425	}
1426	Distortion.prototype.distortInverse = function (radius) {
1427	  var r0 = 0;
1428	  var r1 = 1;
1429	  var dr0 = radius - this.distort(r0);
1430	  while (Math.abs(r1 - r0) > 0.0001             ) {
1431		var dr1 = radius - this.distort(r1);
1432		var r2 = r1 - dr1 * ((r1 - r0) / (dr1 - dr0));
1433		r0 = r1;
1434		r1 = r2;
1435		dr0 = dr1;
1436	  }
1437	  return r1;
1438	};
1439	Distortion.prototype.distort = function (radius) {
1440	  var r2 = radius * radius;
1441	  var ret = 0;
1442	  for (var i = 0; i < this.coefficients.length; i++) {
1443		ret = r2 * (ret + this.coefficients[i]);
1444	  }
1445	  return (ret + 1) * radius;
1446	};
1447	var degToRad = Math.PI / 180;
1448	var radToDeg = 180 / Math.PI;
1449	var Vector3 = function Vector3(x, y, z) {
1450	  this.x = x || 0;
1451	  this.y = y || 0;
1452	  this.z = z || 0;
1453	};
1454	Vector3.prototype = {
1455	  constructor: Vector3,
1456	  set: function set(x, y, z) {
1457		this.x = x;
1458		this.y = y;
1459		this.z = z;
1460		return this;
1461	  },
1462	  copy: function copy(v) {
1463		this.x = v.x;
1464		this.y = v.y;
1465		this.z = v.z;
1466		return this;
1467	  },
1468	  length: function length() {
1469		return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z);
1470	  },
1471	  normalize: function normalize() {
1472		var scalar = this.length();
1473		if (scalar !== 0) {
1474		  var invScalar = 1 / scalar;
1475		  this.multiplyScalar(invScalar);
1476		} else {
1477		  this.x = 0;
1478		  this.y = 0;
1479		  this.z = 0;
1480		}
1481		return this;
1482	  },
1483	  multiplyScalar: function multiplyScalar(scalar) {
1484		this.x *= scalar;
1485		this.y *= scalar;
1486		this.z *= scalar;
1487	  },
1488	  applyQuaternion: function applyQuaternion(q) {
1489		var x = this.x;
1490		var y = this.y;
1491		var z = this.z;
1492		var qx = q.x;
1493		var qy = q.y;
1494		var qz = q.z;
1495		var qw = q.w;
1496		var ix = qw * x + qy * z - qz * y;
1497		var iy = qw * y + qz * x - qx * z;
1498		var iz = qw * z + qx * y - qy * x;
1499		var iw = -qx * x - qy * y - qz * z;
1500		this.x = ix * qw + iw * -qx + iy * -qz - iz * -qy;
1501		this.y = iy * qw + iw * -qy + iz * -qx - ix * -qz;
1502		this.z = iz * qw + iw * -qz + ix * -qy - iy * -qx;
1503		return this;
1504	  },
1505	  dot: function dot(v) {
1506		return this.x * v.x + this.y * v.y + this.z * v.z;
1507	  },
1508	  crossVectors: function crossVectors(a, b) {
1509		var ax = a.x,
1510			ay = a.y,
1511			az = a.z;
1512		var bx = b.x,
1513			by = b.y,
1514			bz = b.z;
1515		this.x = ay * bz - az * by;
1516		this.y = az * bx - ax * bz;
1517		this.z = ax * by - ay * bx;
1518		return this;
1519	  }
1520	};
1521	var Quaternion = function Quaternion(x, y, z, w) {
1522	  this.x = x || 0;
1523	  this.y = y || 0;
1524	  this.z = z || 0;
1525	  this.w = w !== undefined ? w : 1;
1526	};
1527	Quaternion.prototype = {
1528	  constructor: Quaternion,
1529	  set: function set(x, y, z, w) {
1530		this.x = x;
1531		this.y = y;
1532		this.z = z;
1533		this.w = w;
1534		return this;
1535	  },
1536	  copy: function copy(quaternion) {
1537		this.x = quaternion.x;
1538		this.y = quaternion.y;
1539		this.z = quaternion.z;
1540		this.w = quaternion.w;
1541		return this;
1542	  },
1543	  setFromEulerXYZ: function setFromEulerXYZ(x, y, z) {
1544		var c1 = Math.cos(x / 2);
1545		var c2 = Math.cos(y / 2);
1546		var c3 = Math.cos(z / 2);
1547		var s1 = Math.sin(x / 2);
1548		var s2 = Math.sin(y / 2);
1549		var s3 = Math.sin(z / 2);
1550		this.x = s1 * c2 * c3 + c1 * s2 * s3;
1551		this.y = c1 * s2 * c3 - s1 * c2 * s3;
1552		this.z = c1 * c2 * s3 + s1 * s2 * c3;
1553		this.w = c1 * c2 * c3 - s1 * s2 * s3;
1554		return this;
1555	  },
1556	  setFromEulerYXZ: function setFromEulerYXZ(x, y, z) {
1557		var c1 = Math.cos(x / 2);
1558		var c2 = Math.cos(y / 2);
1559		var c3 = Math.cos(z / 2);
1560		var s1 = Math.sin(x / 2);
1561		var s2 = Math.sin(y / 2);
1562		var s3 = Math.sin(z / 2);
1563		this.x = s1 * c2 * c3 + c1 * s2 * s3;
1564		this.y = c1 * s2 * c3 - s1 * c2 * s3;
1565		this.z = c1 * c2 * s3 - s1 * s2 * c3;
1566		this.w = c1 * c2 * c3 + s1 * s2 * s3;
1567		return this;
1568	  },
1569	  setFromAxisAngle: function setFromAxisAngle(axis, angle) {
1570		var halfAngle = angle / 2,
1571			s = Math.sin(halfAngle);
1572		this.x = axis.x * s;
1573		this.y = axis.y * s;
1574		this.z = axis.z * s;
1575		this.w = Math.cos(halfAngle);
1576		return this;
1577	  },
1578	  multiply: function multiply(q) {
1579		return this.multiplyQuaternions(this, q);
1580	  },
1581	  multiplyQuaternions: function multiplyQuaternions(a, b) {
1582		var qax = a.x,
1583			qay = a.y,
1584			qaz = a.z,
1585			qaw = a.w;
1586		var qbx = b.x,
1587			qby = b.y,
1588			qbz = b.z,
1589			qbw = b.w;
1590		this.x = qax * qbw + qaw * qbx + qay * qbz - qaz * qby;
1591		this.y = qay * qbw + qaw * qby + qaz * qbx - qax * qbz;
1592		this.z = qaz * qbw + qaw * qbz + qax * qby - qay * qbx;
1593		this.w = qaw * qbw - qax * qbx - qay * qby - qaz * qbz;
1594		return this;
1595	  },
1596	  inverse: function inverse() {
1597		this.x *= -1;
1598		this.y *= -1;
1599		this.z *= -1;
1600		this.normalize();
1601		return this;
1602	  },
1603	  normalize: function normalize() {
1604		var l = Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w);
1605		if (l === 0) {
1606		  this.x = 0;
1607		  this.y = 0;
1608		  this.z = 0;
1609		  this.w = 1;
1610		} else {
1611		  l = 1 / l;
1612		  this.x = this.x * l;
1613		  this.y = this.y * l;
1614		  this.z = this.z * l;
1615		  this.w = this.w * l;
1616		}
1617		return this;
1618	  },
1619	  slerp: function slerp(qb, t) {
1620		if (t === 0) return this;
1621		if (t === 1) return this.copy(qb);
1622		var x = this.x,
1623			y = this.y,
1624			z = this.z,
1625			w = this.w;
1626		var cosHalfTheta = w * qb.w + x * qb.x + y * qb.y + z * qb.z;
1627		if (cosHalfTheta < 0) {
1628		  this.w = -qb.w;
1629		  this.x = -qb.x;
1630		  this.y = -qb.y;
1631		  this.z = -qb.z;
1632		  cosHalfTheta = -cosHalfTheta;
1633		} else {
1634		  this.copy(qb);
1635		}
1636		if (cosHalfTheta >= 1.0) {
1637		  this.w = w;
1638		  this.x = x;
1639		  this.y = y;
1640		  this.z = z;
1641		  return this;
1642		}
1643		var halfTheta = Math.acos(cosHalfTheta);
1644		var sinHalfTheta = Math.sqrt(1.0 - cosHalfTheta * cosHalfTheta);
1645		if (Math.abs(sinHalfTheta) < 0.001) {
1646		  this.w = 0.5 * (w + this.w);
1647		  this.x = 0.5 * (x + this.x);
1648		  this.y = 0.5 * (y + this.y);
1649		  this.z = 0.5 * (z + this.z);
1650		  return this;
1651		}
1652		var ratioA = Math.sin((1 - t) * halfTheta) / sinHalfTheta,
1653			ratioB = Math.sin(t * halfTheta) / sinHalfTheta;
1654		this.w = w * ratioA + this.w * ratioB;
1655		this.x = x * ratioA + this.x * ratioB;
1656		this.y = y * ratioA + this.y * ratioB;
1657		this.z = z * ratioA + this.z * ratioB;
1658		return this;
1659	  },
1660	  setFromUnitVectors: function () {
1661		var v1, r;
1662		var EPS = 0.000001;
1663		return function (vFrom, vTo) {
1664		  if (v1 === undefined) v1 = new Vector3();
1665		  r = vFrom.dot(vTo) + 1;
1666		  if (r < EPS) {
1667			r = 0;
1668			if (Math.abs(vFrom.x) > Math.abs(vFrom.z)) {
1669			  v1.set(-vFrom.y, vFrom.x, 0);
1670			} else {
1671			  v1.set(0, -vFrom.z, vFrom.y);
1672			}
1673		  } else {
1674			v1.crossVectors(vFrom, vTo);
1675		  }
1676		  this.x = v1.x;
1677		  this.y = v1.y;
1678		  this.z = v1.z;
1679		  this.w = r;
1680		  this.normalize();
1681		  return this;
1682		};
1683	  }()
1684	};
1685	function Device(params) {
1686	  this.width = params.width || getScreenWidth();
1687	  this.height = params.height || getScreenHeight();
1688	  this.widthMeters = params.widthMeters;
1689	  this.heightMeters = params.heightMeters;
1690	  this.bevelMeters = params.bevelMeters;
1691	}
1692	var DEFAULT_ANDROID = new Device({
1693	  widthMeters: 0.110,
1694	  heightMeters: 0.062,
1695	  bevelMeters: 0.004
1696	});
1697	var DEFAULT_IOS = new Device({
1698	  widthMeters: 0.1038,
1699	  heightMeters: 0.0584,
1700	  bevelMeters: 0.004
1701	});
1702	var Viewers = {
1703	  CardboardV1: new CardboardViewer({
1704		id: 'CardboardV1',
1705		label: 'Cardboard I/O 2014',
1706		fov: 40,
1707		interLensDistance: 0.060,
1708		baselineLensDistance: 0.035,
1709		screenLensDistance: 0.042,
1710		distortionCoefficients: [0.441, 0.156],
1711		inverseCoefficients: [-0.4410035, 0.42756155, -0.4804439, 0.5460139, -0.58821183, 0.5733938, -0.48303202, 0.33299083, -0.17573841, 0.0651772, -0.01488963, 0.001559834]
1712	  }),
1713	  CardboardV2: new CardboardViewer({
1714		id: 'CardboardV2',
1715		label: 'Cardboard I/O 2015',
1716		fov: 60,
1717		interLensDistance: 0.064,
1718		baselineLensDistance: 0.035,
1719		screenLensDistance: 0.039,
1720		distortionCoefficients: [0.34, 0.55],
1721		inverseCoefficients: [-0.33836704, -0.18162185, 0.862655, -1.2462051, 1.0560602, -0.58208317, 0.21609078, -0.05444823, 0.009177956, -9.904169E-4, 6.183535E-5, -1.6981803E-6]
1722	  })
1723	};
1724	function DeviceInfo(deviceParams, additionalViewers) {
1725	  this.viewer = Viewers.CardboardV2;
1726	  this.updateDeviceParams(deviceParams);
1727	  this.distortion = new Distortion(this.viewer.distortionCoefficients);
1728	  for (var i = 0; i < additionalViewers.length; i++) {
1729		var viewer = additionalViewers[i];
1730		Viewers[viewer.id] = new CardboardViewer(viewer);
1731	  }
1732	}
1733	DeviceInfo.prototype.updateDeviceParams = function (deviceParams) {
1734	  this.device = this.determineDevice_(deviceParams) || this.device;
1735	};
1736	DeviceInfo.prototype.getDevice = function () {
1737	  return this.device;
1738	};
1739	DeviceInfo.prototype.setViewer = function (viewer) {
1740	  this.viewer = viewer;
1741	  this.distortion = new Distortion(this.viewer.distortionCoefficients);
1742	};
1743	DeviceInfo.prototype.determineDevice_ = function (deviceParams) {
1744	  if (!deviceParams) {
1745		if (isIOS()) {
1746		  console.warn('Using fallback iOS device measurements.');
1747		  return DEFAULT_IOS;
1748		} else {
1749		  console.warn('Using fallback Android device measurements.');
1750		  return DEFAULT_ANDROID;
1751		}
1752	  }
1753	  var METERS_PER_INCH = 0.0254;
1754	  var metersPerPixelX = METERS_PER_INCH / deviceParams.xdpi;
1755	  var metersPerPixelY = METERS_PER_INCH / deviceParams.ydpi;
1756	  var width = getScreenWidth();
1757	  var height = getScreenHeight();
1758	  return new Device({
1759		widthMeters: metersPerPixelX * width,
1760		heightMeters: metersPerPixelY * height,
1761		bevelMeters: deviceParams.bevelMm * 0.001
1762	  });
1763	};
1764	DeviceInfo.prototype.getDistortedFieldOfViewLeftEye = function () {
1765	  var viewer = this.viewer;
1766	  var device = this.device;
1767	  var distortion = this.distortion;
1768	  var eyeToScreenDistance = viewer.screenLensDistance;
1769	  var outerDist = (device.widthMeters - viewer.interLensDistance) / 2;
1770	  var innerDist = viewer.interLensDistance / 2;
1771	  var bottomDist = viewer.baselineLensDistance - device.bevelMeters;
1772	  var topDist = device.heightMeters - bottomDist;
1773	  var outerAngle = radToDeg * Math.atan(distortion.distort(outerDist / eyeToScreenDistance));
1774	  var innerAngle = radToDeg * Math.atan(distortion.distort(innerDist / eyeToScreenDistance));
1775	  var bottomAngle = radToDeg * Math.atan(distortion.distort(bottomDist / eyeToScreenDistance));
1776	  var topAngle = radToDeg * Math.atan(distortion.distort(topDist / eyeToScreenDistance));
1777	  return {
1778		leftDegrees: Math.min(outerAngle, viewer.fov),
1779		rightDegrees: Math.min(innerAngle, viewer.fov),
1780		downDegrees: Math.min(bottomAngle, viewer.fov),
1781		upDegrees: Math.min(topAngle, viewer.fov)
1782	  };
1783	};
1784	DeviceInfo.prototype.getLeftEyeVisibleTanAngles = function () {
1785	  var viewer = this.viewer;
1786	  var device = this.device;
1787	  var distortion = this.distortion;
1788	  var fovLeft = Math.tan(-degToRad * viewer.fov);
1789	  var fovTop = Math.tan(degToRad * viewer.fov);
1790	  var fovRight = Math.tan(degToRad * viewer.fov);
1791	  var fovBottom = Math.tan(-degToRad * viewer.fov);
1792	  var halfWidth = device.widthMeters / 4;
1793	  var halfHeight = device.heightMeters / 2;
1794	  var verticalLensOffset = viewer.baselineLensDistance - device.bevelMeters - halfHeight;
1795	  var centerX = viewer.interLensDistance / 2 - halfWidth;
1796	  var centerY = -verticalLensOffset;
1797	  var centerZ = viewer.screenLensDistance;
1798	  var screenLeft = distortion.distort((centerX - halfWidth) / centerZ);
1799	  var screenTop = distortion.distort((centerY + halfHeight) / centerZ);
1800	  var screenRight = distortion.distort((centerX + halfWidth) / centerZ);
1801	  var screenBottom = distortion.distort((centerY - halfHeight) / centerZ);
1802	  var result = new Float32Array(4);
1803	  result[0] = Math.max(fovLeft, screenLeft);
1804	  result[1] = Math.min(fovTop, screenTop);
1805	  result[2] = Math.min(fovRight, screenRight);
1806	  result[3] = Math.max(fovBottom, screenBottom);
1807	  return result;
1808	};
1809	DeviceInfo.prototype.getLeftEyeNoLensTanAngles = function () {
1810	  var viewer = this.viewer;
1811	  var device = this.device;
1812	  var distortion = this.distortion;
1813	  var result = new Float32Array(4);
1814	  var fovLeft = distortion.distortInverse(Math.tan(-degToRad * viewer.fov));
1815	  var fovTop = distortion.distortInverse(Math.tan(degToRad * viewer.fov));
1816	  var fovRight = distortion.distortInverse(Math.tan(degToRad * viewer.fov));
1817	  var fovBottom = distortion.distortInverse(Math.tan(-degToRad * viewer.fov));
1818	  var halfWidth = device.widthMeters / 4;
1819	  var halfHeight = device.heightMeters / 2;
1820	  var verticalLensOffset = viewer.baselineLensDistance - device.bevelMeters - halfHeight;
1821	  var centerX = viewer.interLensDistance / 2 - halfWidth;
1822	  var centerY = -verticalLensOffset;
1823	  var centerZ = viewer.screenLensDistance;
1824	  var screenLeft = (centerX - halfWidth) / centerZ;
1825	  var screenTop = (centerY + halfHeight) / centerZ;
1826	  var screenRight = (centerX + halfWidth) / centerZ;
1827	  var screenBottom = (centerY - halfHeight) / centerZ;
1828	  result[0] = Math.max(fovLeft, screenLeft);
1829	  result[1] = Math.min(fovTop, screenTop);
1830	  result[2] = Math.min(fovRight, screenRight);
1831	  result[3] = Math.max(fovBottom, screenBottom);
1832	  return result;
1833	};
1834	DeviceInfo.prototype.getLeftEyeVisibleScreenRect = function (undistortedFrustum) {
1835	  var viewer = this.viewer;
1836	  var device = this.device;
1837	  var dist = viewer.screenLensDistance;
1838	  var eyeX = (device.widthMeters - viewer.interLensDistance) / 2;
1839	  var eyeY = viewer.baselineLensDistance - device.bevelMeters;
1840	  var left = (undistortedFrustum[0] * dist + eyeX) / device.widthMeters;
1841	  var top = (undistortedFrustum[1] * dist + eyeY) / device.heightMeters;
1842	  var right = (undistortedFrustum[2] * dist + eyeX) / device.widthMeters;
1843	  var bottom = (undistortedFrustum[3] * dist + eyeY) / device.heightMeters;
1844	  return {
1845		x: left,
1846		y: bottom,
1847		width: right - left,
1848		height: top - bottom
1849	  };
1850	};
1851	DeviceInfo.prototype.getFieldOfViewLeftEye = function (opt_isUndistorted) {
1852	  return opt_isUndistorted ? this.getUndistortedFieldOfViewLeftEye() : this.getDistortedFieldOfViewLeftEye();
1853	};
1854	DeviceInfo.prototype.getFieldOfViewRightEye = function (opt_isUndistorted) {
1855	  var fov = this.getFieldOfViewLeftEye(opt_isUndistorted);
1856	  return {
1857		leftDegrees: fov.rightDegrees,
1858		rightDegrees: fov.leftDegrees,
1859		upDegrees: fov.upDegrees,
1860		downDegrees: fov.downDegrees
1861	  };
1862	};
1863	DeviceInfo.prototype.getUndistortedFieldOfViewLeftEye = function () {
1864	  var p = this.getUndistortedParams_();
1865	  return {
1866		leftDegrees: radToDeg * Math.atan(p.outerDist),
1867		rightDegrees: radToDeg * Math.atan(p.innerDist),
1868		downDegrees: radToDeg * Math.atan(p.bottomDist),
1869		upDegrees: radToDeg * Math.atan(p.topDist)
1870	  };
1871	};
1872	DeviceInfo.prototype.getUndistortedViewportLeftEye = function () {
1873	  var p = this.getUndistortedParams_();
1874	  var viewer = this.viewer;
1875	  var device = this.device;
1876	  var eyeToScreenDistance = viewer.screenLensDistance;
1877	  var screenWidth = device.widthMeters / eyeToScreenDistance;
1878	  var screenHeight = device.heightMeters / eyeToScreenDistance;
1879	  var xPxPerTanAngle = device.width / screenWidth;
1880	  var yPxPerTanAngle = device.height / screenHeight;
1881	  var x = Math.round((p.eyePosX - p.outerDist) * xPxPerTanAngle);
1882	  var y = Math.round((p.eyePosY - p.bottomDist) * yPxPerTanAngle);
1883	  return {
1884		x: x,
1885		y: y,
1886		width: Math.round((p.eyePosX + p.innerDist) * xPxPerTanAngle) - x,
1887		height: Math.round((p.eyePosY + p.topDist) * yPxPerTanAngle) - y
1888	  };
1889	};
1890	DeviceInfo.prototype.getUndistortedParams_ = function () {
1891	  var viewer = this.viewer;
1892	  var device = this.device;
1893	  var distortion = this.distortion;
1894	  var eyeToScreenDistance = viewer.screenLensDistance;
1895	  var halfLensDistance = viewer.interLensDistance / 2 / eyeToScreenDistance;
1896	  var screenWidth = device.widthMeters / eyeToScreenDistance;
1897	  var screenHeight = device.heightMeters / eyeToScreenDistance;
1898	  var eyePosX = screenWidth / 2 - halfLensDistance;
1899	  var eyePosY = (viewer.baselineLensDistance - device.bevelMeters) / eyeToScreenDistance;
1900	  var maxFov = viewer.fov;
1901	  var viewerMax = distortion.distortInverse(Math.tan(degToRad * maxFov));
1902	  var outerDist = Math.min(eyePosX, viewerMax);
1903	  var innerDist = Math.min(halfLensDistance, viewerMax);
1904	  var bottomDist = Math.min(eyePosY, viewerMax);
1905	  var topDist = Math.min(screenHeight - eyePosY, viewerMax);
1906	  return {
1907		outerDist: outerDist,
1908		innerDist: innerDist,
1909		topDist: topDist,
1910		bottomDist: bottomDist,
1911		eyePosX: eyePosX,
1912		eyePosY: eyePosY
1913	  };
1914	};
1915	function CardboardViewer(params) {
1916	  this.id = params.id;
1917	  this.label = params.label;
1918	  this.fov = params.fov;
1919	  this.interLensDistance = params.interLensDistance;
1920	  this.baselineLensDistance = params.baselineLensDistance;
1921	  this.screenLensDistance = params.screenLensDistance;
1922	  this.distortionCoefficients = params.distortionCoefficients;
1923	  this.inverseCoefficients = params.inverseCoefficients;
1924	}
1925	DeviceInfo.Viewers = Viewers;
1926	var format = 1;
1927	var last_updated = "2018-02-20T22:55:10Z";
1928	var devices = [{"type":"android","rules":[{"mdmh":"asus/*/Nexus 7/*"},{"ua":"Nexus 7"}],"dpi":[320.8,323],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"asus/*/ASUS_Z00AD/*"},{"ua":"ASUS_Z00AD"}],"dpi":[403,404.6],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Google/*/Pixel XL/*"},{"ua":"Pixel XL"}],"dpi":[537.9,533],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Google/*/Pixel/*"},{"ua":"Pixel"}
1928],"dpi":[432.6,436.7],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"HTC/*/HTC6435LVW/*"},{"ua":"HTC6435LVW"}],"dpi":[449.7,443.3],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"HTC/*/HTC One XL/*"},{"ua":"HTC One XL"}],"dpi":[315.3,314.6],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"htc/*/Nexus 9/*"},{"ua":"Nexus 9"}],"dpi":289,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"HTC/*/HTC One M9/*"},{"ua":"HTC One M9"}],"dpi":[442.5,443.3],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"HTC/*/HTC One_M8/*"},{"ua":"HTC One_M8"}],"dpi":[449.7,447.4],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"HTC/*/HTC One/*"},{"ua":"HTC One"}],"dpi":472.8,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Huawei/*/Nexus 6P/*"},{"ua":"Nexus 6P"}],"dpi":[515.1,518],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"LENOVO/*/Lenovo PB2-690Y/*"},{"ua":"Lenovo PB2-690Y"}],"dpi":[457.2,454.713],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"LGE/*/Nexus 5X/*"},{"ua":"Nexus 5X"}],"dpi":[422,419.9],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"LGE/*/LGMS345/*"},{"ua":"LGMS345"}],"dpi":[221.7,219.1],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"LGE/*/LG-D800/*"},{"ua":"LG-D800"}],"dpi":[422,424.1],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"LGE/*/LG-D850/*"},{"ua":"LG-D850"}],"dpi":[537.9,541.9],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"LGE/*/VS985 4G/*"},{"ua":"VS985 4G"}],"dpi":[537.9,535.6],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"LGE/*/Nexus 5/*"},{"ua":"Nexus 5 B"}],"dpi":[442.4,444.8],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"LGE/*/Nexus 4/*"},{"ua":"Nexus 4"}],"dpi":[319.8,318.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"LGE/*/LG-P769/*"},{"ua":"LG-P769"}],"dpi":[240.6,247.5],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"LGE/*/LGMS323/*"},{"ua":"LGMS323"}],"dpi":[206.6,204.6],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"LGE/*/LGLS996/*"},{"ua":"LGLS996"}],"dpi":[403.4,401.5],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Micromax/*/4560MMX/*"},{"ua":"4560MMX"}],"dpi":[240,219.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Micromax/*/A250/*"},{"ua":"Micromax A250"}],"dpi":[480,446.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Micromax/*/Micromax AQ4501/*"},{"ua":"Micromax AQ4501"}],"dpi":240,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"motorola/*/G5/*"},{"ua":"Moto G (5) Plus"}],"dpi":[403.4,403],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/DROID RAZR/*"},{"ua":"DROID RAZR"}],"dpi":[368.1,256.7],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/XT830C/*"},{"ua":"XT830C"}],"dpi":[254,255.9],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/XT1021/*"},{"ua":"XT1021"}],"dpi":[254,256.7],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"motorola/*/XT1023/*"},{"ua":"XT1023"}],"dpi":[254,256.7],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"motorola/*/XT1028/*"},{"ua":"XT1028"}],"dpi":[326.6,327.6],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/XT1034/*"},{"ua":"XT1034"}],"dpi":[326.6,328.4],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"motorola/*/XT1053/*"},{"ua":"XT1053"}],"dpi":[315.3,316.1],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/XT1562/*"},{"ua":"XT1562"}],"dpi":[403.4,402.7],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/Nexus 6/*"},{"ua":"Nexus 6 B"}],"dpi":[494.3,489.7],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/XT1063/*"},{"ua":"XT1063"}
1928],"dpi":[295,296.6],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/XT1064/*"},{"ua":"XT1064"}],"dpi":[295,295.6],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"motorola/*/XT1092/*"},{"ua":"XT1092"}],"dpi":[422,424.1],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"motorola/*/XT1095/*"},{"ua":"XT1095"}],"dpi":[422,423.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/G4/*"},{"ua":"Moto G (4)"}],"dpi":401,"bw":4,"ac":1000},{"type":"android","rules":[{"mdmh":"OnePlus/*/A0001/*"},{"ua":"A0001"}],"dpi":[403.4,401],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"OnePlus/*/ONE E1005/*"},{"ua":"ONE E1005"}],"dpi":[442.4,441.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"OnePlus/*/ONE A2005/*"},{"ua":"ONE A2005"}],"dpi":[391.9,405.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"OnePlus/*/ONEPLUS A5000/*"},{"ua":"ONEPLUS A5000 "}],"dpi":[403.411,399.737],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"OnePlus/*/ONE A5010/*"},{"ua":"ONEPLUS A5010"}],"dpi":[403,400],"bw":2,"ac":1000},{"type":"android","rules":[{"mdmh":"OPPO/*/X909/*"},{"ua":"X909"}],"dpi":[442.4,444.1],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/GT-I9082/*"},{"ua":"GT-I9082"}],"dpi":[184.7,185.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G360P/*"},{"ua":"SM-G360P"}],"dpi":[196.7,205.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/Nexus S/*"},{"ua":"Nexus S"}],"dpi":[234.5,229.8],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/GT-I9300/*"},{"ua":"GT-I9300"}],"dpi":[304.8,303.9],"bw":5,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-T230NU/*"},{"ua":"SM-T230NU"}],"dpi":216,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SGH-T399/*"},{"ua":"SGH-T399"}],"dpi":[217.7,231.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SGH-M919/*"},{"ua":"SGH-M919"}],"dpi":[440.8,437.7],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-N9005/*"},{"ua":"SM-N9005"}],"dpi":[386.4,387],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SAMSUNG-SM-N900A/*"},{"ua":"SAMSUNG-SM-N900A"}],"dpi":[386.4,387.7],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/GT-I9500/*"},{"ua":"GT-I9500"}],"dpi":[442.5,443.3],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/GT-I9505/*"},{"ua":"GT-I9505"}],"dpi":439.4,"bw":4,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G900F/*"},{"ua":"SM-G900F"}],"dpi":[415.6,431.6],"bw":5,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G900M/*"},{"ua":"SM-G900M"}],"dpi":[415.6,431.6],"bw":5,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G800F/*"},{"ua":"SM-G800F"}],"dpi":326.8,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G906S/*"},{"ua":"SM-G906S"}],"dpi":[562.7,572.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/GT-I9300/*"},{"ua":"GT-I9300"}],"dpi":[306.7,304.8],"bw":5,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-T535/*"},{"ua":"SM-T535"}],"dpi":[142.6,136.4],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-N920C/*"},{"ua":"SM-N920C"}],"dpi":[515.1,518.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-N920P/*"},{"ua":"SM-N920P"}],"dpi":[386.3655,390.144],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-N920W8/*"},{"ua":"SM-N920W8"}],"dpi":[515.1,518.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/GT-I9300I/*"},{"ua":"GT-I9300I"}],"dpi":[304.8,305.8],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/GT-I9195/*"},{"ua":"GT-I9195"}],"dpi":[249.4,256.7],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SPH-L520/*"},{"ua":"SPH-L520"}],"dpi":[249.4,255.9],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SAMSUNG-SGH-I717/*"},{"ua":"SAMSUNG-SGH-I717"}],"dpi":285.8,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SPH-D710/*"},{"ua":"SPH-D710"}],"dpi":[217.7,204.2],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/GT-N7100/*"},{"ua":"GT-N7100"}],"dpi":265.1,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SCH-I605/*"},{"ua":"SCH-I605"}],"dpi":265.1,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/Galaxy Nexus/*"},{"ua":"Galaxy Nexus"}],"dpi":[315.3,314.2],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-N910H/*"},{"ua":"SM-N910H"}],"dpi":[515.1,518],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-N910C/*"},{"ua":"SM-N910C"}],"dpi":[515.2,520.2],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G130M/*"},{"ua":"SM-G130M"}],"dpi":[165.9,164.8],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G928I/*"},{"ua":"SM-G928I"}],"dpi":[515.1,518.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G920F/*"},{"ua":"SM-G920F"}],"dpi":580.6,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G920P/*"},{"ua":"SM-G920P"}],"dpi":[522.5,577],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G925F/*"},{"ua":"SM-G925F"}],"dpi":580.6,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G925V/*"},{"ua":"SM-G925V"}],"dpi":[522.5,576.6],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G930F/*"},{"ua":"SM-G930F"}],"dpi":576.6,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G935F/*"},{"ua":"SM-G935F"}],"dpi":533,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G950F/*"},{"ua":"SM-G950F"}],"dpi":[562.707,565.293],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G955U/*"},{"ua":"SM-G955U"}],"dpi":[522.514,525.762],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"Sony/*/C6903/*"},{"ua":"C6903"}],"dpi":[442.5,443.3],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"Sony/*/D6653/*"},{"ua":"D6653"}],"dpi":[428.6,427.6],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Sony/*/E6653/*"},{"ua":"E6653"}],"dpi":[428.6,425.7],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Sony/*/E6853/*"},{"ua":"E6853"}],"dpi":[403.4,401.9],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Sony/*/SGP321/*"},{"ua":"SGP321"}],"dpi":[224.7,224.1],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"TCT/*/ALCATEL ONE TOUCH Fierce/*"},{"ua":"ALCATEL ONE TOUCH Fierce"}],"dpi":[240,247.5],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"THL/*/thl 5000/*"},{"ua":"thl 5000"}],"dpi":[480,443.3],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Fly/*/IQ4412/*"},{"ua":"IQ4412"}],"dpi":307.9,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"ZTE/*/ZTE Blade L2/*"},{"ua":"ZTE Blade L2"}],"dpi":240,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"BENEVE/*/VR518/*"},{"ua":"VR518"}],"dpi":480,"bw":3,"ac":500}
vendor: 9,300 bytes, lines 1928-2178
1928,{"type":"ios","rules":[{"res":[640,960]}],"dpi":[325.1,328.4],"bw":4,"ac":1000},{"type":"ios","rules":[{"res":[640,1136]}],"dpi":[317.1,320.2],"bw":3,"ac":1000},{"type":"ios","rules":[{"res":[750,1334]}],"dpi":326.4,"bw":4,"ac":1000},{"type":"ios","rules":[{"res":[1242,2208]}],"dpi":[453.6,458.4],"bw":4,"ac":1000},{"type":"ios","rules":[{"res":[1125,2001]}],"dpi":[410.9,415.4],"bw":4,"ac":1000},{"type":"ios","rules":[{"res":[1125,2436]}],"dpi":458,"bw":4,"ac":1000}];
1929	var DPDB_CACHE = {
1930		format: format,
1931		last_updated: last_updated,
1932		devices: devices
1933	};
1934	function Dpdb(url, onDeviceParamsUpdated) {
1935	  this.dpdb = DPDB_CACHE;
1936	  this.recalculateDeviceParams_();
1937	  if (url) {
1938		this.onDeviceParamsUpdated = onDeviceParamsUpdated;
1939		var xhr = new XMLHttpRequest();
1940		var obj = this;
1941		xhr.open('GET', url, true);
1942		xhr.addEventListener('load', function () {
1943		  obj.loading = false;
1944		  if (xhr.status >= 200 && xhr.status <= 299) {
1945			obj.dpdb = JSON.parse(xhr.response);
1946			obj.recalculateDeviceParams_();
1947		  } else {
1948			console.error('Error loading online DPDB!');
1949		  }
1950		});
1951		xhr.send();
1952	  }
1953	}
1954	Dpdb.prototype.getDeviceParams = function () {
1955	  return this.deviceParams;
1956	};
1957	Dpdb.prototype.recalculateDeviceParams_ = function () {
1958	  var newDeviceParams = this.calcDeviceParams_();
1959	  if (newDeviceParams) {
1960		this.deviceParams = newDeviceParams;
1961		if (this.onDeviceParamsUpdated) {
1962		  this.onDeviceParamsUpdated(this.deviceParams);
1963		}
1964	  } else {
1965		console.error('Failed to recalculate device parameters.');
1966	  }
1967	};
1968	Dpdb.prototype.calcDeviceParams_ = function () {
1969	  var db = this.dpdb;
1970	  if (!db) {
1971		console.error('DPDB not available.');
1972		return null;
1973	  }
1974	  if (db.format != 1) {
1975		console.error('DPDB has unexpected format version.');
1976		return null;
1977	  }
1978	  if (!db.devices || !db.devices.length) {
1979		console.error('DPDB does not have a devices section.');
1980		return null;
1981	  }
1982	  var userAgent = navigator.userAgent || navigator.vendor || window.opera;
1983	  var width = getScreenWidth();
1984	  var height = getScreenHeight();
1985	  if (!db.devices) {
1986		console.error('DPDB has no devices section.');
1987		return null;
1988	  }
1989	  for (var i = 0; i < db.devices.length; i++) {
1990		var device = db.devices[i];
1991		if (!device.rules) {
1992		  console.warn('Device[' + i + '] has no rules section.');
1993		  continue;
1994		}
1995		if (device.type != 'ios' && device.type != 'android') {
1996		  console.warn('Device[' + i + '] has invalid type.');
1997		  continue;
1998		}
1999		if (isIOS() != (device.type == 'ios')) continue;
2000		var matched = false;
2001		for (var j = 0; j < device.rules.length; j++) {
2002		  var rule = device.rules[j];
2003		  if (this.matchRule_(rule, userAgent, width, height)) {
2004			matched = true;
2005			break;
2006		  }
2007		}
2008		if (!matched) continue;
2009		var xdpi = device.dpi[0] || device.dpi;
2010		var ydpi = device.dpi[1] || device.dpi;
2011		return new DeviceParams({ xdpi: xdpi, ydpi: ydpi, bevelMm: device.bw });
2012	  }
2013	  console.warn('No DPDB device match.');
2014	  return null;
2015	};
2016	Dpdb.prototype.matchRule_ = function (rule, ua, screenWidth, screenHeight) {
2017	  if (!rule.ua && !rule.res) return false;
2018	  if (rule.ua && ua.indexOf(rule.ua) < 0) return false;
2019	  if (rule.res) {
2020		if (!rule.res[0] || !rule.res[1]) return false;
2021		var resX = rule.res[0];
2022		var resY = rule.res[1];
2023		if (Math.min(screenWidth, screenHeight) != Math.min(resX, resY) || Math.max(screenWidth, screenHeight) != Math.max(resX, resY)) {
2024		  return false;
2025		}
2026	  }
2027	  return true;
2028	};
2029	function DeviceParams(params) {
2030	  this.xdpi = params.xdpi;
2031	  this.ydpi = params.ydpi;
2032	  this.bevelMm = params.bevelMm;
2033	}
2034	function SensorSample(sample, timestampS) {
2035	  this.set(sample, timestampS);
2036	}
2037	SensorSample.prototype.set = function (sample, timestampS) {
2038	  this.sample = sample;
2039	  this.timestampS = timestampS;
2040	};
2041	SensorSample.prototype.copy = function (sensorSample) {
2042	  this.set(sensorSample.sample, sensorSample.timestampS);
2043	};
2044	function ComplementaryFilter(kFilter, isDebug) {
2045	  this.kFilter = kFilter;
2046	  this.isDebug = isDebug;
2047	  this.currentAccelMeasurement = new SensorSample();
2048	  this.currentGyroMeasurement = new SensorSample();
2049	  this.previousGyroMeasurement = new SensorSample();
2050	  if (isIOS()) {
2051		this.filterQ = new Quaternion(-1, 0, 0, 1);
2052	  } else {
2053		this.filterQ = new Quaternion(1, 0, 0, 1);
2054	  }
2055	  this.previousFilterQ = new Quaternion();
2056	  this.previousFilterQ.copy(this.filterQ);
2057	  this.accelQ = new Quaternion();
2058	  this.isOrientationInitialized = false;
2059	  this.estimatedGravity = new Vector3();
2060	  this.measuredGravity = new Vector3();
2061	  this.gyroIntegralQ = new Quaternion();
2062	}
2063	ComplementaryFilter.prototype.addAccelMeasurement = function (vector, timestampS) {
2064	  this.currentAccelMeasurement.set(vector, timestampS);
2065	};
2066	ComplementaryFilter.prototype.addGyroMeasurement = function (vector, timestampS) {
2067	  this.currentGyroMeasurement.set(vector, timestampS);
2068	  var deltaT = timestampS - this.previousGyroMeasurement.timestampS;
2069	  if (isTimestampDeltaValid(deltaT)) {
2070		this.run_();
2071	  }
2072	  this.previousGyroMeasurement.copy(this.currentGyroMeasurement);
2073	};
2074	ComplementaryFilter.prototype.run_ = function () {
2075	  if (!this.isOrientationInitialized) {
2076		this.accelQ = this.accelToQuaternion_(this.currentAccelMeasurement.sample);
2077		this.previousFilterQ.copy(this.accelQ);
2078		this.isOrientationInitialized = true;
2079		return;
2080	  }
2081	  var deltaT = this.currentGyroMeasurement.timestampS - this.previousGyroMeasurement.timestampS;
2082	  var gyroDeltaQ = this.gyroToQuaternionDelta_(this.currentGyroMeasurement.sample, deltaT);
2083	  this.gyroIntegralQ.multiply(gyroDeltaQ);
2084	  this.filterQ.copy(this.previousFilterQ);
2085	  this.filterQ.multiply(gyroDeltaQ);
2086	  var invFilterQ = new Quaternion();
2087	  invFilterQ.copy(this.filterQ);
2088	  invFilterQ.inverse();
2089	  this.estimatedGravity.set(0, 0, -1);
2090	  this.estimatedGravity.applyQuaternion(invFilterQ);
2091	  this.estimatedGravity.normalize();
2092	  this.measuredGravity.copy(this.currentAccelMeasurement.sample);
2093	  this.measuredGravity.normalize();
2094	  var deltaQ = new Quaternion();
2095	  deltaQ.setFromUnitVectors(this.estimatedGravity, this.measuredGravity);
2096	  deltaQ.inverse();
2097	  if (this.isDebug) {
2098		console.log('Delta: %d deg, G_est: (%s, %s, %s), G_meas: (%s, %s, %s)', radToDeg * getQuaternionAngle(deltaQ), this.estimatedGravity.x.toFixed(1), this.estimatedGravity.y.toFixed(1), this.estimatedGravity.z.toFixed(1), this.measuredGravity.x.toFixed(1), this.measuredGravity.y.toFixed(1), this.measuredGravity.z.toFixed(1));
2099	  }
2100	  var targetQ = new Quaternion();
2101	  targetQ.copy(this.filterQ);
2102	  targetQ.multiply(deltaQ);
2103	  this.filterQ.slerp(targetQ, 1 - this.kFilter);
2104	  this.previousFilterQ.copy(this.filterQ);
2105	};
2106	ComplementaryFilter.prototype.getOrientation = function () {
2107	  return this.filterQ;
2108	};
2109	ComplementaryFilter.prototype.accelToQuaternion_ = function (accel) {
2110	  var normAccel = new Vector3();
2111	  normAccel.copy(accel);
2112	  normAccel.normalize();
2113	  var quat = new Quaternion();
2114	  quat.setFromUnitVectors(new Vector3(0, 0, -1), normAccel);
2115	  quat.inverse();
2116	  return quat;
2117	};
2118	ComplementaryFilter.prototype.gyroToQuaternionDelta_ = function (gyro, dt) {
2119	  var quat = new Quaternion();
2120	  var axis = new Vector3();
2121	  axis.copy(gyro);
2122	  axis.normalize();
2123	  quat.setFromAxisAngle(axis, gyro.length() * dt);
2124	  return quat;
2125	};
2126	function PosePredictor(predictionTimeS, isDebug) {
2127	  this.predictionTimeS = predictionTimeS;
2128	  this.isDebug = isDebug;
2129	  this.previousQ = new Quaternion();
2130	  this.previousTimestampS = null;
2131	  this.deltaQ = new Quaternion();
2132	  this.outQ = new Quaternion();
2133	}
2134	PosePredictor.prototype.getPrediction = function (currentQ, gyro, timestampS) {
2135	  if (!this.previousTimestampS) {
2136		this.previousQ.copy(currentQ);
2137		this.previousTimestampS = timestampS;
2138		return currentQ;
2139	  }
2140	  var axis = new Vector3();
2141	  axis.copy(gyro);
2142	  axis.normalize();
2143	  var angularSpeed = gyro.length();
2144	  if (angularSpeed < degToRad * 20) {
2145		if (this.isDebug) {
2146		  console.log('Moving slowly, at %s deg/s: no prediction', (radToDeg * angularSpeed).toFixed(1));
2147		}
2148		this.outQ.copy(currentQ);
2149		this.previousQ.copy(currentQ);
2150		return this.outQ;
2151	  }
2152	  var predictAngle = angularSpeed * this.predictionTimeS;
2153	  this.deltaQ.setFromAxisAngle(axis, predictAngle);
2154	  this.outQ.copy(this.previousQ);
2155	  this.outQ.multiply(this.deltaQ);
2156	  this.previousQ.copy(currentQ);
2157	  this.previousTimestampS = timestampS;
2158	  return this.outQ;
2159	};
2160	function FusionPoseSensor(kFilter, predictionTime, yawOnly, isDebug) {
2161	  this.yawOnly = yawOnly;
2162	  this.accelerometer = new Vector3();
2163	  this.gyroscope = new Vector3();
2164	  this.filter = new ComplementaryFilter(kFilter, isDebug);
2165	  this.posePredictor = new PosePredictor(predictionTime, isDebug);
2166	  this.isFirefoxAndroid = isFirefoxAndroid();
2167	  this.isIOS = isIOS();
2168	  var chromeVersion = getChromeVersion();
2169	  this.isDeviceMotionInRadians = !this.isIOS && chromeVersion && chromeVersion < 66;
2170	  this.isWithoutDeviceMotion = isChromeWithoutDeviceMotion();
2171	  this.filterToWorldQ = new Quaternion();
2172	  if (isIOS()) {
2173		this.filterToWorldQ.setFromAxisAngle(new Vector3(1, 0, 0), Math.PI / 2);
2174	  } else {
2175		this.filterToWorldQ.setFromAxisAngle(new Vector3(1, 0, 0), -Math.PI / 2);
2176	  }
2177	  this.inverseWorldToScreenQ = new Quaternion();
2178	  this.worldToScreenQ = new Quaternion();
vendor: 7,633 bytes, lines 2179-2385
2179	  this.originalPoseAdjustQ = new Quaternion();
2180	  this.originalPoseAdjustQ.setFromAxisAngle(new Vector3(0, 0, 1), -window.orientation * Math.PI / 180);
2181	  this.setScreenTransform_();
2182	  if (isLandscapeMode()) {
2183		this.filterToWorldQ.multiply(this.inverseWorldToScreenQ);
2184	  }
2185	  this.resetQ = new Quaternion();
2186	  this.orientationOut_ = new Float32Array(4);
2187	  this.start();
2188	}
2189	FusionPoseSensor.prototype.getPosition = function () {
2190	  return null;
2191	};
2192	FusionPoseSensor.prototype.getOrientation = function () {
2193	  var orientation = void 0;
2194	  if (this.isWithoutDeviceMotion && this._deviceOrientationQ) {
2195		this.deviceOrientationFixQ = this.deviceOrientationFixQ || function () {
2196		  var z = new Quaternion().setFromAxisAngle(new Vector3(0, 0, -1), 0);
2197		  var y = new Quaternion();
2198		  if (window.orientation === -90) {
2199			y.setFromAxisAngle(new Vector3(0, 1, 0), Math.PI / -2);
2200		  } else {
2201			y.setFromAxisAngle(new Vector3(0, 1, 0), Math.PI / 2);
2202		  }
2203		  return z.multiply(y);
2204		}();
2205		this.deviceOrientationFilterToWorldQ = this.deviceOrientationFilterToWorldQ || function () {
2206		  var q = new Quaternion();
2207		  q.setFromAxisAngle(new Vector3(1, 0, 0), -Math.PI / 2);
2208		  return q;
2209		}();
2210		orientation = this._deviceOrientationQ;
2211		var out = new Quaternion();
2212		out.copy(orientation);
2213		out.multiply(this.deviceOrientationFilterToWorldQ);
2214		out.multiply(this.resetQ);
2215		out.multiply(this.worldToScreenQ);
2216		out.multiplyQuaternions(this.deviceOrientationFixQ, out);
2217		if (this.yawOnly) {
2218		  out.x = 0;
2219		  out.z = 0;
2220		  out.normalize();
2221		}
2222		this.orientationOut_[0] = out.x;
2223		this.orientationOut_[1] = out.y;
2224		this.orientationOut_[2] = out.z;
2225		this.orientationOut_[3] = out.w;
2226		return this.orientationOut_;
2227	  } else {
2228		var filterOrientation = this.filter.getOrientation();
2229		orientation = this.posePredictor.getPrediction(filterOrientation, this.gyroscope, this.previousTimestampS);
2230	  }
2231	  var out = new Quaternion();
2232	  out.copy(this.filterToWorldQ);
2233	  out.multiply(this.resetQ);
2234	  out.multiply(orientation);
2235	  out.multiply(this.worldToScreenQ);
2236	  if (this.yawOnly) {
2237		out.x = 0;
2238		out.z = 0;
2239		out.normalize();
2240	  }
2241	  this.orientationOut_[0] = out.x;
2242	  this.orientationOut_[1] = out.y;
2243	  this.orientationOut_[2] = out.z;
2244	  this.orientationOut_[3] = out.w;
2245	  return this.orientationOut_;
2246	};
2247	FusionPoseSensor.prototype.resetPose = function () {
2248	  this.resetQ.copy(this.filter.getOrientation());
2249	  this.resetQ.x = 0;
2250	  this.resetQ.y = 0;
2251	  this.resetQ.z *= -1;
2252	  this.resetQ.normalize();
2253	  if (isLandscapeMode()) {
2254		this.resetQ.multiply(this.inverseWorldToScreenQ);
2255	  }
2256	  this.resetQ.multiply(this.originalPoseAdjustQ);
2257	};
2258	FusionPoseSensor.prototype.onDeviceOrientation_ = function (e) {
2259	  this._deviceOrientationQ = this._deviceOrientationQ || new Quaternion();
2260	  var alpha = e.alpha,
2261		  beta = e.beta,
2262		  gamma = e.gamma;
2263	  alpha = (alpha || 0) * Math.PI / 180;
2264	  beta = (beta || 0) * Math.PI / 180;
2265	  gamma = (gamma || 0) * Math.PI / 180;
2266	  this._deviceOrientationQ.setFromEulerYXZ(beta, alpha, -gamma);
2267	};
2268	FusionPoseSensor.prototype.onDeviceMotion_ = function (deviceMotion) {
2269	  this.updateDeviceMotion_(deviceMotion);
2270	};
2271	FusionPoseSensor.prototype.updateDeviceMotion_ = function (deviceMotion) {
2272	  var accGravity = deviceMotion.accelerationIncludingGravity;
2273	  var rotRate = deviceMotion.rotationRate;
2274	  var timestampS = deviceMotion.timeStamp / 1000;
2275	  var deltaS = timestampS - this.previousTimestampS;
2276	  if (deltaS < 0) {
2277		warnOnce('fusion-pose-sensor:invalid:non-monotonic', 'Invalid timestamps detected: non-monotonic timestamp from devicemotion');
2278		this.previousTimestampS = timestampS;
2279		return;
2280	  } else if (deltaS <= MIN_TIMESTEP || deltaS > MAX_TIMESTEP) {
2281		warnOnce('fusion-pose-sensor:invalid:outside-threshold', 'Invalid timestamps detected: Timestamp from devicemotion outside expected range.');
2282		this.previousTimestampS = timestampS;
2283		return;
2284	  }
2285	  this.accelerometer.set(-accGravity.x, -accGravity.y, -accGravity.z);
2286	  if (isR7()) {
2287		this.gyroscope.set(-rotRate.beta, rotRate.alpha, rotRate.gamma);
2288	  } else {
2289		this.gyroscope.set(rotRate.alpha, rotRate.beta, rotRate.gamma);
2290	  }
2291	  if (!this.isDeviceMotionInRadians) {
2292		this.gyroscope.multiplyScalar(Math.PI / 180);
2293	  }
2294	  this.filter.addAccelMeasurement(this.accelerometer, timestampS);
2295	  this.filter.addGyroMeasurement(this.gyroscope, timestampS);
2296	  this.previousTimestampS = timestampS;
2297	};
2298	FusionPoseSensor.prototype.onOrientationChange_ = function (screenOrientation) {
2299	  this.setScreenTransform_();
2300	};
2301	FusionPoseSensor.prototype.onMessage_ = function (event) {
2302	  var message = event.data;
2303	  if (!message || !message.type) {
2304		return;
2305	  }
2306	  var type = message.type.toLowerCase();
2307	  if (type !== 'devicemotion') {
2308		return;
2309	  }
2310	  this.updateDeviceMotion_(message.deviceMotionEvent);
2311	};
2312	FusionPoseSensor.prototype.setScreenTransform_ = function () {
2313	  this.worldToScreenQ.set(0, 0, 0, 1);
2314	  switch (window.orientation) {
2315		case 0:
2316		  break;
2317		case 90:
2318		  this.worldToScreenQ.setFromAxisAngle(new Vector3(0, 0, 1), -Math.PI / 2);
2319		  break;
2320		case -90:
2321		  this.worldToScreenQ.setFromAxisAngle(new Vector3(0, 0, 1), Math.PI / 2);
2322		  break;
2323	  }
2324	  this.inverseWorldToScreenQ.copy(this.worldToScreenQ);
2325	  this.inverseWorldToScreenQ.inverse();
2326	};
2327	FusionPoseSensor.prototype.start = function () {
2328	  this.onDeviceMotionCallback_ = this.onDeviceMotion_.bind(this);
2329	  this.onOrientationChangeCallback_ = this.onOrientationChange_.bind(this);
2330	  this.onMessageCallback_ = this.onMessage_.bind(this);
2331	  this.onDeviceOrientationCallback_ = this.onDeviceOrientation_.bind(this);
2332	  if (isIOS() && isInsideCrossOriginIFrame()) {
2333		window.addEventListener('message', this.onMessageCallback_);
2334	  }
2335	  window.addEventListener('orientationchange', this.onOrientationChangeCallback_);
2336	  if (this.isWithoutDeviceMotion) {
2337		window.addEventListener('deviceorientation', this.onDeviceOrientationCallback_);
2338	  } else {
2339		window.addEventListener('devicemotion', this.onDeviceMotionCallback_);
2340	  }
2341	};
2342	FusionPoseSensor.prototype.stop = function () {
2343	  window.removeEventListener('devicemotion', this.onDeviceMotionCallback_);
2344	  window.removeEventListener('deviceorientation', this.onDeviceOrientationCallback_);
2345	  window.removeEventListener('orientationchange', this.onOrientationChangeCallback_);
2346	  window.removeEventListener('message', this.onMessageCallback_);
2347	};
2348	var SENSOR_FREQUENCY = 60;
2349	var X_AXIS = new Vector3(1, 0, 0);
2350	var Z_AXIS = new Vector3(0, 0, 1);
2351	var orientation = {};
2352	if (screen.orientation) {
2353	  orientation = screen.orientation;
2354	} else if (screen.msOrientation) {
2355	  orientation = screen.msOrientation;
2356	} else {
2357	  Object.defineProperty(orientation, 'angle', {
2358		get: function get$$1() {
2359		  return window.orientation || 0;
2360		}
2361	  });
2362	}
2363	var SENSOR_TO_VR = new Quaternion();
2364	SENSOR_TO_VR.setFromAxisAngle(X_AXIS, -Math.PI / 2);
2365	SENSOR_TO_VR.multiply(new Quaternion().setFromAxisAngle(Z_AXIS, Math.PI / 2));
2366	var PoseSensor = function () {
2367	  function PoseSensor(config) {
2368		classCallCheck(this, PoseSensor);
2369		this.config = config;
2370		this.sensor = null;
2371		this.fusionSensor = null;
2372		this._out = new Float32Array(4);
2373		this.api = null;
2374		this.errors = [];
2375		this._sensorQ = new Quaternion();
2376		this._worldToScreenQ = new Quaternion();
2377		this._outQ = new Quaternion();
2378		this._onSensorRead = this._onSensorRead.bind(this);
2379		this._onSensorError = this._onSensorError.bind(this);
2380		this._onOrientationChange = this._onOrientationChange.bind(this);
2381		this._onOrientationChange();
2382		this.init();
2383	  }
2384	  createClass(PoseSensor, [{
2385		key: 'init',
vendor: 5,556 bytes, lines 2386-2474
2386		value: function init() {
2387		  var sensor = null;
2388		  try {
2389			sensor = new RelativeOrientationSensor({ frequency: SENSOR_FREQUENCY });
2390			sensor.addEventListener('error', this._onSensorError);
2391		  } catch (error) {
2392			this.errors.push(error);
2393			if (error.name === 'SecurityError') {
2394			  console.error('Cannot construct sensors due to the Feature Policy');
2395			  console.warn('Attempting to fall back using "devicemotion"; however this will ' + 'fail in the future without correct permissions.');
2396			  this.useDeviceMotion();
2397			} else if (error.name === 'ReferenceError') {
2398			  this.useDeviceMotion();
2399			} else {
2400			  console.error(error);
2401			}
2402		  }
2403		  if (sensor) {
2404			this.api = 'sensor';
2405			this.sensor = sensor;
2406			this.sensor.addEventListener('reading', this._onSensorRead);
2407			this.sensor.start();
2408		  }
2409		  window.addEventListener('orientationchange', this._onOrientationChange);
2410		}
2411	  }, {
2412		key: 'useDeviceMotion',
2413		value: function useDeviceMotion() {
2414		  this.api = 'devicemotion';
2415		  this.fusionSensor = new FusionPoseSensor(this.config.K_FILTER, this.config.PREDICTION_TIME_S, this.config.YAW_ONLY, this.config.DEBUG);
2416		  if (this.sensor) {
2417			this.sensor.removeEventListener('reading', this._onSensorRead);
2418			this.sensor.removeEventListener('error', this._onSensorError);
2419			this.sensor = null;
2420		  }
2421		}
2422	  }, {
2423		key: 'getOrientation',
2424		value: function getOrientation() {
2425		  if (this.fusionSensor) {
2426			return this.fusionSensor.getOrientation();
2427		  }
2428		  if (!this.sensor || !this.sensor.quaternion) {
2429			this._out[0] = this._out[1] = this._out[2] = 0;
2430			this._out[3] = 1;
2431			return this._out;
2432		  }
2433		  var q = this.sensor.quaternion;
2434		  this._sensorQ.set(q[0], q[1], q[2], q[3]);
2435		  var out = this._outQ;
2436		  out.copy(SENSOR_TO_VR);
2437		  out.multiply(this._sensorQ);
2438		  out.multiply(this._worldToScreenQ);
2439		  if (this.config.YAW_ONLY) {
2440			out.x = out.z = 0;
2441			out.normalize();
2442		  }
2443		  this._out[0] = out.x;
2444		  this._out[1] = out.y;
2445		  this._out[2] = out.z;
2446		  this._out[3] = out.w;
2447		  return this._out;
2448		}
2449	  }, {
2450		key: '_onSensorError',
2451		value: function _onSensorError(event) {
2452		  this.errors.push(event.error);
2453		  if (event.error.name === 'NotAllowedError') {
2454			console.error('Permission to access sensor was denied');
2455		  } else if (event.error.name === 'NotReadableError') {
2456			console.error('Sensor could not be read');
2457		  } else {
2458			console.error(event.error);
2459		  }
2460		  this.useDeviceMotion();
2461		}
2462	  }, {
2463		key: '_onSensorRead',
2464		value: function _onSensorRead() {}
2465	  }, {
2466		key: '_onOrientationChange',
2467		value: function _onOrientationChange() {
2468		  var angle = -orientation.angle * Math.PI / 180;
2469		  this._worldToScreenQ.setFromAxisAngle(Z_AXIS, angle);
2470		}
2471	  }]);
2472	  return PoseSensor;
2473	}();
2474	var rotateInstructionsAsset = 'PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+Cjxzdmcgd2lkdGg9IjE5OHB4IiBoZWlnaHQ9IjI0MHB4IiB2aWV3Qm94PSIwIDAgMTk4IDI0MCIgdmVyc2lvbj0iMS4xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB4bWxuczpza2V0Y2g9Imh0dHA6Ly93d3cuYm9oZW1pYW5jb2RpbmcuY29tL3NrZXRjaC9ucyI+CiAgICA8IS0tIEdlbmVyYXRvcjogU2tldGNoIDMuMy4zICgxMjA4MSkgLSBodHRwOi8vd3d3LmJvaGVtaWFuY29kaW5nLmNvbS9za2V0Y2ggLS0+CiAgICA8dGl0bGU+dHJhbnNpdGlvbjwvdGl0bGU+CiAgICA8ZGVzYz5DcmVhdGVkIHdpdGggU2tldGNoLjwvZGVzYz4KICAgIDxkZWZzPjwvZGVmcz4KICAgIDxnIGlkPSJQYWdlLTEiIHN0cm9rZT0ibm9uZSIgc3Ryb2tlLXdpZHRoPSIxIiBmaWxsPSJub25lIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiIHNrZXRjaDp0eXBlPSJNU1BhZ2UiPgogICAgICAgIDxnIGlkPSJ0cmFuc2l0aW9uIiBza2V0Y2g6dHlwZT0iTVNBcnRib2FyZEdyb3VwIj4KICAgICAgICAgICAgPGcgaWQ9IkltcG9ydGVkLUxheWVycy1Db3B5LTQtKy1JbXBvcnRlZC1MYXllcnMtQ29weS0rLUltcG9ydGVkLUxheWVycy1Db3B5LTItQ29weSIgc2tldGNoOnR5cGU9Ik1TTGF5ZXJHcm91cCI+CiAgICAgICAgICAgICAgICA8ZyBpZD0iSW1wb3J0ZWQtTGF5ZXJzLUNvcHktNCIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMC4wMDAwMDAsIDEwNy4wMDAwMDApIiBza2V0Y2g6dHlwZT0iTVNTaGFwZUdyb3VwIj4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNMTQ5LjYyNSwyLjUyNyBDMTQ5LjYyNSwyLjUyNyAxNTUuODA1LDYuMDk2IDE1Ni4zNjIsNi40MTggTDE1Ni4zNjIsNy4zMDQgQzE1Ni4zNjIsNy40ODEgMTU2LjM3NSw3LjY2NCAxNTYuNCw3Ljg1MyBDMTU2LjQxLDcuOTM0IDE1Ni40Miw4LjAxNSAxNTYuNDI3LDguMDk1IEMxNTYuNTY3LDkuNTEgMTU3LjQwMSwxMS4wOTMgMTU4LjUzMiwxMi4wOTQgTDE2NC4yNTIsMTcuMTU2IEwxNjQuMzMzLDE3LjA2NiBDMTY0LjMzMywxNy4wNjYgMTY4LjcxNSwxNC41MzYgMTY5LjU2OCwxNC4wNDIgQzE3MS4wMjUsMTQuODgzIDE5NS41MzgsMjkuMDM1IDE5NS41MzgsMjkuMDM1IEwxOTUuNTM4LDgzLjAzNiBDMTk1LjUzOCw4My44MDcgMTk1LjE1Miw4NC4yNTMgMTk0LjU5LDg0LjI1MyBDMTk0LjM1Nyw4NC4yNTMgMTk0LjA5NSw4NC4xNzcgMTkzLjgxOCw4NC4wMTcgTDE2OS44NTEsNzAuMTc5IEwxNjkuODM3LDcwLjIwMyBMMTQyLjUxNSw4NS45NzggTDE0MS42NjUsODQuNjU1IEMxMzYuOTM0LDgzLjEyNiAxMzEuOTE3LDgxLjkxNSAxMjYuNzE0LDgxLjA0NSBDMTI2LjcwOSw4MS4wNiAxMjYuNzA3LDgxLjA2OSAxMjYuNzA3LDgxLjA2OSBMMTIxLjY0LDk4LjAzIEwxMTMuNzQ5LDEwMi41ODYgTDExMy43MTIsMTAyLjUyMyBMMTEzLjcxMiwxMzAuMTEzIEMxMTMuNzEyLDEzMC44ODUgMTEzLjMyNiwxMzEuMzMgMTEyLjc2NCwxMzEuMzMgQzExMi41MzIsMTMxLjMzIDExMi4yNjksMTMxLjI1NCAxMTEuOTkyLDEzMS4wOTQgTDY5LjUxOSwxMDYuNTcyIEM2OC41NjksMTA2LjAyMyA2Ny43OTksMTA0LjY5NSA2Ny43OTksMTAzLjYwNSBMNjcuNzk5LDEwMi41NyBMNjcuNzc4LDEwMi42MTcgQzY3LjI3LDEwMi4zOTMgNjYuNjQ4LDEwMi4yNDkgNjUuOTYyLDEwMi4yMTggQzY1Ljg3NSwxMDIuMjE0IDY1Ljc4OCwxMDIuMjEyIDY1LjcwMSwxMDIuMjEyIEM2NS42MDYsMTAyLjIxMiA2NS41MTEsMTAyLjIxNSA2NS40MTYsMTAyLjIxOSBDNjUuMTk1LDEwMi4yMjkgNjQuOTc0LDEwMi4yMzUgNjQuNzU0LDEwMi4yMzUgQzY0LjMzMSwxMDIuMjM1IDYzLjkxMSwxMDIuMjE2IDYzLjQ5OCwxMDIuMTc4IEM2MS44NDMsMTAyLjAyNSA2MC4yOTgsMTAxLjU3OCA1OS4wOTQsMTAwLjg4MiBMMTIuNTE4LDczLjk5MiBMMTIuNTIzLDc0LjAwNCBMMi4yNDUsNTUuMjU0IEMxLjI0NCw1My40MjcgMi4wMDQsNTEuMDM4IDMuOTQzLDQ5LjkxOCBMNTkuOTU0LDE3LjU3MyB
2474DNjAuNjI2LDE3LjE4NSA2MS4zNSwxNy4wMDEgNjIuMDUzLDE3LjAwMSBDNjMuMzc5LDE3LjAwMSA2NC42MjUsMTcuNjYgNjUuMjgsMTguODU0IEw2NS4yODUsMTguODUxIEw2NS41MTIsMTkuMjY0IEw2NS41MDYsMTkuMjY4IEM2NS45MDksMjAuMDAzIDY2LjQwNSwyMC42OCA2Ni45ODMsMjEuMjg2IEw2Ny4yNiwyMS41NTYgQzY5LjE3NCwyMy40MDYgNzEuNzI4LDI0LjM1NyA3NC4zNzMsMjQuMzU3IEM3Ni4zMjIsMjQuMzU3IDc4LjMyMSwyMy44NCA4MC4xNDgsMjIuNzg1IEM4MC4xNjEsMjIuNzg1IDg3LjQ2NywxOC41NjYgODcuNDY3LDE4LjU2NiBDODguMTM5LDE4LjE3OCA4OC44NjMsMTcuOTk0IDg5LjU2NiwxNy45OTQgQzkwLjg5MiwxNy45OTQgOTIuMTM4LDE4LjY1MiA5Mi43OTIsMTkuODQ3IEw5Ni4wNDIsMjUuNzc1IEw5Ni4wNjQsMjUuNzU3IEwxMDIuODQ5LDI5LjY3NCBMMTAyLjc0NCwyOS40OTIgTDE0OS42MjUsMi41MjcgTTE0OS42MjUsMC44OTIgQzE0OS4zNDMsMC44OTIgMTQ5LjA2MiwwLjk2NSAxNDguODEsMS4xMSBMMTAyLjY0MSwyNy42NjYgTDk3LjIzMSwyNC41NDIgTDk0LjIyNiwxOS4wNjEgQzkzLjMxMywxNy4zOTQgOTEuNTI3LDE2LjM1OSA4OS41NjYsMTYuMzU4IEM4OC41NTUsMTYuMzU4IDg3LjU0NiwxNi42MzIgODYuNjQ5LDE3LjE1IEM4My44NzgsMTguNzUgNzkuNjg3LDIxLjE2OSA3OS4zNzQsMjEuMzQ1IEM3OS4zNTksMjEuMzUzIDc5LjM0NSwyMS4zNjEgNzkuMzMsMjEuMzY5IEM3Ny43OTgsMjIuMjU0IDc2LjA4NCwyMi43MjIgNzQuMzczLDIyLjcyMiBDNzIuMDgxLDIyLjcyMiA2OS45NTksMjEuODkgNjguMzk3LDIwLjM4IEw2OC4xNDUsMjAuMTM1IEM2Ny43MDYsMTkuNjcyIDY3LjMyMywxOS4xNTYgNjcuMDA2LDE4LjYwMSBDNjYuOTg4LDE4LjU1OSA2Ni45NjgsMTguNTE5IDY2Ljk0NiwxOC40NzkgTDY2LjcxOSwxOC4wNjUgQzY2LjY5LDE4LjAxMiA2Ni42NTgsMTcuOTYgNjYuNjI0LDE3LjkxMSBDNjUuNjg2LDE2LjMzNyA2My45NTEsMTUuMzY2IDYyLjA1MywxNS4zNjYgQzYxLjA0MiwxNS4zNjYgNjAuMDMzLDE1LjY0IDU5LjEzNiwxNi4xNTggTDMuMTI1LDQ4LjUwMiBDMC40MjYsNTAuMDYxIC0wLjYxMyw1My40NDIgMC44MTEsNTYuMDQgTDExLjA4OSw3NC43OSBDMTEuMjY2LDc1LjExMyAxMS41MzcsNzUuMzUzIDExLjg1LDc1LjQ5NCBMNTguMjc2LDEwMi4yOTggQzU5LjY3OSwxMDMuMTA4IDYxLjQzMywxMDMuNjMgNjMuMzQ4LDEwMy44MDYgQzYzLjgxMiwxMDMuODQ4IDY0LjI4NSwxMDMuODcgNjQuNzU0LDEwMy44NyBDNjUsMTAzLjg3IDY1LjI0OSwxMDMuODY0IDY1LjQ5NCwxMDMuODUyIEM2NS41NjMsMTAzLjg0OSA2NS42MzIsMTAzLjg0NyA2NS43MDEsMTAzLjg0NyBDNjUuNzY0LDEwMy44NDcgNjUuODI4LDEwMy44NDkgNjUuODksMTAzLjg1MiBDNjUuOTg2LDEwMy44NTYgNjYuMDgsMTAzLjg2MyA2Ni4xNzMsMTAzLjg3NCBDNjYuMjgyLDEwNS40NjcgNjcuMzMyLDEwNy4xOTcgNjguNzAyLDEwNy45ODggTDExMS4xNzQsMTMyLjUxIEMxMTEuNjk4LDEzMi44MTIgMTEyLjIzMiwxMzIuOTY1IDExMi43NjQsMTMyLjk2NSBDMTE0LjI2MSwxMzIuOTY1IDExNS4zNDcsMTMxLjc2NSAxMTUuMzQ3LDEzMC4xMTMgTDExNS4zNDcsMTAzLjU1MSBMMTIyLjQ1OCw5OS40NDYgQzEyMi44MTksOTkuMjM3IDEyMy4wODcsOTguODk4IDEyMy4yMDcsOTguNDk4IEwxMjcuODY1LDgyLjkwNSBDMTMyLjI3OSw4My43MDIgMTM2LjU1Nyw4NC43NTMgMTQwLjYwNyw4Ni4wMzMgTDE0MS4xNCw4Ni44NjIgQzE0MS40NTEsODcuMzQ2IDE0MS45NzcsODcuNjEzIDE0Mi41MTYsODcuNjEzIEMxNDIuNzk0LDg3LjYxMyAxNDMuMDc2LDg3LjU0MiAxNDMuMzMzLDg3LjM5MyBMMTY5Ljg2NSw3Mi4wNzYgTDE5Myw4NS40MzMgQzE5My41MjMsODUuNzM1IDE5NC4wNTgsODUuODg4IDE5NC41OSw4NS44ODggQzE5Ni4wODcsODUuODg4IDE5Ny4xNzMsODQuNjg5IDE5Ny4xNzMsODMuMDM2IEwxOTcuMTczLDI5LjAzNSBDMTk3LjE3MywyOC40NTEgMTk2Ljg2MSwyNy45MTEgMTk2LjM1NSwyNy42MTkgQzE5Ni4zNTUsMjcuNjE5IDE3MS44NDMsMTMuNDY3IDE3MC4zODUsMTIuNjI2IEMxNzAuMTMyLDEyLjQ4IDE2OS44NSwxMi40MDcgMTY5LjU2OCwxMi40MDcgQzE2OS4yODUsMTIuNDA3IDE2OS4wMDIsMTIuNDgxIDE2OC43NDksMTIuNjI3IEMxNjguMTQzLDEyLjk3OCAxNjUuNzU2LDE0LjM1NyAxNjQuNDI0LDE1LjEyNSBMMTU5LjYxNSwxMC44NyBDMTU4Ljc5NiwxMC4xNDUgMTU4LjE1NCw4LjkzNyAxNTguMDU0LDcuOTM0IEMxNTguMDQ1LDcuODM3IDE1OC4wMzQsNy43MzkgMTU4LjAyMSw3LjY0IEMxNTguMDA1LDcuNTIzIDE1Ny45OTgsNy40MSAxNTcuOTk4LDcuMzA0IEwxNTcuOTk4LDYuNDE4IEMxNTcuOTk4LDUuODM0IDE1Ny42ODYsNS4yOTUgMTU3LjE4MSw1LjAwMiBDMTU2LjYyNCw0LjY4IDE1MC40NDIsMS4xMTEgMTUwLjQ0MiwxLjExMSBDMTUwLjE4OSwwLjk2NSAxNDkuOTA3LDAuODkyIDE0OS42MjUsMC44OTIiIGlkPSJGaWxsLTEiIGZpbGw9IiM0NTVBNjQiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNOTYuMDI3LDI1LjYzNiBMMTQyLjYwMyw1Mi41MjcgQzE0My44MDcsNTMuMjIyIDE0NC41ODIsNTQuMTE0IDE0NC44NDUsNTUuMDY4IEwxNDQuODM1LDU1LjA3NSBMNjMuNDYxLDEwMi4wNTcgTDYzLjQ2LDEwMi4wNTcgQzYxLjgwNiwxMDEuOTA1IDYwLjI2MSwxMDEuNDU3IDU5LjA1NywxMDAuNzYyIEwxMi40ODEsNzMuODcxIEw5Ni4wMjcsMjUuNjM2IiBpZD0iRmlsbC0yIiBmaWxsPSIjRkFGQUZBIj48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTYzLjQ2MSwxMDIuMTc0IEM2My40NTMsMTAyLjE3NCA2My40NDYsMTAyLjE3NCA2My40MzksMTAyLjE3MiBDNjEuNzQ2LDEwMi4wMTYgNjAuMjExLDEwMS41NjMgNTguOTk4LDEwMC44NjMgTDEyLjQyMiw3My45NzMgQzEyLjM4Niw3My45NTIgMTIuMzY0LDczLjkxNCAxMi4zNjQsNzMuODcxIEMxMi4zNjQsNzMuODMgMTIuMzg2LDczLjc5MSAxMi40MjIsNzMuNzcgTDk1Ljk2OCwyNS41MzUgQzk2LjAwNCwyNS41MTQgOTYuMDQ5LDI1LjUxNCA5Ni4wODUsMjUuNTM1IEwxNDIuNjYxLDUyLjQyNiBDMTQzLjg4OCw1My4xMzQgMTQ0LjY4Miw1NC4wMzggMTQ0Ljk1Nyw1NS4wMzcgQzE0NC45Nyw1NS4wODMgMTQ0Ljk1Myw1NS4xMzMgMTQ0LjkxNSw1NS4xNjEgQzE0NC45MTEsNTUuMTY1IDE0NC44OTgsNTUuMTc0IDE0NC44OTQsNTUuMTc3IEw2My41MTksMTAyLjE1OCBDNjMuNTAxLDEwMi4xNjkgNjMuNDgxLDEwMi4xNzQgNjMuNDYxLDEwMi4xNzQgTDYzLjQ2MSwxMDIuMTc0IFogTTEyLjcxNCw3My44NzEgTDU5LjExNSwxMDAuNjYxIEM2MC4yOTMsMTAxLjM0MSA2MS43ODYsMTAxLjc4MiA2My40MzUsMTAxLjkzNyBMMTQ0LjcwNyw1NS4wMTUgQzE0NC40MjgsNTQuMTA4IDE0My42ODIsNTMuMjg1IDE0Mi41NDQsNTIuNjI4IEw5Ni4wMjcsMjUuNzcxIEwxMi43MTQsNzMuODcxIEwxMi43MTQsNzMuODcxIFoiIGlkPSJGaWxsLTMiIGZpbGw9IiM2MDdEOEIiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNMTQ4LjMyNyw1OC40NzEgQzE0OC4xNDUsNTguNDggMTQ3Ljk2Miw1OC40OCAxNDcuNzgxLDU4LjQ3MiBDMTQ1Ljg4Nyw1OC4zODkgMTQ0LjQ3OSw1Ny40MzQgMTQ0LjYzNiw1Ni4zNCB
2474DMTQ0LjY4OSw1NS45NjcgMTQ0LjY2NCw1NS41OTcgMTQ0LjU2NCw1NS4yMzUgTDYzLjQ2MSwxMDIuMDU3IEM2NC4wODksMTAyLjExNSA2NC43MzMsMTAyLjEzIDY1LjM3OSwxMDIuMDk5IEM2NS41NjEsMTAyLjA5IDY1Ljc0MywxMDIuMDkgNjUuOTI1LDEwMi4wOTggQzY3LjgxOSwxMDIuMTgxIDY5LjIyNywxMDMuMTM2IDY5LjA3LDEwNC4yMyBMMTQ4LjMyNyw1OC40NzEiIGlkPSJGaWxsLTQiIGZpbGw9IiNGRkZGRkYiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNNjkuMDcsMTA0LjM0NyBDNjkuMDQ4LDEwNC4zNDcgNjkuMDI1LDEwNC4zNCA2OS4wMDUsMTA0LjMyNyBDNjguOTY4LDEwNC4zMDEgNjguOTQ4LDEwNC4yNTcgNjguOTU1LDEwNC4yMTMgQzY5LDEwMy44OTYgNjguODk4LDEwMy41NzYgNjguNjU4LDEwMy4yODggQzY4LjE1MywxMDIuNjc4IDY3LjEwMywxMDIuMjY2IDY1LjkyLDEwMi4yMTQgQzY1Ljc0MiwxMDIuMjA2IDY1LjU2MywxMDIuMjA3IDY1LjM4NSwxMDIuMjE1IEM2NC43NDIsMTAyLjI0NiA2NC4wODcsMTAyLjIzMiA2My40NSwxMDIuMTc0IEM2My4zOTksMTAyLjE2OSA2My4zNTgsMTAyLjEzMiA2My4zNDcsMTAyLjA4MiBDNjMuMzM2LDEwMi4wMzMgNjMuMzU4LDEwMS45ODEgNjMuNDAyLDEwMS45NTYgTDE0NC41MDYsNTUuMTM0IEMxNDQuNTM3LDU1LjExNiAxNDQuNTc1LDU1LjExMyAxNDQuNjA5LDU1LjEyNyBDMTQ0LjY0Miw1NS4xNDEgMTQ0LjY2OCw1NS4xNyAxNDQuNjc3LDU1LjIwNCBDMTQ0Ljc4MSw1NS41ODUgMTQ0LjgwNiw1NS45NzIgMTQ0Ljc1MSw1Ni4zNTcgQzE0NC43MDYsNTYuNjczIDE0NC44MDgsNTYuOTk0IDE0NS4wNDcsNTcuMjgyIEMxNDUuNTUzLDU3Ljg5MiAxNDYuNjAyLDU4LjMwMyAxNDcuNzg2LDU4LjM1NSBDMTQ3Ljk2NCw1OC4zNjMgMTQ4LjE0Myw1OC4zNjMgMTQ4LjMyMSw1OC4zNTQgQzE0OC4zNzcsNTguMzUyIDE0OC40MjQsNTguMzg3IDE0OC40MzksNTguNDM4IEMxNDguNDU0LDU4LjQ5IDE0OC40MzIsNTguNTQ1IDE0OC4zODUsNTguNTcyIEw2OS4xMjksMTA0LjMzMSBDNjkuMTExLDEwNC4zNDIgNjkuMDksMTA0LjM0NyA2OS4wNywxMDQuMzQ3IEw2OS4wNywxMDQuMzQ3IFogTTY1LjY2NSwxMDEuOTc1IEM2NS43NTQsMTAxLjk3NSA2NS44NDIsMTAxLjk3NyA2NS45MywxMDEuOTgxIEM2Ny4xOTYsMTAyLjAzNyA2OC4yODMsMTAyLjQ2OSA2OC44MzgsMTAzLjEzOSBDNjkuMDY1LDEwMy40MTMgNjkuMTg4LDEwMy43MTQgNjkuMTk4LDEwNC4wMjEgTDE0Ny44ODMsNTguNTkyIEMxNDcuODQ3LDU4LjU5MiAxNDcuODExLDU4LjU5MSAxNDcuNzc2LDU4LjU4OSBDMTQ2LjUwOSw1OC41MzMgMTQ1LjQyMiw1OC4xIDE0NC44NjcsNTcuNDMxIEMxNDQuNTg1LDU3LjA5MSAxNDQuNDY1LDU2LjcwNyAxNDQuNTIsNTYuMzI0IEMxNDQuNTYzLDU2LjAyMSAxNDQuNTUyLDU1LjcxNiAxNDQuNDg4LDU1LjQxNCBMNjMuODQ2LDEwMS45NyBDNjQuMzUzLDEwMi4wMDIgNjQuODY3LDEwMi4wMDYgNjUuMzc0LDEwMS45ODIgQzY1LjQ3MSwxMDEuOTc3IDY1LjU2OCwxMDEuOTc1IDY1LjY2NSwxMDEuOTc1IEw2NS42NjUsMTAxLjk3NSBaIiBpZD0iRmlsbC01IiBmaWxsPSIjNjA3RDhCIj48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTIuMjA4LDU1LjEzNCBDMS4yMDcsNTMuMzA3IDEuOTY3LDUwLjkxNyAzLjkwNiw0OS43OTcgTDU5LjkxNywxNy40NTMgQzYxLjg1NiwxNi4zMzMgNjQuMjQxLDE2LjkwNyA2NS4yNDMsMTguNzM0IEw2NS40NzUsMTkuMTQ0IEM2NS44NzIsMTkuODgyIDY2LjM2OCwyMC41NiA2Ni45NDUsMjEuMTY1IEw2Ny4yMjMsMjEuNDM1IEM3MC41NDgsMjQuNjQ5IDc1LjgwNiwyNS4xNTEgODAuMTExLDIyLjY2NSBMODcuNDMsMTguNDQ1IEM4OS4zNywxNy4zMjYgOTEuNzU0LDE3Ljg5OSA5Mi43NTUsMTkuNzI3IEw5Ni4wMDUsMjUuNjU1IEwxMi40ODYsNzMuODg0IEwyLjIwOCw1NS4xMzQgWiIgaWQ9IkZpbGwtNiIgZmlsbD0iI0ZBRkFGQSI+PC9wYXRoPgogICAgICAgICAgICAgICAgICAgIDxwYXRoIGQ9Ik0xMi40ODYsNzQuMDAxIEMxMi40NzYsNzQuMDAxIDEyLjQ2NSw3My45OTkgMTIuNDU1LDczLjk5NiBDMTIuNDI0LDczLjk4OCAxMi4zOTksNzMuOTY3IDEyLjM4NCw3My45NCBMMi4xMDYsNTUuMTkgQzEuMDc1LDUzLjMxIDEuODU3LDUwLjg0NSAzLjg0OCw0OS42OTYgTDU5Ljg1OCwxNy4zNTIgQzYwLjUyNSwxNi45NjcgNjEuMjcxLDE2Ljc2NCA2Mi4wMTYsMTYuNzY0IEM2My40MzEsMTYuNzY0IDY0LjY2NiwxNy40NjYgNjUuMzI3LDE4LjY0NiBDNjUuMzM3LDE4LjY1NCA2NS4zNDUsMTguNjYzIDY1LjM1MSwxOC42NzQgTDY1LjU3OCwxOS4wODggQzY1LjU4NCwxOS4xIDY1LjU4OSwxOS4xMTIgNjUuNTkxLDE5LjEyNiBDNjUuOTg1LDE5LjgzOCA2Ni40NjksMjAuNDk3IDY3LjAzLDIxLjA4NSBMNjcuMzA1LDIxLjM1MSBDNjkuMTUxLDIzLjEzNyA3MS42NDksMjQuMTIgNzQuMzM2LDI0LjEyIEM3Ni4zMTMsMjQuMTIgNzguMjksMjMuNTgyIDgwLjA1MywyMi41NjMgQzgwLjA2NCwyMi41NTcgODAuMDc2LDIyLjU1MyA4MC4wODgsMjIuNTUgTDg3LjM3MiwxOC4zNDQgQzg4LjAzOCwxNy45NTkgODguNzg0LDE3Ljc1NiA4OS41MjksMTcuNzU2IEM5MC45NTYsMTcuNzU2IDkyLjIwMSwxOC40NzIgOTIuODU4LDE5LjY3IEw5Ni4xMDcsMjUuNTk5IEM5Ni4xMzgsMjUuNjU0IDk2LjExOCwyNS43MjQgOTYuMDYzLDI1Ljc1NiBMMTIuNTQ1LDczLjk4NSBDMTIuNTI2LDczLjk5NiAxMi41MDYsNzQuMDAxIDEyLjQ4Niw3NC4wMDEgTDEyLjQ4Niw3NC4wMDEgWiBNNjIuMDE2LDE2Ljk5NyBDNjEuMzEyLDE2Ljk5NyA2MC42MDYsMTcuMTkgNTkuOTc1LDE3LjU1NCBMMy45NjUsNDkuODk5IEMyLjA4Myw1MC45ODUgMS4zNDEsNTMuMzA4IDIuMzEsNTUuMDc4IEwxMi41MzEsNzMuNzIzIEw5NS44NDgsMjUuNjExIEw5Mi42NTMsMTkuNzgyIEM5Mi4wMzgsMTguNjYgOTAuODcsMTcuOTkgODkuNTI5LDE3Ljk5IEM4OC44MjUsMTcuOTkgODguMTE5LDE4LjE4MiA4Ny40ODksMTguNTQ3IEw4MC4xNzIsMjIuNzcyIEM4MC4xNjEsMjIuNzc4IDgwLjE0OSwyMi43ODIgODAuMTM3LDIyLjc4NSBDNzguMzQ2LDIzLjgxMSA3Ni4zNDEsMjQuMzU0IDc0LjMzNiwyNC4zNTQgQzcxLjU4OCwyNC4zNTQgNjkuMDMzLDIzLjM0NyA2Ny4xNDIsMjEuNTE5IEw2Ni44NjQsMjEuMjQ5IEM2Ni4yNzcsMjAuNjM0IDY1Ljc3NCwxOS45NDcgNjUuMzY3LDE5LjIwMyBDNjUuMzYsMTkuMTkyIDY1LjM1NiwxOS4xNzkgNjUuMzU0LDE5LjE2NiBMNjUuMTYzLDE4LjgxOSBDNjUuMTU0LDE4LjgxMSA2NS4xNDYsMTguODAxIDY1LjE0LDE4Ljc5IEM2NC41MjUsMTcuNjY3IDYzLjM1NywxNi45OTcgNjIuMDE2LDE2Ljk5NyBMNjIuMDE2LDE2Ljk5NyBaIiBpZD0iRmlsbC03IiBmaWxsPSIjNjA3RDhCIj48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTQyLjQzNCw0OC44MDggTDQyLjQzNCw0OC44MDggQzM5LjkyNCw0OC44MDcgMzcuNzM3LDQ3LjU1IDM2LjU4Miw0NS40NDMgQzM0Ljc3MSw0Mi4xMzkgMzYuMTQ0LDM3LjgwOSAzOS42NDEsMzUuNzg5IEw1MS45MzIsMjguNjkxIEM1My4xMDMsMjguMDE1IDU0LjQxMywyNy42NTggNTUuNzIxLDI3LjY1OCBDNTguMjMxLDI3LjY1OCA2MC40MTgsMjguOTE2IDYxLjU3MywzMS4wMjMgQzYzLjM4NCwzNC4zMjcgNjIuMDEyLDM4LjY1NyA1OC41MTQsNDAuNjc3IEw0Ni4yMjMsNDcuNzc1IEM0NS4wNTMsNDguNDUgNDMuNzQyLDQ4LjgwOCA0Mi40MzQsNDguODA4IEw0Mi40MzQsNDguODA4IFogTTU1LjcyMSwyOC4xMjUgQzU0LjQ5NSwyOC4xMjUgNTMuMjY1LDI4LjQ2MSA1Mi4xNjYsMjkuMDk2IEwzOS44NzUsMzYuMTk0IEMzNi41OTYsMzguMDg3IDM1LjMwMiw0Mi4xMzYgMzYuOTkyLDQ1LjIxOCBDMzguMDYzLDQ3LjE3MyA0MC4wOTgsNDguMzQgNDIuNDM0LDQ4LjM0IEM0My42NjEsNDguMzQgNDQuODksNDguMDA1IDQ1Ljk5LDQ3LjM3IEw1OC4yODEsNDAuMjcyIEM2MS41NiwzOC4zNzkgNjIuODUzLDM0LjMzIDYxLjE2NCwzMS4yNDggQzYwLjA5MiwyOS4yOTMgNTguMDU4LDI4LjEyNSA1NS43MjEsMjguMTI1IEw1NS43MjEsMjguMTI1IFoiIGlkPSJGaWxsLTgiIGZpbGw9IiM2MDdEOEIiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNMTQ5LjU4OCwyLjQwNyBDMTQ5LjU4OCwyLjQwNyAxNTUuNzY4LDUuOTc1IDE1Ni4zMjUsNi4yOTcgTDE1Ni4zMjUsNy4xODQgQzE1Ni4zMjUsNy4zNiAxNTYuMzM4LDcuNTQ0IDE1Ni4zNjIsNy43MzMgQzE1Ni4zNzMsNy44MTQgMTU2LjM4Miw3Ljg5NCAxNTYuMzksNy45NzUgQzE1Ni41Myw5LjM5IDE1Ny4zNjMsMTAuOTczIDE1OC40OTUsMTEuOTc0IEwxNjUuODkxLDE4LjUxOSBDMTY2LjA2OCwxOC42NzUgMTY2LjI0OSwxOC44MTQgMTY2LjQzMiwxOC45MzQgQzE2OC4wMTEsMTkuOTc0IDE2OS4zODIsMTkuNCAxNjkuNDk0LDE3LjY1MiBDMTY5LjU0MywxNi44NjggMTY5LjU1MSwxNi4wNTcgMTY5LjUxNywxNS4yMjMgTDE2OS41MTQsMTUuMDYzIEwxNjkuNTE0LDEzLjkxMiBDMTcwLjc4LDE0LjY0MiAxOTUuNTAxLDI4LjkxNSAxOTUuNTAxLDI4LjkxNSBMMTk1LjUwMSw4Mi45MTUgQzE5NS41MDEsODQuMDA1IDE5NC43MzEsODQuNDQ1IDE5My43ODEsODMuODk3IEwxNTEuMzA4LDU5LjM3NCBDMTUwLjM1OCw1OC44MjYgMTQ5LjU4OCw1Ny40OTcgMTQ5LjU4OCw1Ni40MDggTDE0OS41ODgsMjIuMzc1IiBpZD0iRmlsbC05IiBmaWxsPSIjRkFGQUZBIj48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTE5NC41NTMsODQuMjUgQzE5NC4yOTYsODQuMjUgMTk0LjAxMyw4NC4xNjUgMTkzLjcyMiw4My45OTcgTDE1MS4yNSw1OS40NzYgQzE1MC4yNjksNTguOTA5IDE0OS40NzEsNTcuNTMzIDE0OS40NzEsNTYuNDA4IEwxNDkuNDcxLDIyLjM3NSBMMTQ5LjcwNSwyMi4zNzUgTDE0OS43MDUsNTYuNDA4IEMxNDkuNzA1LDU3LjQ1OSAxNTAuNDUsNTguNzQ0IDE1MS4zNjYsNTkuMjc0IEwxOTMuODM5LDgzLjc5NSBDMTk0LjI2Myw4NC4wNCAxOTQuNjU1LDg0LjA4MyAxOTQuOTQyLDgzLjkxNyBDMTk1LjIyNyw4My43NTMgMTk1LjM4NCw4My4zOTcgMTk1LjM4NCw4Mi45MTUgTDE5NS4zODQsMjguOTgyIEMxOTQuMTAyLDI4LjI0MiAxNzIuMTA0LDE1LjU0MiAxNjkuNjMxLDE0LjExNCBMMTY5LjYzNCwxNS4yMiBDMTY5LjY2OCwxNi4wNTIgMTY5LjY2LDE2Ljg3NCAxNjkuNjEsMTcuNjU5IEMxNjkuNTU2LDE4LjUwMyAxNjkuMjE0LDE
24745LjEyMyAxNjguNjQ3LDE5LjQwNSBDMTY4LjAyOCwxOS43MTQgMTY3LjE5NywxOS41NzggMTY2LjM2NywxOS4wMzIgQzE2Ni4xODEsMTguOTA5IDE2NS45OTUsMTguNzY2IDE2NS44MTQsMTguNjA2IEwxNTguNDE3LDEyLjA2MiBDMTU3LjI1OSwxMS4wMzYgMTU2LjQxOCw5LjQzNyAxNTYuMjc0LDcuOTg2IEMxNTYuMjY2LDcuOTA3IDE1Ni4yNTcsNy44MjcgMTU2LjI0Nyw3Ljc0OCBDMTU2LjIyMSw3LjU1NSAxNTYuMjA5LDcuMzY1IDE1Ni4yMDksNy4xODQgTDE1Ni4yMDksNi4zNjQgQzE1NS4zNzUsNS44ODMgMTQ5LjUyOSwyLjUwOCAxNDkuNTI5LDIuNTA4IEwxNDkuNjQ2LDIuMzA2IEMxNDkuNjQ2LDIuMzA2IDE1NS44MjcsNS44NzQgMTU2LjM4NCw2LjE5NiBMMTU2LjQ0Miw2LjIzIEwxNTYuNDQyLDcuMTg0IEMxNTYuNDQyLDcuMzU1IDE1Ni40NTQsNy41MzUgMTU2LjQ3OCw3LjcxNyBDMTU2LjQ4OSw3LjggMTU2LjQ5OSw3Ljg4MiAxNTYuNTA3LDcuOTYzIEMxNTYuNjQ1LDkuMzU4IDE1Ny40NTUsMTAuODk4IDE1OC41NzIsMTEuODg2IEwxNjUuOTY5LDE4LjQzMSBDMTY2LjE0MiwxOC41ODQgMTY2LjMxOSwxOC43MiAxNjYuNDk2LDE4LjgzNyBDMTY3LjI1NCwxOS4zMzYgMTY4LDE5LjQ2NyAxNjguNTQzLDE5LjE5NiBDMTY5LjAzMywxOC45NTMgMTY5LjMyOSwxOC40MDEgMTY5LjM3NywxNy42NDUgQzE2OS40MjcsMTYuODY3IDE2OS40MzQsMTYuMDU0IDE2OS40MDEsMTUuMjI4IEwxNjkuMzk3LDE1LjA2NSBMMTY5LjM5NywxMy43MSBMMTY5LjU3MiwxMy44MSBDMTcwLjgzOSwxNC41NDEgMTk1LjU1OSwyOC44MTQgMTk1LjU1OSwyOC44MTQgTDE5NS42MTgsMjguODQ3IEwxOTUuNjE4LDgyLjkxNSBDMTk1LjYxOCw4My40ODQgMTk1LjQyLDgzLjkxMSAxOTUuMDU5LDg0LjExOSBDMTk0LjkwOCw4NC4yMDYgMTk0LjczNyw4NC4yNSAxOTQuNTUzLDg0LjI1IiBpZD0iRmlsbC0xMCIgZmlsbD0iIzYwN0Q4QiI+PC9wYXRoPgogICAgICAgICAgICAgICAgICAgIDxwYXRoIGQ9Ik0xNDUuNjg1LDU2LjE2MSBMMTY5LjgsNzAuMDgzIEwxNDMuODIyLDg1LjA4MSBMMTQyLjM2LDg0Ljc3NCBDMTM1LjgyNiw4Mi42MDQgMTI4LjczMiw4MS4wNDYgMTIxLjM0MSw4MC4xNTggQzExNi45NzYsNzkuNjM0IDExMi42NzgsODEuMjU0IDExMS43NDMsODMuNzc4IEMxMTEuNTA2LDg0LjQxNCAxMTEuNTAzLDg1LjA3MSAxMTEuNzMyLDg1LjcwNiBDMTEzLjI3LDg5Ljk3MyAxMTUuOTY4LDk0LjA2OSAxMTkuNzI3LDk3Ljg0MSBMMTIwLjI1OSw5OC42ODYgQzEyMC4yNiw5OC42ODUgOTQuMjgyLDExMy42ODMgOTQuMjgyLDExMy42ODMgTDcwLjE2Nyw5OS43NjEgTDE0NS42ODUsNTYuMTYxIiBpZD0iRmlsbC0xMSIgZmlsbD0iI0ZGRkZGRiI+PC9wYXRoPgogICAgICAgICAgICAgICAgICAgIDxwYXRoIGQ9Ik05NC4yODIsMTEzLjgxOCBMOTQuMjIzLDExMy43ODUgTDY5LjkzMyw5OS43NjEgTDcwLjEwOCw5OS42NiBMMTQ1LjY4NSw1Ni4wMjYgTDE0NS43NDMsNTYuMDU5IEwxNzAuMDMzLDcwLjA4MyBMMTQzLjg0Miw4NS4yMDUgTDE0My43OTcsODUuMTk1IEMxNDMuNzcyLDg1LjE5IDE0Mi4zMzYsODQuODg4IDE0Mi4zMzYsODQuODg4IEMxMzUuNzg3LDgyLjcxNCAxMjguNzIzLDgxLjE2MyAxMjEuMzI3LDgwLjI3NCBDMTIwLjc4OCw4MC4yMDkgMTIwLjIzNiw4MC4xNzcgMTE5LjY4OSw4MC4xNzcgQzExNS45MzEsODAuMTc3IDExMi42MzUsODEuNzA4IDExMS44NTIsODMuODE5IEMxMTEuNjI0LDg0LjQzMiAxMTEuNjIxLDg1LjA1MyAxMTEuODQyLDg1LjY2NyBDMTEzLjM3Nyw4OS45MjUgMTE2LjA1OCw5My45OTMgMTE5LjgxLDk3Ljc1OCBMMTE5LjgyNiw5Ny43NzkgTDEyMC4zNTIsOTguNjE0IEMxMjAuMzU0LDk4LjYxNyAxMjAuMzU2LDk4LjYyIDEyMC4zNTgsOTguNjI0IEwxMjAuNDIyLDk4LjcyNiBMMTIwLjMxNyw5OC43ODcgQzEyMC4yNjQsOTguODE4IDk0LjU5OSwxMTMuNjM1IDk0LjM0LDExMy43ODUgTDk0LjI4MiwxMTMuODE4IEw5NC4yODIsMTEzLjgxOCBaIE03MC40MDEsOTkuNzYxIEw5NC4yODIsMTEzLjU0OSBMMTE5LjA4NCw5OS4yMjkgQzExOS42Myw5OC45MTQgMTE5LjkzLDk4Ljc0IDEyMC4xMDEsOTguNjU0IEwxMTkuNjM1LDk3LjkxNCBDMTE1Ljg2NCw5NC4xMjcgMTEzLjE2OCw5MC4wMzMgMTExLjYyMiw4NS43NDYgQzExMS4zODIsODUuMDc5IDExMS4zODYsODQuNDA0IDExMS42MzMsODMuNzM4IEMxMTIuNDQ4LDgxLjUzOSAxMTUuODM2LDc5Ljk0MyAxMTkuNjg5LDc5Ljk0MyBDMTIwLjI0Niw3OS45NDMgMTIwLjgwNiw3OS45NzYgMTIxLjM1NSw4MC4wNDIgQzEyOC43NjcsODAuOTMzIDEzNS44NDYsODIuNDg3IDE0Mi4zOTYsODQuNjYzIEMxNDMuMjMyLDg0LjgzOCAxNDMuNjExLDg0LjkxNyAxNDMuNzg2LDg0Ljk2NyBMMTY5LjU2Niw3MC4wODMgTDE0NS42ODUsNTYuMjk1IEw3MC40MDEsOTkuNzYxIEw3MC40MDEsOTkuNzYxIFoiIGlkPSJGaWxsLTEyIiBmaWxsPSIjNjA3RDhCIj48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTE2Ny4yMywxOC45NzkgTDE2Ny4yMyw2OS44NSBMMTM5LjkwOSw4NS42MjMgTDEzMy40NDgsNzEuNDU2IEMxMzIuNTM4LDY5LjQ2IDEzMC4wMiw2OS43MTggMTI3LjgyNCw3Mi4wMyBDMTI2Ljc2OSw3My4xNCAxMjUuOTMxLDc0LjU4NSAxMjUuNDk0LDc2LjA0OCBMMTE5LjAzNCw5Ny42NzYgTDkxLjcxMiwxMTMuNDUgTDkxLjcxMiw2Mi41NzkgTDE2Ny4yMywxOC45NzkiIGlkPSJGaWxsLTEzIiBmaWxsPSIjRkZGRkZGIj48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTkxLjcxMiwxMTMuNTY3IEM5MS42OTIsMTEzLjU2NyA5MS42NzIsMTEzLjU2MSA5MS42NTMsMTEzLjU1MSBDOTEuNjE4LDExMy41MyA5MS41OTUsMTEzLjQ5MiA5MS41OTUsMTEzLjQ1IEw5MS41OTUsNjIuNTc5IEM5MS41OTUsNjIuNTM3IDkxLjYxOCw2Mi40OTkgOTEuNjUzLDYyLjQ3OCBMMTY3LjE3MiwxOC44NzggQzE2Ny4yMDgsMTguODU3IDE2Ny4yNTIsMTguODU3IDE2Ny4yODgsMTguODc4IEMxNjcuMzI0LDE4Ljg5OSAxNjcuMzQ3LDE4LjkzNyAxNjcuMzQ3LDE4Ljk3OSBMMTY3LjM0Nyw2OS44NSBDMTY3LjM0Nyw2OS44OTEgMTY3LjMyNCw2OS45MyAxNjcuMjg4LDY5Ljk1IEwxMzkuOTY3LDg1LjcyNSBDMTM5LjkzOSw4NS43NDEgMTM5LjkwNSw4NS43NDUgMTM5Ljg3Myw4NS43MzUgQzEzOS44NDIsODUuNzI1IDEzOS44MTYsODUuNzAyIDEzOS44MDIsODUuNjcyIEwxMzMuMzQyLDcxLjUwNCBDMTMyLjk2Nyw3MC42ODIgMTMyLjI4LDcwLjIyOSAxMzEuNDA4LDcwLjIyOSBDMTMwLjMxOSw3MC4yMjkgMTI5LjA0NCw3MC45MTUgMTI3LjkwOCw3Mi4xMSBDMTI2Ljg3NCw3My4yIDEyNi4wMzQsNzQuNjQ3IDEyNS42MDYsNzYuMDgyIEwxMTkuMTQ2LDk3LjcwOSBDMTE5LjEzNyw5Ny43MzggMTE5LjExOCw5Ny43NjIgMTE5LjA5Miw5Ny43NzcgTDkxLjc3LDExMy41NTEgQzkxLjc1MiwxMTMuNTYxIDkxLjczMiwxMTMuNTY3IDkxLjcxMiwxMTMuNTY3IEw5MS43MTIsMTEzLjU2NyBaIE05MS44MjksNjIuNjQ3IEw5MS44MjksMTEzLjI0OCBMMTE4LjkzNSw5Ny41OTggTDEyNS4zODIsNzYuMDE1IEMxMjUuODI3LDc0LjUyNSAxMjYuNjY0LDczLjA4MSAxMjcuNzM5LDcxLjk1IEM
2474xMjguOTE5LDcwLjcwOCAxMzAuMjU2LDY5Ljk5NiAxMzEuNDA4LDY5Ljk5NiBDMTMyLjM3Nyw2OS45OTYgMTMzLjEzOSw3MC40OTcgMTMzLjU1NCw3MS40MDcgTDEzOS45NjEsODUuNDU4IEwxNjcuMTEzLDY5Ljc4MiBMMTY3LjExMywxOS4xODEgTDkxLjgyOSw2Mi42NDcgTDkxLjgyOSw2Mi42NDcgWiIgaWQ9IkZpbGwtMTQiIGZpbGw9IiM2MDdEOEIiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNMTY4LjU0MywxOS4yMTMgTDE2OC41NDMsNzAuMDgzIEwxNDEuMjIxLDg1Ljg1NyBMMTM0Ljc2MSw3MS42ODkgQzEzMy44NTEsNjkuNjk0IDEzMS4zMzMsNjkuOTUxIDEyOS4xMzcsNzIuMjYzIEMxMjguMDgyLDczLjM3NCAxMjcuMjQ0LDc0LjgxOSAxMjYuODA3LDc2LjI4MiBMMTIwLjM0Niw5Ny45MDkgTDkzLjAyNSwxMTMuNjgzIEw5My4wMjUsNjIuODEzIEwxNjguNTQzLDE5LjIxMyIgaWQ9IkZpbGwtMTUiIGZpbGw9IiNGRkZGRkYiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNOTMuMDI1LDExMy44IEM5My4wMDUsMTEzLjggOTIuOTg0LDExMy43OTUgOTIuOTY2LDExMy43ODUgQzkyLjkzMSwxMTMuNzY0IDkyLjkwOCwxMTMuNzI1IDkyLjkwOCwxMTMuNjg0IEw5Mi45MDgsNjIuODEzIEM5Mi45MDgsNjIuNzcxIDkyLjkzMSw2Mi43MzMgOTIuOTY2LDYyLjcxMiBMMTY4LjQ4NCwxOS4xMTIgQzE2OC41MiwxOS4wOSAxNjguNTY1LDE5LjA5IDE2OC42MDEsMTkuMTEyIEMxNjguNjM3LDE5LjEzMiAxNjguNjYsMTkuMTcxIDE2OC42NiwxOS4yMTIgTDE2OC42Niw3MC4wODMgQzE2OC42Niw3MC4xMjUgMTY4LjYzNyw3MC4xNjQgMTY4LjYwMSw3MC4xODQgTDE0MS4yOCw4NS45NTggQzE0MS4yNTEsODUuOTc1IDE0MS4yMTcsODUuOTc5IDE0MS4xODYsODUuOTY4IEMxNDEuMTU0LDg1Ljk1OCAxNDEuMTI5LDg1LjkzNiAxNDEuMTE1LDg1LjkwNiBMMTM0LjY1NSw3MS43MzggQzEzNC4yOCw3MC45MTUgMTMzLjU5Myw3MC40NjMgMTMyLjcyLDcwLjQ2MyBDMTMxLjYzMiw3MC40NjMgMTMwLjM1Nyw3MS4xNDggMTI5LjIyMSw3Mi4zNDQgQzEyOC4xODYsNzMuNDMzIDEyNy4zNDcsNzQuODgxIDEyNi45MTksNzYuMzE1IEwxMjAuNDU4LDk3Ljk0MyBDMTIwLjQ1LDk3Ljk3MiAxMjAuNDMxLDk3Ljk5NiAxMjAuNDA1LDk4LjAxIEw5My4wODMsMTEzLjc4NSBDOTMuMDY1LDExMy43OTUgOTMuMDQ1LDExMy44IDkzLjAyNSwxMTMuOCBMOTMuMDI1LDExMy44IFogTTkzLjE0Miw2Mi44ODEgTDkzLjE0MiwxMTMuNDgxIEwxMjAuMjQ4LDk3LjgzMiBMMTI2LjY5NSw3Ni4yNDggQzEyNy4xNCw3NC43NTggMTI3Ljk3Nyw3My4zMTUgMTI5LjA1Miw3Mi4xODMgQzEzMC4yMzEsNzAuOTQyIDEzMS41NjgsNzAuMjI5IDEzMi43Miw3MC4yMjkgQzEzMy42ODksNzAuMjI5IDEzNC40NTIsNzAuNzMxIDEzNC44NjcsNzEuNjQxIEwxNDEuMjc0LDg1LjY5MiBMMTY4LjQyNiw3MC4wMTYgTDE2OC40MjYsMTkuNDE1IEw5My4xNDIsNjIuODgxIEw5My4xNDIsNjIuODgxIFoiIGlkPSJGaWxsLTE2IiBmaWxsPSIjNjA3RDhCIj48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTE2OS44LDcwLjA4MyBMMTQyLjQ3OCw4NS44NTcgTDEzNi4wMTgsNzEuNjg5IEMxMzUuMTA4LDY5LjY5NCAxMzIuNTksNjkuOTUxIDEzMC4zOTMsNzIuMjYzIEMxMjkuMzM5LDczLjM3NCAxMjguNSw3NC44MTkgMTI4LjA2NCw3Ni4yODIgTDEyMS42MDMsOTcuOTA5IEw5NC4yODIsMTEzLjY4MyBMOTQuMjgyLDYyLjgxMyBMMTY5LjgsMTkuMjEzIEwxNjkuOCw3MC4wODMgWiIgaWQ9IkZpbGwtMTciIGZpbGw9IiNGQUZBRkEiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNOTQuMjgyLDExMy45MTcgQzk0LjI0MSwxMTMuOTE3IDk0LjIwMSwxMTMuOTA3IDk0LjE2NSwxMTMuODg2IEM5NC4wOTMsMTEzLjg0NSA5NC4wNDgsMTEzLjc2NyA5NC4wNDgsMTEzLjY4NCBMOTQuMDQ4LDYyLjgxMyBDOTQuMDQ4LDYyLjczIDk0LjA5Myw2Mi42NTIgOTQuMTY1LDYyLjYxMSBMMTY5LjY4MywxOS4wMSBDMTY5Ljc1NSwxOC45NjkgMTY5Ljg0NCwxOC45NjkgMTY5LjkxNywxOS4wMSBDMTY5Ljk4OSwxOS4wNTIgMTcwLjAzMywxOS4xMjkgMTcwLjAzMywxOS4yMTIgTDE3MC4wMzMsNzAuMDgzIEMxNzAuMDMzLDcwLjE2NiAxNjkuOTg5LDcwLjI0NCAxNjkuOTE3LDcwLjI4NSBMMTQyLjU5NSw4Ni4wNiBDMTQyLjUzOCw4Ni4wOTIgMTQyLjQ2OSw4Ni4xIDE0Mi40MDcsODYuMDggQzE0Mi4zNDQsODYuMDYgMTQyLjI5Myw4Ni4wMTQgMTQyLjI2Niw4NS45NTQgTDEzNS44MDUsNzEuNzg2IEMxMzUuNDQ1LDcwLjk5NyAxMzQuODEzLDcwLjU4IDEzMy45NzcsNzAuNTggQzEzMi45MjEsNzAuNTggMTMxLjY3Niw3MS4yNTIgMTMwLjU2Miw3Mi40MjQgQzEyOS41NCw3My41MDEgMTI4LjcxMSw3NC45MzEgMTI4LjI4Nyw3Ni4zNDggTDEyMS44MjcsOTcuOTc2IEMxMjEuODEsOTguMDM0IDEyMS43NzEsOTguMDgyIDEyMS43Miw5OC4xMTIgTDk0LjM5OCwxMTMuODg2IEM5NC4zNjIsMTEzLjkwNyA5NC4zMjIsMTEzLjkxNyA5NC4yODIsMTEzLjkxNyBMOTQuMjgyLDExMy45MTcgWiBNOTQuNTE1LDYyLjk0OCBMOTQuNTE1LDExMy4yNzkgTDEyMS40MDYsOTcuNzU0IEwxMjcuODQsNzYuMjE1IEMxMjguMjksNzQuNzA4IDEyOS4xMzcsNzMuMjQ3IDEzMC4yMjQsNzIuMTAzIEMxMzEuNDI1LDcwLjgzOCAxMzIuNzkzLDcwLjExMiAxMzMuOTc3LDcwLjExMiBDMTM0Ljk5NSw3MC4xMTIgMTM1Ljc5NSw3MC42MzggMTM2LjIzLDcxLjU5MiBMMTQyLjU4NCw4NS41MjYgTDE2OS41NjYsNjkuOTQ4IEwxNjkuNTY2LDE5LjYxNyBMOTQuNTE1LDYyLjk0OCBMOTQuNTE1LDYyLjk0OCBaIiBpZD0iRmlsbC0xOCIgZmlsbD0iIzYwN0Q4QiI+PC9wYXRoPgogICAgICAgICAgICAgICAgICAgIDxwYXRoIGQ9Ik0xMDkuODk0LDkyLjk0MyBMMTA5Ljg5NCw5Mi45NDMgQzEwOC4xMiw5Mi45NDMgMTA2LjY1Myw5Mi4yMTggMTA1LjY1LDkwLjgyMyBDMTA1LjU4Myw5MC43MzEgMTA1LjU5Myw5MC42MSAxMDUuNjczLDkwLjUyOSBDMTA1Ljc1Myw5MC40NDggMTA1Ljg4LDkwLjQ0IDEwNS45NzQsOTAuNTA2IEMxMDYuNzU0LDkxLjA1MyAxMDcuNjc5LDkxLjMzMyAxMDguNzI0LDkxLjMzMyBDMTEwLjA0Nyw5MS4zMzMgMTExLjQ3OCw5MC44OTQgMTEyLjk4LDkwLjAyNyBDMTE4LjI5MSw4Ni45NiAxMjIuNjExLDc5LjUwOSAxMjIuNjExLDczLjQxNiBDMTIyLjYxMSw3MS40ODkgMTIyLjE2OSw2OS44NTYgMTIxLjMzMyw2OC42OTIgQzEyMS4yNjYsNjguNiAxMjEuMjc2LDY4LjQ3MyAxMjEuMzU2LDY4LjM5MiBDMTIxLjQzNiw2OC4zMTEgMTIxLjU2Myw2OC4yOTkgMTIxLjY1Niw2OC4zNjUgQzEyMy4zMjcsNjkuNTM3IDEyNC4yNDcsNzEuNzQ2IDEyNC4yNDcsNzQuNTg0IEMxMjQuMjQ3LDgwLjgyNiAxMTkuODIxLDg4LjQ0NyAxMTQuMzgyLDkxLjU4NyBDMTEyLjgwOCw5Mi40OTUgMTExLjI5OCw5Mi45NDMgMTA5Ljg5NCw5Mi45NDMgTDEwOS44OTQsOTIuOTQzIFogTTEwNi45MjUsOTEuNDAxIEMxMDcuNzM4LDkyLjA1MiAxMDguNzQ1LDkyLjI3OCAxMDkuODkzLDkyLjI3OCBMMTA5Ljg5NCw5Mi4yNzggQzExMS4y
2474MTUsOTIuMjc4IDExMi42NDcsOTEuOTUxIDExNC4xNDgsOTEuMDg0IEMxMTkuNDU5LDg4LjAxNyAxMjMuNzgsODAuNjIxIDEyMy43OCw3NC41MjggQzEyMy43OCw3Mi41NDkgMTIzLjMxNyw3MC45MjkgMTIyLjQ1NCw2OS43NjcgQzEyMi44NjUsNzAuODAyIDEyMy4wNzksNzIuMDQyIDEyMy4wNzksNzMuNDAyIEMxMjMuMDc5LDc5LjY0NSAxMTguNjUzLDg3LjI4NSAxMTMuMjE0LDkwLjQyNSBDMTExLjY0LDkxLjMzNCAxMTAuMTMsOTEuNzQyIDEwOC43MjQsOTEuNzQyIEMxMDguMDgzLDkxLjc0MiAxMDcuNDgxLDkxLjU5MyAxMDYuOTI1LDkxLjQwMSBMMTA2LjkyNSw5MS40MDEgWiIgaWQ9IkZpbGwtMTkiIGZpbGw9IiM2MDdEOEIiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNMTEzLjA5Nyw5MC4yMyBDMTE4LjQ4MSw4Ny4xMjIgMTIyLjg0NSw3OS41OTQgMTIyLjg0NSw3My40MTYgQzEyMi44NDUsNzEuMzY1IDEyMi4zNjIsNjkuNzI0IDEyMS41MjIsNjguNTU2IEMxMTkuNzM4LDY3LjMwNCAxMTcuMTQ4LDY3LjM2MiAxMTQuMjY1LDY5LjAyNiBDMTA4Ljg4MSw3Mi4xMzQgMTA0LjUxNyw3OS42NjIgMTA0LjUxNyw4NS44NCBDMTA0LjUxNyw4Ny44OTEgMTA1LDg5LjUzMiAxMDUuODQsOTAuNyBDMTA3LjYyNCw5MS45NTIgMTEwLjIxNCw5MS44OTQgMTEzLjA5Nyw5MC4yMyIgaWQ9IkZpbGwtMjAiIGZpbGw9IiNGQUZBRkEiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNMTA4LjcyNCw5MS42MTQgTDEwOC43MjQsOTEuNjE0IEMxMDcuNTgyLDkxLjYxNCAxMDYuNTY2LDkxLjQwMSAxMDUuNzA1LDkwLjc5NyBDMTA1LjY4NCw5MC43ODMgMTA1LjY2NSw5MC44MTEgMTA1LjY1LDkwLjc5IEMxMDQuNzU2LDg5LjU0NiAxMDQuMjgzLDg3Ljg0MiAxMDQuMjgzLDg1LjgxNyBDMTA0LjI4Myw3OS41NzUgMTA4LjcwOSw3MS45NTMgMTE0LjE0OCw2OC44MTIgQzExNS43MjIsNjcuOTA0IDExNy4yMzIsNjcuNDQ5IDExOC42MzgsNjcuNDQ5IEMxMTkuNzgsNjcuNDQ5IDEyMC43OTYsNjcuNzU4IDEyMS42NTYsNjguMzYyIEMxMjEuNjc4LDY4LjM3NyAxMjEuNjk3LDY4LjM5NyAxMjEuNzEyLDY4LjQxOCBDMTIyLjYwNiw2OS42NjIgMTIzLjA3OSw3MS4zOSAxMjMuMDc5LDczLjQxNSBDMTIzLjA3OSw3OS42NTggMTE4LjY1Myw4Ny4xOTggMTEzLjIxNCw5MC4zMzggQzExMS42NCw5MS4yNDcgMTEwLjEzLDkxLjYxNCAxMDguNzI0LDkxLjYxNCBMMTA4LjcyNCw5MS42MTQgWiBNMTA2LjAwNiw5MC41MDUgQzEwNi43OCw5MS4wMzcgMTA3LjY5NCw5MS4yODEgMTA4LjcyNCw5MS4yODEgQzExMC4wNDcsOTEuMjgxIDExMS40NzgsOTAuODY4IDExMi45OCw5MC4wMDEgQzExOC4yOTEsODYuOTM1IDEyMi42MTEsNzkuNDk2IDEyMi42MTEsNzMuNDAzIEMxMjIuNjExLDcxLjQ5NCAxMjIuMTc3LDY5Ljg4IDEyMS4zNTYsNjguNzE4IEMxMjAuNTgyLDY4LjE4NSAxMTkuNjY4LDY3LjkxOSAxMTguNjM4LDY3LjkxOSBDMTE3LjMxNSw2Ny45MTkgMTE1Ljg4Myw2OC4zNiAxMTQuMzgyLDY5LjIyNyBDMTA5LjA3MSw3Mi4yOTMgMTA0Ljc1MSw3OS43MzMgMTA0Ljc1MSw4NS44MjYgQzEwNC43NTEsODcuNzM1IDEwNS4xODUsODkuMzQzIDEwNi4wMDYsOTAuNTA1IEwxMDYuMDA2LDkwLjUwNSBaIiBpZD0iRmlsbC0yMSIgZmlsbD0iIzYwN0Q4QiI+PC9wYXRoPgogICAgICAgICAgICAgICAgICAgIDxwYXRoIGQ9Ik0xNDkuMzE4LDcuMjYyIEwxMzkuMzM0LDE2LjE0IEwxNTUuMjI3LDI3LjE3MSBMMTYwLjgxNiwyMS4wNTkgTDE0OS4zMTgsNy4yNjIiIGlkPSJGaWxsLTIyIiBmaWxsPSIjRkFGQUZBIj48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTE2OS42NzYsMTMuODQgTDE1OS45MjgsMTkuNDY3IEMxNTYuMjg2LDIxLjU3IDE1MC40LDIxLjU4IDE0Ni43ODEsMTkuNDkxIEMxNDMuMTYxLDE3LjQwMiAxNDMuMTgsMTQuMDAzIDE0Ni44MjIsMTEuOSBMMTU2LjMxNyw2LjI5MiBMMTQ5LjU4OCwyLjQwNyBMNjcuNzUyLDQ5LjQ3OCBMMTEzLjY3NSw3NS45OTIgTDExNi43NTYsNzQuMjEzIEMxMTcuMzg3LDczLjg0OCAxMTcuNjI1LDczLjMxNSAxMTcuMzc0LDcyLjgyMyBDMTE1LjAxNyw2OC4xOTEgMTE0Ljc4MSw2My4yNzcgMTE2LjY5MSw1OC41NjEgQzEyMi4zMjksNDQuNjQxIDE0MS4yLDMzLjc0NiAxNjUuMzA5LDMwLjQ5MSBDMTczLjQ3OCwyOS4zODggMTgxLjk4OSwyOS41MjQgMTkwLjAxMywzMC44ODUgQzE5MC44NjUsMzEuMDMgMTkxLjc4OSwzMC44OTMgMTkyLjQyLDMwLjUyOCBMMTk1LjUwMSwyOC43NSBMMTY5LjY3NiwxMy44NCIgaWQ9IkZpbGwtMjMiIGZpbGw9IiNGQUZBRkEiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNMTEzLjY3NSw3Ni40NTkgQzExMy41OTQsNzYuNDU5IDExMy41MTQsNzYuNDM4IDExMy40NDIsNzYuMzk3IEw2Ny41MTgsNDkuODgyIEM2Ny4zNzQsNDkuNzk5IDY3LjI4NCw0OS42NDUgNjcuMjg1LDQ5LjQ3OCBDNjcuMjg1LDQ5LjMxMSA2Ny4zNzQsNDkuMTU3IDY3LjUxOSw0OS4wNzMgTDE0OS4zNTUsMi4wMDIgQzE0OS40OTksMS45MTkgMTQ5LjY3NywxLjkxOSAxNDkuODIxLDIuMDAyIEwxNTYuNTUsNS44ODcgQzE1Ni43NzQsNi4wMTcgMTU2Ljg1LDYuMzAyIDE1Ni43MjIsNi41MjYgQzE1Ni41OTIsNi43NDkgMTU2LjMwNyw2LjgyNiAxNTYuMDgzLDYuNjk2IEwxNDkuNTg3LDIuOTQ2IEw2OC42ODcsNDkuNDc5IEwxMTMuNjc1LDc1LjQ1MiBMMTE2LjUyMyw3My44MDggQzExNi43MTUsNzMuNjk3IDExNy4xNDMsNzMuMzk5IDExNi45NTgsNzMuMDM1IEMxMTQuNTQyLDY4LjI4NyAxMTQuMyw2My4yMjEgMTE2LjI1OCw1OC4zODUgQzExOS4wNjQsNTEuNDU4IDEyNS4xNDMsNDUuMTQzIDEzMy44NCw0MC4xMjIgQzE0Mi40OTcsMzUuMTI0IDE1My4zNTgsMzEuNjMzIDE2NS4yNDcsMzAuMDI4IEMxNzMuNDQ1LDI4LjkyMSAxODIuMDM3LDI5LjA1OCAxOTAuMDkxLDMwLjQyNSBDMTkwLjgzLDMwLjU1IDE5MS42NTIsMzAuNDMyIDE5Mi4xODYsMzAuMTI0IEwxOTQuNTY3LDI4Ljc1IEwxNjkuNDQyLDE0LjI0NCBDMTY5LjIxOSwxNC4xMTUgMTY5LjE0MiwxMy44MjkgMTY5LjI3MSwxMy42MDYgQzE2OS40LDEzLjM4MiAxNjkuNjg1LDEzLjMwNiAxNjkuOTA5LDEzLjQzNSBMMTk1LjczNCwyOC4zNDUgQzE5NS44NzksMjguNDI4IDE5NS45NjgsMjguNTgzIDE5NS45NjgsMjguNzUgQzE5NS45NjgsMjguOTE2IDE5NS44NzksMjkuMDcxIDE5NS43MzQsMjkuMTU0IEwxOTIuNjUzLDMwLjkzMyBDMTkxLjkzMiwzMS4zNSAxOTAuODksMzEuNTA4IDE4OS45MzUsMzEuMzQ2IEMxODEuOTcyLDI5Ljk5NSAxNzMuNDc4LDI5Ljg2IDE2NS4zNzIsMzAuOTU0IEMxNTMuNjAyLDMyLjU0MyAxNDIuODYsMzUuOTkzIDEzNC4zMDcsNDAuOTMxIEMxMjUuNzkzLDQ1Ljg0NyAxMTkuODUxLDUyLjAwNCAxMTcuMTI0LDU4LjczNiBDMTE1LjI3LDYzLjMxNCAxMTUuNTAxLDY4LjExMiAxMTcuNzksNzIuNjExIEMxMTguMTYsNzMuMzM2IDExNy44NDUsNzQuMTI0IDExNi45OSw3NC42MTcgTDExMy45MDksNzYuMzk3IEMxMTMuODM2LDc2LjQzOCAxMTMuNzU2LDc2LjQ1OSAxMTMuNjc1LDc2LjQ1OSIgaWQ9IkZpbGwtMjQiIGZpbGw9IiM0NTVBNjQiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNMTUzLjMxNiwyMS4yNzkgQzE1MC45MDMsMjEuMjc5IDE0OC40OTUsMjAuNzUxIDE0Ni42NjQsMTkuNjkzIEMxNDQuODQ2LDE4LjY0NCAxNDMuODQ0LDE3LjIzMiAxNDMuODQ0LDE1LjcxOCBDMTQzLjg0NCwxNC4xOTEgMTQ0Ljg2LDEyLjc2MyAxNDYuNzA1LDExLjY5OCBMMTU2LjE5OCw2LjA5MSBDMTU2LjMwOSw2LjAyNSAxNTYuNDUyLDYuMDYyIDE1Ni41MTgsNi4xNzMgQzE1Ni41ODMsNi4yODQgMTU2LjU0Nyw2LjQyNyAxNTYuNDM2LDYuNDkzIEwxNDYuOTQsMTIuMTAyIEMxNDUuMjQ0LDEzLjA4MSAxNDQuMzEyLDE0LjM2NSAxNDQuMzEyLDE1LjcxOCBDMTQ0LjMxMiwxNy4wNTggMTQ1LjIzL
2474DE4LjMyNiAxNDYuODk3LDE5LjI4OSBDMTUwLjQ0NiwyMS4zMzggMTU2LjI0LDIxLjMyNyAxNTkuODExLDE5LjI2NSBMMTY5LjU1OSwxMy42MzcgQzE2OS42NywxMy41NzMgMTY5LjgxMywxMy42MTEgMTY5Ljg3OCwxMy43MjMgQzE2OS45NDMsMTMuODM0IDE2OS45MDQsMTMuOTc3IDE2OS43OTMsMTQuMDQyIEwxNjAuMDQ1LDE5LjY3IEMxNTguMTg3LDIwLjc0MiAxNTUuNzQ5LDIxLjI3OSAxNTMuMzE2LDIxLjI3OSIgaWQ9IkZpbGwtMjUiIGZpbGw9IiM2MDdEOEIiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNMTEzLjY3NSw3NS45OTIgTDY3Ljc2Miw0OS40ODQiIGlkPSJGaWxsLTI2IiBmaWxsPSIjNDU1QTY0Ij48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTExMy42NzUsNzYuMzQyIEMxMTMuNjE1LDc2LjM0MiAxMTMuNTU1LDc2LjMyNyAxMTMuNSw3Ni4yOTUgTDY3LjU4Nyw0OS43ODcgQzY3LjQxOSw0OS42OSA2Ny4zNjIsNDkuNDc2IDY3LjQ1OSw0OS4zMDkgQzY3LjU1Niw0OS4xNDEgNjcuNzcsNDkuMDgzIDY3LjkzNyw0OS4xOCBMMTEzLjg1LDc1LjY4OCBDMTE0LjAxOCw3NS43ODUgMTE0LjA3NSw3NiAxMTMuOTc4LDc2LjE2NyBDMTEzLjkxNCw3Ni4yNzkgMTEzLjc5Niw3Ni4zNDIgMTEzLjY3NSw3Ni4zNDIiIGlkPSJGaWxsLTI3IiBmaWxsPSIjNDU1QTY0Ij48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTY3Ljc2Miw0OS40ODQgTDY3Ljc2MiwxMDMuNDg1IEM2Ny43NjIsMTA0LjU3NSA2OC41MzIsMTA1LjkwMyA2OS40ODIsMTA2LjQ1MiBMMTExLjk1NSwxMzAuOTczIEMxMTIuOTA1LDEzMS41MjIgMTEzLjY3NSwxMzEuMDgzIDExMy42NzUsMTI5Ljk5MyBMMTEzLjY3NSw3NS45OTIiIGlkPSJGaWxsLTI4IiBmaWxsPSIjRkFGQUZBIj48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTExMi43MjcsMTMxLjU2MSBDMTEyLjQzLDEzMS41NjEgMTEyLjEwNywxMzEuNDY2IDExMS43OCwxMzEuMjc2IEw2OS4zMDcsMTA2Ljc1NSBDNjguMjQ0LDEwNi4xNDIgNjcuNDEyLDEwNC43MDUgNjcuNDEyLDEwMy40ODUgTDY3LjQxMiw0OS40ODQgQzY3LjQxMiw0OS4yOSA2Ny41NjksNDkuMTM0IDY3Ljc2Miw0OS4xMzQgQzY3Ljk1Niw0OS4xMzQgNjguMTEzLDQ5LjI5IDY4LjExMyw0OS40ODQgTDY4LjExMywxMDMuNDg1IEM2OC4xMTMsMTA0LjQ0NSA2OC44MiwxMDUuNjY1IDY5LjY1NywxMDYuMTQ4IEwxMTIuMTMsMTMwLjY3IEMxMTIuNDc0LDEzMC44NjggMTEyLjc5MSwxMzAuOTEzIDExMywxMzAuNzkyIEMxMTMuMjA2LDEzMC42NzMgMTEzLjMyNSwxMzAuMzgxIDExMy4zMjUsMTI5Ljk5MyBMMTEzLjMyNSw3NS45OTIgQzExMy4zMjUsNzUuNzk4IDExMy40ODIsNzUuNjQxIDExMy42NzUsNzUuNjQxIEMxMTMuODY5LDc1LjY0MSAxMTQuMDI1LDc1Ljc5OCAxMTQuMDI1LDc1Ljk5MiBMMTE0LjAyNSwxMjkuOTkzIEMxMTQuMDI1LDEzMC42NDggMTEzLjc4NiwxMzEuMTQ3IDExMy4zNSwxMzEuMzk5IEMxMTMuMTYyLDEzMS41MDcgMTEyLjk1MiwxMzEuNTYxIDExMi43MjcsMTMxLjU2MSIgaWQ9IkZpbGwtMjkiIGZpbGw9IiM0NTVBNjQiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNMTEyLjg2LDQwLjUxMiBDMTEyLjg2LDQwLjUxMiAxMTIuODYsNDAuNTEyIDExMi44NTksNDAuNTEyIEMxMTAuNTQxLDQwLjUxMiAxMDguMzYsMzkuOTkgMTA2LjcxNywzOS4wNDEgQzEwNS4wMTIsMzguMDU3IDEwNC4wNzQsMzYuNzI2IDEwNC4wNzQsMzUuMjkyIEMxMDQuMDc0LDMzLjg0NyAxMDUuMDI2LDMyLjUwMSAxMDYuNzU0LDMxLjUwNCBMMTE4Ljc5NSwyNC41NTEgQzEyMC40NjMsMjMuNTg5IDEyMi42NjksMjMuMDU4IDEyNS4wMDcsMjMuMDU4IEMxMjcuMzI1LDIzLjA1OCAxMjkuNTA2LDIzLjU4MSAxMzEuMTUsMjQuNTMgQzEzMi44NTQsMjUuNTE0IDEzMy43OTMsMjYuODQ1IDEzMy43OTMsMjguMjc4IEMxMzMuNzkzLDI5LjcyNCAxMzIuODQxLDMxLjA2OSAxMzEuMTEzLDMyLjA2NyBMMTE5LjA3MSwzOS4wMTkgQzExNy40MDMsMzkuOTgyIDExNS4xOTcsNDAuNTEyIDExMi44Niw0MC41MTIgTDExMi44Niw0MC41MTIgWiBNMTI1LjAwNywyMy43NTkgQzEyMi43OSwyMy43NTkgMTIwLjcwOSwyNC4yNTYgMTE5LjE0NiwyNS4xNTggTDEwNy4xMDQsMzIuMTEgQzEwNS42MDIsMzIuOTc4IDEwNC43NzQsMzQuMTA4IDEwNC43NzQsMzUuMjkyIEMxMDQuNzc0LDM2LjQ2NSAxMDUuNTg5LDM3LjU4MSAxMDcuMDY3LDM4LjQzNCBDMTA4LjYwNSwzOS4zMjMgMTEwLjY2MywzOS44MTIgMTEyLjg1OSwzOS44MTIgTDExMi44NiwzOS44MTIgQzExNS4wNzYsMzkuODEyIDExNy4xNTgsMzkuMzE1IDExOC43MjEsMzguNDEzIEwxMzAuNzYyLDMxLjQ2IEMxMzIuMjY0LDMwLjU5MyAxMzMuMDkyLDI5LjQ2MyAxMzMuMDkyLDI4LjI3OCBDMTMzLjA5MiwyNy4xMDYgMTMyLjI3OCwyNS45OSAxMzAuOCwyNS4xMzYgQzEyOS4yNjEsMjQuMjQ4IDEyNy4yMDQsMjMuNzU5IDEyNS4wMDcsMjMuNzU5IEwxMjUuMDA3LDIzLjc1OSBaIiBpZD0iRmlsbC0zMCIgZmlsbD0iIzYwN0Q4QiI+PC9wYXRoPgogICAgICAgICAgICAgICAgICAgIDxwYXRoIGQ9Ik0xNjUuNjMsMTYuMjE5IEwxNTkuODk2LDE5LjUzIEMxNTYuNzI5LDIxLjM1OCAxNTEuNjEsMjEuMzY3IDE0OC40NjMsMTkuNTUgQzE0NS4zMTYsMTcuNzMzIDE0NS4zMzIsMTQuNzc4IDE0OC40OTksMTIuOTQ5IEwxNTQuMjMzLDkuNjM5IEwxNjUuNjMsMTYuMjE5IiBpZD0iRmlsbC0zMSIgZmlsbD0iI0ZBRkFGQSI+PC9wYXRoPgogICAgICAgICAgICAgICAgICAgIDxwYXRoIGQ9Ik0xNTQuMjMzLDEwLjQ0OCBMMTY0LjIyOCwxNi4yMTkgTDE1OS41NDYsMTguOTIzIEMxNTguMTEyLDE
24745Ljc1IDE1Ni4xOTQsMjAuMjA2IDE1NC4xNDcsMjAuMjA2IEMxNTIuMTE4LDIwLjIwNiAxNTAuMjI0LDE5Ljc1NyAxNDguODE0LDE4Ljk0MyBDMTQ3LjUyNCwxOC4xOTkgMTQ2LjgxNCwxNy4yNDkgMTQ2LjgxNCwxNi4yNjkgQzE0Ni44MTQsMTUuMjc4IDE0Ny41MzcsMTQuMzE0IDE0OC44NSwxMy41NTYgTDE1NC4yMzMsMTAuNDQ4IE0xNTQuMjMzLDkuNjM5IEwxNDguNDk5LDEyLjk0OSBDMTQ1LjMzMiwxNC43NzggMTQ1LjMxNiwxNy43MzMgMTQ4LjQ2MywxOS41NSBDMTUwLjAzMSwyMC40NTUgMTUyLjA4NiwyMC45MDcgMTU0LjE0NywyMC45MDcgQzE1Ni4yMjQsMjAuOTA3IDE1OC4zMDYsMjAuNDQ3IDE1OS44OTYsMTkuNTMgTDE2NS42MywxNi4yMTkgTDE1NC4yMzMsOS42MzkiIGlkPSJGaWxsLTMyIiBmaWxsPSIjNjA3RDhCIj48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTE0NS40NDUsNzIuNjY3IEwxNDUuNDQ1LDcyLjY2NyBDMTQzLjY3Miw3Mi42NjcgMTQyLjIwNCw3MS44MTcgMTQxLjIwMiw3MC40MjIgQzE0MS4xMzUsNzAuMzMgMTQxLjE0NSw3MC4xNDcgMTQxLjIyNSw3MC4wNjYgQzE0MS4zMDUsNjkuOTg1IDE0MS40MzIsNjkuOTQ2IDE0MS41MjUsNzAuMDExIEMxNDIuMzA2LDcwLjU1OSAxNDMuMjMxLDcwLjgyMyAxNDQuMjc2LDcwLjgyMiBDMTQ1LjU5OCw3MC44MjIgMTQ3LjAzLDcwLjM3NiAxNDguNTMyLDY5LjUwOSBDMTUzLjg0Miw2Ni40NDMgMTU4LjE2Myw1OC45ODcgMTU4LjE2Myw1Mi44OTQgQzE1OC4xNjMsNTAuOTY3IDE1Ny43MjEsNDkuMzMyIDE1Ni44ODQsNDguMTY4IEMxNTYuODE4LDQ4LjA3NiAxNTYuODI4LDQ3Ljk0OCAxNTYuOTA4LDQ3Ljg2NyBDMTU2Ljk4OCw0Ny43ODYgMTU3LjExNCw0Ny43NzQgMTU3LjIwOCw0Ny44NCBDMTU4Ljg3OCw0OS4wMTIgMTU5Ljc5OCw1MS4yMiAxNTkuNzk4LDU0LjA1OSBDMTU5Ljc5OCw2MC4zMDEgMTU1LjM3Myw2OC4wNDYgMTQ5LjkzMyw3MS4xODYgQzE0OC4zNiw3Mi4wOTQgMTQ2Ljg1LDcyLjY2NyAxNDUuNDQ1LDcyLjY2NyBMMTQ1LjQ0NSw3Mi42NjcgWiBNMTQyLjQ3Niw3MSBDMTQzLjI5LDcxLjY1MSAxNDQuMjk2LDcyLjAwMiAxNDUuNDQ1LDcyLjAwMiBDMTQ2Ljc2Nyw3Mi4wMDIgMTQ4LjE5OCw3MS41NSAxNDkuNyw3MC42ODIgQzE1NS4wMSw2Ny42MTcgMTU5LjMzMSw2MC4xNTkgMTU5LjMzMSw1NC4wNjUgQzE1OS4zMzEsNTIuMDg1IDE1OC44NjgsNTAuNDM1IDE1OC4wMDYsNDkuMjcyIEMxNTguNDE3LDUwLjMwNyAxNTguNjMsNTEuNTMyIDE1OC42Myw1Mi44OTIgQzE1OC42Myw1OS4xMzQgMTU0LjIwNSw2Ni43NjcgMTQ4Ljc2NSw2OS45MDcgQzE0Ny4xOTIsNzAuODE2IDE0NS42ODEsNzEuMjgzIDE0NC4yNzYsNzEuMjgzIEMxNDMuNjM0LDcxLjI4MyAxNDMuMDMzLDcxLjE5MiAxNDIuNDc2LDcxIEwxNDIuNDc2LDcxIFoiIGlkPSJGaWxsLTMzIiBmaWxsPSIjNjA3RDhCIj48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTE0OC42NDgsNjkuNzA0IEMxNTQuMDMyLDY2LjU5NiAxNTguMzk2LDU5LjA2OCAxNTguMzk2LDUyLjg5MSBDMTU4LjM5Niw1MC44MzkgMTU3LjkxMyw0OS4xOTggMTU3LjA3NCw0OC4wMyBDMTU1LjI4OSw0Ni43NzggMTUyLjY5OSw0Ni44MzYgMTQ5LjgxNiw0OC41MDEgQzE0NC40MzMsNTEuNjA5IDE0MC4wNjgsNTkuMTM3IDE0MC4wNjgsNjUuMzE0IEMxNDAuMDY4LDY3LjM2NSAxNDAuNTUyLDY5LjAwNiAxNDEuMzkxLDcwLjE3NCBDMTQzLjE3Niw3MS40MjcgMTQ1Ljc2NSw3MS4zNjkgMTQ4LjY0OCw2OS43MDQiIGlkPSJGaWxsLTM0IiBmaWxsPSIjRkFGQUZBIj48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTE0NC4yNzYsNzEuMjc2IEwxNDQuMjc2LDcxLjI3NiBDMTQzLjEzMyw3MS4yNzYgMTQyLjExOCw3MC45NjkgMTQxLjI1Nyw3MC4zNjUgQzE0MS4yMzYsNzAuMzUxIDE0MS4yMTcsNzAuMzMyIDE0MS4yMDIsNzAuMzExIEMxNDAuMzA3LDY5LjA2NyAxMzkuODM1LDY3LjMzOSAxMzkuODM1LDY1LjMxNCBDMTM5LjgzNSw1OS4wNzMgMTQ0LjI2LDUxLjQzOSAxNDkuNyw0OC4yOTggQzE1MS4yNzMsNDcuMzkgMTUyLjc4NCw0Ni45MjkgMTU0LjE4OSw0Ni45MjkgQzE1NS4zMzIsNDYuOTI5IDE1Ni4zNDcsNDcuMjM2IDE1Ny4yMDgsNDcuODM5IEMxNTcuMjI5LDQ3Ljg1NCAxNTcuMjQ4LDQ3Ljg3MyAxNTcuMjYzLDQ3Ljg5NCBDMTU4LjE1Nyw0OS4xMzggMTU4LjYzLDUwLjg2NSAxNTguNjMsNTIuODkxIEMxNTguNjMsNTkuMTMyIDE1NC4yMDUsNjYuNzY2IDE0OC43NjUsNjkuOTA3IEMxNDcuMTkyLDcwLjgxNSAxNDUuNjgxLDcxLjI3NiAxNDQuMjc2LDcxLjI3NiBMMTQ0LjI3Niw3MS4yNzYgWiBNMTQxLjU1OCw3MC4xMDQgQzE0Mi4zMzEsNzAuNjM3IDE0My4yNDUsNzEuMDA1IDE0NC4yNzYsNzEuMDA1IEMxNDUuNTk4LDcxLjAwNSAxNDcuMDMsNzAuNDY3IDE0OC41MzIsNjkuNiBDMTUzLjg0Miw2Ni41MzQgMTU4LjE2Myw1OS4wMzMgMTU4LjE2Myw1Mi45MzkgQzE1OC4xNjMsNTEuMDMxIDE1Ny43MjksNDkuMzg1IDE1Ni45MDcsNDguMjIzIEMxNTYuMTMzLDQ3LjY5MSAxNTUuMjE5LDQ3LjQwOSAxNTQuMTg5LDQ3LjQwOSBDMTUyLjg2Nyw0Ny40MDkgMTUxLjQzNSw0Ny44NDIgMTQ5LjkzMyw0OC43MDkgQzE0NC42MjMsNTEuNzc1IDE0MC4zMDIsNTkuMjczIDE0MC4zMDIsNjUuMzY2IEMxNDAuMzAyLDY3LjI3NiAxNDAuNzM2LDY4Ljk0MiAxNDEuNTU4LDcwLjEwNCBMMTQxLjU1OCw3MC4xMDQgWiIgaWQ9IkZpbGwtMzUiIGZpbGw9IiM2MDdEOEIiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNMTUwLjcyLDY1LjM2MSBMMTUwLjM1Nyw2NS4wNjYgQzE1MS4xNDcsNjQuMDkyIDE1MS44NjksNjMuMDQgMTUyLjUwNSw2MS45MzggQzE1My4zMTMsNjAuNTM5IDE1My45NzgsNTkuMDY3IDE1NC40ODIsNTcuNTYzIEwxNTQuOTI1LDU3LjcxMiBDMTU0LjQxMiw1OS4yNDUgMTUzLjczMyw2MC43NDUgMTUyLjkxLDYyLjE3MiBDMTUyLjI2Miw2My4yOTUgMTUxLjUyNSw2NC4zNjggMTUwLjcyLDY1LjM2MSIgaWQ9IkZpbGwtMzYiIGZpbGw9IiM2MDdEOEIiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNMTE1LjkxNyw4NC41MTQgTDExNS41NTQsODQuMjIgQzExNi4zNDQsODMuMjQ1IDExNy4wNjYsODIuMTk0IDExNy43MDIsODEuMDkyIEMxMTguNTEsNzkuNjkyIDExOS4xNzUsNzguMjIgMTE5LjY3OCw3Ni43MTcgTDEyMC4xMjEsNzYuODY1IEMxMTkuNjA4LDc4LjM5OCAxMTguOTMsNzkuODk5IDExOC4xMDYsODEuMzI2IEMxMTcuNDU4LDgyLjQ0OCAxMTYuNzIyLDgzLjUyMSAxMTUuOTE3LDg0LjUxNCIgaWQ9IkZpbGwtMzciIGZpbGw9IiM2MDdEOEIiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNMTE0LDEzMC40NzYgTDExNCwxMzAuMDA4IEwxMTQsNzYuMDUyIEwxMTQsNzUuNTg0IEwxMTQsNzYuMDUyIEwxMTQsMTMwLjAwOCBMMTE0LDEzMC40NzYiIGlkPSJGaWxsLTM4IiBmaWxsPSIjNjA3RDhCIj48L3BhdGg+CiAgICAgICAgICAgICAgICA8L2c+CiAgICAgICAgICAgICAgICA8ZyBpZD0iSW1wb3J0ZWQtTGF5ZXJzLUNvcHkiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDYyLjAwMDAwMCwgMC4wMDAwMDApIiBza2V0Y2g6dHlwZT0iTVNTaGFwZUdyb3VwIj4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNMTkuODIyLDM3LjQ3NCBDMTkuODM5LDM3LjMzOSAxOS43NDcsMzcuMTk0IDE5LjU1NSwzNy4wODIgQzE5LjIyOCwzNi44OTQgMTguNzI5LDM2Ljg3MiAxOC40NDYsMzcuMDM3IEwxMi40MzQsNDAuNTA4IEMxMi4zMDMsNDAuNTg0IDEyLjI0LDQwLjY4NiAxMi4yNDMsNDAuNzkzIEMxMi4yNDUsNDAuOTI1IDEyLjI0NSw0MS4yNTQgMTIuMjQ1LDQxLjM3MSBMMTIuMjQ1LDQxLjQxNCBMMTIuMjM4LDQxLjU0MiBDOC4xNDgsNDMuODg3IDUuNjQ3LDQ1LjMyMSA1LjY0Nyw0NS4zMjEgQzUuNjQ2LDQ1LjMyMSAzLjU3LDQ2LjM2NyAyLjg2LDUwLjUxMyBDMi44Niw1MC41MTMgMS45NDgsNTcuNDc0IDEuOTYyLDcwLjI1OCBDMS45NzcsODIuODI4IDIuNTY4LDg3LjMyOCAzLjEyOSw5MS42MDkgQzMuMzQ5LDkzLjI5MyA2LjEzLDkzLjczNCA2LjEzLDkzLjczNCBDNi40NjEsOTMuNzc0IDYuODI4LDkzLjcwNyA3LjIxLDkzLjQ4NiBMODIuNDgzLDQ5LjkzNSBDODQuMjkxLDQ4Ljg2NiA4NS4xNSw0Ni4yMTYgODUuNTM5LDQzLjY1MSBDODYuNzUyLDM1LjY2MSA4Ny4yMTQsMTAuNjczIDg1LjI2NCwzLjc3MyBDODUuMDY4LDMuMDggODQuNzU0LDIuNjkgODQuMzk2LDIuNDkxIEw4Mi4zMSwxLjcwMSBDODEuNTgzLDEuNzI5IDgwLjg5NCwyLjE2OCA4MC43NzYsMi4yMzYgQzgwLjYzNiwyLjMxNyA0MS44MDcsMjQuNTg1IDIwLjAzMiwzNy4wNzIgTDE5LjgyMiwzNy40NzQiIGlkPSJGaWxsLTEiIGZpbGw9IiNGRkZGRkYiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNODIuMzExLDEuNzAxIEw4NC4zOTYsMi40OTEgQzg0Ljc1NCwyLjY5IDg1LjA2OCwzLjA4IDg1LjI2NCwzLjc3MyBDODcuMjEzLDEwLjY3MyA4Ni43NTEsMzUuNjYgODUuNTM5LDQzLjY1MSBDODUuMTQ5LDQ2LjIxNiA4NC4yOSw0OC44NjYgODIuNDgzLDQ5LjkzNSB
2474MNy4yMSw5My40ODYgQzYuODk3LDkzLjY2NyA2LjU5NSw5My43NDQgNi4zMTQsOTMuNzQ0IEw2LjEzMSw5My43MzMgQzYuMTMxLDkzLjczNCAzLjM0OSw5My4yOTMgMy4xMjgsOTEuNjA5IEMyLjU2OCw4Ny4zMjcgMS45NzcsODIuODI4IDEuOTYzLDcwLjI1OCBDMS45NDgsNTcuNDc0IDIuODYsNTAuNTEzIDIuODYsNTAuNTEzIEMzLjU3LDQ2LjM2NyA1LjY0Nyw0NS4zMjEgNS42NDcsNDUuMzIxIEM1LjY0Nyw0NS4zMjEgOC4xNDgsNDMuODg3IDEyLjIzOCw0MS41NDIgTDEyLjI0NSw0MS40MTQgTDEyLjI0NSw0MS4zNzEgQzEyLjI0NSw0MS4yNTQgMTIuMjQ1LDQwLjkyNSAxMi4yNDMsNDAuNzkzIEMxMi4yNCw0MC42ODYgMTIuMzAyLDQwLjU4MyAxMi40MzQsNDAuNTA4IEwxOC40NDYsMzcuMDM2IEMxOC41NzQsMzYuOTYyIDE4Ljc0NiwzNi45MjYgMTguOTI3LDM2LjkyNiBDMTkuMTQ1LDM2LjkyNiAxOS4zNzYsMzYuOTc5IDE5LjU1NCwzNy4wODIgQzE5Ljc0NywzNy4xOTQgMTkuODM5LDM3LjM0IDE5LjgyMiwzNy40NzQgTDIwLjAzMywzNy4wNzIgQzQxLjgwNiwyNC41ODUgODAuNjM2LDIuMzE4IDgwLjc3NywyLjIzNiBDODAuODk0LDIuMTY4IDgxLjU4MywxLjcyOSA4Mi4zMTEsMS43MDEgTTgyLjMxMSwwLjcwNCBMODIuMjcyLDAuNzA1IEM4MS42NTQsMC43MjggODAuOTg5LDAuOTQ5IDgwLjI5OCwxLjM2MSBMODAuMjc3LDEuMzczIEM4MC4xMjksMS40NTggNTkuNzY4LDEzLjEzNSAxOS43NTgsMzYuMDc5IEMxOS41LDM1Ljk4MSAxOS4yMTQsMzUuOTI5IDE4LjkyNywzNS45MjkgQzE4LjU2MiwzNS45MjkgMTguMjIzLDM2LjAxMyAxNy45NDcsMzYuMTczIEwxMS45MzUsMzkuNjQ0IEMxMS40OTMsMzkuODk5IDExLjIzNiw0MC4zMzQgMTEuMjQ2LDQwLjgxIEwxMS4yNDcsNDAuOTYgTDUuMTY3LDQ0LjQ0NyBDNC43OTQsNDQuNjQ2IDIuNjI1LDQ1Ljk3OCAxLjg3Nyw1MC4zNDUgTDEuODcxLDUwLjM4NCBDMS44NjIsNTAuNDU0IDAuOTUxLDU3LjU1NyAwLjk2NSw3MC4yNTkgQzAuOTc5LDgyLjg3OSAxLjU2OCw4Ny4zNzUgMi4xMzcsOTEuNzI0IEwyLjEzOSw5MS43MzkgQzIuNDQ3LDk0LjA5NCA1LjYxNCw5NC42NjIgNS45NzUsOTQuNzE5IEw2LjAwOSw5NC43MjMgQzYuMTEsOTQuNzM2IDYuMjEzLDk0Ljc0MiA2LjMxNCw5NC43NDIgQzYuNzksOTQuNzQyIDcuMjYsOTQuNjEgNy43MSw5NC4zNSBMODIuOTgzLDUwLjc5OCBDODQuNzk0LDQ5LjcyNyA4NS45ODIsNDcuMzc1IDg2LjUyNSw0My44MDEgQzg3LjcxMSwzNS45ODcgODguMjU5LDEwLjcwNSA4Ni4yMjQsMy41MDIgQzg1Ljk3MSwyLjYwOSA4NS41MiwxLjk3NSA4NC44ODEsMS42MiBMODQuNzQ5LDEuNTU4IEw4Mi42NjQsMC43NjkgQzgyLjU1MSwwLjcyNSA4Mi40MzEsMC43MDQgODIuMzExLDAuNzA0IiBpZD0iRmlsbC0yIiBmaWxsPSIjNDU1QTY0Ij48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTY2LjI2NywxMS41NjUgTDY3Ljc2MiwxMS45OTkgTDExLjQyMyw0NC4zMjUiIGlkPSJGaWxsLTMiIGZpbGw9IiNGRkZGRkYiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNMTIuMjAyLDkwLjU0NSBDMTIuMDI5LDkwLjU0NSAxMS44NjIsOTAuNDU1IDExLjc2OSw5MC4yOTUgQzExLjYzMiw5MC4wNTcgMTEuNzEzLDg5Ljc1MiAxMS45NTIsODkuNjE0IEwzMC4zODksNzguOTY5IEMzMC42MjgsNzguODMxIDMwLjkzMyw3OC45MTMgMzEuMDcxLDc5LjE1MiBDMzEuMjA4LDc5LjM5IDMxLjEyNyw3OS42OTYgMzAuODg4LDc5LjgzMyBMMTIuNDUxLDkwLjQ3OCBMMTIuMjAyLDkwLjU0NSIgaWQ9IkZpbGwtNCIgZmlsbD0iIzYwN0Q4QiI+PC9wYXRoPgogICAgICAgICAgICAgICAgICAgIDxwYXRoIGQ9Ik0xMy43NjQsNDIuNjU0IEwxMy42NTYsNDIuNTkyIEwxMy43MDIsNDIuNDIxIEwxOC44MzcsMzkuNDU3IEwxOS4wMDcsMzkuNTAyIEwxOC45NjIsMzkuNjczIEwxMy44MjcsNDIuNjM3IEwxMy43NjQsNDIuNjU0IiBpZD0iRmlsbC01IiBmaWxsPSIjNjA3RDhCIj48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTguNTIsOTAuMzc1IEw4LjUyLDQ2LjQyMSBMOC41ODMsNDYuMzg1IEw3NS44NCw3LjU1NCBMNzUuODQsNTEuNTA4IEw3NS43NzgsNTEuNTQ0IEw4LjUyLDkwLjM3NSBMOC41Miw5MC4zNzUgWiBNOC43Nyw0Ni41NjQgTDguNzcsODkuOTQ0IEw3NS41OTEsNTEuMzY1IEw3NS41OTEsNy45ODUgTDguNzcsNDYuNTY0IEw4Ljc3LDQ2LjU2NCBaIiBpZD0iRmlsbC02IiBmaWxsPSIjNjA3RDhCIj48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTI0Ljk4Niw4My4xODIgQzI0Ljc1Niw4My4zMzEgMjQuMzc0LDgzLjU2NiAyNC4xMzcsODMuNzA1IEwxMi42MzIsOTAuNDA2IEMxMi4zOTUsOTAuNTQ1IDEyLjQyNiw5MC42NTggMTIuNyw5MC42NTggTDEzLjI2NSw5MC42NTggQzEzLjU0LDkwLjY1OCAxMy45NTgsOTAuNTQ1IDE0LjE5NSw5MC40MDYgTDI1LjcsODMuNzA1IEMyNS45MzcsODMuNTY2IDI2LjEyOCw4My40NTIgMjYuMTI1LDgzLjQ0OSBDMjYuMTIyLDgzLjQ0NyAyNi4xMTksODMuMjIgMjYuMTE5LDgyLjk0NiBDMjYuMTE5LDgyLjY3MiAyNS45MzEsODIuNTY5IDI1LjcwMSw4Mi43MTkgTDI0Ljk4Niw4My4xODIiIGlkPSJGaWxsLTciIGZpbGw9IiM2MDdEOEIiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNMTMuMjY2LDkwLjc4MiBMMTIuNyw5MC43ODIgQzEyLjUsOTAuNzgyIDEyLjM4NCw5MC43MjYgMTIuMzU0LDkwLjYxNiBDMTIuMzI0LDkwLjUwNiAxMi4zOTcsOTAuMzk5IDEyLjU2OSw5MC4yOTkgTDI0LjA3NCw4My41OTcgQzI0LjMxLDgzLjQ1OSAyNC42ODksODMuMjI2IDI0LjkxOCw4My4wNzggTDI1LjYzMyw4Mi42MTQgQzI1LjcyMyw4Mi41NTUgMjUuODEzLDgyLjUyNSAyNS44OTksODIuNTI1IEMyNi4wNzEsODIuNTI1IDI2LjI0NCw4Mi42NTUgMjYuMjQ0LDgyLjk0NiBDMjYuMjQ0LDgzLjE2IDI2LjI0NSw4My4zMDkgMjYuMjQ3LDgzLjM4MyBMMjYuMjUzLDgzLjM4NyBMMjYuMjQ5LDgzLjQ1NiBDMjYuMjQ2LDgzLjUzMSAyNi4yNDYsODMuNTMxIDI1Ljc2Myw4My44MTIgTDE0LjI1OCw5MC41MTQgQzE0LDkwLjY2NSAxMy41NjQsOTAuNzgyIDEzLjI2Niw5MC43ODIgTDEzLjI2Niw5MC43ODIgWiBNMTIuNjY2LDkwLjUzMiBMMTIuNyw5MC41MzMgTDEzLjI2Niw5MC41MzMgQzEzLjUxOCw5MC41MzMgMTMuOTE1LDkwLjQyNSAxNC4xMzIsOTAuMjk5IEwyNS42MzcsODMuNTk3IEMyNS44MDUsODMuNDk5IDI1LjkzMSw4My40MjQgMjUuOTk4LDgzLjM4MyBDMjUuOTk0LDgzLjI5OSAyNS45OTQsODMuMTY1IDI1Ljk5NCw4Mi45NDYgTDI1Ljg5OSw4Mi43NzUgTDI1Ljc2OCw4Mi44MjQgTDI1LjA1NCw4My4yODcgQzI0LjgyMiw4My40MzcgMjQuNDM4LDgzLjY3MyAyNC4yLDgzLjgxMiBMMTIuNjk1LDkwLjUxNCBMMTIuNjY2LDkwLjUzMiBMMTIuNjY2LDkwLjUzMiBaIiBpZD0iRmlsbC04IiBmaWxsPSIjNjA3RDhCIj48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTEzLjI2Niw4OS44NzEgTDEyLjcsODkuODcxIEMxMi41LDg5Ljg3MSAxMi4zODQsODkuODE1IDEyLjM1NCw4OS43MDUgQzEyLjMyNCw4OS41OTUgMTIuMzk3LDg5LjQ4OCAxMi41NjksODkuMzg4IEwyNC4wNzQsODIuNjg2IEMyNC4zMzIsODIuNTM1IDI0Ljc2OCw4Mi40MTggMjUuMDY3LDgyLjQxOCBMMjUuNjMyLDgyLjQxOCBDMjUuODMyLDgyLjQxOCAyNS45NDgsODIuNDc0IDI1Ljk3OCw4Mi41ODQgQzI2LjAwOCw4Mi42OTQgMjUuOTM1LDgyLjgwMSAyNS43NjMsODIuOTAxIEwxNC4yNTgsODkuNjAzIEMxNCw4OS43NTQgMTMuNTY0LDg5Ljg3MSAxMy4yNjYsODkuODcxIEwxMy4yNjYsODkuODcxIFogTTEyLjY2Niw4OS42MjEgTDEyLjcsODkuNjIyIEwxMy4yNjYsODkuNjIyIEMxMy41MTgsODkuNjIyIDEzLjkxNSw4OS41MTUgMTQuMTMyLDg5LjM4OCBMMjUuNjM3LDgyLjY4NiB
2474MMjUuNjY3LDgyLjY2OCBMMjUuNjMyLDgyLjY2NyBMMjUuMDY3LDgyLjY2NyBDMjQuODE1LDgyLjY2NyAyNC40MTgsODIuNzc1IDI0LjIsODIuOTAxIEwxMi42OTUsODkuNjAzIEwxMi42NjYsODkuNjIxIEwxMi42NjYsODkuNjIxIFoiIGlkPSJGaWxsLTkiIGZpbGw9IiM2MDdEOEIiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNMTIuMzcsOTAuODAxIEwxMi4zNyw4OS41NTQgTDEyLjM3LDkwLjgwMSIgaWQ9IkZpbGwtMTAiIGZpbGw9IiM2MDdEOEIiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNNi4xMyw5My45MDEgQzUuMzc5LDkzLjgwOCA0LjgxNiw5My4xNjQgNC42OTEsOTIuNTI1IEMzLjg2LDg4LjI4NyAzLjU0LDgzLjc0MyAzLjUyNiw3MS4xNzMgQzMuNTExLDU4LjM4OSA0LjQyMyw1MS40MjggNC40MjMsNTEuNDI4IEM1LjEzNCw0Ny4yODIgNy4yMSw0Ni4yMzYgNy4yMSw0Ni4yMzYgQzcuMjEsNDYuMjM2IDgxLjY2NywzLjI1IDgyLjA2OSwzLjAxNyBDODIuMjkyLDIuODg4IDg0LjU1NiwxLjQzMyA4NS4yNjQsMy45NCBDODcuMjE0LDEwLjg0IDg2Ljc1MiwzNS44MjcgODUuNTM5LDQzLjgxOCBDODUuMTUsNDYuMzgzIDg0LjI5MSw0OS4wMzMgODIuNDgzLDUwLjEwMSBMNy4yMSw5My42NTMgQzYuODI4LDkzLjg3NCA2LjQ2MSw5My45NDEgNi4xMyw5My45MDEgQzYuMTMsOTMuOTAxIDMuMzQ5LDkzLjQ2IDMuMTI5LDkxLjc3NiBDMi41NjgsODcuNDk1IDEuOTc3LDgyLjk5NSAxLjk2Miw3MC40MjUgQzEuOTQ4LDU3LjY0MSAyLjg2LDUwLjY4IDIuODYsNTAuNjggQzMuNTcsNDYuNTM0IDUuNjQ3LDQ1LjQ4OSA1LjY0Nyw0NS40ODkgQzUuNjQ2LDQ1LjQ4OSA4LjA2NSw0NC4wOTIgMTIuMjQ1LDQxLjY3OSBMMTMuMTE2LDQxLjU2IEwxOS43MTUsMzcuNzMgTDE5Ljc2MSwzNy4yNjkgTDYuMTMsOTMuOTAxIiBpZD0iRmlsbC0xMSIgZmlsbD0iI0ZBRkFGQSI+PC9wYXRoPgogICAgICAgICAgICAgICAgICAgIDxwYXRoIGQ9Ik02LjMxNyw5NC4xNjEgTDYuMTAyLDk0LjE0OCBMNi4xMDEsOTQuMTQ4IEw1Ljg1Nyw5NC4xMDEgQzUuMTM4LDkzLjk0NSAzLjA4NSw5My4zNjUgMi44ODEsOTEuODA5IEMyLjMxMyw4Ny40NjkgMS43MjcsODIuOTk2IDEuNzEzLDcwLjQyNSBDMS42OTksNTcuNzcxIDIuNjA0LDUwLjcxOCAyLjYxMyw1MC42NDggQzMuMzM4LDQ2LjQxNyA1LjQ0NSw0NS4zMSA1LjUzNSw0NS4yNjYgTDEyLjE2Myw0MS40MzkgTDEzLjAzMyw0MS4zMiBMMTkuNDc5LDM3LjU3OCBMMTkuNTEzLDM3LjI0NCBDMTkuNTI2LDM3LjEwNyAxOS42NDcsMzcuMDA4IDE5Ljc4NiwzNy4wMjEgQzE5LjkyMiwzNy4wMzQgMjAuMDIzLDM3LjE1NiAyMC4wMDksMzcuMjkzIEwxOS45NSwzNy44ODIgTDEzLjE5OCw0MS44MDEgTDEyLjMyOCw0MS45MTkgTDUuNzcyLDQ1LjcwNCBDNS43NDEsNDUuNzIgMy43ODIsNDYuNzcyIDMuMTA2LDUwLjcyMiBDMy4wOTksNTAuNzgyIDIuMTk4LDU3LjgwOCAyLjIxMiw3MC40MjQgQzIuMjI2LDgyLjk2MyAyLjgwOSw4Ny40MiAzLjM3Myw5MS43MjkgQzMuNDY0LDkyLjQyIDQuMDYyLDkyLjg4MyA0LjY4Miw5My4xODEgQzQuNTY2LDkyLjk4NCA0LjQ4Niw5Mi43NzYgNC40NDYsOTIuNTcyIEMzLjY2NSw4OC41ODggMy4yOTEsODQuMzcgMy4yNzYsNzEuMTczIEMzLjI2Miw1OC41MiA0LjE2Nyw1MS40NjYgNC4xNzYsNTEuMzk2IEM0LjkwMSw0Ny4xNjUgNy4wMDgsNDYuMDU5IDcuMDk4LDQ2LjAxNCBDNy4wOTQsNDYuMDE1IDgxLjU0MiwzLjAzNCA4MS45NDQsMi44MDIgTDgxLjk3MiwyLjc4NSBDODIuODc2LDIuMjQ3IDgzLjY5MiwyLjA5NyA4NC4zMzIsMi4zNTIgQzg0Ljg4NywyLjU3MyA4NS4yODEsMy4wODUgODUuNTA0LDMuODcyIEM4Ny41MTgsMTEgODYuOTY0LDM2LjA5MSA4NS43ODUsNDMuODU1IEM4NS4yNzgsNDcuMTk2IDg0LjIxLDQ5LjM3IDgyLjYxLDUwLjMxNyBMNy4zMzUsOTMuODY5IEM2Ljk5OSw5NC4wNjMgNi42NTgsOTQuMTYxIDYuMzE3LDk0LjE2MSBMNi4zMTcsOTQuMTYxIFogTTYuMTcsOTMuNjU0IEM2LjQ2Myw5My42OSA2Ljc3NCw5My42MTcgNy4wODUsOTMuNDM3IEw4Mi4zNTgsNDkuODg2IEM4NC4xODEsNDguODA4IDg0Ljk2LDQ1Ljk3MSA4NS4yOTIsNDMuNzggQzg2LjQ2NiwzNi4wNDkgODcuMDIzLDExLjA4NSA4NS4wMjQsNC4wMDggQzg0Ljg0NiwzLjM3NyA4NC41NTEsMi45NzYgODQuMTQ4LDIuODE2IEM4My42NjQsMi42MjMgODIuOTgyLDIuNzY0IDgyLjIyNywzLjIxMyBMODIuMTkzLDMuMjM0IEM4MS43OTEsMy40NjYgNy4zMzUsNDYuNDUyIDcuMzM1LDQ2LjQ1MiBDNy4zMDQsNDYuNDY5IDUuMzQ2LDQ3LjUyMSA0LjY2OSw1MS40NzEgQzQuNjYyLDUxLjUzIDMuNzYxLDU4LjU1NiAzLjc3NSw3MS4xNzMgQzMuNzksODQuMzI4IDQuMTYxLDg4LjUyNCA0LjkzNiw5Mi40NzYgQzUuMDI2LDkyLjkzNyA1LjQxMiw5My40NTkgNS45NzMsOTMuNjE1IEM2LjA4Nyw5My42NCA2LjE1OCw5My42NTIgNi4xNjksOTMuNjU0IEw2LjE3LDkzLjY1NCBMNi4xNyw5My42NTQgWiIgaWQ9IkZpbGwtMTIiIGZpbGw9IiM0NTVBNjQiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNNy4zMTcsNjguOTgyIEM3LjgwNiw2OC43MDEgOC4yMDIsNjguOTI2IDguMjAyLDY5LjQ4NyBDOC4yMDIsNzAuMDQ3IDcuODA2LDcwLjczIDcuMzE3LDcxLjAxMiBDNi44MjksNzEuMjk0IDYuNDMzLDcxLjA2OSA2LjQzMyw3MC41MDggQzYuNDMzLDY5Ljk0OCA2LjgyOSw2OS4yNjUgNy4zMTcsNjguOTgyIiBpZD0iRmlsbC0xMyIgZmlsbD0iI0ZGRkZGRiI+PC9wYXRoPgogICAgICAgICAgICAgICAgICAgIDxwYXRoIGQ9Ik02LjkyLDcxLjEzMyBDNi42MzEsNzEuMTMzIDYuNDMzLDcwLjkwNSA2LjQzMyw3MC41MDggQzYuNDMzLDY5Ljk0OCA2LjgyOSw2OS4yNjUgNy4zMTcsNjguOTgyIEM3LjQ2LDY4LjkgNy41OTUsNjguODYxIDcuNzE0LDY4Ljg2MSBDOC4wMDMsNjguODYxIDguMjAyLDY5LjA5IDguMjAyLDY5LjQ4NyBDOC4yMDIsNzAuMDQ3IDcuODA2LDcwLjczIDcuMzE3LDcxLjAxMiBDNy4xNzQsNzEuMDk0IDcuMDM5LDcxLjEzMyA2LjkyLDcxLjEzMyBNNy43MTQsNjguNjc0IEM3LjU1Nyw2OC42NzQgNy4zOTIsNjguNzIzIDcuMjI0LDY4LjgyMSBDNi42NzYsNjkuMTM4IDYuMjQ2L
2474DY5Ljg3OSA2LjI0Niw3MC41MDggQzYuMjQ2LDcwLjk5NCA2LjUxNyw3MS4zMiA2LjkyLDcxLjMyIEM3LjA3OCw3MS4zMiA3LjI0Myw3MS4yNzEgNy40MTEsNzEuMTc0IEM3Ljk1OSw3MC44NTcgOC4zODksNzAuMTE3IDguMzg5LDY5LjQ4NyBDOC4zODksNjkuMDAxIDguMTE3LDY4LjY3NCA3LjcxNCw2OC42NzQiIGlkPSJGaWxsLTE0IiBmaWxsPSIjODA5N0EyIj48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTYuOTIsNzAuOTQ3IEM2LjY0OSw3MC45NDcgNi42MjEsNzAuNjQgNi42MjEsNzAuNTA4IEM2LjYyMSw3MC4wMTcgNi45ODIsNjkuMzkyIDcuNDExLDY5LjE0NSBDNy41MjEsNjkuMDgyIDcuNjI1LDY5LjA0OSA3LjcxNCw2OS4wNDkgQzcuOTg2LDY5LjA0OSA4LjAxNSw2OS4zNTUgOC4wMTUsNjkuNDg3IEM4LjAxNSw2OS45NzggNy42NTIsNzAuNjAzIDcuMjI0LDcwLjg1MSBDNy4xMTUsNzAuOTE0IDcuMDEsNzAuOTQ3IDYuOTIsNzAuOTQ3IE03LjcxNCw2OC44NjEgQzcuNTk1LDY4Ljg2MSA3LjQ2LDY4LjkgNy4zMTcsNjguOTgyIEM2LjgyOSw2OS4yNjUgNi40MzMsNjkuOTQ4IDYuNDMzLDcwLjUwOCBDNi40MzMsNzAuOTA1IDYuNjMxLDcxLjEzMyA2LjkyLDcxLjEzMyBDNy4wMzksNzEuMTMzIDcuMTc0LDcxLjA5NCA3LjMxNyw3MS4wMTIgQzcuODA2LDcwLjczIDguMjAyLDcwLjA0NyA4LjIwMiw2OS40ODcgQzguMjAyLDY5LjA5IDguMDAzLDY4Ljg2MSA3LjcxNCw2OC44NjEiIGlkPSJGaWxsLTE1IiBmaWxsPSIjODA5N0EyIj48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTcuNDQ0LDg1LjM1IEM3LjcwOCw4NS4xOTggNy45MjEsODUuMzE5IDcuOTIxLDg1LjYyMiBDNy45MjEsODUuOTI1IDcuNzA4LDg2LjI5MiA3LjQ0NCw4Ni40NDQgQzcuMTgxLDg2LjU5NyA2Ljk2Nyw4Ni40NzUgNi45NjcsODYuMTczIEM2Ljk2Nyw4NS44NzEgNy4xODEsODUuNTAyIDcuNDQ0LDg1LjM1IiBpZD0iRmlsbC0xNiIgZmlsbD0iI0ZGRkZGRiI+PC9wYXRoPgogICAgICAgICAgICAgICAgICAgIDxwYXRoIGQ9Ik03LjIzLDg2LjUxIEM3LjA3NCw4Ni41MSA2Ljk2Nyw4Ni4zODcgNi45NjcsODYuMTczIEM2Ljk2Nyw4NS44NzEgNy4xODEsODUuNTAyIDcuNDQ0LDg1LjM1IEM3LjUyMSw4NS4zMDUgNy41OTQsODUuMjg0IDcuNjU4LDg1LjI4NCBDNy44MTQsODUuMjg0IDcuOTIxLDg1LjQwOCA3LjkyMSw4NS42MjIgQzcuOTIxLDg1LjkyNSA3LjcwOCw4Ni4yOTIgNy40NDQsODYuNDQ0IEM3LjM2Nyw4Ni40ODkgNy4yOTQsODYuNTEgNy4yMyw4Ni41MSBNNy42NTgsODUuMDk4IEM3LjU1OCw4NS4wOTggNy40NTUsODUuMTI3IDcuMzUxLDg1LjE4OCBDNy4wMzEsODUuMzczIDYuNzgxLDg1LjgwNiA2Ljc4MSw4Ni4xNzMgQzYuNzgxLDg2LjQ4MiA2Ljk2Niw4Ni42OTcgNy4yMyw4Ni42OTcgQzcuMzMsODYuNjk3IDcuNDMzLDg2LjY2NiA3LjUzOCw4Ni42MDcgQzcuODU4LDg2LjQyMiA4LjEwOCw4NS45ODkgOC4xMDgsODUuNjIyIEM4LjEwOCw4NS4zMTMgNy45MjMsODUuMDk4IDcuNjU4LDg1LjA5OCIgaWQ9IkZpbGwtMTciIGZpbGw9IiM4MDk3QTIiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNNy4yMyw4Ni4zMjIgTDcuMTU0LDg2LjE3MyBDNy4xNTQsODUuOTM4IDcuMzMzLDg1LjYyOSA3LjUzOCw4NS41MTIgTDcuNjU4LDg1LjQ3MSBMNy43MzQsODUuNjIyIEM3LjczNCw4NS44NTYgNy41NTUsODYuMTY0IDcuMzUxLDg2LjI4MiBMNy4yMyw4Ni4zMjIgTTcuNjU4LDg1LjI4NCBDNy41OTQsODUuMjg0IDcuNTIxLDg1LjMwNSA3LjQ0NCw4NS4zNSBDNy4xODEsODUuNTAyIDYuOTY3LDg1Ljg3MSA2Ljk2Nyw4Ni4xNzMgQzYuOTY3LDg2LjM4NyA3LjA3NCw4Ni41MSA3LjIzLDg2LjUxIEM3LjI5NCw4Ni41MSA3LjM2Nyw4Ni40ODkgNy40NDQsODYuNDQ0IEM3LjcwOCw4Ni4yOTIgNy45MjEsODUuOTI1IDcuOTIxLDg1LjYyMiBDNy45MjEsODUuNDA4IDcuODE0LDg1LjI4NCA3LjY1OCw4NS4yODQiIGlkPSJGaWxsLTE4IiBmaWxsPSIjODA5N0EyIj48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTc3LjI3OCw3Ljc2OSBMNzcuMjc4LDUxLjQzNiBMMTAuMjA4LDkwLjE2IEwxMC4yMDgsNDYuNDkzIEw3Ny4yNzgsNy43NjkiIGlkPSJGaWxsLTE5IiBmaWxsPSIjNDU1QTY0Ij48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTEwLjA4Myw5MC4zNzUgTDEwLjA4Myw0Ni40MjEgTDEwLjE0Niw0Ni4zODUgTDc3LjQwMyw3LjU1NCBMNzcuNDAzLDUxLjUwOCBMNzcuMzQxLDUxLjU0NCBMMTAuMDgzLDkwLjM3NSBMMTAuMDgzLDkwLjM3NSBaIE0xMC4zMzMsNDYuNTY0IEwxMC4zMzMsODkuOTQ0IEw3Ny4xNTQsNTEuMzY1IEw3Ny4xNTQsNy45ODUgTDEwLjMzMyw0Ni41NjQgTDEwLjMzMyw0Ni41NjQgWiIgaWQ9IkZpbGwtMjAiIGZpbGw9IiM2MDdEOEIiPjwvcGF0aD4KICAgICAgICAgICAgICAgIDwvZz4KICAgICAgICAgICAgICAgIDxwYXRoIGQ9Ik0xMjUuNzM3LDg4LjY0NyBMMTE4LjA5OCw5MS45ODEgTDExOC4wOTgsODQgTDEwNi42MzksODguNzEzIEwxMDYuNjM5LDk2Ljk4MiBMOTksMTAwLjMxNSBMMTEyLjM2OSwxMDMuOTYxIEwxMjUuNzM3LDg4LjY0NyIgaWQ9IkltcG9ydGVkLUxheWVycy1Db3B5LTIiIGZpbGw9IiM0NTVBNjQiIHNrZXRjaDp0eXBlPSJNU1NoYXBlR3JvdXAiPjwvcGF0aD4KICAgICAgICAgICAgPC9nPgogICAgICAgIDwvZz4KICAgIDwvZz4KPC9zdmc+';
2475	function RotateInstructions() {
2476	  this.loadIcon_();
2477	  var overlay = document.createElement('div');
2478	  var s = overlay.style;
2479	  s.position = 'fixed';
2480	  s.top = 0;
2481	  s.right = 0;
2482	  s.bottom = 0;
2483	  s.left = 0;
2484	  s.backgroundColor = 'gray';
2485	  s.fontFamily = 'sans-serif';
2486	  s.zIndex = 1000000;
2487	  var img = document.createElement('img');
2488	  img.src = this.icon;
2489	  var s = img.style;
2490	  s.marginLeft = '25%';
2491	  s.marginTop = '25%';
2492	  s.width = '50%';
2493	  overlay.appendChild(img);
2494	  var text = document.createElement('div');
2495	  var s = text.style;
2496	  s.textAlign = 'center';
2497	  s.fontSize = '16px';
2498	  s.lineHeight = '24px';
2499	  s.margin = '24px 25%';
2500	  s.width = '50%';
2501	  text.innerHTML = 'Place your phone into your Cardboard viewer.';
2502	  overlay.appendChild(text);
2503	  var snackbar = document.createElement('div');
2504	  var s = snackbar.style;
2505	  s.backgroundColor = '#CFD8DC';
2506	  s.position = 'fixed';
2507	  s.bottom = 0;
2508	  s.width = '100%';
2509	  s.height = '48px';
2510	  s.padding = '14px 24px';
2511	  s.boxSizing = 'border-box';
2512	  s.color = '#656A6B';
2513	  overlay.appendChild(snackbar);
2514	  var snackbarText = document.createElement('div');
2515	  snackbarText.style.float = 'left';
2516	  snackbarText.innerHTML = 'No Cardboard viewer?';
2517	  var snackbarButton = document.createElement('a');
2518	  snackbarButton.href = 'https://www.google.com/get/cardboard/get-cardboard/';
2519	  snackbarButton.innerHTML = 'get one';
2520	  snackbarButton.target = '_blank';
2521	  var s = snackbarButton.style;
2522	  s.float = 'right';
2523	  s.fontWeight = 600;
2524	  s.textTransform = 'uppercase';
2525	  s.borderLeft = '1px solid gray';
2526	  s.paddingLeft = '24px';
vendor: 4,328 bytes, lines 2527-2662
2527	  s.textDecoration = 'none';
2528	  s.color = '#656A6B';
2529	  snackbar.appendChild(snackbarText);
2530	  snackbar.appendChild(snackbarButton);
2531	  this.overlay = overlay;
2532	  this.text = text;
2533	  this.hide();
2534	}
2535	RotateInstructions.prototype.show = function (parent) {
2536	  if (!parent && !this.overlay.parentElement) {
2537		document.body.appendChild(this.overlay);
2538	  } else if (parent) {
2539		if (this.overlay.parentElement && this.overlay.parentElement != parent) this.overlay.parentElement.removeChild(this.overlay);
2540		parent.appendChild(this.overlay);
2541	  }
2542	  this.overlay.style.display = 'block';
2543	  var img = this.overlay.querySelector('img');
2544	  var s = img.style;
2545	  if (isLandscapeMode()) {
2546		s.width = '20%';
2547		s.marginLeft = '40%';
2548		s.marginTop = '3%';
2549	  } else {
2550		s.width = '50%';
2551		s.marginLeft = '25%';
2552		s.marginTop = '25%';
2553	  }
2554	};
2555	RotateInstructions.prototype.hide = function () {
2556	  this.overlay.style.display = 'none';
2557	};
2558	RotateInstructions.prototype.showTemporarily = function (ms, parent) {
2559	  this.show(parent);
2560	  this.timer = setTimeout(this.hide.bind(this), ms);
2561	};
2562	RotateInstructions.prototype.disableShowTemporarily = function () {
2563	  clearTimeout(this.timer);
2564	};
2565	RotateInstructions.prototype.update = function () {
2566	  this.disableShowTemporarily();
2567	  if (!isLandscapeMode() && isMobile()) {
2568		this.show();
2569	  } else {
2570		this.hide();
2571	  }
2572	};
2573	RotateInstructions.prototype.loadIcon_ = function () {
2574	  this.icon = base64('image/svg+xml', rotateInstructionsAsset);
2575	};
2576	var DEFAULT_VIEWER = 'CardboardV1';
2577	var VIEWER_KEY = 'WEBVR_CARDBOARD_VIEWER';
2578	var CLASS_NAME = 'webvr-polyfill-viewer-selector';
2579	function ViewerSelector(defaultViewer) {
2580	  try {
2581		this.selectedKey = localStorage.getItem(VIEWER_KEY);
2582	  } catch (error) {
2583		console.error('Failed to load viewer profile: %s', error);
2584	  }
2585	  if (!this.selectedKey) {
2586		this.selectedKey = defaultViewer || DEFAULT_VIEWER;
2587	  }
2588	  this.dialog = this.createDialog_(DeviceInfo.Viewers);
2589	  this.root = null;
2590	  this.onChangeCallbacks_ = [];
2591	}
2592	ViewerSelector.prototype.show = function (root) {
2593	  this.root = root;
2594	  root.appendChild(this.dialog);
2595	  var selected = this.dialog.querySelector('#' + this.selectedKey);
2596	  selected.checked = true;
2597	  this.dialog.style.display = 'block';
2598	};
2599	ViewerSelector.prototype.hide = function () {
2600	  if (this.root && this.root.contains(this.dialog)) {
2601		this.root.removeChild(this.dialog);
2602	  }
2603	  this.dialog.style.display = 'none';
2604	};
2605	ViewerSelector.prototype.getCurrentViewer = function () {
2606	  return DeviceInfo.Viewers[this.selectedKey];
2607	};
2608	ViewerSelector.prototype.getSelectedKey_ = function () {
2609	  var input = this.dialog.querySelector('input[name=field]:checked');
2610	  if (input) {
2611		return input.id;
2612	  }
2613	  return null;
2614	};
2615	ViewerSelector.prototype.onChange = function (cb) {
2616	  this.onChangeCallbacks_.push(cb);
2617	};
2618	ViewerSelector.prototype.fireOnChange_ = function (viewer) {
2619	  for (var i = 0; i < this.onChangeCallbacks_.length; i++) {
2620		this.onChangeCallbacks_[i](viewer);
2621	  }
2622	};
2623	ViewerSelector.prototype.onSave_ = function () {
2624	  this.selectedKey = this.getSelectedKey_();
2625	  if (!this.selectedKey || !DeviceInfo.Viewers[this.selectedKey]) {
2626		console.error('ViewerSelector.onSave_: this should never happen!');
2627		return;
2628	  }
2629	  this.fireOnChange_(DeviceInfo.Viewers[this.selectedKey]);
2630	  try {
2631		localStorage.setItem(VIEWER_KEY, this.selectedKey);
2632	  } catch (error) {
2633		console.error('Failed to save viewer profile: %s', error);
2634	  }
2635	  this.hide();
2636	};
2637	ViewerSelector.prototype.createDialog_ = function (options) {
2638	  var container = document.createElement('div');
2639	  container.classList.add(CLASS_NAME);
2640	  container.style.display = 'none';
2641	  var overlay = document.createElement('div');
2642	  var s = overlay.style;
2643	  s.position = 'fixed';
2644	  s.left = 0;
2645	  s.top = 0;
2646	  s.width = '100%';
2647	  s.height = '100%';
2648	  s.background = 'rgba(0, 0, 0, 0.3)';
2649	  overlay.addEventListener('click', this.hide.bind(this));
2650	  var width = 280;
2651	  var dialog = document.createElement('div');
2652	  var s = dialog.style;
2653	  s.boxSizing = 'border-box';
2654	  s.position = 'fixed';
2655	  s.top = '24px';
2656	  s.left = '50%';
2657	  s.marginLeft = -width / 2 + 'px';
2658	  s.width = width + 'px';
2659	  s.padding = '24px';
2660	  s.overflow = 'hidden';
2661	  s.background = '#fafafa';
2662	  s.fontFamily = "'Roboto', sans-serif";
vendor: 8,869 bytes, lines 2663-2818
2663	  s.boxShadow = '0px 5px 20px #666';
2664	  dialog.appendChild(this.createH1_('Select your viewer'));
2665	  for (var id in options) {
2666		dialog.appendChild(this.createChoice_(id, options[id].label));
2667	  }
2668	  dialog.appendChild(this.createButton_('Save', this.onSave_.bind(this)));
2669	  container.appendChild(overlay);
2670	  container.appendChild(dialog);
2671	  return container;
2672	};
2673	ViewerSelector.prototype.createH1_ = function (name) {
2674	  var h1 = document.createElement('h1');
2675	  var s = h1.style;
2676	  s.color = 'black';
2677	  s.fontSize = '20px';
2678	  s.fontWeight = 'bold';
2679	  s.marginTop = 0;
2680	  s.marginBottom = '24px';
2681	  h1.innerHTML = name;
2682	  return h1;
2683	};
2684	ViewerSelector.prototype.createChoice_ = function (id, name) {
2685	  var div = document.createElement('div');
2686	  div.style.marginTop = '8px';
2687	  div.style.color = 'black';
2688	  var input = document.createElement('input');
2689	  input.style.fontSize = '30px';
2690	  input.setAttribute('id', id);
2691	  input.setAttribute('type', 'radio');
2692	  input.setAttribute('value', id);
2693	  input.setAttribute('name', 'field');
2694	  var label = document.createElement('label');
2695	  label.style.marginLeft = '4px';
2696	  label.setAttribute('for', id);
2697	  label.innerHTML = name;
2698	  div.appendChild(input);
2699	  div.appendChild(label);
2700	  return div;
2701	};
2702	ViewerSelector.prototype.createButton_ = function (label, onclick) {
2703	  var button = document.createElement('button');
2704	  button.innerHTML = label;
2705	  var s = button.style;
2706	  s.float = 'right';
2707	  s.textTransform = 'uppercase';
2708	  s.color = '#1094f7';
2709	  s.fontSize = '14px';
2710	  s.letterSpacing = 0;
2711	  s.border = 0;
2712	  s.background = 'none';
2713	  s.marginTop = '16px';
2714	  button.addEventListener('click', onclick);
2715	  return button;
2716	};
2717	var commonjsGlobal$$1 = typeof window !== 'undefined' ? window : typeof commonjsGlobal$1 !== 'undefined' ? commonjsGlobal$1 : typeof self !== 'undefined' ? self : {};
2718	function unwrapExports$$1 (x) {
2719		return x && x.__esModule ? x['default'] : x;
2720	}
2721	function createCommonjsModule$$1(fn, module) {
2722		return module = { exports: {} }, fn(module, module.exports), module.exports;
2723	}
2724	var NoSleep = createCommonjsModule$$1(function (module, exports) {
2725	(function webpackUniversalModuleDefinition(root, factory) {
2726		module.exports = factory();
2727	})(commonjsGlobal$$1, function() {
2728	return          (function(modules) {
2729				 var installedModules = {};
2730				 function __webpack_require__(moduleId) {
2731					 if(installedModules[moduleId]) {
2732						 return installedModules[moduleId].exports;
2733					 }
2734					 var module = installedModules[moduleId] = {
2735						 i: moduleId,
2736						 l: false,
2737						 exports: {}
2738					 };
2739					 modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
2740					 module.l = true;
2741					 return module.exports;
2742				 }
2743				 __webpack_require__.m = modules;
2744				 __webpack_require__.c = installedModules;
2745				 __webpack_require__.d = function(exports, name, getter) {
2746					 if(!__webpack_require__.o(exports, name)) {
2747						 Object.defineProperty(exports, name, {
2748							 configurable: false,
2749							 enumerable: true,
2750							 get: getter
2751						 });
2752					 }
2753				 };
2754				 __webpack_require__.n = function(module) {
2755					 var getter = module && module.__esModule ?
2756						 function getDefault() { return module['default']; } :
2757						 function getModuleExports() { return module; };
2758					 __webpack_require__.d(getter, 'a', getter);
2759					 return getter;
2760				 };
2761				 __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
2762				 __webpack_require__.p = "";
2763				 return __webpack_require__(__webpack_require__.s = 0);
2764			 })
2765			 ([
2766		  (function(module, exports, __webpack_require__) {
2767	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; }; }();
2768	function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
2769	var mediaFile = __webpack_require__(1);
2770	var oldIOS = typeof navigator !== 'undefined' && parseFloat(('' + (/CPU.*OS ([0-9_]{3,4})[0-9_]{0,1}|(CPU like).*AppleWebKit.*Mobile/i.exec(navigator.userAgent) || [0, ''])[1]).replace('undefined', '3_2').replace('_', '.').replace('_', '')) < 10 && !window.MSStream;
2771	var NoSleep = function () {
2772	  function NoSleep() {
2773		_classCallCheck(this, NoSleep);
2774		if (oldIOS) {
2775		  this.noSleepTimer = null;
2776		} else {
2777		  this.noSleepVideo = document.createElement('video');
2778		  this.noSleepVideo.setAttribute('playsinline', '');
2779		  this.noSleepVideo.setAttribute('src', mediaFile);
2780		  this.noSleepVideo.addEventListener('timeupdate', function (e) {
2781			if (this.noSleepVideo.currentTime > 0.5) {
2782			  this.noSleepVideo.currentTime = Math.random();
2783			}
2784		  }.bind(this));
2785		}
2786	  }
2787	  _createClass(NoSleep, [{
2788		key: 'enable',
2789		value: function enable() {
2790		  if (oldIOS) {
2791			this.disable();
2792			this.noSleepTimer = window.setInterval(function () {
2793			  window.location.href = '/';
2794			  window.setTimeout(window.stop, 0);
2795			}, 15000);
2796		  } else {
2797			this.noSleepVideo.play();
2798		  }
2799		}
2800	  }, {
2801		key: 'disable',
2802		value: function disable() {
2803		  if (oldIOS) {
2804			if (this.noSleepTimer) {
2805			  window.clearInterval(this.noSleepTimer);
2806			  this.noSleepTimer = null;
2807			}
2808		  } else {
2809			this.noSleepVideo.pause();
2810		  }
2811		}
2812	  }]);
2813	  return NoSleep;
2814	}();
2815	module.exports = NoSleep;
2816		  }),
2817		  (function(module, exports, __webpack_require__) {
2818	module.exports = 'data:video/mp4;base64,AAAAIGZ0eXBtcDQyAAACAGlzb21pc28yYXZjMW1wNDEAAAAIZnJlZQAACKBtZGF0AAAC8wYF///v3EXpvebZSLeWLNgg2SPu73gyNjQgLSBjb3JlIDE0MiByMjQ3OSBkZDc5YTYxIC0gSC4yNjQvTVBFRy00IEFWQyBjb2RlYyAtIENvcHlsZWZ0IDIwMDMtMjAxNCAtIGh0dHA6Ly93d3cudmlkZW9sYW4ub3JnL3gyNjQuaHRtbCAtIG9wdGlvbnM6IGNhYmFjPTEgcmVmPTEgZGVibG9jaz0xOjA6MCBhbmFseXNlPTB4MToweDExMSBtZT1oZXggc3VibWU9MiBwc3k9MSBwc3lfcmQ9MS4wMDowLjAwIG1peGVkX3JlZj0wIG1lX3JhbmdlPTE2IGNocm9tYV9tZT0xIHRyZWxsaXM9MCA4eDhkY3Q9MCBjcW09MCBkZWFkem9uZT0yMSwxMSBmYXN0X3Bza2lwPTEgY2hyb21hX3FwX29mZnNldD0wIHRocmVhZHM9NiBsb29rYWhlYWRfdGhyZWFkcz0xIHNsaWNlZF90aHJlYWRzPTAgbnI9MCBkZWNpbWF0ZT0xIGludGVybGFjZWQ9MCBibHVyYXlfY29tcGF0PTAgY29uc3RyYWluZWRfaW50cmE9MCBiZnJhbWVzPTMgYl9weXJhbWlkPTIgYl9hZGFwdD0xIGJfYmlhcz0wIGRpcmVjdD0xIHdlaWdodGI9MSBvcGVuX2dvcD0wIHdlaWdodHA9MSBrZXlpbnQ9MzAwIGtleWludF9taW49MzAgc2NlbmVjdXQ9NDAgaW50cmFfcmVmcmVzaD0wIHJjX2xvb2thaGVhZD0xMCByYz1jcmYgbWJ0cmVlPTEgY3JmPTIwLjAgcWNvbXA9MC42MCBxcG1pbj0wIHFwbWF4PTY5IHFwc3RlcD00IHZidl9tYXhyYXRlPTIwMDAwIHZidl9idWZzaXplPTI1MDAwIGNyZl9tYXg9MC4wIG5hbF9ocmQ9bm9uZSBmaWxsZXI9MCBpcF9yYXRpbz0xLjQwIGFxPTE6MS4wMACAAAAAOWWIhAA3//p+C7v8tDDSTjf97w55i3SbRPO4ZY+hkjD5hbkAkL3zpJ6h/LR1CAABzgB1kqqzUorlhQAAAAxBmiQYhn/+qZYADLgAAAAJQZ5CQhX/AAj5IQADQGgcIQADQGgcAAAACQGeYUQn/wALKCEAA0BoHAAAAAkBnmNEJ/8ACykhAANAaBwhAANAaBwAAAANQZpoNExDP/6plgAMuSEAA0BoHAAAAAtBnoZFESwr/wAI+SEAA0BoHCEAA0BoHAAAAAkBnqVEJ/8ACykhAANAaBwAAAAJAZ6nRCf/AAsoIQADQGgcIQADQGgcAAAADUGarDRMQz/+qZYADLghAANAaBwAAAALQZ7KRRUsK/8ACPkhAANAaBwAAAAJAZ7pRCf/AAsoIQADQGgcIQADQGgcAAAACQGe60Qn/wALKCEAA0BoHAAAAA1BmvA0TEM//qmWAAy5IQADQGgcIQADQGgcAAAAC0GfDkUVLCv/AAj5IQADQGgcAAAACQGfLUQn/wALKSEAA0BoHCEAA0BoHAAAAAkBny9EJ/8ACyghAANAaBwAAAANQZs0NExDP/6plgAMuCEAA0BoHAAAAAtBn1JFFSwr/wAI+SEAA0BoHCEAA0BoHAAAAAkBn3FEJ/8ACyghAANAaBwAAAAJAZ9zRCf/AAsoIQADQGgcIQADQGgcAAAADUGbeDRMQz/+qZYADLkhAANAaBwAAAALQZ+WRRUsK/8ACPghAANAaBwhAANAaBwAAAAJAZ+1RCf/AAspIQADQGgcAAAACQGft0Qn/wALKSEAA0BoHCEAA0BoHAAAAA1Bm7w0TEM//qmWAAy4IQADQGgcAAAAC0Gf2kUVLCv/AAj5IQADQGgcAAAACQGf+UQn/wALKCEAA0BoHCEAA0BoHAAAAAkBn/tEJ/8ACykhAANAaBwAAAANQZvgNExDP/6plgAMuSEAA0BoHCEAA0BoHAAAAAtBnh5FFSwr/wAI+CEAA0BoHAAAAAkBnj1EJ/8ACyghAANAaBwhAANAaBwAAAAJAZ4/RCf/AAspIQADQGgcAAAADUGaJDRMQz/+qZYADLghAANAaBwAAAALQZ5CRRUsK/8ACPkhAANAaBwhAANAaBwAAAAJAZ5hRCf/AAsoIQADQGgcAAAACQGeY0Qn/wALKSEAA0BoHCEAA0BoHAAAAA1Bmmg0TEM//qmWAAy5IQADQGgcAAAAC0GehkUVLCv/AAj5IQADQGgcIQADQGgcAAAACQGepUQn/wALKSEAA0BoHAAAAAkBnqdEJ/8ACyghAANAaBwAAAANQZqsNExDP/6plgAMuCEAA0BoHCEAA0BoHAAAAAtBnspFFSwr/wAI+SEAA0BoHAAAAAkBnulEJ/8ACyghAANAaBwhAANAaBwAAAAJAZ7rRCf/AAsoIQADQGgcAAAADUGa8DRMQz/+qZYADLkhAANAaBwhAANAaBwAAAALQZ8ORRUsK/8ACPkhAANAaBwAAAAJAZ8tRCf/AAspIQADQGgcIQADQGgcAAAACQGfL0Qn/wALKCEAA0BoHAAAAA1BmzQ0TEM//qmWAAy4IQADQGgcAAAAC0GfUkUVLCv/AAj5IQADQGgcIQADQGgcAAAACQGfcUQn/wALKCEAA0BoHAAAAAkBn3NEJ/8ACyghAANAaBwhAANAaBwAAAANQZt4NExC//6plgAMuSEAA0BoHAAAAAtBn5ZFFSwr/wAI+CEAA0BoHCEAA0BoHAAAAAkBn7VEJ/8ACykhAANAaBwAAAAJAZ+3RCf/AAspIQADQGgcAAAADUGbuzRMQn/+nhAAYsAhAANAaBwhAANAaBwAAAAJQZ/aQhP/AAspIQADQGgcAAAACQGf+U
2818Qn/wALKCEAA0BoHCEAA0BoHCEAA0BoHCEAA0BoHCEAA0BoHCEAA0BoHAAACiFtb292AAAAbG12aGQAAAAA1YCCX9WAgl8AAAPoAAAH/AABAAABAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAGGlvZHMAAAAAEICAgAcAT////v7/AAAF+XRyYWsAAABcdGtoZAAAAAPVgIJf1YCCXwAAAAEAAAAAAAAH0AAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAEAAAAAAygAAAMoAAAAAACRlZHRzAAAAHGVsc3QAAAAAAAAAAQAAB9AAABdwAAEAAAAABXFtZGlhAAAAIG1kaGQAAAAA1YCCX9WAgl8AAV+QAAK/IFXEAAAAAAAtaGRscgAAAAAAAAAAdmlkZQAAAAAAAAAAAAAAAFZpZGVvSGFuZGxlcgAAAAUcbWluZgAAABR2bWhkAAAAAQAAAAAAAAAAAAAAJGRpbmYAAAAcZHJlZgAAAAAAAAABAAAADHVybCAAAAABAAAE3HN0YmwAAACYc3RzZAAAAAAAAAABAAAAiGF2YzEAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAygDKAEgAAABIAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAY//8AAAAyYXZjQwFNQCj/4QAbZ01AKOyho3ySTUBAQFAAAAMAEAAr8gDxgxlgAQAEaO+G8gAAABhzdHRzAAAAAAAAAAEAAAA8AAALuAAAABRzdHNzAAAAAAAAAAEAAAABAAAB8GN0dHMAAAAAAAAAPAAAAAEAABdwAAAAAQAAOpgAAAABAAAXcAAAAAEAAAAAAAAAAQAAC7gAAAABAAA6mAAAAAEAABdwAAAAAQAAAAAAAAABAAALuAAAAAEAADqYAAAAAQAAF3AAAAABAAAAAAAAAAEAAAu4AAAAAQAAOpgAAAABAAAXcAAAAAEAAAAAAAAAAQAAC7gAAAABAAA6mAAAAAEAABdwAAAAAQAAAAAAAAABAAALuAAAAAEAADqYAAAAAQAAF3AAAAABAAAAAAAAAAEAAAu4AAAAAQAAOpgAAAABAAAXcAAAAAEAAAAAAAAAAQAAC7gAAAABAAA6mAAAAAEAABdwAAAAAQAAAAAAAAABAAALuAAAAAEAADqYAAAAAQAAF3AAAAABAAAAAAAAAAEAAAu4AAAAAQAAOpgAAAABAAAXcAAAAAEAAAAAAAAAAQAAC7gAAAABAAA6mAAAAAEAABdwAAAAAQAAAAAAAAABAAALuAAAAAEAADqYAAAAAQAAF3AAAAABAAAAAAAAAAEAAAu4AAAAAQAAOpgAAAABAAAXcAAAAAEAAAAAAAAAAQAAC7gAAAABAAA6mAAAAAEAABdwAAAAAQAAAAAAAAABAAALuAAAAAEAAC7gAAAAAQAAF3AAAAABAAAAAAAAABxzdHNjAAAAAAAAAAEAAAABAAAAAQAAAAEAAAEEc3RzegAAAAAAAAAAAAAAPAAAAzQAAAAQAAAADQAAAA0AAAANAAAAEQAAAA8AAAANAAAADQAAABEAAAAPAAAADQAAAA0AAAARAAAADwAAAA0AAAANAAAAEQAAAA8AAAANAAAADQAAABEAAAAPAAAADQAAAA0AAAARAAAADwAAAA0AAAANAAAAEQAAAA8AAAANAAAADQAAABEAAAAPAAAADQAAAA0AAAARAAAADwAAAA0AAAANAAAAEQAAAA8AAAANAAAADQAAABEAAAAPAAAADQAAAA0AAAARAAAADwAAAA0AAAANAAAAEQAAAA8AAAANAAAADQAAABEAAAANAAAADQAAAQBzdGNvAAAAAAAAADwAAAAwAAADZAAAA3QAAAONAAADoAAAA7kAAAPQAAAD6wAAA/4AAAQXAAAELgAABEMAAARcAAAEbwAABIwAAAShAAAEugAABM0AAATkAAAE/wAABRIAAAUrAAAFQgAABV0AAAVwAAAFiQAABaAAAAW1AAAFzgAABeEAAAX+AAAGEwAABiwAAAY/AAAGVgAABnEAAAaEAAAGnQAABrQAAAbPAAAG4gAABvUAAAcSAAAHJwAAB0AAAAdTAAAHcAAAB4UAAAeeAAAHsQAAB8gAAAfjAAAH9gAACA8AAAgmAAAIQQAACFQAAAhnAAAIhAAACJcAAAMsdHJhawAAAFx0a2hkAAAAA9WAgl/VgIJfAAAAAgAAAAAAAAf8AAAAAAAAAAAAAAABAQAAAAABAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAACsm1kaWEAAAAgbWRoZAAAAADVgIJf1YCCXwAArEQAAWAAVcQAAAAAACdoZGxyAAAAAAAAAABzb3VuAAAAAAAAAAAAAAAAU3RlcmVvAAAAAmNtaW5mAAAAEHNtaGQAAAAAAAAAAAAAACRkaW5mAAAAHGRyZWYAAAAAAAAAAQAAAAx1cmwgAAAAAQAAAidzdGJsAAAAZ3N0c2QAAAAAAAAAAQAAAFdtcDRhAAAAAAAAAAEAAAAAAAAAAAACABAAAAAArEQAAAAAADNlc2RzAAAAAAOAgIAiAAIABICAgBRAFQAAAAADDUAAAAAABYCAgAISEAaAgIABAgAAABhzdHRzAAAAAAAAAAEAAABYAAAEAAAAABxzdHNjAAAAAAAAAAEAAAABAAAAAQAAAAEAAAAUc3RzegAAAAAAAAAGAAAAWAAAAXBzdGNvAAAAAAAAAFgAAAOBAAADhwAAA5oAAAOtAAADswAAA8oAAAPfAAAD5QAAA/gAAAQLAAAEEQAABCgAAAQ9AAAEUAAABFYAAARpAAAEgAAABIYAAASbAAAErgAABLQAAATHAAAE3gAABPMAAAT5AAAFDAAABR8AAAUlAAAFPAAABVEAAAVXAAAFagAABX0AAAWDAAAFmgAABa8AAAXCAAAFyAAABdsAAAXyAAAF+AAABg0AAAYgAAAGJgAABjkAAAZQAAAGZQAABmsAAAZ+AAAGkQAABpcAAAauAAAGwwAABskAAAbcAAAG7wAABwYAAAcMAAAHIQAABzQAAAc6AAAHTQAAB2QAAAdqAAAHfwAAB5IAAAeYAAAHqwAAB8IAAAfXAAAH3QAAB/AAAAgDAAAICQAACCAAAAg1AAAIOwAACE4AAAhhAAAIeAAACH4AAAiRAAAIpAAACKoAAAiwAAAItgAACLwAAAjCAAAAFnVkdGEAAAAObmFtZVN0ZXJlbwAAAHB1ZHRhAAAAaG1ldGEAAAAAAAAAIWhkbHIAAAAAAAAAAG1kaXJhcHBsAAAAAAAAAAAAAAAAO2lsc3QAAAAzqXRvbwAAACtkYXRhAAAAAQAAAABIYW5kQnJha2UgMC4xMC4yIDIwMTUwNjExMDA=';
2819		  })
2820			 ]);
2821	});
2822	});
2823	var NoSleep$1 = unwrapExports$$1(NoSleep);
2824	var nextDisplayId = 1000;
2825	var defaultLeftBounds = [0, 0, 0.5, 1];
2826	var defaultRightBounds = [0.5, 0, 0.5, 1];
2827	var raf = window.requestAnimationFrame;
2828	var caf = window.cancelAnimationFrame;
2829	function VRFrameData() {
2830	  this.leftProjectionMatrix = new Float32Array(16);
vendor: 23,756 bytes, lines 2831-3499
2831	  this.leftViewMatrix = new Float32Array(16);
2832	  this.rightProjectionMatrix = new Float32Array(16);
2833	  this.rightViewMatrix = new Float32Array(16);
2834	  this.pose = null;
2835	}
2836	function VRDisplayCapabilities(config) {
2837	  Object.defineProperties(this, {
2838		hasPosition: {
2839		  writable: false, enumerable: true, value: config.hasPosition
2840		},
2841		hasExternalDisplay: {
2842		  writable: false, enumerable: true, value: config.hasExternalDisplay
2843		},
2844		canPresent: {
2845		  writable: false, enumerable: true, value: config.canPresent
2846		},
2847		maxLayers: {
2848		  writable: false, enumerable: true, value: config.maxLayers
2849		},
2850		hasOrientation: {
2851		  enumerable: true, get: function get() {
2852			deprecateWarning('VRDisplayCapabilities.prototype.hasOrientation', 'VRDisplay.prototype.getFrameData');
2853			return config.hasOrientation;
2854		  }
2855		}
2856	  });
2857	}
2858	function VRDisplay(config) {
2859	  config = config || {};
2860	  var USE_WAKELOCK = 'wakelock' in config ? config.wakelock : true;
2861	  this.isPolyfilled = true;
2862	  this.displayId = nextDisplayId++;
2863	  this.displayName = '';
2864	  this.depthNear = 0.01;
2865	  this.depthFar = 10000.0;
2866	  this.isPresenting = false;
2867	  Object.defineProperty(this, 'isConnected', {
2868		get: function get() {
2869		  deprecateWarning('VRDisplay.prototype.isConnected', 'VRDisplayCapabilities.prototype.hasExternalDisplay');
2870		  return false;
2871		}
2872	  });
2873	  this.capabilities = new VRDisplayCapabilities({
2874		hasPosition: false,
2875		hasOrientation: false,
2876		hasExternalDisplay: false,
2877		canPresent: false,
2878		maxLayers: 1
2879	  });
2880	  this.stageParameters = null;
2881	  this.waitingForPresent_ = false;
2882	  this.layer_ = null;
2883	  this.originalParent_ = null;
2884	  this.fullscreenElement_ = null;
2885	  this.fullscreenWrapper_ = null;
2886	  this.fullscreenElementCachedStyle_ = null;
2887	  this.fullscreenEventTarget_ = null;
2888	  this.fullscreenChangeHandler_ = null;
2889	  this.fullscreenErrorHandler_ = null;
2890	  if (USE_WAKELOCK && isMobile()) {
2891		this.wakelock_ = new NoSleep$1();
2892	  }
2893	}
2894	VRDisplay.prototype.getFrameData = function (frameData) {
2895	  return frameDataFromPose(frameData, this._getPose(), this);
2896	};
2897	VRDisplay.prototype.getPose = function () {
2898	  deprecateWarning('VRDisplay.prototype.getPose', 'VRDisplay.prototype.getFrameData');
2899	  return this._getPose();
2900	};
2901	VRDisplay.prototype.resetPose = function () {
2902	  deprecateWarning('VRDisplay.prototype.resetPose');
2903	  return this._resetPose();
2904	};
2905	VRDisplay.prototype.getImmediatePose = function () {
2906	  deprecateWarning('VRDisplay.prototype.getImmediatePose', 'VRDisplay.prototype.getFrameData');
2907	  return this._getPose();
2908	};
2909	VRDisplay.prototype.requestAnimationFrame = function (callback) {
2910	  return raf(callback);
2911	};
2912	VRDisplay.prototype.cancelAnimationFrame = function (id) {
2913	  return caf(id);
2914	};
2915	VRDisplay.prototype.wrapForFullscreen = function (element) {
2916	  if (isIOS()) {
2917		return element;
2918	  }
2919	  if (!this.fullscreenWrapper_) {
2920		this.fullscreenWrapper_ = document.createElement('div');
2921		var cssProperties = ['height: ' + Math.min(screen.height, screen.width) + 'px !important', 'top: 0 !important', 'left: 0 !important', 'right: 0 !important', 'border: 0', 'margin: 0', 'padding: 0', 'z-index: 999999 !important', 'position: fixed'];
2922		this.fullscreenWrapper_.setAttribute('style', cssProperties.join('; ') + ';');
2923		this.fullscreenWrapper_.classList.add('webvr-polyfill-fullscreen-wrapper');
2924	  }
2925	  if (this.fullscreenElement_ == element) {
2926		return this.fullscreenWrapper_;
2927	  }
2928	  if (this.fullscreenElement_) {
2929		if (this.originalParent_) {
2930		  this.originalParent_.appendChild(this.fullscreenElement_);
2931		} else {
2932		  this.fullscreenElement_.parentElement.removeChild(this.fullscreenElement_);
2933		}
2934	  }
2935	  this.fullscreenElement_ = element;
2936	  this.originalParent_ = element.parentElement;
2937	  if (!this.originalParent_) {
2938		document.body.appendChild(element);
2939	  }
2940	  if (!this.fullscreenWrapper_.parentElement) {
2941		var parent = this.fullscreenElement_.parentElement;
2942		parent.insertBefore(this.fullscreenWrapper_, this.fullscreenElement_);
2943		parent.removeChild(this.fullscreenElement_);
2944	  }
2945	  this.fullscreenWrapper_.insertBefore(this.fullscreenElement_, this.fullscreenWrapper_.firstChild);
2946	  this.fullscreenElementCachedStyle_ = this.fullscreenElement_.getAttribute('style');
2947	  var self = this;
2948	  function applyFullscreenElementStyle() {
2949		if (!self.fullscreenElement_) {
2950		  return;
2951		}
2952		var cssProperties = ['position: absolute', 'top: 0', 'left: 0', 'width: ' + Math.max(screen.width, screen.height) + 'px', 'height: ' + Math.min(screen.height, screen.width) + 'px', 'border: 0', 'margin: 0', 'padding: 0'];
2953		self.fullscreenElement_.setAttribute('style', cssProperties.join('; ') + ';');
2954	  }
2955	  applyFullscreenElementStyle();
2956	  return this.fullscreenWrapper_;
2957	};
2958	VRDisplay.prototype.removeFullscreenWrapper = function () {
2959	  if (!this.fullscreenElement_) {
2960		return;
2961	  }
2962	  var element = this.fullscreenElement_;
2963	  if (this.fullscreenElementCachedStyle_) {
2964		element.setAttribute('style', this.fullscreenElementCachedStyle_);
2965	  } else {
2966		element.removeAttribute('style');
2967	  }
2968	  this.fullscreenElement_ = null;
2969	  this.fullscreenElementCachedStyle_ = null;
2970	  var parent = this.fullscreenWrapper_.parentElement;
2971	  this.fullscreenWrapper_.removeChild(element);
2972	  if (this.originalParent_ === parent) {
2973		parent.insertBefore(element, this.fullscreenWrapper_);
2974	  }
2975	  else if (this.originalParent_) {
2976		  this.originalParent_.appendChild(element);
2977		}
2978	  parent.removeChild(this.fullscreenWrapper_);
2979	  return element;
2980	};
2981	VRDisplay.prototype.requestPresent = function (layers) {
2982	  var wasPresenting = this.isPresenting;
2983	  var self = this;
2984	  if (!(layers instanceof Array)) {
2985		deprecateWarning('VRDisplay.prototype.requestPresent with non-array argument', 'an array of VRLayers as the first argument');
2986		layers = [layers];
2987	  }
2988	  return new Promise(function (resolve, reject) {
2989		if (!self.capabilities.canPresent) {
2990		  reject(new Error('VRDisplay is not capable of presenting.'));
2991		  return;
2992		}
2993		if (layers.length == 0 || layers.length > self.capabilities.maxLayers) {
2994		  reject(new Error('Invalid number of layers.'));
2995		  return;
2996		}
2997		var incomingLayer = layers[0];
2998		if (!incomingLayer.source) {
2999		  resolve();
3000		  return;
3001		}
3002		var leftBounds = incomingLayer.leftBounds || defaultLeftBounds;
3003		var rightBounds = incomingLayer.rightBounds || defaultRightBounds;
3004		if (wasPresenting) {
3005		  var layer = self.layer_;
3006		  if (layer.source !== incomingLayer.source) {
3007			layer.source = incomingLayer.source;
3008		  }
3009		  for (var i = 0; i < 4; i++) {
3010			layer.leftBounds[i] = leftBounds[i];
3011			layer.rightBounds[i] = rightBounds[i];
3012		  }
3013		  self.wrapForFullscreen(self.layer_.source);
3014		  self.updatePresent_();
3015		  resolve();
3016		  return;
3017		}
3018		self.layer_ = {
3019		  predistorted: incomingLayer.predistorted,
3020		  source: incomingLayer.source,
3021		  leftBounds: leftBounds.slice(0),
3022		  rightBounds: rightBounds.slice(0)
3023		};
3024		self.waitingForPresent_ = false;
3025		if (self.layer_ && self.layer_.source) {
3026		  var fullscreenElement = self.wrapForFullscreen(self.layer_.source);
3027		  var onFullscreenChange = function onFullscreenChange() {
3028			var actualFullscreenElement = getFullscreenElement();
3029			self.isPresenting = fullscreenElement === actualFullscreenElement;
3030			if (self.isPresenting) {
3031			  if (screen.orientation && screen.orientation.lock) {
3032				screen.orientation.lock('landscape-primary').catch(function (error) {
3033				  console.error('screen.orientation.lock() failed due to', error.message);
3034				});
3035			  }
3036			  self.waitingForPresent_ = false;
3037			  self.beginPresent_();
3038			  resolve();
3039			} else {
3040			  if (screen.orientation && screen.orientation.unlock) {
3041				screen.orientation.unlock();
3042			  }
3043			  self.removeFullscreenWrapper();
3044			  self.disableWakeLock();
3045			  self.endPresent_();
3046			  self.removeFullscreenListeners_();
3047			}
3048			self.fireVRDisplayPresentChange_();
3049		  };
3050		  var onFullscreenError = function onFullscreenError() {
3051			if (!self.waitingForPresent_) {
3052			  return;
3053			}
3054			self.removeFullscreenWrapper();
3055			self.removeFullscreenListeners_();
3056			self.disableWakeLock();
3057			self.waitingForPresent_ = false;
3058			self.isPresenting = false;
3059			reject(new Error('Unable to present.'));
3060		  };
3061		  self.addFullscreenListeners_(fullscreenElement, onFullscreenChange, onFullscreenError);
3062		  if (requestFullscreen(fullscreenElement)) {
3063			self.enableWakeLock();
3064			self.waitingForPresent_ = true;
3065		  } else if (isIOS() || isWebViewAndroid()) {
3066			self.enableWakeLock();
3067			self.isPresenting = true;
3068			self.beginPresent_();
3069			self.fireVRDisplayPresentChange_();
3070			resolve();
3071		  }
3072		}
3073		if (!self.waitingForPresent_ && !isIOS()) {
3074		  exitFullscreen();
3075		  reject(new Error('Unable to present.'));
3076		}
3077	  });
3078	};
3079	VRDisplay.prototype.exitPresent = function () {
3080	  var wasPresenting = this.isPresenting;
3081	  var self = this;
3082	  this.isPresenting = false;
3083	  this.layer_ = null;
3084	  this.disableWakeLock();
3085	  return new Promise(function (resolve, reject) {
3086		if (wasPresenting) {
3087		  if (!exitFullscreen() && isIOS()) {
3088			self.endPresent_();
3089			self.fireVRDisplayPresentChange_();
3090		  }
3091		  if (isWebViewAndroid()) {
3092			self.removeFullscreenWrapper();
3093			self.removeFullscreenListeners_();
3094			self.endPresent_();
3095			self.fireVRDisplayPresentChange_();
3096		  }
3097		  resolve();
3098		} else {
3099		  reject(new Error('Was not presenting to VRDisplay.'));
3100		}
3101	  });
3102	};
3103	VRDisplay.prototype.getLayers = function () {
3104	  if (this.layer_) {
3105		return [this.layer_];
3106	  }
3107	  return [];
3108	};
3109	VRDisplay.prototype.fireVRDisplayPresentChange_ = function () {
3110	  var event = new CustomEvent('vrdisplaypresentchange', { detail: { display: this } });
3111	  window.dispatchEvent(event);
3112	};
3113	VRDisplay.prototype.fireVRDisplayConnect_ = function () {
3114	  var event = new CustomEvent('vrdisplayconnect', { detail: { display: this } });
3115	  window.dispatchEvent(event);
3116	};
3117	VRDisplay.prototype.addFullscreenListeners_ = function (element, changeHandler, errorHandler) {
3118	  this.removeFullscreenListeners_();
3119	  this.fullscreenEventTarget_ = element;
3120	  this.fullscreenChangeHandler_ = changeHandler;
3121	  this.fullscreenErrorHandler_ = errorHandler;
3122	  if (changeHandler) {
3123		if (document.fullscreenEnabled) {
3124		  element.addEventListener('fullscreenchange', changeHandler, false);
3125		} else if (document.webkitFullscreenEnabled) {
3126		  element.addEventListener('webkitfullscreenchange', changeHandler, false);
3127		} else if (document.mozFullScreenEnabled) {
3128		  document.addEventListener('mozfullscreenchange', changeHandler, false);
3129		} else if (document.msFullscreenEnabled) {
3130		  element.addEventListener('msfullscreenchange', changeHandler, false);
3131		}
3132	  }
3133	  if (errorHandler) {
3134		if (document.fullscreenEnabled) {
3135		  element.addEventListener('fullscreenerror', errorHandler, false);
3136		} else if (document.webkitFullscreenEnabled) {
3137		  element.addEventListener('webkitfullscreenerror', errorHandler, false);
3138		} else if (document.mozFullScreenEnabled) {
3139		  document.addEventListener('mozfullscreenerror', errorHandler, false);
3140		} else if (document.msFullscreenEnabled) {
3141		  element.addEventListener('msfullscreenerror', errorHandler, false);
3142		}
3143	  }
3144	};
3145	VRDisplay.prototype.removeFullscreenListeners_ = function () {
3146	  if (!this.fullscreenEventTarget_) return;
3147	  var element = this.fullscreenEventTarget_;
3148	  if (this.fullscreenChangeHandler_) {
3149		var changeHandler = this.fullscreenChangeHandler_;
3150		element.removeEventListener('fullscreenchange', changeHandler, false);
3151		element.removeEventListener('webkitfullscreenchange', changeHandler, false);
3152		document.removeEventListener('mozfullscreenchange', changeHandler, false);
3153		element.removeEventListener('msfullscreenchange', changeHandler, false);
3154	  }
3155	  if (this.fullscreenErrorHandler_) {
3156		var errorHandler = this.fullscreenErrorHandler_;
3157		element.removeEventListener('fullscreenerror', errorHandler, false);
3158		element.removeEventListener('webkitfullscreenerror', errorHandler, false);
3159		document.removeEventListener('mozfullscreenerror', errorHandler, false);
3160		element.removeEventListener('msfullscreenerror', errorHandler, false);
3161	  }
3162	  this.fullscreenEventTarget_ = null;
3163	  this.fullscreenChangeHandler_ = null;
3164	  this.fullscreenErrorHandler_ = null;
3165	};
3166	VRDisplay.prototype.enableWakeLock = function () {
3167	  if (this.wakelock_) {
3168		this.wakelock_.enable();
3169	  }
3170	};
3171	VRDisplay.prototype.disableWakeLock = function () {
3172	  if (this.wakelock_) {
3173		this.wakelock_.disable();
3174	  }
3175	};
3176	VRDisplay.prototype.beginPresent_ = function () {
3177	};
3178	VRDisplay.prototype.endPresent_ = function () {
3179	};
3180	VRDisplay.prototype.submitFrame = function (pose) {
3181	};
3182	VRDisplay.prototype.getEyeParameters = function (whichEye) {
3183	  return null;
3184	};
3185	var config = {
3186	  ADDITIONAL_VIEWERS: [],
3187	  DEFAULT_VIEWER: '',
3188	  MOBILE_WAKE_LOCK: true,
3189	  DEBUG: false,
3190	  DPDB_URL: 'https://dpdb.webvr.rocks/dpdb.json',
3191	  K_FILTER: 0.98,
3192	  PREDICTION_TIME_S: 0.040,
3193	  CARDBOARD_UI_DISABLED: false,
3194	  ROTATE_INSTRUCTIONS_DISABLED: false,
3195	  YAW_ONLY: false,
3196	  BUFFER_SCALE: 0.5,
3197	  DIRTY_SUBMIT_FRAME_BINDINGS: false
3198	};
3199	var Eye = {
3200	  LEFT: 'left',
3201	  RIGHT: 'right'
3202	};
3203	function CardboardVRDisplay(config$$1) {
3204	  var defaults = extend({}, config);
3205	  config$$1 = extend(defaults, config$$1 || {});
3206	  VRDisplay.call(this, {
3207		wakelock: config$$1.MOBILE_WAKE_LOCK
3208	  });
3209	  this.config = config$$1;
3210	  this.displayName = 'Cardboard VRDisplay';
3211	  this.capabilities = new VRDisplayCapabilities({
3212		hasPosition: false,
3213		hasOrientation: true,
3214		hasExternalDisplay: false,
3215		canPresent: true,
3216		maxLayers: 1
3217	  });
3218	  this.stageParameters = null;
3219	  this.bufferScale_ = this.config.BUFFER_SCALE;
3220	  this.poseSensor_ = new PoseSensor(this.config);
3221	  this.distorter_ = null;
3222	  this.cardboardUI_ = null;
3223	  this.dpdb_ = new Dpdb(this.config.DPDB_URL, this.onDeviceParamsUpdated_.bind(this));
3224	  this.deviceInfo_ = new DeviceInfo(this.dpdb_.getDeviceParams(), config$$1.ADDITIONAL_VIEWERS);
3225	  this.viewerSelector_ = new ViewerSelector(config$$1.DEFAULT_VIEWER);
3226	  this.viewerSelector_.onChange(this.onViewerChanged_.bind(this));
3227	  this.deviceInfo_.setViewer(this.viewerSelector_.getCurrentViewer());
3228	  if (!this.config.ROTATE_INSTRUCTIONS_DISABLED) {
3229		this.rotateInstructions_ = new RotateInstructions();
3230	  }
3231	  if (isIOS()) {
3232		window.addEventListener('resize', this.onResize_.bind(this));
3233	  }
3234	}
3235	CardboardVRDisplay.prototype = Object.create(VRDisplay.prototype);
3236	CardboardVRDisplay.prototype._getPose = function () {
3237	  return {
3238		position: null,
3239		orientation: this.poseSensor_.getOrientation(),
3240		linearVelocity: null,
3241		linearAcceleration: null,
3242		angularVelocity: null,
3243		angularAcceleration: null
3244	  };
3245	};
3246	CardboardVRDisplay.prototype._resetPose = function () {
3247	  if (this.poseSensor_.resetPose) {
3248		this.poseSensor_.resetPose();
3249	  }
3250	};
3251	CardboardVRDisplay.prototype._getFieldOfView = function (whichEye) {
3252	  var fieldOfView;
3253	  if (whichEye == Eye.LEFT) {
3254		fieldOfView = this.deviceInfo_.getFieldOfViewLeftEye();
3255	  } else if (whichEye == Eye.RIGHT) {
3256		fieldOfView = this.deviceInfo_.getFieldOfViewRightEye();
3257	  } else {
3258		console.error('Invalid eye provided: %s', whichEye);
3259		return null;
3260	  }
3261	  return fieldOfView;
3262	};
3263	CardboardVRDisplay.prototype._getEyeOffset = function (whichEye) {
3264	  var offset;
3265	  if (whichEye == Eye.LEFT) {
3266		offset = [-this.deviceInfo_.viewer.interLensDistance * 0.5, 0.0, 0.0];
3267	  } else if (whichEye == Eye.RIGHT) {
3268		offset = [this.deviceInfo_.viewer.interLensDistance * 0.5, 0.0, 0.0];
3269	  } else {
3270		console.error('Invalid eye provided: %s', whichEye);
3271		return null;
3272	  }
3273	  return offset;
3274	};
3275	CardboardVRDisplay.prototype.getEyeParameters = function (whichEye) {
3276	  var offset = this._getEyeOffset(whichEye);
3277	  var fieldOfView = this._getFieldOfView(whichEye);
3278	  var eyeParams = {
3279		offset: offset,
3280		renderWidth: this.deviceInfo_.device.width * 0.5 * this.bufferScale_,
3281		renderHeight: this.deviceInfo_.device.height * this.bufferScale_
3282	  };
3283	  Object.defineProperty(eyeParams, 'fieldOfView', {
3284		enumerable: true,
3285		get: function get() {
3286		  deprecateWarning('VRFieldOfView', 'VRFrameData\'s projection matrices');
3287		  return fieldOfView;
3288		}
3289	  });
3290	  return eyeParams;
3291	};
3292	CardboardVRDisplay.prototype.onDeviceParamsUpdated_ = function (newParams) {
3293	  if (this.config.DEBUG) {
3294		console.log('DPDB reported that device params were updated.');
3295	  }
3296	  this.deviceInfo_.updateDeviceParams(newParams);
3297	  if (this.distorter_) {
3298		this.distorter_.updateDeviceInfo(this.deviceInfo_);
3299	  }
3300	};
3301	CardboardVRDisplay.prototype.updateBounds_ = function () {
3302	  if (this.layer_ && this.distorter_ && (this.layer_.leftBounds || this.layer_.rightBounds)) {
3303		this.distorter_.setTextureBounds(this.layer_.leftBounds, this.layer_.rightBounds);
3304	  }
3305	};
3306	CardboardVRDisplay.prototype.beginPresent_ = function () {
3307	  var gl = this.layer_.source.getContext('webgl');
3308	  if (!gl) gl = this.layer_.source.getContext('experimental-webgl');
3309	  if (!gl) gl = this.layer_.source.getContext('webgl2');
3310	  if (!gl) return;
3311	  if (this.layer_.predistorted) {
3312		if (!this.config.CARDBOARD_UI_DISABLED) {
3313		  gl.canvas.width = getScreenWidth() * this.bufferScale_;
3314		  gl.canvas.height = getScreenHeight() * this.bufferScale_;
3315		  this.cardboardUI_ = new CardboardUI(gl);
3316		}
3317	  } else {
3318		if (!this.config.CARDBOARD_UI_DISABLED) {
3319		  this.cardboardUI_ = new CardboardUI(gl);
3320		}
3321		this.distorter_ = new CardboardDistorter(gl, this.cardboardUI_, this.config.BUFFER_SCALE, this.config.DIRTY_SUBMIT_FRAME_BINDINGS);
3322		this.distorter_.updateDeviceInfo(this.deviceInfo_);
3323	  }
3324	  if (this.cardboardUI_) {
3325		this.cardboardUI_.listen(function (e) {
3326		  this.viewerSelector_.show(this.layer_.source.parentElement);
3327		  e.stopPropagation();
3328		  e.preventDefault();
3329		}.bind(this), function (e) {
3330		  this.exitPresent();
3331		  e.stopPropagation();
3332		  e.preventDefault();
3333		}.bind(this));
3334	  }
3335	  if (this.rotateInstructions_) {
3336		if (isLandscapeMode() && isMobile()) {
3337		  this.rotateInstructions_.showTemporarily(3000, this.layer_.source.parentElement);
3338		} else {
3339		  this.rotateInstructions_.update();
3340		}
3341	  }
3342	  this.orientationHandler = this.onOrientationChange_.bind(this);
3343	  window.addEventListener('orientationchange', this.orientationHandler);
3344	  this.vrdisplaypresentchangeHandler = this.updateBounds_.bind(this);
3345	  window.addEventListener('vrdisplaypresentchange', this.vrdisplaypresentchangeHandler);
3346	  this.fireVRDisplayDeviceParamsChange_();
3347	};
3348	CardboardVRDisplay.prototype.endPresent_ = function () {
3349	  if (this.distorter_) {
3350		this.distorter_.destroy();
3351		this.distorter_ = null;
3352	  }
3353	  if (this.cardboardUI_) {
3354		this.cardboardUI_.destroy();
3355		this.cardboardUI_ = null;
3356	  }
3357	  if (this.rotateInstructions_) {
3358		this.rotateInstructions_.hide();
3359	  }
3360	  this.viewerSelector_.hide();
3361	  window.removeEventListener('orientationchange', this.orientationHandler);
3362	  window.removeEventListener('vrdisplaypresentchange', this.vrdisplaypresentchangeHandler);
3363	};
3364	CardboardVRDisplay.prototype.updatePresent_ = function () {
3365	  this.endPresent_();
3366	  this.beginPresent_();
3367	};
3368	CardboardVRDisplay.prototype.submitFrame = function (pose) {
3369	  if (this.distorter_) {
3370		this.updateBounds_();
3371		this.distorter_.submitFrame();
3372	  } else if (this.cardboardUI_ && this.layer_) {
3373		var canvas = this.layer_.source.getContext('webgl').canvas;
3374		if (canvas.width != this.lastWidth || canvas.height != this.lastHeight) {
3375		  this.cardboardUI_.onResize();
3376		}
3377		this.lastWidth = canvas.width;
3378		this.lastHeight = canvas.height;
3379		this.cardboardUI_.render();
3380	  }
3381	};
3382	CardboardVRDisplay.prototype.onOrientationChange_ = function (e) {
3383	  this.viewerSelector_.hide();
3384	  if (this.rotateInstructions_) {
3385		this.rotateInstructions_.update();
3386	  }
3387	  this.onResize_();
3388	};
3389	CardboardVRDisplay.prototype.onResize_ = function (e) {
3390	  if (this.layer_) {
3391		var gl = this.layer_.source.getContext('webgl');
3392		var cssProperties = ['position: absolute', 'top: 0', 'left: 0',
3393		'width: 100vw', 'height: 100vh', 'border: 0', 'margin: 0',
3394		'padding: 0px', 'box-sizing: content-box'];
3395		gl.canvas.setAttribute('style', cssProperties.join('; ') + ';');
3396		safariCssSizeWorkaround(gl.canvas);
3397	  }
3398	};
3399	CardboardVRDisplay.prototype.onViewerChanged_ = function (viewer) {
3400	  this.deviceInfo_.setViewer(viewer);
3401	  if (this.distorter_) {
3402		this.distorter_.updateDeviceInfo(this.deviceInfo_);
3403	  }
3404	  this.fireVRDisplayDeviceParamsChange_();
3405	};
3406	CardboardVRDisplay.prototype.fireVRDisplayDeviceParamsChange_ = function () {
3407	  var event = new CustomEvent('vrdisplaydeviceparamschange', {
3408		detail: {
3409		  vrdisplay: this,
3410		  deviceInfo: this.deviceInfo_
3411		}
3412	  });
3413	  window.dispatchEvent(event);
3414	};
3415	CardboardVRDisplay.VRFrameData = VRFrameData;
3416	CardboardVRDisplay.VRDisplay = VRDisplay;
3417	return CardboardVRDisplay;
3418	})));
3419	});
3420	var CardboardVRDisplay = unwrapExports(cardboardVrDisplay);
3421  
3422	var version = "0.10.6";
3423  
3424	var DefaultConfig = {
3425	  ADDITIONAL_VIEWERS: [],
3426	  DEFAULT_VIEWER: '',
3427	  PROVIDE_MOBILE_VRDISPLAY: true,
3428	  GET_VR_DISPLAYS_TIMEOUT: 1000,
3429	  MOBILE_WAKE_LOCK: true,
3430	  DEBUG: false,
3431	  DPDB_URL: 'https://dpdb.webvr.rocks/dpdb.json',
3432	  K_FILTER: 0.98,
3433	  PREDICTION_TIME_S: 0.040,
3434	  TOUCH_PANNER_DISABLED: true,
3435	  CARDBOARD_UI_DISABLED: false,
3436	  ROTATE_INSTRUCTIONS_DISABLED: false,
3437	  YAW_ONLY: false,
3438	  BUFFER_SCALE: 0.5,
3439	  DIRTY_SUBMIT_FRAME_BINDINGS: false
3440	};
3441  
3442	function WebVRPolyfill(config) {
3443	  this.config = extend(extend({}, DefaultConfig), config);
3444	  this.polyfillDisplays = [];
3445	  this.enabled = false;
3446	  this.hasNative = 'getVRDisplays' in navigator;
3447	  this.native = {};
3448	  this.native.getVRDisplays = navigator.getVRDisplays;
3449	  this.native.VRFrameData = window.VRFrameData;
3450	  this.native.VRDisplay = window.VRDisplay;
3451	  if (!this.hasNative || this.config.PROVIDE_MOBILE_VRDISPLAY && isMobile()) {
3452		this.enable();
3453		this.getVRDisplays().then(function (displays) {
3454		  if (displays && displays[0] && displays[0].fireVRDisplayConnect_) {
3455			displays[0].fireVRDisplayConnect_();
3456		  }
3457		});
3458	  }
3459	}
3460	WebVRPolyfill.prototype.getPolyfillDisplays = function () {
3461	  if (this._polyfillDisplaysPopulated) {
3462		return this.polyfillDisplays;
3463	  }
3464	  if (isMobile()) {
3465		var vrDisplay = new CardboardVRDisplay({
3466		  ADDITIONAL_VIEWERS: this.config.ADDITIONAL_VIEWERS,
3467		  DEFAULT_VIEWER: this.config.DEFAULT_VIEWER,
3468		  MOBILE_WAKE_LOCK: this.config.MOBILE_WAKE_LOCK,
3469		  DEBUG: this.config.DEBUG,
3470		  DPDB_URL: this.config.DPDB_URL,
3471		  CARDBOARD_UI_DISABLED: this.config.CARDBOARD_UI_DISABLED,
3472		  K_FILTER: this.config.K_FILTER,
3473		  PREDICTION_TIME_S: this.config.PREDICTION_TIME_S,
3474		  TOUCH_PANNER_DISABLED: this.config.TOUCH_PANNER_DISABLED,
3475		  ROTATE_INSTRUCTIONS_DISABLED: this.config.ROTATE_INSTRUCTIONS_DISABLED,
3476		  YAW_ONLY: this.config.YAW_ONLY,
3477		  BUFFER_SCALE: this.config.BUFFER_SCALE,
3478		  DIRTY_SUBMIT_FRAME_BINDINGS: this.config.DIRTY_SUBMIT_FRAME_BINDINGS
3479		});
3480		this.polyfillDisplays.push(vrDisplay);
3481	  }
3482	  this._polyfillDisplaysPopulated = true;
3483	  return this.polyfillDisplays;
3484	};
3485	WebVRPolyfill.prototype.enable = function () {
3486	  this.enabled = true;
3487	  if (this.hasNative && this.native.VRFrameData) {
3488		var NativeVRFrameData = this.native.VRFrameData;
3489		var nativeFrameData = new this.native.VRFrameData();
3490		var nativeGetFrameData = this.native.VRDisplay.prototype.getFrameData;
3491		window.VRDisplay.prototype.getFrameData = function (frameData) {
3492		  if (frameData instanceof NativeVRFrameData) {
3493			nativeGetFrameData.call(this, frameData);
3494			return;
3495		  }
3496		  nativeGetFrameData.call(this, nativeFrameData);
3497		  frameData.pose = nativeFrameData.pose;
3498		  copyArray(nativeFrameData.leftProjectionMatrix, frameData.leftProjectionMatrix);
3499		  copyArray(nativeFrameData.rightProjectionMatrix, frameData.rightProjectionMatrix);
3500		  copyArray(nativeFrameData.leftViewMatrix, frameData.leftViewMatrix);
3501		  copyArray(nativeFrameData.rightViewMatrix, frameData.rightViewMatrix);
3502		};
3503	  }
3504	  navigator.getVRDisplays = this.getVRDisplays.bind(this);
3505	  window.VRDisplay = CardboardVRDisplay.VRDisplay;
3506	  window.VRFrameData = CardboardVRDisplay.VRFrameData;
3507	};
3508	WebVRPolyfill.prototype.getVRDisplays = function () {
3509	  var _this = this;
3510	  var config = this.config;
3511	  if (!this.hasNative) {
3512		return Promise.resolve(this.getPolyfillDisplays());
3513	  }
3514	  var timeoutId;
3515	  var vrDisplaysNative = this.native.getVRDisplays.call(navigator);
3516	  var timeoutPromise = new Promise(function (resolve) {
3517		timeoutId = setTimeout(function () {
3518		  console.warn('Native WebVR implementation detected, but `getVRDisplays()` failed to resolve. Falling back to polyfill.');
3519		  resolve([]);
3520		}, config.GET_VR_DISPLAYS_TIMEOUT);
3521	  });
3522	  return race([vrDisplaysNative, timeoutPromise]).then(function (nativeDisplays) {
3523		clearTimeout(timeoutId);
3524		return nativeDisplays.length > 0 ? nativeDisplays : _this.getPolyfillDisplays();
3525	  });
3526	};
3527	WebVRPolyfill.version = version;
3528	WebVRPolyfill.VRFrameData = CardboardVRDisplay.VRFrameData;
3529	WebVRPolyfill.VRDisplay = CardboardVRDisplay.VRDisplay;
3530  
3531  
3532	var webvrPolyfill = Object.freeze({
3533		default: WebVRPolyfill
3534	});
3535  
3536	var require$$0 = ( webvrPolyfill && WebVRPolyfill ) || webvrPolyfill;
3537  
3538	if (typeof commonjsGlobal$1 !== 'undefined' && commonjsGlobal$1.window) {
3539	  if (!commonjsGlobal$1.document) {
3540		commonjsGlobal$1.document = commonjsGlobal$1.window.document;
3541	  }
3542	  if (!commonjsGlobal$1.navigator) {
3543		commonjsGlobal$1.navigator = commonjsGlobal$1.window.navigator;
3544	  }
3545	}
3546	var src = require$$0;
3547  
3548	return src;
3549  
3550	})));
3551	});
3552  
3553	var WebVRPolyfill = unwrapExports(webvrPolyfill);
3554  
3555	// Polyfills
3556  
3557	if ( Number.EPSILON === undefined ) {
3558  
3559		Number.EPSILON = Math.pow( 2, - 52 );
3560  
3561	}
3562  
3563	if ( Number.isInteger === undefined ) {
3564  
3565		// Missing in IE
3566		// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isInteger
3567  
3568		Number.isInteger = function ( value ) {
3569  
3570			return typeof value === 'number' && isFinite( value ) && Math.floor( value ) === value;
3571  
3572		};
3573  
3574	}
3575  
3576	//
3577  
3578	if ( Math.sign === undefined ) {
3579  
3580		// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/sign
3581  
3582		Math.sign = function ( x ) {
3583  
3584			return ( x < 0 ) ? - 1 : ( x > 0 ) ? 1 : + x;
3585  
3586		};
3587  
3588	}
3589  
3590	if ( 'name' in Function.prototype === false ) {
3591  
3592		// Missing in IE
3593		// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/name
3594  
3595		Object.defineProperty( Function.prototype, 'name', {
3596  
3597			get: function () {
3598  
3599				return this.toString().match( /^\s*function\s*([^\(\s]*)/ )[ 1 ];
3600  
3601			}
3602  
3603		} );
3604  
3605	}
3606  
3607	if ( Object.assign === undefined ) {
3608  
3609		// Missing in IE
3610		// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign
3611  
3612		( function () {
3613  
3614			Object.assign = function ( target ) {
3615  
3616				if ( target === undefined || target === null ) {
3617  
3618					throw new TypeError( 'Cannot convert undefined or null to object' );
3619  
3620				}
3621  
3622				var output = Object( target );
3623  
3624				for ( var index = 1; index < arguments.length; index ++ ) {
3625  
3626					var source = arguments[ index ];
3627  
3628					if ( source !== undefined && source !== null ) {
3629  
3630						for ( var nextKey in source ) {
3631  
3632							if ( Object.prototype.hasOwnProperty.call( source, nextKey ) ) {
3633  
3634								output[ nextKey ] = source[ nextKey ];
3635  
3636							}
3637  
3638						}
3639  
3640					}
3641  
3642				}
3643  
3644				return output;
3645  
3646			};
3647  
3648		} )();
3649  
3650	}
3651  
3652	/**
3653	 * https://github.com/mrdoob/eventdispatcher.js/
3654	 */
3655  
3656	function EventDispatcher() {}
3657  
3658	Object.assign( EventDispatcher.prototype, {
3659  
vendor: 103,161 bytes, lines 3660-8707
3660		addEventListener: function ( type, listener ) {
3661  
3662			if ( this._listeners === undefined ) this._listeners = {};
3663  
3664			var listeners = this._listeners;
3665  
3666			if ( listeners[ type ] === undefined ) {
3667  
3668				listeners[ type ] = [];
3669  
3670			}
3671  
3672			if ( listeners[ type ].indexOf( listener ) === - 1 ) {
3673  
3674				listeners[ type ].push( listener );
3675  
3676			}
3677  
3678		},
3679  
3680		hasEventListener: function ( type, listener ) {
3681  
3682			if ( this._listeners === undefined ) return false;
3683  
3684			var listeners = this._listeners;
3685  
3686			return listeners[ type ] !== undefined && listeners[ type ].indexOf( listener ) !== - 1;
3687  
3688		},
3689  
3690		removeEventListener: function ( type, listener ) {
3691  
3692			if ( this._listeners === undefined ) return;
3693  
3694			var listeners = this._listeners;
3695			var listenerArray = listeners[ type ];
3696  
3697			if ( listenerArray !== undefined ) {
3698  
3699				var index = listenerArray.indexOf( listener );
3700  
3701				if ( index !== - 1 ) {
3702  
3703					listenerArray.splice( index, 1 );
3704  
3705				}
3706  
3707			}
3708  
3709		},
3710  
3711		dispatchEvent: function ( event ) {
3712  
3713			if ( this._listeners === undefined ) return;
3714  
3715			var listeners = this._listeners;
3716			var listenerArray = listeners[ event.type ];
3717  
3718			if ( listenerArray !== undefined ) {
3719  
3720				event.target = this;
3721  
3722				var array = listenerArray.slice( 0 );
3723  
3724				for ( var i = 0, l = array.length; i < l; i ++ ) {
3725  
3726					array[ i ].call( this, event );
3727  
3728				}
3729  
3730			}
3731  
3732		}
3733  
3734	} );
3735  
3736	var REVISION = '93';
3737	var MOUSE = { LEFT: 0, MIDDLE: 1, RIGHT: 2 };
3738	var CullFaceNone = 0;
3739	var CullFaceBack = 1;
3740	var CullFaceFront = 2;
3741	var PCFShadowMap = 1;
3742	var PCFSoftShadowMap = 2;
3743	var FrontSide = 0;
3744	var BackSide = 1;
3745	var DoubleSide = 2;
3746	var FlatShading = 1;
3747	var NoColors = 0;
3748	var FaceColors = 1;
3749	var VertexColors = 2;
3750	var NoBlending = 0;
3751	var NormalBlending = 1;
3752	var AdditiveBlending = 2;
3753	var SubtractiveBlending = 3;
3754	var MultiplyBlending = 4;
3755	var CustomBlending = 5;
3756	var AddEquation = 100;
3757	var SubtractEquation = 101;
3758	var ReverseSubtractEquation = 102;
3759	var MinEquation = 103;
3760	var MaxEquation = 104;
3761	var ZeroFactor = 200;
3762	var OneFactor = 201;
3763	var SrcColorFactor = 202;
3764	var OneMinusSrcColorFactor = 203;
3765	var SrcAlphaFactor = 204;
3766	var OneMinusSrcAlphaFactor = 205;
3767	var DstAlphaFactor = 206;
3768	var OneMinusDstAlphaFactor = 207;
3769	var DstColorFactor = 208;
3770	var OneMinusDstColorFactor = 209;
3771	var SrcAlphaSaturateFactor = 210;
3772	var NeverDepth = 0;
3773	var AlwaysDepth = 1;
3774	var LessDepth = 2;
3775	var LessEqualDepth = 3;
3776	var EqualDepth = 4;
3777	var GreaterEqualDepth = 5;
3778	var GreaterDepth = 6;
3779	var NotEqualDepth = 7;
3780	var MultiplyOperation = 0;
3781	var MixOperation = 1;
3782	var AddOperation = 2;
3783	var NoToneMapping = 0;
3784	var LinearToneMapping = 1;
3785	var ReinhardToneMapping = 2;
3786	var Uncharted2ToneMapping = 3;
3787	var CineonToneMapping = 4;
3788	var UVMapping = 300;
3789	var CubeReflectionMapping = 301;
3790	var CubeRefractionMapping = 302;
3791	var EquirectangularReflectionMapping = 303;
3792	var EquirectangularRefractionMapping = 304;
3793	var SphericalReflectionMapping = 305;
3794	var CubeUVReflectionMapping = 306;
3795	var CubeUVRefractionMapping = 307;
3796	var RepeatWrapping = 1000;
3797	var ClampToEdgeWrapping = 1001;
3798	var MirroredRepeatWrapping = 1002;
3799	var NearestFilter = 1003;
3800	var NearestMipMapNearestFilter = 1004;
3801	var NearestMipMapLinearFilter = 1005;
3802	var LinearFilter = 1006;
3803	var LinearMipMapNearestFilter = 1007;
3804	var LinearMipMapLinearFilter = 1008;
3805	var UnsignedByteType = 1009;
3806	var ByteType = 1010;
3807	var ShortType = 1011;
3808	var UnsignedShortType = 1012;
3809	var IntType = 1013;
3810	var UnsignedIntType = 1014;
3811	var FloatType = 1015;
3812	var HalfFloatType = 1016;
3813	var UnsignedShort4444Type = 1017;
3814	var UnsignedShort5551Type = 1018;
3815	var UnsignedShort565Type = 1019;
3816	var UnsignedInt248Type = 1020;
3817	var AlphaFormat = 1021;
3818	var RGBFormat = 1022;
3819	var RGBAFormat = 1023;
3820	var LuminanceFormat = 1024;
3821	var LuminanceAlphaFormat = 1025;
3822	var DepthFormat = 1026;
3823	var DepthStencilFormat = 1027;
3824	var RGB_S3TC_DXT1_Format = 33776;
3825	var RGBA_S3TC_DXT1_Format = 33777;
3826	var RGBA_S3TC_DXT3_Format = 33778;
3827	var RGBA_S3TC_DXT5_Format = 33779;
3828	var RGB_PVRTC_4BPPV1_Format = 35840;
3829	var RGB_PVRTC_2BPPV1_Format = 35841;
3830	var RGBA_PVRTC_4BPPV1_Format = 35842;
3831	var RGBA_PVRTC_2BPPV1_Format = 35843;
3832	var RGB_ETC1_Format = 36196;
3833	var RGBA_ASTC_4x4_Format = 37808;
3834	var RGBA_ASTC_5x4_Format = 37809;
3835	var RGBA_ASTC_5x5_Format = 37810;
3836	var RGBA_ASTC_6x5_Format = 37811;
3837	var RGBA_ASTC_6x6_Format = 37812;
3838	var RGBA_ASTC_8x5_Format = 37813;
3839	var RGBA_ASTC_8x6_Format = 37814;
3840	var RGBA_ASTC_8x8_Format = 37815;
3841	var RGBA_ASTC_10x5_Format = 37816;
3842	var RGBA_ASTC_10x6_Format = 37817;
3843	var RGBA_ASTC_10x8_Format = 37818;
3844	var RGBA_ASTC_10x10_Format = 37819;
3845	var RGBA_ASTC_12x10_Format = 37820;
3846	var RGBA_ASTC_12x12_Format = 37821;
3847	var LoopOnce = 2200;
3848	var LoopRepeat = 2201;
3849	var LoopPingPong = 2202;
3850	var InterpolateDiscrete = 2300;
3851	var InterpolateLinear = 2301;
3852	var InterpolateSmooth = 2302;
3853	var ZeroCurvatureEnding = 2400;
3854	var ZeroSlopeEnding = 2401;
3855	var WrapAroundEnding = 2402;
3856	var TrianglesDrawMode = 0;
3857	var TriangleStripDrawMode = 1;
3858	var TriangleFanDrawMode = 2;
3859	var LinearEncoding = 3000;
3860	var sRGBEncoding = 3001;
3861	var GammaEncoding = 3007;
3862	var RGBEEncoding = 3002;
3863	var RGBM7Encoding = 3004;
3864	var RGBM16Encoding = 3005;
3865	var RGBDEncoding = 3006;
3866	var BasicDepthPacking = 3200;
3867	var RGBADepthPacking = 3201;
3868  
3869	/**
3870	 * @author alteredq / http://alteredqualia.com/
3871	 * @author mrdoob / http://mrdoob.com/
3872	 */
3873  
3874	var _Math = {
3875  
3876		DEG2RAD: Math.PI / 180,
3877		RAD2DEG: 180 / Math.PI,
3878  
3879		generateUUID: ( function () {
3880  
3881			// http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript/21963136#21963136
3882  
3883			var lut = [];
3884  
3885			for ( var i = 0; i < 256; i ++ ) {
3886  
3887				lut[ i ] = ( i < 16 ? '0' : '' ) + ( i ).toString( 16 );
3888  
3889			}
3890  
3891			return function generateUUID() {
3892  
3893				var d0 = Math.random() * 0xffffffff | 0;
3894				var d1 = Math.random() * 0xffffffff | 0;
3895				var d2 = Math.random() * 0xffffffff | 0;
3896				var d3 = Math.random() * 0xffffffff | 0;
3897				var uuid = lut[ d0 & 0xff ] + lut[ d0 >> 8 & 0xff ] + lut[ d0 >> 16 & 0xff ] + lut[ d0 >> 24 & 0xff ] + '-' +
3898					lut[ d1 & 0xff ] + lut[ d1 >> 8 & 0xff ] + '-' + lut[ d1 >> 16 & 0x0f | 0x40 ] + lut[ d1 >> 24 & 0xff ] + '-' +
3899					lut[ d2 & 0x3f | 0x80 ] + lut[ d2 >> 8 & 0xff ] + '-' + lut[ d2 >> 16 & 0xff ] + lut[ d2 >> 24 & 0xff ] +
3900					lut[ d3 & 0xff ] + lut[ d3 >> 8 & 0xff ] + lut[ d3 >> 16 & 0xff ] + lut[ d3 >> 24 & 0xff ];
3901  
3902				// .toUpperCase() here flattens concatenated strings to save heap memory space.
3903				return uuid.toUpperCase();
3904  
3905			};
3906  
3907		} )(),
3908  
3909		clamp: function ( value, min, max ) {
3910  
3911			return Math.max( min, Math.min( max, value ) );
3912  
3913		},
3914  
3915		// compute euclidian modulo of m % n
3916		// https://en.wikipedia.org/wiki/Modulo_operation
3917  
3918		euclideanModulo: function ( n, m ) {
3919  
3920			return ( ( n % m ) + m ) % m;
3921  
3922		},
3923  
3924		// Linear mapping from range <a1, a2> to range <b1, b2>
3925  
3926		mapLinear: function ( x, a1, a2, b1, b2 ) {
3927  
3928			return b1 + ( x - a1 ) * ( b2 - b1 ) / ( a2 - a1 );
3929  
3930		},
3931  
3932		// https://en.wikipedia.org/wiki/Linear_interpolation
3933  
3934		lerp: function ( x, y, t ) {
3935  
3936			return ( 1 - t ) * x + t * y;
3937  
3938		},
3939  
3940		// http://en.wikipedia.org/wiki/Smoothstep
3941  
3942		smoothstep: function ( x, min, max ) {
3943  
3944			if ( x <= min ) return 0;
3945			if ( x >= max ) return 1;
3946  
3947			x = ( x - min ) / ( max - min );
3948  
3949			return x * x * ( 3 - 2 * x );
3950  
3951		},
3952  
3953		smootherstep: function ( x, min, max ) {
3954  
3955			if ( x <= min ) return 0;
3956			if ( x >= max ) return 1;
3957  
3958			x = ( x - min ) / ( max - min );
3959  
3960			return x * x * x * ( x * ( x * 6 - 15 ) + 10 );
3961  
3962		},
3963  
3964		// Random integer from <low, high> interval
3965  
3966		randInt: function ( low, high ) {
3967  
3968			return low + Math.floor( Math.random() * ( high - low + 1 ) );
3969  
3970		},
3971  
3972		// Random float from <low, high> interval
3973  
3974		randFloat: function ( low, high ) {
3975  
3976			return low + Math.random() * ( high - low );
3977  
3978		},
3979  
3980		// Random float from <-range/2, range/2> interval
3981  
3982		randFloatSpread: function ( range ) {
3983  
3984			return range * ( 0.5 - Math.random() );
3985  
3986		},
3987  
3988		degToRad: function ( degrees ) {
3989  
3990			return degrees * _Math.DEG2RAD;
3991  
3992		},
3993  
3994		radToDeg: function ( radians ) {
3995  
3996			return radians * _Math.RAD2DEG;
3997  
3998		},
3999  
4000		isPowerOfTwo: function ( value ) {
4001  
4002			return ( value & ( value - 1 ) ) === 0 && value !== 0;
4003  
4004		},
4005  
4006		ceilPowerOfTwo: function ( value ) {
4007  
4008			return Math.pow( 2, Math.ceil( Math.log( value ) / Math.LN2 ) );
4009  
4010		},
4011  
4012		floorPowerOfTwo: function ( value ) {
4013  
4014			return Math.pow( 2, Math.floor( Math.log( value ) / Math.LN2 ) );
4015  
4016		}
4017  
4018	};
4019  
4020	/**
4021	 * @author mrdoob / http://mrdoob.com/
4022	 * @author philogb / http://blog.thejit.org/
4023	 * @author egraether / http://egraether.com/
4024	 * @author zz85 / http://www.lab4games.net/zz85/blog
4025	 */
4026  
4027	function Vector2( x, y ) {
4028  
4029		this.x = x || 0;
4030		this.y = y || 0;
4031  
4032	}
4033  
4034	Object.defineProperties( Vector2.prototype, {
4035  
4036		"width": {
4037  
4038			get: function () {
4039  
4040				return this.x;
4041  
4042			},
4043  
4044			set: function ( value ) {
4045  
4046				this.x = value;
4047  
4048			}
4049  
4050		},
4051  
4052		"height": {
4053  
4054			get: function () {
4055  
4056				return this.y;
4057  
4058			},
4059  
4060			set: function ( value ) {
4061  
4062				this.y = value;
4063  
4064			}
4065  
4066		}
4067  
4068	} );
4069  
4070	Object.assign( Vector2.prototype, {
4071  
4072		isVector2: true,
4073  
4074		set: function ( x, y ) {
4075  
4076			this.x = x;
4077			this.y = y;
4078  
4079			return this;
4080  
4081		},
4082  
4083		setScalar: function ( scalar ) {
4084  
4085			this.x = scalar;
4086			this.y = scalar;
4087  
4088			return this;
4089  
4090		},
4091  
4092		setX: function ( x ) {
4093  
4094			this.x = x;
4095  
4096			return this;
4097  
4098		},
4099  
4100		setY: function ( y ) {
4101  
4102			this.y = y;
4103  
4104			return this;
4105  
4106		},
4107  
4108		setComponent: function ( index, value ) {
4109  
4110			switch ( index ) {
4111  
4112				case 0: this.x = value; break;
4113				case 1: this.y = value; break;
4114				default: throw new Error( 'index is out of range: ' + index );
4115  
4116			}
4117  
4118			return this;
4119  
4120		},
4121  
4122		getComponent: function ( index ) {
4123  
4124			switch ( index ) {
4125  
4126				case 0: return this.x;
4127				case 1: return this.y;
4128				default: throw new Error( 'index is out of range: ' + index );
4129  
4130			}
4131  
4132		},
4133  
4134		clone: function () {
4135  
4136			return new this.constructor( this.x, this.y );
4137  
4138		},
4139  
4140		copy: function ( v ) {
4141  
4142			this.x = v.x;
4143			this.y = v.y;
4144  
4145			return this;
4146  
4147		},
4148  
4149		add: function ( v, w ) {
4150  
4151			if ( w !== undefined ) {
4152  
4153				console.warn( 'THREE.Vector2: .add() now only accepts one argument. Use .addVectors( a, b ) instead.' );
4154				return this.addVectors( v, w );
4155  
4156			}
4157  
4158			this.x += v.x;
4159			this.y += v.y;
4160  
4161			return this;
4162  
4163		},
4164  
4165		addScalar: function ( s ) {
4166  
4167			this.x += s;
4168			this.y += s;
4169  
4170			return this;
4171  
4172		},
4173  
4174		addVectors: function ( a, b ) {
4175  
4176			this.x = a.x + b.x;
4177			this.y = a.y + b.y;
4178  
4179			return this;
4180  
4181		},
4182  
4183		addScaledVector: function ( v, s ) {
4184  
4185			this.x += v.x * s;
4186			this.y += v.y * s;
4187  
4188			return this;
4189  
4190		},
4191  
4192		sub: function ( v, w ) {
4193  
4194			if ( w !== undefined ) {
4195  
4196				console.warn( 'THREE.Vector2: .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' );
4197				return this.subVectors( v, w );
4198  
4199			}
4200  
4201			this.x -= v.x;
4202			this.y -= v.y;
4203  
4204			return this;
4205  
4206		},
4207  
4208		subScalar: function ( s ) {
4209  
4210			this.x -= s;
4211			this.y -= s;
4212  
4213			return this;
4214  
4215		},
4216  
4217		subVectors: function ( a, b ) {
4218  
4219			this.x = a.x - b.x;
4220			this.y = a.y - b.y;
4221  
4222			return this;
4223  
4224		},
4225  
4226		multiply: function ( v ) {
4227  
4228			this.x *= v.x;
4229			this.y *= v.y;
4230  
4231			return this;
4232  
4233		},
4234  
4235		multiplyScalar: function ( scalar ) {
4236  
4237			this.x *= scalar;
4238			this.y *= scalar;
4239  
4240			return this;
4241  
4242		},
4243  
4244		divide: function ( v ) {
4245  
4246			this.x /= v.x;
4247			this.y /= v.y;
4248  
4249			return this;
4250  
4251		},
4252  
4253		divideScalar: function ( scalar ) {
4254  
4255			return this.multiplyScalar( 1 / scalar );
4256  
4257		},
4258  
4259		applyMatrix3: function ( m ) {
4260  
4261			var x = this.x, y = this.y;
4262			var e = m.elements;
4263  
4264			this.x = e[ 0 ] * x + e[ 3 ] * y + e[ 6 ];
4265			this.y = e[ 1 ] * x + e[ 4 ] * y + e[ 7 ];
4266  
4267			return this;
4268  
4269		},
4270  
4271		min: function ( v ) {
4272  
4273			this.x = Math.min( this.x, v.x );
4274			this.y = Math.min( this.y, v.y );
4275  
4276			return this;
4277  
4278		},
4279  
4280		max: function ( v ) {
4281  
4282			this.x = Math.max( this.x, v.x );
4283			this.y = Math.max( this.y, v.y );
4284  
4285			return this;
4286  
4287		},
4288  
4289		clamp: function ( min, max ) {
4290  
4291			// assumes min < max, componentwise
4292  
4293			this.x = Math.max( min.x, Math.min( max.x, this.x ) );
4294			this.y = Math.max( min.y, Math.min( max.y, this.y ) );
4295  
4296			return this;
4297  
4298		},
4299  
4300		clampScalar: function () {
4301  
4302			var min = new Vector2();
4303			var max = new Vector2();
4304  
4305			return function clampScalar( minVal, maxVal ) {
4306  
4307				min.set( minVal, minVal );
4308				max.set( maxVal, maxVal );
4309  
4310				return this.clamp( min, max );
4311  
4312			};
4313  
4314		}(),
4315  
4316		clampLength: function ( min, max ) {
4317  
4318			var length = this.length();
4319  
4320			return this.divideScalar( length || 1 ).multiplyScalar( Math.max( min, Math.min( max, length ) ) );
4321  
4322		},
4323  
4324		floor: function () {
4325  
4326			this.x = Math.floor( this.x );
4327			this.y = Math.floor( this.y );
4328  
4329			return this;
4330  
4331		},
4332  
4333		ceil: function () {
4334  
4335			this.x = Math.ceil( this.x );
4336			this.y = Math.ceil( this.y );
4337  
4338			return this;
4339  
4340		},
4341  
4342		round: function () {
4343  
4344			this.x = Math.round( this.x );
4345			this.y = Math.round( this.y );
4346  
4347			return this;
4348  
4349		},
4350  
4351		roundToZero: function () {
4352  
4353			this.x = ( this.x < 0 ) ? Math.ceil( this.x ) : Math.floor( this.x );
4354			this.y = ( this.y < 0 ) ? Math.ceil( this.y ) : Math.floor( this.y );
4355  
4356			return this;
4357  
4358		},
4359  
4360		negate: function () {
4361  
4362			this.x = - this.x;
4363			this.y = - this.y;
4364  
4365			return this;
4366  
4367		},
4368  
4369		dot: function ( v ) {
4370  
4371			return this.x * v.x + this.y * v.y;
4372  
4373		},
4374  
4375		lengthSq: function () {
4376  
4377			return this.x * this.x + this.y * this.y;
4378  
4379		},
4380  
4381		length: function () {
4382  
4383			return Math.sqrt( this.x * this.x + this.y * this.y );
4384  
4385		},
4386  
4387		manhattanLength: function () {
4388  
4389			return Math.abs( this.x ) + Math.abs( this.y );
4390  
4391		},
4392  
4393		normalize: function () {
4394  
4395			return this.divideScalar( this.length() || 1 );
4396  
4397		},
4398  
4399		angle: function () {
4400  
4401			// computes the angle in radians with respect to the positive x-axis
4402  
4403			var angle = Math.atan2( this.y, this.x );
4404  
4405			if ( angle < 0 ) angle += 2 * Math.PI;
4406  
4407			return angle;
4408  
4409		},
4410  
4411		distanceTo: function ( v ) {
4412  
4413			return Math.sqrt( this.distanceToSquared( v ) );
4414  
4415		},
4416  
4417		distanceToSquared: function ( v ) {
4418  
4419			var dx = this.x - v.x, dy = this.y - v.y;
4420			return dx * dx + dy * dy;
4421  
4422		},
4423  
4424		manhattanDistanceTo: function ( v ) {
4425  
4426			return Math.abs( this.x - v.x ) + Math.abs( this.y - v.y );
4427  
4428		},
4429  
4430		setLength: function ( length ) {
4431  
4432			return this.normalize().multiplyScalar( length );
4433  
4434		},
4435  
4436		lerp: function ( v, alpha ) {
4437  
4438			this.x += ( v.x - this.x ) * alpha;
4439			this.y += ( v.y - this.y ) * alpha;
4440  
4441			return this;
4442  
4443		},
4444  
4445		lerpVectors: function ( v1, v2, alpha ) {
4446  
4447			return this.subVectors( v2, v1 ).multiplyScalar( alpha ).add( v1 );
4448  
4449		},
4450  
4451		equals: function ( v ) {
4452  
4453			return ( ( v.x === this.x ) && ( v.y === this.y ) );
4454  
4455		},
4456  
4457		fromArray: function ( array, offset ) {
4458  
4459			if ( offset === undefined ) offset = 0;
4460  
4461			this.x = array[ offset ];
4462			this.y = array[ offset + 1 ];
4463  
4464			return this;
4465  
4466		},
4467  
4468		toArray: function ( array, offset ) {
4469  
4470			if ( array === undefined ) array = [];
4471			if ( offset === undefined ) offset = 0;
4472  
4473			array[ offset ] = this.x;
4474			array[ offset + 1 ] = this.y;
4475  
4476			return array;
4477  
4478		},
4479  
4480		fromBufferAttribute: function ( attribute, index, offset ) {
4481  
4482			if ( offset !== undefined ) {
4483  
4484				console.warn( 'THREE.Vector2: offset has been removed from .fromBufferAttribute().' );
4485  
4486			}
4487  
4488			this.x = attribute.getX( index );
4489			this.y = attribute.getY( index );
4490  
4491			return this;
4492  
4493		},
4494  
4495		rotateAround: function ( center, angle ) {
4496  
4497			var c = Math.cos( angle ), s = Math.sin( angle );
4498  
4499			var x = this.x - center.x;
4500			var y = this.y - center.y;
4501  
4502			this.x = x * c - y * s + center.x;
4503			this.y = x * s + y * c + center.y;
4504  
4505			return this;
4506  
4507		}
4508  
4509	} );
4510  
4511	/**
4512	 * @author mrdoob / http://mrdoob.com/
4513	 * @author supereggbert / http://www.paulbrunt.co.uk/
4514	 * @author philogb / http://blog.thejit.org/
4515	 * @author jordi_ros / http://plattsoft.com
4516	 * @author D1plo1d / http://github.com/D1plo1d
4517	 * @author alteredq / http://alteredqualia.com/
4518	 * @author mikael emtinger / http://gomo.se/
4519	 * @author timknip / http://www.floorplanner.com/
4520	 * @author bhouston / http://clara.io
4521	 * @author WestLangley / http://github.com/WestLangley
4522	 */
4523  
4524	function Matrix4() {
4525  
4526		this.elements = [
4527  
4528			1, 0, 0, 0,
4529			0, 1, 0, 0,
4530			0, 0, 1, 0,
4531			0, 0, 0, 1
4532  
4533		];
4534  
4535		if ( arguments.length > 0 ) {
4536  
4537			console.error( 'THREE.Matrix4: the constructor no longer reads arguments. use .set() instead.' );
4538  
4539		}
4540  
4541	}
4542  
4543	Object.assign( Matrix4.prototype, {
4544  
4545		isMatrix4: true,
4546  
4547		set: function ( n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44 ) {
4548  
4549			var te = this.elements;
4550  
4551			te[ 0 ] = n11; te[ 4 ] = n12; te[ 8 ] = n13; te[ 12 ] = n14;
4552			te[ 1 ] = n21; te[ 5 ] = n22; te[ 9 ] = n23; te[ 13 ] = n24;
4553			te[ 2 ] = n31; te[ 6 ] = n32; te[ 10 ] = n33; te[ 14 ] = n34;
4554			te[ 3 ] = n41; te[ 7 ] = n42; te[ 11 ] = n43; te[ 15 ] = n44;
4555  
4556			return this;
4557  
4558		},
4559  
4560		identity: function () {
4561  
4562			this.set(
4563  
4564				1, 0, 0, 0,
4565				0, 1, 0, 0,
4566				0, 0, 1, 0,
4567				0, 0, 0, 1
4568  
4569			);
4570  
4571			return this;
4572  
4573		},
4574  
4575		clone: function () {
4576  
4577			return new Matrix4().fromArray( this.elements );
4578  
4579		},
4580  
4581		copy: function ( m ) {
4582  
4583			var te = this.elements;
4584			var me = m.elements;
4585  
4586			te[ 0 ] = me[ 0 ]; te[ 1 ] = me[ 1 ]; te[ 2 ] = me[ 2 ]; te[ 3 ] = me[ 3 ];
4587			te[ 4 ] = me[ 4 ]; te[ 5 ] = me[ 5 ]; te[ 6 ] = me[ 6 ]; te[ 7 ] = me[ 7 ];
4588			te[ 8 ] = me[ 8 ]; te[ 9 ] = me[ 9 ]; te[ 10 ] = me[ 10 ]; te[ 11 ] = me[ 11 ];
4589			te[ 12 ] = me[ 12 ]; te[ 13 ] = me[ 13 ]; te[ 14 ] = me[ 14 ]; te[ 15 ] = me[ 15 ];
4590  
4591			return this;
4592  
4593		},
4594  
4595		copyPosition: function ( m ) {
4596  
4597			var te = this.elements, me = m.elements;
4598  
4599			te[ 12 ] = me[ 12 ];
4600			te[ 13 ] = me[ 13 ];
4601			te[ 14 ] = me[ 14 ];
4602  
4603			return this;
4604  
4605		},
4606  
4607		extractBasis: function ( xAxis, yAxis, zAxis ) {
4608  
4609			xAxis.setFromMatrixColumn( this, 0 );
4610			yAxis.setFromMatrixColumn( this, 1 );
4611			zAxis.setFromMatrixColumn( this, 2 );
4612  
4613			return this;
4614  
4615		},
4616  
4617		makeBasis: function ( xAxis, yAxis, zAxis ) {
4618  
4619			this.set(
4620				xAxis.x, yAxis.x, zAxis.x, 0,
4621				xAxis.y, yAxis.y, zAxis.y, 0,
4622				xAxis.z, yAxis.z, zAxis.z, 0,
4623				0, 0, 0, 1
4624			);
4625  
4626			return this;
4627  
4628		},
4629  
4630		extractRotation: function () {
4631  
4632			var v1 = new Vector3();
4633  
4634			return function extractRotation( m ) {
4635  
4636				// this method does not support reflection matrices
4637  
4638				var te = this.elements;
4639				var me = m.elements;
4640  
4641				var scaleX = 1 / v1.setFromMatrixColumn( m, 0 ).length();
4642				var scaleY = 1 / v1.setFromMatrixColumn( m, 1 ).length();
4643				var scaleZ = 1 / v1.setFromMatrixColumn( m, 2 ).length();
4644  
4645				te[ 0 ] = me[ 0 ] * scaleX;
4646				te[ 1 ] = me[ 1 ] * scaleX;
4647				te[ 2 ] = me[ 2 ] * scaleX;
4648				te[ 3 ] = 0;
4649  
4650				te[ 4 ] = me[ 4 ] * scaleY;
4651				te[ 5 ] = me[ 5 ] * scaleY;
4652				te[ 6 ] = me[ 6 ] * scaleY;
4653				te[ 7 ] = 0;
4654  
4655				te[ 8 ] = me[ 8 ] * scaleZ;
4656				te[ 9 ] = me[ 9 ] * scaleZ;
4657				te[ 10 ] = me[ 10 ] * scaleZ;
4658				te[ 11 ] = 0;
4659  
4660				te[ 12 ] = 0;
4661				te[ 13 ] = 0;
4662				te[ 14 ] = 0;
4663				te[ 15 ] = 1;
4664  
4665				return this;
4666  
4667			};
4668  
4669		}(),
4670  
4671		makeRotationFromEuler: function ( euler ) {
4672  
4673			if ( ! ( euler && euler.isEuler ) ) {
4674  
4675				console.error( 'THREE.Matrix4: .makeRotationFromEuler() now expects a Euler rotation rather than a Vector3 and order.' );
4676  
4677			}
4678  
4679			var te = this.elements;
4680  
4681			var x = euler.x, y = euler.y, z = euler.z;
4682			var a = Math.cos( x ), b = Math.sin( x );
4683			var c = Math.cos( y ), d = Math.sin( y );
4684			var e = Math.cos( z ), f = Math.sin( z );
4685  
4686			if ( euler.order === 'XYZ' ) {
4687  
4688				var ae = a * e, af = a * f, be = b * e, bf = b * f;
4689  
4690				te[ 0 ] = c * e;
4691				te[ 4 ] = - c * f;
4692				te[ 8 ] = d;
4693  
4694				te[ 1 ] = af + be * d;
4695				te[ 5 ] = ae - bf * d;
4696				te[ 9 ] = - b * c;
4697  
4698				te[ 2 ] = bf - ae * d;
4699				te[ 6 ] = be + af * d;
4700				te[ 10 ] = a * c;
4701  
4702			} else if ( euler.order === 'YXZ' ) {
4703  
4704				var ce = c * e, cf = c * f, de = d * e, df = d * f;
4705  
4706				te[ 0 ] = ce + df * b;
4707				te[ 4 ] = de * b - cf;
4708				te[ 8 ] = a * d;
4709  
4710				te[ 1 ] = a * f;
4711				te[ 5 ] = a * e;
4712				te[ 9 ] = - b;
4713  
4714				te[ 2 ] = cf * b - de;
4715				te[ 6 ] = df + ce * b;
4716				te[ 10 ] = a * c;
4717  
4718			} else if ( euler.order === 'ZXY' ) {
4719  
4720				var ce = c * e, cf = c * f, de = d * e, df = d * f;
4721  
4722				te[ 0 ] = ce - df * b;
4723				te[ 4 ] = - a * f;
4724				te[ 8 ] = de + cf * b;
4725  
4726				te[ 1 ] = cf + de * b;
4727				te[ 5 ] = a * e;
4728				te[ 9 ] = df - ce * b;
4729  
4730				te[ 2 ] = - a * d;
4731				te[ 6 ] = b;
4732				te[ 10 ] = a * c;
4733  
4734			} else if ( euler.order === 'ZYX' ) {
4735  
4736				var ae = a * e, af = a * f, be = b * e, bf = b * f;
4737  
4738				te[ 0 ] = c * e;
4739				te[ 4 ] = be * d - af;
4740				te[ 8 ] = ae * d + bf;
4741  
4742				te[ 1 ] = c * f;
4743				te[ 5 ] = bf * d + ae;
4744				te[ 9 ] = af * d - be;
4745  
4746				te[ 2 ] = - d;
4747				te[ 6 ] = b * c;
4748				te[ 10 ] = a * c;
4749  
4750			} else if ( euler.order === 'YZX' ) {
4751  
4752				var ac = a * c, ad = a * d, bc = b * c, bd = b * d;
4753  
4754				te[ 0 ] = c * e;
4755				te[ 4 ] = bd - ac * f;
4756				te[ 8 ] = bc * f + ad;
4757  
4758				te[ 1 ] = f;
4759				te[ 5 ] = a * e;
4760				te[ 9 ] = - b * e;
4761  
4762				te[ 2 ] = - d * e;
4763				te[ 6 ] = ad * f + bc;
4764				te[ 10 ] = ac - bd * f;
4765  
4766			} else if ( euler.order === 'XZY' ) {
4767  
4768				var ac = a * c, ad = a * d, bc = b * c, bd = b * d;
4769  
4770				te[ 0 ] = c * e;
4771				te[ 4 ] = - f;
4772				te[ 8 ] = d * e;
4773  
4774				te[ 1 ] = ac * f + bd;
4775				te[ 5 ] = a * e;
4776				te[ 9 ] = ad * f - bc;
4777  
4778				te[ 2 ] = bc * f - ad;
4779				te[ 6 ] = b * e;
4780				te[ 10 ] = bd * f + ac;
4781  
4782			}
4783  
4784			// bottom row
4785			te[ 3 ] = 0;
4786			te[ 7 ] = 0;
4787			te[ 11 ] = 0;
4788  
4789			// last column
4790			te[ 12 ] = 0;
4791			te[ 13 ] = 0;
4792			te[ 14 ] = 0;
4793			te[ 15 ] = 1;
4794  
4795			return this;
4796  
4797		},
4798  
4799		makeRotationFromQuaternion: function () {
4800  
4801			var zero = new Vector3( 0, 0, 0 );
4802			var one = new Vector3( 1, 1, 1 );
4803  
4804			return function makeRotationFromQuaternion( q ) {
4805  
4806				return this.compose( zero, q, one );
4807  
4808			};
4809  
4810		}(),
4811  
4812		lookAt: function () {
4813  
4814			var x = new Vector3();
4815			var y = new Vector3();
4816			var z = new Vector3();
4817  
4818			return function lookAt( eye, target, up ) {
4819  
4820				var te = this.elements;
4821  
4822				z.subVectors( eye, target );
4823  
4824				if ( z.lengthSq() === 0 ) {
4825  
4826					// eye and target are in the same position
4827  
4828					z.z = 1;
4829  
4830				}
4831  
4832				z.normalize();
4833				x.crossVectors( up, z );
4834  
4835				if ( x.lengthSq() === 0 ) {
4836  
4837					// up and z are parallel
4838  
4839					if ( Math.abs( up.z ) === 1 ) {
4840  
4841						z.x += 0.0001;
4842  
4843					} else {
4844  
4845						z.z += 0.0001;
4846  
4847					}
4848  
4849					z.normalize();
4850					x.crossVectors( up, z );
4851  
4852				}
4853  
4854				x.normalize();
4855				y.crossVectors( z, x );
4856  
4857				te[ 0 ] = x.x; te[ 4 ] = y.x; te[ 8 ] = z.x;
4858				te[ 1 ] = x.y; te[ 5 ] = y.y; te[ 9 ] = z.y;
4859				te[ 2 ] = x.z; te[ 6 ] = y.z; te[ 10 ] = z.z;
4860  
4861				return this;
4862  
4863			};
4864  
4865		}(),
4866  
4867		multiply: function ( m, n ) {
4868  
4869			if ( n !== undefined ) {
4870  
4871				console.warn( 'THREE.Matrix4: .multiply() now only accepts one argument. Use .multiplyMatrices( a, b ) instead.' );
4872				return this.multiplyMatrices( m, n );
4873  
4874			}
4875  
4876			return this.multiplyMatrices( this, m );
4877  
4878		},
4879  
4880		premultiply: function ( m ) {
4881  
4882			return this.multiplyMatrices( m, this );
4883  
4884		},
4885  
4886		multiplyMatrices: function ( a, b ) {
4887  
4888			var ae = a.elements;
4889			var be = b.elements;
4890			var te = this.elements;
4891  
4892			var a11 = ae[ 0 ], a12 = ae[ 4 ], a13 = ae[ 8 ], a14 = ae[ 12 ];
4893			var a21 = ae[ 1 ], a22 = ae[ 5 ], a23 = ae[ 9 ], a24 = ae[ 13 ];
4894			var a31 = ae[ 2 ], a32 = ae[ 6 ], a33 = ae[ 10 ], a34 = ae[ 14 ];
4895			var a41 = ae[ 3 ], a42 = ae[ 7 ], a43 = ae[ 11 ], a44 = ae[ 15 ];
4896  
4897			var b11 = be[ 0 ], b12 = be[ 4 ], b13 = be[ 8 ], b14 = be[ 12 ];
4898			var b21 = be[ 1 ], b22 = be[ 5 ], b23 = be[ 9 ], b24 = be[ 13 ];
4899			var b31 = be[ 2 ], b32 = be[ 6 ], b33 = be[ 10 ], b34 = be[ 14 ];
4900			var b41 = be[ 3 ], b42 = be[ 7 ], b43 = be[ 11 ], b44 = be[ 15 ];
4901  
4902			te[ 0 ] = a11 * b11 + a12 * b21 + a13 * b31 + a14 * b41;
4903			te[ 4 ] = a11 * b12 + a12 * b22 + a13 * b32 + a14 * b42;
4904			te[ 8 ] = a11 * b13 + a12 * b23 + a13 * b33 + a14 * b43;
4905			te[ 12 ] = a11 * b14 + a12 * b24 + a13 * b34 + a14 * b44;
4906  
4907			te[ 1 ] = a21 * b11 + a22 * b21 + a23 * b31 + a24 * b41;
4908			te[ 5 ] = a21 * b12 + a22 * b22 + a23 * b32 + a24 * b42;
4909			te[ 9 ] = a21 * b13 + a22 * b23 + a23 * b33 + a24 * b43;
4910			te[ 13 ] = a21 * b14 + a22 * b24 + a23 * b34 + a24 * b44;
4911  
4912			te[ 2 ] = a31 * b11 + a32 * b21 + a33 * b31 + a34 * b41;
4913			te[ 6 ] = a31 * b12 + a32 * b22 + a33 * b32 + a34 * b42;
4914			te[ 10 ] = a31 * b13 + a32 * b23 + a33 * b33 + a34 * b43;
4915			te[ 14 ] = a31 * b14 + a32 * b24 + a33 * b34 + a34 * b44;
4916  
4917			te[ 3 ] = a41 * b11 + a42 * b21 + a43 * b31 + a44 * b41;
4918			te[ 7 ] = a41 * b12 + a42 * b22 + a43 * b32 + a44 * b42;
4919			te[ 11 ] = a41 * b13 + a42 * b23 + a43 * b33 + a44 * b43;
4920			te[ 15 ] = a41 * b14 + a42 * b24 + a43 * b34 + a44 * b44;
4921  
4922			return this;
4923  
4924		},
4925  
4926		multiplyScalar: function ( s ) {
4927  
4928			var te = this.elements;
4929  
4930			te[ 0 ] *= s; te[ 4 ] *= s; te[ 8 ] *= s; te[ 12 ] *= s;
4931			te[ 1 ] *= s; te[ 5 ] *= s; te[ 9 ] *= s; te[ 13 ] *= s;
4932			te[ 2 ] *= s; te[ 6 ] *= s; te[ 10 ] *= s; te[ 14 ] *= s;
4933			te[ 3 ] *= s; te[ 7 ] *= s; te[ 11 ] *= s; te[ 15 ] *= s;
4934  
4935			return this;
4936  
4937		},
4938  
4939		applyToBufferAttribute: function () {
4940  
4941			var v1 = new Vector3();
4942  
4943			return function applyToBufferAttribute( attribute ) {
4944  
4945				for ( var i = 0, l = attribute.count; i < l; i ++ ) {
4946  
4947					v1.x = attribute.getX( i );
4948					v1.y = attribute.getY( i );
4949					v1.z = attribute.getZ( i );
4950  
4951					v1.applyMatrix4( this );
4952  
4953					attribute.setXYZ( i, v1.x, v1.y, v1.z );
4954  
4955				}
4956  
4957				return attribute;
4958  
4959			};
4960  
4961		}(),
4962  
4963		determinant: function () {
4964  
4965			var te = this.elements;
4966  
4967			var n11 = te[ 0 ], n12 = te[ 4 ], n13 = te[ 8 ], n14 = te[ 12 ];
4968			var n21 = te[ 1 ], n22 = te[ 5 ], n23 = te[ 9 ], n24 = te[ 13 ];
4969			var n31 = te[ 2 ], n32 = te[ 6 ], n33 = te[ 10 ], n34 = te[ 14 ];
4970			var n41 = te[ 3 ], n42 = te[ 7 ], n43 = te[ 11 ], n44 = te[ 15 ];
4971  
4972			//TODO: make this more efficient
4973			//( based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm )
4974  
4975			return (
4976				n41 * (
4977					+ n14 * n23 * n32
4978					 - n13 * n24 * n32
4979					 - n14 * n22 * n33
4980					 + n12 * n24 * n33
4981					 + n13 * n22 * n34
4982					 - n12 * n23 * n34
4983				) +
4984				n42 * (
4985					+ n11 * n23 * n34
4986					 - n11 * n24 * n33
4987					 + n14 * n21 * n33
4988					 - n13 * n21 * n34
4989					 + n13 * n24 * n31
4990					 - n14 * n23 * n31
4991				) +
4992				n43 * (
4993					+ n11 * n24 * n32
4994					 - n11 * n22 * n34
4995					 - n14 * n21 * n32
4996					 + n12 * n21 * n34
4997					 + n14 * n22 * n31
4998					 - n12 * n24 * n31
4999				) +
5000				n44 * (
5001					- n13 * n22 * n31
5002					 - n11 * n23 * n32
5003					 + n11 * n22 * n33
5004					 + n13 * n21 * n32
5005					 - n12 * n21 * n33
5006					 + n12 * n23 * n31
5007				)
5008  
5009			);
5010  
5011		},
5012  
5013		transpose: function () {
5014  
5015			var te = this.elements;
5016			var tmp;
5017  
5018			tmp = te[ 1 ]; te[ 1 ] = te[ 4 ]; te[ 4 ] = tmp;
5019			tmp = te[ 2 ]; te[ 2 ] = te[ 8 ]; te[ 8 ] = tmp;
5020			tmp = te[ 6 ]; te[ 6 ] = te[ 9 ]; te[ 9 ] = tmp;
5021  
5022			tmp = te[ 3 ]; te[ 3 ] = te[ 12 ]; te[ 12 ] = tmp;
5023			tmp = te[ 7 ]; te[ 7 ] = te[ 13 ]; te[ 13 ] = tmp;
5024			tmp = te[ 11 ]; te[ 11 ] = te[ 14 ]; te[ 14 ] = tmp;
5025  
5026			return this;
5027  
5028		},
5029  
5030		setPosition: function ( v ) {
5031  
5032			var te = this.elements;
5033  
5034			te[ 12 ] = v.x;
5035			te[ 13 ] = v.y;
5036			te[ 14 ] = v.z;
5037  
5038			return this;
5039  
5040		},
5041  
5042		getInverse: function ( m, throwOnDegenerate ) {
5043  
5044			// based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm
5045			var te = this.elements,
5046				me = m.elements,
5047  
5048				n11 = me[ 0 ], n21 = me[ 1 ], n31 = me[ 2 ], n41 = me[ 3 ],
5049				n12 = me[ 4 ], n22 = me[ 5 ], n32 = me[ 6 ], n42 = me[ 7 ],
5050				n13 = me[ 8 ], n23 = me[ 9 ], n33 = me[ 10 ], n43 = me[ 11 ],
5051				n14 = me[ 12 ], n24 = me[ 13 ], n34 = me[ 14 ], n44 = me[ 15 ],
5052  
5053				t11 = n23 * n34 * n42 - n24 * n33 * n42 + n24 * n32 * n43 - n22 * n34 * n43 - n23 * n32 * n44 + n22 * n33 * n44,
5054				t12 = n14 * n33 * n42 - n13 * n34 * n42 - n14 * n32 * n43 + n12 * n34 * n43 + n13 * n32 * n44 - n12 * n33 * n44,
5055				t13 = n13 * n24 * n42 - n14 * n23 * n42 + n14 * n22 * n43 - n12 * n24 * n43 - n13 * n22 * n44 + n12 * n23 * n44,
5056				t14 = n14 * n23 * n32 - n13 * n24 * n32 - n14 * n22 * n33 + n12 * n24 * n33 + n13 * n22 * n34 - n12 * n23 * n34;
5057  
5058			var det = n11 * t11 + n21 * t12 + n31 * t13 + n41 * t14;
5059  
5060			if ( det === 0 ) {
5061  
5062				var msg = "THREE.Matrix4: .getInverse() can't invert matrix, determinant is 0";
5063  
5064				if ( throwOnDegenerate === true ) {
5065  
5066					throw new Error( msg );
5067  
5068				} else {
5069  
5070					console.warn( msg );
5071  
5072				}
5073  
5074				return this.identity();
5075  
5076			}
5077  
5078			var detInv = 1 / det;
5079  
5080			te[ 0 ] = t11 * detInv;
5081			te[ 1 ] = ( n24 * n33 * n41 - n23 * n34 * n41 - n24 * n31 * n43 + n21 * n34 * n43 + n23 * n31 * n44 - n21 * n33 * n44 ) * detInv;
5082			te[ 2 ] = ( n22 * n34 * n41 - n24 * n32 * n41 + n24 * n31 * n42 - n21 * n34 * n42 - n22 * n31 * n44 + n21 * n32 * n44 ) * detInv;
5083			te[ 3 ] = ( n23 * n32 * n41 - n22 * n33 * n41 - n23 * n31 * n42 + n21 * n33 * n42 + n22 * n31 * n43 - n21 * n32 * n43 ) * detInv;
5084  
5085			te[ 4 ] = t12 * detInv;
5086			te[ 5 ] = ( n13 * n34 * n41 - n14 * n33 * n41 + n14 * n31 * n43 - n11 * n34 * n43 - n13 * n31 * n44 + n11 * n33 * n44 ) * detInv;
5087			te[ 6 ] = ( n14 * n32 * n41 - n12 * n34 * n41 - n14 * n31 * n42 + n11 * n34 * n42 + n12 * n31 * n44 - n11 * n32 * n44 ) * detInv;
5088			te[ 7 ] = ( n12 * n33 * n41 - n13 * n32 * n41 + n13 * n31 * n42 - n11 * n33 * n42 - n12 * n31 * n43 + n11 * n32 * n43 ) * detInv;
5089  
5090			te[ 8 ] = t13 * detInv;
5091			te[ 9 ] = ( n14 * n23 * n41 - n13 * n24 * n41 - n14 * n21 * n43 + n11 * n24 * n43 + n13 * n21 * n44 - n11 * n23 * n44 ) * detInv;
5092			te[ 10 ] = ( n12 * n24 * n41 - n14 * n22 * n41 + n14 * n21 * n42 - n11 * n24 * n42 - n12 * n21 * n44 + n11 * n22 * n44 ) * detInv;
5093			te[ 11 ] = ( n13 * n22 * n41 - n12 * n23 * n41 - n13 * n21 * n42 + n11 * n23 * n42 + n12 * n21 * n43 - n11 * n22 * n43 ) * detInv;
5094  
5095			te[ 12 ] = t14 * detInv;
5096			te[ 13 ] = ( n13 * n24 * n31 - n14 * n23 * n31 + n14 * n21 * n33 - n11 * n24 * n33 - n13 * n21 * n34 + n11 * n23 * n34 ) * detInv;
5097			te[ 14 ] = ( n14 * n22 * n31 - n12 * n24 * n31 - n14 * n21 * n32 + n11 * n24 * n32 + n12 * n21 * n34 - n11 * n22 * n34 ) * detInv;
5098			te[ 15 ] = ( n12 * n23 * n31 - n13 * n22 * n31 + n13 * n21 * n32 - n11 * n23 * n32 - n12 * n21 * n33 + n11 * n22 * n33 ) * detInv;
5099  
5100			return this;
5101  
5102		},
5103  
5104		scale: function ( v ) {
5105  
5106			var te = this.elements;
5107			var x = v.x, y = v.y, z = v.z;
5108  
5109			te[ 0 ] *= x; te[ 4 ] *= y; te[ 8 ] *= z;
5110			te[ 1 ] *= x; te[ 5 ] *= y; te[ 9 ] *= z;
5111			te[ 2 ] *= x; te[ 6 ] *= y; te[ 10 ] *= z;
5112			te[ 3 ] *= x; te[ 7 ] *= y; te[ 11 ] *= z;
5113  
5114			return this;
5115  
5116		},
5117  
5118		getMaxScaleOnAxis: function () {
5119  
5120			var te = this.elements;
5121  
5122			var scaleXSq = te[ 0 ] * te[ 0 ] + te[ 1 ] * te[ 1 ] + te[ 2 ] * te[ 2 ];
5123			var scaleYSq = te[ 4 ] * te[ 4 ] + te[ 5 ] * te[ 5 ] + te[ 6 ] * te[ 6 ];
5124			var scaleZSq = te[ 8 ] * te[ 8 ] + te[ 9 ] * te[ 9 ] + te[ 10 ] * te[ 10 ];
5125  
5126			return Math.sqrt( Math.max( scaleXSq, scaleYSq, scaleZSq ) );
5127  
5128		},
5129  
5130		makeTranslation: function ( x, y, z ) {
5131  
5132			this.set(
5133  
5134				1, 0, 0, x,
5135				0, 1, 0, y,
5136				0, 0, 1, z,
5137				0, 0, 0, 1
5138  
5139			);
5140  
5141			return this;
5142  
5143		},
5144  
5145		makeRotationX: function ( theta ) {
5146  
5147			var c = Math.cos( theta ), s = Math.sin( theta );
5148  
5149			this.set(
5150  
5151				1, 0, 0, 0,
5152				0, c, - s, 0,
5153				0, s, c, 0,
5154				0, 0, 0, 1
5155  
5156			);
5157  
5158			return this;
5159  
5160		},
5161  
5162		makeRotationY: function ( theta ) {
5163  
5164			var c = Math.cos( theta ), s = Math.sin( theta );
5165  
5166			this.set(
5167  
5168				 c, 0, s, 0,
5169				 0, 1, 0, 0,
5170				- s, 0, c, 0,
5171				 0, 0, 0, 1
5172  
5173			);
5174  
5175			return this;
5176  
5177		},
5178  
5179		makeRotationZ: function ( theta ) {
5180  
5181			var c = Math.cos( theta ), s = Math.sin( theta );
5182  
5183			this.set(
5184  
5185				c, - s, 0, 0,
5186				s, c, 0, 0,
5187				0, 0, 1, 0,
5188				0, 0, 0, 1
5189  
5190			);
5191  
5192			return this;
5193  
5194		},
5195  
5196		makeRotationAxis: function ( axis, angle ) {
5197  
5198			// Based on http://www.gamedev.net/reference/articles/article1199.asp
5199  
5200			var c = Math.cos( angle );
5201			var s = Math.sin( angle );
5202			var t = 1 - c;
5203			var x = axis.x, y = axis.y, z = axis.z;
5204			var tx = t * x, ty = t * y;
5205  
5206			this.set(
5207  
5208				tx * x + c, tx * y - s * z, tx * z + s * y, 0,
5209				tx * y + s * z, ty * y + c, ty * z - s * x, 0,
5210				tx * z - s * y, ty * z + s * x, t * z * z + c, 0,
5211				0, 0, 0, 1
5212  
5213			);
5214  
5215			 return this;
5216  
5217		},
5218  
5219		makeScale: function ( x, y, z ) {
5220  
5221			this.set(
5222  
5223				x, 0, 0, 0,
5224				0, y, 0, 0,
5225				0, 0, z, 0,
5226				0, 0, 0, 1
5227  
5228			);
5229  
5230			return this;
5231  
5232		},
5233  
5234		makeShear: function ( x, y, z ) {
5235  
5236			this.set(
5237  
5238				1, y, z, 0,
5239				x, 1, z, 0,
5240				x, y, 1, 0,
5241				0, 0, 0, 1
5242  
5243			);
5244  
5245			return this;
5246  
5247		},
5248  
5249		compose: function ( position, quaternion, scale ) {
5250  
5251			var te = this.elements;
5252  
5253			var x = quaternion._x, y = quaternion._y, z = quaternion._z, w = quaternion._w;
5254			var x2 = x + x,	y2 = y + y, z2 = z + z;
5255			var xx = x * x2, xy = x * y2, xz = x * z2;
5256			var yy = y * y2, yz = y * z2, zz = z * z2;
5257			var wx = w * x2, wy = w * y2, wz = w * z2;
5258  
5259			var sx = scale.x, sy = scale.y, sz = scale.z;
5260  
5261				te[ 0 ] = ( 1 - ( yy + zz ) ) * sx;
5262				te[ 1 ] = ( xy + wz ) * sx;
5263				te[ 2 ] = ( xz - wy ) * sx;
5264				te[ 3 ] = 0;
5265  
5266				te[ 4 ] = ( xy - wz ) * sy;
5267				te[ 5 ] = ( 1 - ( xx + zz ) ) * sy;
5268				te[ 6 ] = ( yz + wx ) * sy;
5269				te[ 7 ] = 0;
5270  
5271				te[ 8 ] = ( xz + wy ) * sz;
5272				te[ 9 ] = ( yz - wx ) * sz;
5273				te[ 10 ] = ( 1 - ( xx + yy ) ) * sz;
5274				te[ 11 ] = 0;
5275  
5276				te[ 12 ] = position.x;
5277				te[ 13 ] = position.y;
5278				te[ 14 ] = position.z;
5279				te[ 15 ] = 1;
5280  
5281				return this;
5282  
5283		},
5284  
5285		decompose: function () {
5286  
5287			var vector = new Vector3();
5288			var matrix = new Matrix4();
5289  
5290			return function decompose( position, quaternion, scale ) {
5291  
5292				var te = this.elements;
5293  
5294				var sx = vector.set( te[ 0 ], te[ 1 ], te[ 2 ] ).length();
5295				var sy = vector.set( te[ 4 ], te[ 5 ], te[ 6 ] ).length();
5296				var sz = vector.set( te[ 8 ], te[ 9 ], te[ 10 ] ).length();
5297  
5298				// if determine is negative, we need to invert one scale
5299				var det = this.determinant();
5300				if ( det < 0 ) sx = - sx;
5301  
5302				position.x = te[ 12 ];
5303				position.y = te[ 13 ];
5304				position.z = te[ 14 ];
5305  
5306				// scale the rotation part
5307				matrix.copy( this );
5308  
5309				var invSX = 1 / sx;
5310				var invSY = 1 / sy;
5311				var invSZ = 1 / sz;
5312  
5313				matrix.elements[ 0 ] *= invSX;
5314				matrix.elements[ 1 ] *= invSX;
5315				matrix.elements[ 2 ] *= invSX;
5316  
5317				matrix.elements[ 4 ] *= invSY;
5318				matrix.elements[ 5 ] *= invSY;
5319				matrix.elements[ 6 ] *= invSY;
5320  
5321				matrix.elements[ 8 ] *= invSZ;
5322				matrix.elements[ 9 ] *= invSZ;
5323				matrix.elements[ 10 ] *= invSZ;
5324  
5325				quaternion.setFromRotationMatrix( matrix );
5326  
5327				scale.x = sx;
5328				scale.y = sy;
5329				scale.z = sz;
5330  
5331				return this;
5332  
5333			};
5334  
5335		}(),
5336  
5337		makePerspective: function ( left, right, top, bottom, near, far ) {
5338  
5339			if ( far === undefined ) {
5340  
5341				console.warn( 'THREE.Matrix4: .makePerspective() has been redefined and has a new signature. Please check the docs.' );
5342  
5343			}
5344  
5345			var te = this.elements;
5346			var x = 2 * near / ( right - left );
5347			var y = 2 * near / ( top - bottom );
5348  
5349			var a = ( right + left ) / ( right - left );
5350			var b = ( top + bottom ) / ( top - bottom );
5351			var c = - ( far + near ) / ( far - near );
5352			var d = - 2 * far * near / ( far - near );
5353  
5354			te[ 0 ] = x;	te[ 4 ] = 0;	te[ 8 ] = a;	te[ 12 ] = 0;
5355			te[ 1 ] = 0;	te[ 5 ] = y;	te[ 9 ] = b;	te[ 13 ] = 0;
5356			te[ 2 ] = 0;	te[ 6 ] = 0;	te[ 10 ] = c;	te[ 14 ] = d;
5357			te[ 3 ] = 0;	te[ 7 ] = 0;	te[ 11 ] = - 1;	te[ 15 ] = 0;
5358  
5359			return this;
5360  
5361		},
5362  
5363		makeOrthographic: function ( left, right, top, bottom, near, far ) {
5364  
5365			var te = this.elements;
5366			var w = 1.0 / ( right - left );
5367			var h = 1.0 / ( top - bottom );
5368			var p = 1.0 / ( far - near );
5369  
5370			var x = ( right + left ) * w;
5371			var y = ( top + bottom ) * h;
5372			var z = ( far + near ) * p;
5373  
5374			te[ 0 ] = 2 * w;	te[ 4 ] = 0;	te[ 8 ] = 0;	te[ 12 ] = - x;
5375			te[ 1 ] = 0;	te[ 5 ] = 2 * h;	te[ 9 ] = 0;	te[ 13 ] = - y;
5376			te[ 2 ] = 0;	te[ 6 ] = 0;	te[ 10 ] = - 2 * p;	te[ 14 ] = - z;
5377			te[ 3 ] = 0;	te[ 7 ] = 0;	te[ 11 ] = 0;	te[ 15 ] = 1;
5378  
5379			return this;
5380  
5381		},
5382  
5383		equals: function ( matrix ) {
5384  
5385			var te = this.elements;
5386			var me = matrix.elements;
5387  
5388			for ( var i = 0; i < 16; i ++ ) {
5389  
5390				if ( te[ i ] !== me[ i ] ) return false;
5391  
5392			}
5393  
5394			return true;
5395  
5396		},
5397  
5398		fromArray: function ( array, offset ) {
5399  
5400			if ( offset === undefined ) offset = 0;
5401  
5402			for ( var i = 0; i < 16; i ++ ) {
5403  
5404				this.elements[ i ] = array[ i + offset ];
5405  
5406			}
5407  
5408			return this;
5409  
5410		},
5411  
5412		toArray: function ( array, offset ) {
5413  
5414			if ( array === undefined ) array = [];
5415			if ( offset === undefined ) offset = 0;
5416  
5417			var te = this.elements;
5418  
5419			array[ offset ] = te[ 0 ];
5420			array[ offset + 1 ] = te[ 1 ];
5421			array[ offset + 2 ] = te[ 2 ];
5422			array[ offset + 3 ] = te[ 3 ];
5423  
5424			array[ offset + 4 ] = te[ 4 ];
5425			array[ offset + 5 ] = te[ 5 ];
5426			array[ offset + 6 ] = te[ 6 ];
5427			array[ offset + 7 ] = te[ 7 ];
5428  
5429			array[ offset + 8 ] = te[ 8 ];
5430			array[ offset + 9 ] = te[ 9 ];
5431			array[ offset + 10 ] = te[ 10 ];
5432			array[ offset + 11 ] = te[ 11 ];
5433  
5434			array[ offset + 12 ] = te[ 12 ];
5435			array[ offset + 13 ] = te[ 13 ];
5436			array[ offset + 14 ] = te[ 14 ];
5437			array[ offset + 15 ] = te[ 15 ];
5438  
5439			return array;
5440  
5441		}
5442  
5443	} );
5444  
5445	/**
5446	 * @author mikael emtinger / http://gomo.se/
5447	 * @author alteredq / http://alteredqualia.com/
5448	 * @author WestLangley / http://github.com/WestLangley
5449	 * @author bhouston / http://clara.io
5450	 */
5451  
5452	function Quaternion( x, y, z, w ) {
5453  
5454		this._x = x || 0;
5455		this._y = y || 0;
5456		this._z = z || 0;
5457		this._w = ( w !== undefined ) ? w : 1;
5458  
5459	}
5460  
5461	Object.assign( Quaternion, {
5462  
5463		slerp: function ( qa, qb, qm, t ) {
5464  
5465			return qm.copy( qa ).slerp( qb, t );
5466  
5467		},
5468  
5469		slerpFlat: function ( dst, dstOffset, src0, srcOffset0, src1, srcOffset1, t ) {
5470  
5471			// fuzz-free, array-based Quaternion SLERP operation
5472  
5473			var x0 = src0[ srcOffset0 + 0 ],
5474				y0 = src0[ srcOffset0 + 1 ],
5475				z0 = src0[ srcOffset0 + 2 ],
5476				w0 = src0[ srcOffset0 + 3 ],
5477  
5478				x1 = src1[ srcOffset1 + 0 ],
5479				y1 = src1[ srcOffset1 + 1 ],
5480				z1 = src1[ srcOffset1 + 2 ],
5481				w1 = src1[ srcOffset1 + 3 ];
5482  
5483			if ( w0 !== w1 || x0 !== x1 || y0 !== y1 || z0 !== z1 ) {
5484  
5485				var s = 1 - t,
5486  
5487					cos = x0 * x1 + y0 * y1 + z0 * z1 + w0 * w1,
5488  
5489					dir = ( cos >= 0 ? 1 : - 1 ),
5490					sqrSin = 1 - cos * cos;
5491  
5492				// Skip the Slerp for tiny steps to avoid numeric problems:
5493				if ( sqrSin > Number.EPSILON ) {
5494  
5495					var sin = Math.sqrt( sqrSin ),
5496						len = Math.atan2( sin, cos * dir );
5497  
5498					s = Math.sin( s * len ) / sin;
5499					t = Math.sin( t * len ) / sin;
5500  
5501				}
5502  
5503				var tDir = t * dir;
5504  
5505				x0 = x0 * s + x1 * tDir;
5506				y0 = y0 * s + y1 * tDir;
5507				z0 = z0 * s + z1 * tDir;
5508				w0 = w0 * s + w1 * tDir;
5509  
5510				// Normalize in case we just did a lerp:
5511				if ( s === 1 - t ) {
5512  
5513					var f = 1 / Math.sqrt( x0 * x0 + y0 * y0 + z0 * z0 + w0 * w0 );
5514  
5515					x0 *= f;
5516					y0 *= f;
5517					z0 *= f;
5518					w0 *= f;
5519  
5520				}
5521  
5522			}
5523  
5524			dst[ dstOffset ] = x0;
5525			dst[ dstOffset + 1 ] = y0;
5526			dst[ dstOffset + 2 ] = z0;
5527			dst[ dstOffset + 3 ] = w0;
5528  
5529		}
5530  
5531	} );
5532  
5533	Object.defineProperties( Quaternion.prototype, {
5534  
5535		x: {
5536  
5537			get: function () {
5538  
5539				return this._x;
5540  
5541			},
5542  
5543			set: function ( value ) {
5544  
5545				this._x = value;
5546				this.onChangeCallback();
5547  
5548			}
5549  
5550		},
5551  
5552		y: {
5553  
5554			get: function () {
5555  
5556				return this._y;
5557  
5558			},
5559  
5560			set: function ( value ) {
5561  
5562				this._y = value;
5563				this.onChangeCallback();
5564  
5565			}
5566  
5567		},
5568  
5569		z: {
5570  
5571			get: function () {
5572  
5573				return this._z;
5574  
5575			},
5576  
5577			set: function ( value ) {
5578  
5579				this._z = value;
5580				this.onChangeCallback();
5581  
5582			}
5583  
5584		},
5585  
5586		w: {
5587  
5588			get: function () {
5589  
5590				return this._w;
5591  
5592			},
5593  
5594			set: function ( value ) {
5595  
5596				this._w = value;
5597				this.onChangeCallback();
5598  
5599			}
5600  
5601		}
5602  
5603	} );
5604  
5605	Object.assign( Quaternion.prototype, {
5606  
5607		set: function ( x, y, z, w ) {
5608  
5609			this._x = x;
5610			this._y = y;
5611			this._z = z;
5612			this._w = w;
5613  
5614			this.onChangeCallback();
5615  
5616			return this;
5617  
5618		},
5619  
5620		clone: function () {
5621  
5622			return new this.constructor( this._x, this._y, this._z, this._w );
5623  
5624		},
5625  
5626		copy: function ( quaternion ) {
5627  
5628			this._x = quaternion.x;
5629			this._y = quaternion.y;
5630			this._z = quaternion.z;
5631			this._w = quaternion.w;
5632  
5633			this.onChangeCallback();
5634  
5635			return this;
5636  
5637		},
5638  
5639		setFromEuler: function ( euler, update ) {
5640  
5641			if ( ! ( euler && euler.isEuler ) ) {
5642  
5643				throw new Error( 'THREE.Quaternion: .setFromEuler() now expects an Euler rotation rather than a Vector3 and order.' );
5644  
5645			}
5646  
5647			var x = euler._x, y = euler._y, z = euler._z, order = euler.order;
5648  
5649			// http://www.mathworks.com/matlabcentral/fileexchange/
5650			// 	20696-function-to-convert-between-dcm-euler-angles-quaternions-and-euler-vectors/
5651			//	content/SpinCalc.m
5652  
5653			var cos = Math.cos;
5654			var sin = Math.sin;
5655  
5656			var c1 = cos( x / 2 );
5657			var c2 = cos( y / 2 );
5658			var c3 = cos( z / 2 );
5659  
5660			var s1 = sin( x / 2 );
5661			var s2 = sin( y / 2 );
5662			var s3 = sin( z / 2 );
5663  
5664			if ( order === 'XYZ' ) {
5665  
5666				this._x = s1 * c2 * c3 + c1 * s2 * s3;
5667				this._y = c1 * s2 * c3 - s1 * c2 * s3;
5668				this._z = c1 * c2 * s3 + s1 * s2 * c3;
5669				this._w = c1 * c2 * c3 - s1 * s2 * s3;
5670  
5671			} else if ( order === 'YXZ' ) {
5672  
5673				this._x = s1 * c2 * c3 + c1 * s2 * s3;
5674				this._y = c1 * s2 * c3 - s1 * c2 * s3;
5675				this._z = c1 * c2 * s3 - s1 * s2 * c3;
5676				this._w = c1 * c2 * c3 + s1 * s2 * s3;
5677  
5678			} else if ( order === 'ZXY' ) {
5679  
5680				this._x = s1 * c2 * c3 - c1 * s2 * s3;
5681				this._y = c1 * s2 * c3 + s1 * c2 * s3;
5682				this._z = c1 * c2 * s3 + s1 * s2 * c3;
5683				this._w = c1 * c2 * c3 - s1 * s2 * s3;
5684  
5685			} else if ( order === 'ZYX' ) {
5686  
5687				this._x = s1 * c2 * c3 - c1 * s2 * s3;
5688				this._y = c1 * s2 * c3 + s1 * c2 * s3;
5689				this._z = c1 * c2 * s3 - s1 * s2 * c3;
5690				this._w = c1 * c2 * c3 + s1 * s2 * s3;
5691  
5692			} else if ( order === 'YZX' ) {
5693  
5694				this._x = s1 * c2 * c3 + c1 * s2 * s3;
5695				this._y = c1 * s2 * c3 + s1 * c2 * s3;
5696				this._z = c1 * c2 * s3 - s1 * s2 * c3;
5697				this._w = c1 * c2 * c3 - s1 * s2 * s3;
5698  
5699			} else if ( order === 'XZY' ) {
5700  
5701				this._x = s1 * c2 * c3 - c1 * s2 * s3;
5702				this._y = c1 * s2 * c3 - s1 * c2 * s3;
5703				this._z = c1 * c2 * s3 + s1 * s2 * c3;
5704				this._w = c1 * c2 * c3 + s1 * s2 * s3;
5705  
5706			}
5707  
5708			if ( update !== false ) this.onChangeCallback();
5709  
5710			return this;
5711  
5712		},
5713  
5714		setFromAxisAngle: function ( axis, angle ) {
5715  
5716			// http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToQuaternion/index.htm
5717  
5718			// assumes axis is normalized
5719  
5720			var halfAngle = angle / 2, s = Math.sin( halfAngle );
5721  
5722			this._x = axis.x * s;
5723			this._y = axis.y * s;
5724			this._z = axis.z * s;
5725			this._w = Math.cos( halfAngle );
5726  
5727			this.onChangeCallback();
5728  
5729			return this;
5730  
5731		},
5732  
5733		setFromRotationMatrix: function ( m ) {
5734  
5735			// http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm
5736  
5737			// assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)
5738  
5739			var te = m.elements,
5740  
5741				m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ],
5742				m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ],
5743				m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ],
5744  
5745				trace = m11 + m22 + m33,
5746				s;
5747  
5748			if ( trace > 0 ) {
5749  
5750				s = 0.5 / Math.sqrt( trace + 1.0 );
5751  
5752				this._w = 0.25 / s;
5753				this._x = ( m32 - m23 ) * s;
5754				this._y = ( m13 - m31 ) * s;
5755				this._z = ( m21 - m12 ) * s;
5756  
5757			} else if ( m11 > m22 && m11 > m33 ) {
5758  
5759				s = 2.0 * Math.sqrt( 1.0 + m11 - m22 - m33 );
5760  
5761				this._w = ( m32 - m23 ) / s;
5762				this._x = 0.25 * s;
5763				this._y = ( m12 + m21 ) / s;
5764				this._z = ( m13 + m31 ) / s;
5765  
5766			} else if ( m22 > m33 ) {
5767  
5768				s = 2.0 * Math.sqrt( 1.0 + m22 - m11 - m33 );
5769  
5770				this._w = ( m13 - m31 ) / s;
5771				this._x = ( m12 + m21 ) / s;
5772				this._y = 0.25 * s;
5773				this._z = ( m23 + m32 ) / s;
5774  
5775			} else {
5776  
5777				s = 2.0 * Math.sqrt( 1.0 + m33 - m11 - m22 );
5778  
5779				this._w = ( m21 - m12 ) / s;
5780				this._x = ( m13 + m31 ) / s;
5781				this._y = ( m23 + m32 ) / s;
5782				this._z = 0.25 * s;
5783  
5784			}
5785  
5786			this.onChangeCallback();
5787  
5788			return this;
5789  
5790		},
5791  
5792		setFromUnitVectors: function () {
5793  
5794			// assumes direction vectors vFrom and vTo are normalized
5795  
5796			var v1 = new Vector3();
5797			var r;
5798  
5799			var EPS = 0.000001;
5800  
5801			return function setFromUnitVectors( vFrom, vTo ) {
5802  
5803				if ( v1 === undefined ) v1 = new Vector3();
5804  
5805				r = vFrom.dot( vTo ) + 1;
5806  
5807				if ( r < EPS ) {
5808  
5809					r = 0;
5810  
5811					if ( Math.abs( vFrom.x ) > Math.abs( vFrom.z ) ) {
5812  
5813						v1.set( - vFrom.y, vFrom.x, 0 );
5814  
5815					} else {
5816  
5817						v1.set( 0, - vFrom.z, vFrom.y );
5818  
5819					}
5820  
5821				} else {
5822  
5823					v1.crossVectors( vFrom, vTo );
5824  
5825				}
5826  
5827				this._x = v1.x;
5828				this._y = v1.y;
5829				this._z = v1.z;
5830				this._w = r;
5831  
5832				return this.normalize();
5833  
5834			};
5835  
5836		}(),
5837  
5838		inverse: function () {
5839  
5840			// quaternion is assumed to have unit length
5841  
5842			return this.conjugate();
5843  
5844		},
5845  
5846		conjugate: function () {
5847  
5848			this._x *= - 1;
5849			this._y *= - 1;
5850			this._z *= - 1;
5851  
5852			this.onChangeCallback();
5853  
5854			return this;
5855  
5856		},
5857  
5858		dot: function ( v ) {
5859  
5860			return this._x * v._x + this._y * v._y + this._z * v._z + this._w * v._w;
5861  
5862		},
5863  
5864		lengthSq: function () {
5865  
5866			return this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w;
5867  
5868		},
5869  
5870		length: function () {
5871  
5872			return Math.sqrt( this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w );
5873  
5874		},
5875  
5876		normalize: function () {
5877  
5878			var l = this.length();
5879  
5880			if ( l === 0 ) {
5881  
5882				this._x = 0;
5883				this._y = 0;
5884				this._z = 0;
5885				this._w = 1;
5886  
5887			} else {
5888  
5889				l = 1 / l;
5890  
5891				this._x = this._x * l;
5892				this._y = this._y * l;
5893				this._z = this._z * l;
5894				this._w = this._w * l;
5895  
5896			}
5897  
5898			this.onChangeCallback();
5899  
5900			return this;
5901  
5902		},
5903  
5904		multiply: function ( q, p ) {
5905  
5906			if ( p !== undefined ) {
5907  
5908				console.warn( 'THREE.Quaternion: .multiply() now only accepts one argument. Use .multiplyQuaternions( a, b ) instead.' );
5909				return this.multiplyQuaternions( q, p );
5910  
5911			}
5912  
5913			return this.multiplyQuaternions( this, q );
5914  
5915		},
5916  
5917		premultiply: function ( q ) {
5918  
5919			return this.multiplyQuaternions( q, this );
5920  
5921		},
5922  
5923		multiplyQuaternions: function ( a, b ) {
5924  
5925			// from http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/code/index.htm
5926  
5927			var qax = a._x, qay = a._y, qaz = a._z, qaw = a._w;
5928			var qbx = b._x, qby = b._y, qbz = b._z, qbw = b._w;
5929  
5930			this._x = qax * qbw + qaw * qbx + qay * qbz - qaz * qby;
5931			this._y = qay * qbw + qaw * qby + qaz * qbx - qax * qbz;
5932			this._z = qaz * qbw + qaw * qbz + qax * qby - qay * qbx;
5933			this._w = qaw * qbw - qax * qbx - qay * qby - qaz * qbz;
5934  
5935			this.onChangeCallback();
5936  
5937			return this;
5938  
5939		},
5940  
5941		slerp: function ( qb, t ) {
5942  
5943			if ( t === 0 ) return this;
5944			if ( t === 1 ) return this.copy( qb );
5945  
5946			var x = this._x, y = this._y, z = this._z, w = this._w;
5947  
5948			// http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/slerp/
5949  
5950			var cosHalfTheta = w * qb._w + x * qb._x + y * qb._y + z * qb._z;
5951  
5952			if ( cosHalfTheta < 0 ) {
5953  
5954				this._w = - qb._w;
5955				this._x = - qb._x;
5956				this._y = - qb._y;
5957				this._z = - qb._z;
5958  
5959				cosHalfTheta = - cosHalfTheta;
5960  
5961			} else {
5962  
5963				this.copy( qb );
5964  
5965			}
5966  
5967			if ( cosHalfTheta >= 1.0 ) {
5968  
5969				this._w = w;
5970				this._x = x;
5971				this._y = y;
5972				this._z = z;
5973  
5974				return this;
5975  
5976			}
5977  
5978			var sinHalfTheta = Math.sqrt( 1.0 - cosHalfTheta * cosHalfTheta );
5979  
5980			if ( Math.abs( sinHalfTheta ) < 0.001 ) {
5981  
5982				this._w = 0.5 * ( w + this._w );
5983				this._x = 0.5 * ( x + this._x );
5984				this._y = 0.5 * ( y + this._y );
5985				this._z = 0.5 * ( z + this._z );
5986  
5987				return this;
5988  
5989			}
5990  
5991			var halfTheta = Math.atan2( sinHalfTheta, cosHalfTheta );
5992			var ratioA = Math.sin( ( 1 - t ) * halfTheta ) / sinHalfTheta,
5993				ratioB = Math.sin( t * halfTheta ) / sinHalfTheta;
5994  
5995			this._w = ( w * ratioA + this._w * ratioB );
5996			this._x = ( x * ratioA + this._x * ratioB );
5997			this._y = ( y * ratioA + this._y * ratioB );
5998			this._z = ( z * ratioA + this._z * ratioB );
5999  
6000			this.onChangeCallback();
6001  
6002			return this;
6003  
6004		},
6005  
6006		equals: function ( quaternion ) {
6007  
6008			return ( quaternion._x === this._x ) && ( quaternion._y === this._y ) && ( quaternion._z === this._z ) && ( quaternion._w === this._w );
6009  
6010		},
6011  
6012		fromArray: function ( array, offset ) {
6013  
6014			if ( offset === undefined ) offset = 0;
6015  
6016			this._x = array[ offset ];
6017			this._y = array[ offset + 1 ];
6018			this._z = array[ offset + 2 ];
6019			this._w = array[ offset + 3 ];
6020  
6021			this.onChangeCallback();
6022  
6023			return this;
6024  
6025		},
6026  
6027		toArray: function ( array, offset ) {
6028  
6029			if ( array === undefined ) array = [];
6030			if ( offset === undefined ) offset = 0;
6031  
6032			array[ offset ] = this._x;
6033			array[ offset + 1 ] = this._y;
6034			array[ offset + 2 ] = this._z;
6035			array[ offset + 3 ] = this._w;
6036  
6037			return array;
6038  
6039		},
6040  
6041		onChange: function ( callback ) {
6042  
6043			this.onChangeCallback = callback;
6044  
6045			return this;
6046  
6047		},
6048  
6049		onChangeCallback: function () {}
6050  
6051	} );
6052  
6053	/**
6054	 * @author mrdoob / http://mrdoob.com/
6055	 * @author kile / http://kile.stravaganza.org/
6056	 * @author philogb / http://blog.thejit.org/
6057	 * @author mikael emtinger / http://gomo.se/
6058	 * @author egraether / http://egraether.com/
6059	 * @author WestLangley / http://github.com/WestLangley
6060	 */
6061  
6062	function Vector3( x, y, z ) {
6063  
6064		this.x = x || 0;
6065		this.y = y || 0;
6066		this.z = z || 0;
6067  
6068	}
6069  
6070	Object.assign( Vector3.prototype, {
6071  
6072		isVector3: true,
6073  
6074		set: function ( x, y, z ) {
6075  
6076			this.x = x;
6077			this.y = y;
6078			this.z = z;
6079  
6080			return this;
6081  
6082		},
6083  
6084		setScalar: function ( scalar ) {
6085  
6086			this.x = scalar;
6087			this.y = scalar;
6088			this.z = scalar;
6089  
6090			return this;
6091  
6092		},
6093  
6094		setX: function ( x ) {
6095  
6096			this.x = x;
6097  
6098			return this;
6099  
6100		},
6101  
6102		setY: function ( y ) {
6103  
6104			this.y = y;
6105  
6106			return this;
6107  
6108		},
6109  
6110		setZ: function ( z ) {
6111  
6112			this.z = z;
6113  
6114			return this;
6115  
6116		},
6117  
6118		setComponent: function ( index, value ) {
6119  
6120			switch ( index ) {
6121  
6122				case 0: this.x = value; break;
6123				case 1: this.y = value; break;
6124				case 2: this.z = value; break;
6125				default: throw new Error( 'index is out of range: ' + index );
6126  
6127			}
6128  
6129			return this;
6130  
6131		},
6132  
6133		getComponent: function ( index ) {
6134  
6135			switch ( index ) {
6136  
6137				case 0: return this.x;
6138				case 1: return this.y;
6139				case 2: return this.z;
6140				default: throw new Error( 'index is out of range: ' + index );
6141  
6142			}
6143  
6144		},
6145  
6146		clone: function () {
6147  
6148			return new this.constructor( this.x, this.y, this.z );
6149  
6150		},
6151  
6152		copy: function ( v ) {
6153  
6154			this.x = v.x;
6155			this.y = v.y;
6156			this.z = v.z;
6157  
6158			return this;
6159  
6160		},
6161  
6162		add: function ( v, w ) {
6163  
6164			if ( w !== undefined ) {
6165  
6166				console.warn( 'THREE.Vector3: .add() now only accepts one argument. Use .addVectors( a, b ) instead.' );
6167				return this.addVectors( v, w );
6168  
6169			}
6170  
6171			this.x += v.x;
6172			this.y += v.y;
6173			this.z += v.z;
6174  
6175			return this;
6176  
6177		},
6178  
6179		addScalar: function ( s ) {
6180  
6181			this.x += s;
6182			this.y += s;
6183			this.z += s;
6184  
6185			return this;
6186  
6187		},
6188  
6189		addVectors: function ( a, b ) {
6190  
6191			this.x = a.x + b.x;
6192			this.y = a.y + b.y;
6193			this.z = a.z + b.z;
6194  
6195			return this;
6196  
6197		},
6198  
6199		addScaledVector: function ( v, s ) {
6200  
6201			this.x += v.x * s;
6202			this.y += v.y * s;
6203			this.z += v.z * s;
6204  
6205			return this;
6206  
6207		},
6208  
6209		sub: function ( v, w ) {
6210  
6211			if ( w !== undefined ) {
6212  
6213				console.warn( 'THREE.Vector3: .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' );
6214				return this.subVectors( v, w );
6215  
6216			}
6217  
6218			this.x -= v.x;
6219			this.y -= v.y;
6220			this.z -= v.z;
6221  
6222			return this;
6223  
6224		},
6225  
6226		subScalar: function ( s ) {
6227  
6228			this.x -= s;
6229			this.y -= s;
6230			this.z -= s;
6231  
6232			return this;
6233  
6234		},
6235  
6236		subVectors: function ( a, b ) {
6237  
6238			this.x = a.x - b.x;
6239			this.y = a.y - b.y;
6240			this.z = a.z - b.z;
6241  
6242			return this;
6243  
6244		},
6245  
6246		multiply: function ( v, w ) {
6247  
6248			if ( w !== undefined ) {
6249  
6250				console.warn( 'THREE.Vector3: .multiply() now only accepts one argument. Use .multiplyVectors( a, b ) instead.' );
6251				return this.multiplyVectors( v, w );
6252  
6253			}
6254  
6255			this.x *= v.x;
6256			this.y *= v.y;
6257			this.z *= v.z;
6258  
6259			return this;
6260  
6261		},
6262  
6263		multiplyScalar: function ( scalar ) {
6264  
6265			this.x *= scalar;
6266			this.y *= scalar;
6267			this.z *= scalar;
6268  
6269			return this;
6270  
6271		},
6272  
6273		multiplyVectors: function ( a, b ) {
6274  
6275			this.x = a.x * b.x;
6276			this.y = a.y * b.y;
6277			this.z = a.z * b.z;
6278  
6279			return this;
6280  
6281		},
6282  
6283		applyEuler: function () {
6284  
6285			var quaternion = new Quaternion();
6286  
6287			return function applyEuler( euler ) {
6288  
6289				if ( ! ( euler && euler.isEuler ) ) {
6290  
6291					console.error( 'THREE.Vector3: .applyEuler() now expects an Euler rotation rather than a Vector3 and order.' );
6292  
6293				}
6294  
6295				return this.applyQuaternion( quaternion.setFromEuler( euler ) );
6296  
6297			};
6298  
6299		}(),
6300  
6301		applyAxisAngle: function () {
6302  
6303			var quaternion = new Quaternion();
6304  
6305			return function applyAxisAngle( axis, angle ) {
6306  
6307				return this.applyQuaternion( quaternion.setFromAxisAngle( axis, angle ) );
6308  
6309			};
6310  
6311		}(),
6312  
6313		applyMatrix3: function ( m ) {
6314  
6315			var x = this.x, y = this.y, z = this.z;
6316			var e = m.elements;
6317  
6318			this.x = e[ 0 ] * x + e[ 3 ] * y + e[ 6 ] * z;
6319			this.y = e[ 1 ] * x + e[ 4 ] * y + e[ 7 ] * z;
6320			this.z = e[ 2 ] * x + e[ 5 ] * y + e[ 8 ] * z;
6321  
6322			return this;
6323  
6324		},
6325  
6326		applyMatrix4: function ( m ) {
6327  
6328			var x = this.x, y = this.y, z = this.z;
6329			var e = m.elements;
6330  
6331			var w = 1 / ( e[ 3 ] * x + e[ 7 ] * y + e[ 11 ] * z + e[ 15 ] );
6332  
6333			this.x = ( e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z + e[ 12 ] ) * w;
6334			this.y = ( e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z + e[ 13 ] ) * w;
6335			this.z = ( e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z + e[ 14 ] ) * w;
6336  
6337			return this;
6338  
6339		},
6340  
6341		applyQuaternion: function ( q ) {
6342  
6343			var x = this.x, y = this.y, z = this.z;
6344			var qx = q.x, qy = q.y, qz = q.z, qw = q.w;
6345  
6346			// calculate quat * vector
6347  
6348			var ix = qw * x + qy * z - qz * y;
6349			var iy = qw * y + qz * x - qx * z;
6350			var iz = qw * z + qx * y - qy * x;
6351			var iw = - qx * x - qy * y - qz * z;
6352  
6353			// calculate result * inverse quat
6354  
6355			this.x = ix * qw + iw * - qx + iy * - qz - iz * - qy;
6356			this.y = iy * qw + iw * - qy + iz * - qx - ix * - qz;
6357			this.z = iz * qw + iw * - qz + ix * - qy - iy * - qx;
6358  
6359			return this;
6360  
6361		},
6362  
6363		project: function () {
6364  
6365			var matrix = new Matrix4();
6366  
6367			return function project( camera ) {
6368  
6369				matrix.multiplyMatrices( camera.projectionMatrix, matrix.getInverse( camera.matrixWorld ) );
6370				return this.applyMatrix4( matrix );
6371  
6372			};
6373  
6374		}(),
6375  
6376		unproject: function () {
6377  
6378			var matrix = new Matrix4();
6379  
6380			return function unproject( camera ) {
6381  
6382				matrix.multiplyMatrices( camera.matrixWorld, matrix.getInverse( camera.projectionMatrix ) );
6383				return this.applyMatrix4( matrix );
6384  
6385			};
6386  
6387		}(),
6388  
6389		transformDirection: function ( m ) {
6390  
6391			// input: THREE.Matrix4 affine matrix
6392			// vector interpreted as a direction
6393  
6394			var x = this.x, y = this.y, z = this.z;
6395			var e = m.elements;
6396  
6397			this.x = e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z;
6398			this.y = e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z;
6399			this.z = e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z;
6400  
6401			return this.normalize();
6402  
6403		},
6404  
6405		divide: function ( v ) {
6406  
6407			this.x /= v.x;
6408			this.y /= v.y;
6409			this.z /= v.z;
6410  
6411			return this;
6412  
6413		},
6414  
6415		divideScalar: function ( scalar ) {
6416  
6417			return this.multiplyScalar( 1 / scalar );
6418  
6419		},
6420  
6421		min: function ( v ) {
6422  
6423			this.x = Math.min( this.x, v.x );
6424			this.y = Math.min( this.y, v.y );
6425			this.z = Math.min( this.z, v.z );
6426  
6427			return this;
6428  
6429		},
6430  
6431		max: function ( v ) {
6432  
6433			this.x = Math.max( this.x, v.x );
6434			this.y = Math.max( this.y, v.y );
6435			this.z = Math.max( this.z, v.z );
6436  
6437			return this;
6438  
6439		},
6440  
6441		clamp: function ( min, max ) {
6442  
6443			// assumes min < max, componentwise
6444  
6445			this.x = Math.max( min.x, Math.min( max.x, this.x ) );
6446			this.y = Math.max( min.y, Math.min( max.y, this.y ) );
6447			this.z = Math.max( min.z, Math.min( max.z, this.z ) );
6448  
6449			return this;
6450  
6451		},
6452  
6453		clampScalar: function () {
6454  
6455			var min = new Vector3();
6456			var max = new Vector3();
6457  
6458			return function clampScalar( minVal, maxVal ) {
6459  
6460				min.set( minVal, minVal, minVal );
6461				max.set( maxVal, maxVal, maxVal );
6462  
6463				return this.clamp( min, max );
6464  
6465			};
6466  
6467		}(),
6468  
6469		clampLength: function ( min, max ) {
6470  
6471			var length = this.length();
6472  
6473			return this.divideScalar( length || 1 ).multiplyScalar( Math.max( min, Math.min( max, length ) ) );
6474  
6475		},
6476  
6477		floor: function () {
6478  
6479			this.x = Math.floor( this.x );
6480			this.y = Math.floor( this.y );
6481			this.z = Math.floor( this.z );
6482  
6483			return this;
6484  
6485		},
6486  
6487		ceil: function () {
6488  
6489			this.x = Math.ceil( this.x );
6490			this.y = Math.ceil( this.y );
6491			this.z = Math.ceil( this.z );
6492  
6493			return this;
6494  
6495		},
6496  
6497		round: function () {
6498  
6499			this.x = Math.round( this.x );
6500			this.y = Math.round( this.y );
6501			this.z = Math.round( this.z );
6502  
6503			return this;
6504  
6505		},
6506  
6507		roundToZero: function () {
6508  
6509			this.x = ( this.x < 0 ) ? Math.ceil( this.x ) : Math.floor( this.x );
6510			this.y = ( this.y < 0 ) ? Math.ceil( this.y ) : Math.floor( this.y );
6511			this.z = ( this.z < 0 ) ? Math.ceil( this.z ) : Math.floor( this.z );
6512  
6513			return this;
6514  
6515		},
6516  
6517		negate: function () {
6518  
6519			this.x = - this.x;
6520			this.y = - this.y;
6521			this.z = - this.z;
6522  
6523			return this;
6524  
6525		},
6526  
6527		dot: function ( v ) {
6528  
6529			return this.x * v.x + this.y * v.y + this.z * v.z;
6530  
6531		},
6532  
6533		// TODO lengthSquared?
6534  
6535		lengthSq: function () {
6536  
6537			return this.x * this.x + this.y * this.y + this.z * this.z;
6538  
6539		},
6540  
6541		length: function () {
6542  
6543			return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z );
6544  
6545		},
6546  
6547		manhattanLength: function () {
6548  
6549			return Math.abs( this.x ) + Math.abs( this.y ) + Math.abs( this.z );
6550  
6551		},
6552  
6553		normalize: function () {
6554  
6555			return this.divideScalar( this.length() || 1 );
6556  
6557		},
6558  
6559		setLength: function ( length ) {
6560  
6561			return this.normalize().multiplyScalar( length );
6562  
6563		},
6564  
6565		lerp: function ( v, alpha ) {
6566  
6567			this.x += ( v.x - this.x ) * alpha;
6568			this.y += ( v.y - this.y ) * alpha;
6569			this.z += ( v.z - this.z ) * alpha;
6570  
6571			return this;
6572  
6573		},
6574  
6575		lerpVectors: function ( v1, v2, alpha ) {
6576  
6577			return this.subVectors( v2, v1 ).multiplyScalar( alpha ).add( v1 );
6578  
6579		},
6580  
6581		cross: function ( v, w ) {
6582  
6583			if ( w !== undefined ) {
6584  
6585				console.warn( 'THREE.Vector3: .cross() now only accepts one argument. Use .crossVectors( a, b ) instead.' );
6586				return this.crossVectors( v, w );
6587  
6588			}
6589  
6590			return this.crossVectors( this, v );
6591  
6592		},
6593  
6594		crossVectors: function ( a, b ) {
6595  
6596			var ax = a.x, ay = a.y, az = a.z;
6597			var bx = b.x, by = b.y, bz = b.z;
6598  
6599			this.x = ay * bz - az * by;
6600			this.y = az * bx - ax * bz;
6601			this.z = ax * by - ay * bx;
6602  
6603			return this;
6604  
6605		},
6606  
6607		projectOnVector: function ( vector ) {
6608  
6609			var scalar = vector.dot( this ) / vector.lengthSq();
6610  
6611			return this.copy( vector ).multiplyScalar( scalar );
6612  
6613		},
6614  
6615		projectOnPlane: function () {
6616  
6617			var v1 = new Vector3();
6618  
6619			return function projectOnPlane( planeNormal ) {
6620  
6621				v1.copy( this ).projectOnVector( planeNormal );
6622  
6623				return this.sub( v1 );
6624  
6625			};
6626  
6627		}(),
6628  
6629		reflect: function () {
6630  
6631			// reflect incident vector off plane orthogonal to normal
6632			// normal is assumed to have unit length
6633  
6634			var v1 = new Vector3();
6635  
6636			return function reflect( normal ) {
6637  
6638				return this.sub( v1.copy( normal ).multiplyScalar( 2 * this.dot( normal ) ) );
6639  
6640			};
6641  
6642		}(),
6643  
6644		angleTo: function ( v ) {
6645  
6646			var theta = this.dot( v ) / ( Math.sqrt( this.lengthSq() * v.lengthSq() ) );
6647  
6648			// clamp, to handle numerical problems
6649  
6650			return Math.acos( _Math.clamp( theta, - 1, 1 ) );
6651  
6652		},
6653  
6654		distanceTo: function ( v ) {
6655  
6656			return Math.sqrt( this.distanceToSquared( v ) );
6657  
6658		},
6659  
6660		distanceToSquared: function ( v ) {
6661  
6662			var dx = this.x - v.x, dy = this.y - v.y, dz = this.z - v.z;
6663  
6664			return dx * dx + dy * dy + dz * dz;
6665  
6666		},
6667  
6668		manhattanDistanceTo: function ( v ) {
6669  
6670			return Math.abs( this.x - v.x ) + Math.abs( this.y - v.y ) + Math.abs( this.z - v.z );
6671  
6672		},
6673  
6674		setFromSpherical: function ( s ) {
6675  
6676			var sinPhiRadius = Math.sin( s.phi ) * s.radius;
6677  
6678			this.x = sinPhiRadius * Math.sin( s.theta );
6679			this.y = Math.cos( s.phi ) * s.radius;
6680			this.z = sinPhiRadius * Math.cos( s.theta );
6681  
6682			return this;
6683  
6684		},
6685  
6686		setFromCylindrical: function ( c ) {
6687  
6688			this.x = c.radius * Math.sin( c.theta );
6689			this.y = c.y;
6690			this.z = c.radius * Math.cos( c.theta );
6691  
6692			return this;
6693  
6694		},
6695  
6696		setFromMatrixPosition: function ( m ) {
6697  
6698			var e = m.elements;
6699  
6700			this.x = e[ 12 ];
6701			this.y = e[ 13 ];
6702			this.z = e[ 14 ];
6703  
6704			return this;
6705  
6706		},
6707  
6708		setFromMatrixScale: function ( m ) {
6709  
6710			var sx = this.setFromMatrixColumn( m, 0 ).length();
6711			var sy = this.setFromMatrixColumn( m, 1 ).length();
6712			var sz = this.setFromMatrixColumn( m, 2 ).length();
6713  
6714			this.x = sx;
6715			this.y = sy;
6716			this.z = sz;
6717  
6718			return this;
6719  
6720		},
6721  
6722		setFromMatrixColumn: function ( m, index ) {
6723  
6724			return this.fromArray( m.elements, index * 4 );
6725  
6726		},
6727  
6728		equals: function ( v ) {
6729  
6730			return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) );
6731  
6732		},
6733  
6734		fromArray: function ( array, offset ) {
6735  
6736			if ( offset === undefined ) offset = 0;
6737  
6738			this.x = array[ offset ];
6739			this.y = array[ offset + 1 ];
6740			this.z = array[ offset + 2 ];
6741  
6742			return this;
6743  
6744		},
6745  
6746		toArray: function ( array, offset ) {
6747  
6748			if ( array === undefined ) array = [];
6749			if ( offset === undefined ) offset = 0;
6750  
6751			array[ offset ] = this.x;
6752			array[ offset + 1 ] = this.y;
6753			array[ offset + 2 ] = this.z;
6754  
6755			return array;
6756  
6757		},
6758  
6759		fromBufferAttribute: function ( attribute, index, offset ) {
6760  
6761			if ( offset !== undefined ) {
6762  
6763				console.warn( 'THREE.Vector3: offset has been removed from .fromBufferAttribute().' );
6764  
6765			}
6766  
6767			this.x = attribute.getX( index );
6768			this.y = attribute.getY( index );
6769			this.z = attribute.getZ( index );
6770  
6771			return this;
6772  
6773		}
6774  
6775	} );
6776  
6777	/**
6778	 * @author alteredq / http://alteredqualia.com/
6779	 * @author WestLangley / http://github.com/WestLangley
6780	 * @author bhouston / http://clara.io
6781	 * @author tschw
6782	 */
6783  
6784	function Matrix3() {
6785  
6786		this.elements = [
6787  
6788			1, 0, 0,
6789			0, 1, 0,
6790			0, 0, 1
6791  
6792		];
6793  
6794		if ( arguments.length > 0 ) {
6795  
6796			console.error( 'THREE.Matrix3: the constructor no longer reads arguments. use .set() instead.' );
6797  
6798		}
6799  
6800	}
6801  
6802	Object.assign( Matrix3.prototype, {
6803  
6804		isMatrix3: true,
6805  
6806		set: function ( n11, n12, n13, n21, n22, n23, n31, n32, n33 ) {
6807  
6808			var te = this.elements;
6809  
6810			te[ 0 ] = n11; te[ 1 ] = n21; te[ 2 ] = n31;
6811			te[ 3 ] = n12; te[ 4 ] = n22; te[ 5 ] = n32;
6812			te[ 6 ] = n13; te[ 7 ] = n23; te[ 8 ] = n33;
6813  
6814			return this;
6815  
6816		},
6817  
6818		identity: function () {
6819  
6820			this.set(
6821  
6822				1, 0, 0,
6823				0, 1, 0,
6824				0, 0, 1
6825  
6826			);
6827  
6828			return this;
6829  
6830		},
6831  
6832		clone: function () {
6833  
6834			return new this.constructor().fromArray( this.elements );
6835  
6836		},
6837  
6838		copy: function ( m ) {
6839  
6840			var te = this.elements;
6841			var me = m.elements;
6842  
6843			te[ 0 ] = me[ 0 ]; te[ 1 ] = me[ 1 ]; te[ 2 ] = me[ 2 ];
6844			te[ 3 ] = me[ 3 ]; te[ 4 ] = me[ 4 ]; te[ 5 ] = me[ 5 ];
6845			te[ 6 ] = me[ 6 ]; te[ 7 ] = me[ 7 ]; te[ 8 ] = me[ 8 ];
6846  
6847			return this;
6848  
6849		},
6850  
6851		setFromMatrix4: function ( m ) {
6852  
6853			var me = m.elements;
6854  
6855			this.set(
6856  
6857				me[ 0 ], me[ 4 ], me[ 8 ],
6858				me[ 1 ], me[ 5 ], me[ 9 ],
6859				me[ 2 ], me[ 6 ], me[ 10 ]
6860  
6861			);
6862  
6863			return this;
6864  
6865		},
6866  
6867		applyToBufferAttribute: function () {
6868  
6869			var v1 = new Vector3();
6870  
6871			return function applyToBufferAttribute( attribute ) {
6872  
6873				for ( var i = 0, l = attribute.count; i < l; i ++ ) {
6874  
6875					v1.x = attribute.getX( i );
6876					v1.y = attribute.getY( i );
6877					v1.z = attribute.getZ( i );
6878  
6879					v1.applyMatrix3( this );
6880  
6881					attribute.setXYZ( i, v1.x, v1.y, v1.z );
6882  
6883				}
6884  
6885				return attribute;
6886  
6887			};
6888  
6889		}(),
6890  
6891		multiply: function ( m ) {
6892  
6893			return this.multiplyMatrices( this, m );
6894  
6895		},
6896  
6897		premultiply: function ( m ) {
6898  
6899			return this.multiplyMatrices( m, this );
6900  
6901		},
6902  
6903		multiplyMatrices: function ( a, b ) {
6904  
6905			var ae = a.elements;
6906			var be = b.elements;
6907			var te = this.elements;
6908  
6909			var a11 = ae[ 0 ], a12 = ae[ 3 ], a13 = ae[ 6 ];
6910			var a21 = ae[ 1 ], a22 = ae[ 4 ], a23 = ae[ 7 ];
6911			var a31 = ae[ 2 ], a32 = ae[ 5 ], a33 = ae[ 8 ];
6912  
6913			var b11 = be[ 0 ], b12 = be[ 3 ], b13 = be[ 6 ];
6914			var b21 = be[ 1 ], b22 = be[ 4 ], b23 = be[ 7 ];
6915			var b31 = be[ 2 ], b32 = be[ 5 ], b33 = be[ 8 ];
6916  
6917			te[ 0 ] = a11 * b11 + a12 * b21 + a13 * b31;
6918			te[ 3 ] = a11 * b12 + a12 * b22 + a13 * b32;
6919			te[ 6 ] = a11 * b13 + a12 * b23 + a13 * b33;
6920  
6921			te[ 1 ] = a21 * b11 + a22 * b21 + a23 * b31;
6922			te[ 4 ] = a21 * b12 + a22 * b22 + a23 * b32;
6923			te[ 7 ] = a21 * b13 + a22 * b23 + a23 * b33;
6924  
6925			te[ 2 ] = a31 * b11 + a32 * b21 + a33 * b31;
6926			te[ 5 ] = a31 * b12 + a32 * b22 + a33 * b32;
6927			te[ 8 ] = a31 * b13 + a32 * b23 + a33 * b33;
6928  
6929			return this;
6930  
6931		},
6932  
6933		multiplyScalar: function ( s ) {
6934  
6935			var te = this.elements;
6936  
6937			te[ 0 ] *= s; te[ 3 ] *= s; te[ 6 ] *= s;
6938			te[ 1 ] *= s; te[ 4 ] *= s; te[ 7 ] *= s;
6939			te[ 2 ] *= s; te[ 5 ] *= s; te[ 8 ] *= s;
6940  
6941			return this;
6942  
6943		},
6944  
6945		determinant: function () {
6946  
6947			var te = this.elements;
6948  
6949			var a = te[ 0 ], b = te[ 1 ], c = te[ 2 ],
6950				d = te[ 3 ], e = te[ 4 ], f = te[ 5 ],
6951				g = te[ 6 ], h = te[ 7 ], i = te[ 8 ];
6952  
6953			return a * e * i - a * f * h - b * d * i + b * f * g + c * d * h - c * e * g;
6954  
6955		},
6956  
6957		getInverse: function ( matrix, throwOnDegenerate ) {
6958  
6959			if ( matrix && matrix.isMatrix4 ) {
6960  
6961				console.error( "THREE.Matrix3: .getInverse() no longer takes a Matrix4 argument." );
6962  
6963			}
6964  
6965			var me = matrix.elements,
6966				te = this.elements,
6967  
6968				n11 = me[ 0 ], n21 = me[ 1 ], n31 = me[ 2 ],
6969				n12 = me[ 3 ], n22 = me[ 4 ], n32 = me[ 5 ],
6970				n13 = me[ 6 ], n23 = me[ 7 ], n33 = me[ 8 ],
6971  
6972				t11 = n33 * n22 - n32 * n23,
6973				t12 = n32 * n13 - n33 * n12,
6974				t13 = n23 * n12 - n22 * n13,
6975  
6976				det = n11 * t11 + n21 * t12 + n31 * t13;
6977  
6978			if ( det === 0 ) {
6979  
6980				var msg = "THREE.Matrix3: .getInverse() can't invert matrix, determinant is 0";
6981  
6982				if ( throwOnDegenerate === true ) {
6983  
6984					throw new Error( msg );
6985  
6986				} else {
6987  
6988					console.warn( msg );
6989  
6990				}
6991  
6992				return this.identity();
6993  
6994			}
6995  
6996			var detInv = 1 / det;
6997  
6998			te[ 0 ] = t11 * detInv;
6999			te[ 1 ] = ( n31 * n23 - n33 * n21 ) * detInv;
7000			te[ 2 ] = ( n32 * n21 - n31 * n22 ) * detInv;
7001  
7002			te[ 3 ] = t12 * detInv;
7003			te[ 4 ] = ( n33 * n11 - n31 * n13 ) * detInv;
7004			te[ 5 ] = ( n31 * n12 - n32 * n11 ) * detInv;
7005  
7006			te[ 6 ] = t13 * detInv;
7007			te[ 7 ] = ( n21 * n13 - n23 * n11 ) * detInv;
7008			te[ 8 ] = ( n22 * n11 - n21 * n12 ) * detInv;
7009  
7010			return this;
7011  
7012		},
7013  
7014		transpose: function () {
7015  
7016			var tmp, m = this.elements;
7017  
7018			tmp = m[ 1 ]; m[ 1 ] = m[ 3 ]; m[ 3 ] = tmp;
7019			tmp = m[ 2 ]; m[ 2 ] = m[ 6 ]; m[ 6 ] = tmp;
7020			tmp = m[ 5 ]; m[ 5 ] = m[ 7 ]; m[ 7 ] = tmp;
7021  
7022			return this;
7023  
7024		},
7025  
7026		getNormalMatrix: function ( matrix4 ) {
7027  
7028			return this.setFromMatrix4( matrix4 ).getInverse( this ).transpose();
7029  
7030		},
7031  
7032		transposeIntoArray: function ( r ) {
7033  
7034			var m = this.elements;
7035  
7036			r[ 0 ] = m[ 0 ];
7037			r[ 1 ] = m[ 3 ];
7038			r[ 2 ] = m[ 6 ];
7039			r[ 3 ] = m[ 1 ];
7040			r[ 4 ] = m[ 4 ];
7041			r[ 5 ] = m[ 7 ];
7042			r[ 6 ] = m[ 2 ];
7043			r[ 7 ] = m[ 5 ];
7044			r[ 8 ] = m[ 8 ];
7045  
7046			return this;
7047  
7048		},
7049  
7050		setUvTransform: function ( tx, ty, sx, sy, rotation, cx, cy ) {
7051  
7052			var c = Math.cos( rotation );
7053			var s = Math.sin( rotation );
7054  
7055			this.set(
7056				sx * c, sx * s, - sx * ( c * cx + s * cy ) + cx + tx,
7057				- sy * s, sy * c, - sy * ( - s * cx + c * cy ) + cy + ty,
7058				0, 0, 1
7059			);
7060  
7061		},
7062  
7063		scale: function ( sx, sy ) {
7064  
7065			var te = this.elements;
7066  
7067			te[ 0 ] *= sx; te[ 3 ] *= sx; te[ 6 ] *= sx;
7068			te[ 1 ] *= sy; te[ 4 ] *= sy; te[ 7 ] *= sy;
7069  
7070			return this;
7071  
7072		},
7073  
7074		rotate: function ( theta ) {
7075  
7076			var c = Math.cos( theta );
7077			var s = Math.sin( theta );
7078  
7079			var te = this.elements;
7080  
7081			var a11 = te[ 0 ], a12 = te[ 3 ], a13 = te[ 6 ];
7082			var a21 = te[ 1 ], a22 = te[ 4 ], a23 = te[ 7 ];
7083  
7084			te[ 0 ] = c * a11 + s * a21;
7085			te[ 3 ] = c * a12 + s * a22;
7086			te[ 6 ] = c * a13 + s * a23;
7087  
7088			te[ 1 ] = - s * a11 + c * a21;
7089			te[ 4 ] = - s * a12 + c * a22;
7090			te[ 7 ] = - s * a13 + c * a23;
7091  
7092			return this;
7093  
7094		},
7095  
7096		translate: function ( tx, ty ) {
7097  
7098			var te = this.elements;
7099  
7100			te[ 0 ] += tx * te[ 2 ]; te[ 3 ] += tx * te[ 5 ]; te[ 6 ] += tx * te[ 8 ];
7101			te[ 1 ] += ty * te[ 2 ]; te[ 4 ] += ty * te[ 5 ]; te[ 7 ] += ty * te[ 8 ];
7102  
7103			return this;
7104  
7105		},
7106  
7107		equals: function ( matrix ) {
7108  
7109			var te = this.elements;
7110			var me = matrix.elements;
7111  
7112			for ( var i = 0; i < 9; i ++ ) {
7113  
7114				if ( te[ i ] !== me[ i ] ) return false;
7115  
7116			}
7117  
7118			return true;
7119  
7120		},
7121  
7122		fromArray: function ( array, offset ) {
7123  
7124			if ( offset === undefined ) offset = 0;
7125  
7126			for ( var i = 0; i < 9; i ++ ) {
7127  
7128				this.elements[ i ] = array[ i + offset ];
7129  
7130			}
7131  
7132			return this;
7133  
7134		},
7135  
7136		toArray: function ( array, offset ) {
7137  
7138			if ( array === undefined ) array = [];
7139			if ( offset === undefined ) offset = 0;
7140  
7141			var te = this.elements;
7142  
7143			array[ offset ] = te[ 0 ];
7144			array[ offset + 1 ] = te[ 1 ];
7145			array[ offset + 2 ] = te[ 2 ];
7146  
7147			array[ offset + 3 ] = te[ 3 ];
7148			array[ offset + 4 ] = te[ 4 ];
7149			array[ offset + 5 ] = te[ 5 ];
7150  
7151			array[ offset + 6 ] = te[ 6 ];
7152			array[ offset + 7 ] = te[ 7 ];
7153			array[ offset + 8 ] = te[ 8 ];
7154  
7155			return array;
7156  
7157		}
7158  
7159	} );
7160  
7161	/**
7162	 * @author mrdoob / http://mrdoob.com/
7163	 * @author alteredq / http://alteredqualia.com/
7164	 * @author szimek / https://github.com/szimek/
7165	 */
7166  
7167	var textureId = 0;
7168  
7169	function Texture( image, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding ) {
7170  
7171		Object.defineProperty( this, 'id', { value: textureId ++ } );
7172  
7173		this.uuid = _Math.generateUUID();
7174  
7175		this.name = '';
7176  
7177		this.image = image !== undefined ? image : Texture.DEFAULT_IMAGE;
7178		this.mipmaps = [];
7179  
7180		this.mapping = mapping !== undefined ? mapping : Texture.DEFAULT_MAPPING;
7181  
7182		this.wrapS = wrapS !== undefined ? wrapS : ClampToEdgeWrapping;
7183		this.wrapT = wrapT !== undefined ? wrapT : ClampToEdgeWrapping;
7184  
7185		this.magFilter = magFilter !== undefined ? magFilter : LinearFilter;
7186		this.minFilter = minFilter !== undefined ? minFilter : LinearMipMapLinearFilter;
7187  
7188		this.anisotropy = anisotropy !== undefined ? anisotropy : 1;
7189  
7190		this.format = format !== undefined ? format : RGBAFormat;
7191		this.type = type !== undefined ? type : UnsignedByteType;
7192  
7193		this.offset = new Vector2( 0, 0 );
7194		this.repeat = new Vector2( 1, 1 );
7195		this.center = new Vector2( 0, 0 );
7196		this.rotation = 0;
7197  
7198		this.matrixAutoUpdate = true;
7199		this.matrix = new Matrix3();
7200  
7201		this.generateMipmaps = true;
7202		this.premultiplyAlpha = false;
7203		this.flipY = true;
7204		this.unpackAlignment = 4;	// valid values: 1, 2, 4, 8 (see http://www.khronos.org/opengles/sdk/docs/man/xhtml/glPixelStorei.xml)
7205  
7206		// Values of encoding !== THREE.LinearEncoding only supported on map, envMap and emissiveMap.
7207		//
7208		// Also changing the encoding after already used by a Material will not automatically make the Material
7209		// update.  You need to explicitly call Material.needsUpdate to trigger it to recompile.
7210		this.encoding = encoding !== undefined ? encoding : LinearEncoding;
7211  
7212		this.version = 0;
7213		this.onUpdate = null;
7214  
7215	}
7216  
7217	Texture.DEFAULT_IMAGE = undefined;
7218	Texture.DEFAULT_MAPPING = UVMapping;
7219  
7220	Texture.prototype = Object.assign( Object.create( EventDispatcher.prototype ), {
7221  
7222		constructor: Texture,
7223  
7224		isTexture: true,
7225  
7226		updateMatrix: function () {
7227  
7228			this.matrix.setUvTransform( this.offset.x, this.offset.y, this.repeat.x, this.repeat.y, this.rotation, this.center.x, this.center.y );
7229  
7230		},
7231  
7232		clone: function () {
7233  
7234			return new this.constructor().copy( this );
7235  
7236		},
7237  
7238		copy: function ( source ) {
7239  
7240			this.name = source.name;
7241  
7242			this.image = source.image;
7243			this.mipmaps = source.mipmaps.slice( 0 );
7244  
7245			this.mapping = source.mapping;
7246  
7247			this.wrapS = source.wrapS;
7248			this.wrapT = source.wrapT;
7249  
7250			this.magFilter = source.magFilter;
7251			this.minFilter = source.minFilter;
7252  
7253			this.anisotropy = source.anisotropy;
7254  
7255			this.format = source.format;
7256			this.type = source.type;
7257  
7258			this.offset.copy( source.offset );
7259			this.repeat.copy( source.repeat );
7260			this.center.copy( source.center );
7261			this.rotation = source.rotation;
7262  
7263			this.matrixAutoUpdate = source.matrixAutoUpdate;
7264			this.matrix.copy( source.matrix );
7265  
7266			this.generateMipmaps = source.generateMipmaps;
7267			this.premultiplyAlpha = source.premultiplyAlpha;
7268			this.flipY = source.flipY;
7269			this.unpackAlignment = source.unpackAlignment;
7270			this.encoding = source.encoding;
7271  
7272			return this;
7273  
7274		},
7275  
7276		toJSON: function ( meta ) {
7277  
7278			var isRootObject = ( meta === undefined || typeof meta === 'string' );
7279  
7280			if ( ! isRootObject && meta.textures[ this.uuid ] !== undefined ) {
7281  
7282				return meta.textures[ this.uuid ];
7283  
7284			}
7285  
7286			function getDataURL( image ) {
7287  
7288				var canvas;
7289  
7290				if ( image instanceof HTMLCanvasElement ) {
7291  
7292					canvas = image;
7293  
7294				} else {
7295  
7296					canvas = document.createElementNS( 'http://www.w3.org/1999/xhtml', 'canvas' );
7297					canvas.width = image.width;
7298					canvas.height = image.height;
7299  
7300					var context = canvas.getContext( '2d' );
7301  
7302					if ( image instanceof ImageData ) {
7303  
7304						context.putImageData( image, 0, 0 );
7305  
7306					} else {
7307  
7308						context.drawImage( image, 0, 0, image.width, image.height );
7309  
7310					}
7311  
7312				}
7313  
7314				if ( canvas.width > 2048 || canvas.height > 2048 ) {
7315  
7316					return canvas.toDataURL( 'image/jpeg', 0.6 );
7317  
7318				} else {
7319  
7320					return canvas.toDataURL( 'image/png' );
7321  
7322				}
7323  
7324			}
7325  
7326			var output = {
7327  
7328				metadata: {
7329					version: 4.5,
7330					type: 'Texture',
7331					generator: 'Texture.toJSON'
7332				},
7333  
7334				uuid: this.uuid,
7335				name: this.name,
7336  
7337				mapping: this.mapping,
7338  
7339				repeat: [ this.repeat.x, this.repeat.y ],
7340				offset: [ this.offset.x, this.offset.y ],
7341				center: [ this.center.x, this.center.y ],
7342				rotation: this.rotation,
7343  
7344				wrap: [ this.wrapS, this.wrapT ],
7345  
7346				format: this.format,
7347				minFilter: this.minFilter,
7348				magFilter: this.magFilter,
7349				anisotropy: this.anisotropy,
7350  
7351				flipY: this.flipY
7352  
7353			};
7354  
7355			if ( this.image !== undefined ) {
7356  
7357				// TODO: Move to THREE.Image
7358  
7359				var image = this.image;
7360  
7361				if ( image.uuid === undefined ) {
7362  
7363					image.uuid = _Math.generateUUID(); // UGH
7364  
7365				}
7366  
7367				if ( ! isRootObject && meta.images[ image.uuid ] === undefined ) {
7368  
7369					meta.images[ image.uuid ] = {
7370						uuid: image.uuid,
7371						url: getDataURL( image )
7372					};
7373  
7374				}
7375  
7376				output.image = image.uuid;
7377  
7378			}
7379  
7380			if ( ! isRootObject ) {
7381  
7382				meta.textures[ this.uuid ] = output;
7383  
7384			}
7385  
7386			return output;
7387  
7388		},
7389  
7390		dispose: function () {
7391  
7392			this.dispatchEvent( { type: 'dispose' } );
7393  
7394		},
7395  
7396		transformUv: function ( uv ) {
7397  
7398			if ( this.mapping !== UVMapping ) return;
7399  
7400			uv.applyMatrix3( this.matrix );
7401  
7402			if ( uv.x < 0 || uv.x > 1 ) {
7403  
7404				switch ( this.wrapS ) {
7405  
7406					case RepeatWrapping:
7407  
7408						uv.x = uv.x - Math.floor( uv.x );
7409						break;
7410  
7411					case ClampToEdgeWrapping:
7412  
7413						uv.x = uv.x < 0 ? 0 : 1;
7414						break;
7415  
7416					case MirroredRepeatWrapping:
7417  
7418						if ( Math.abs( Math.floor( uv.x ) % 2 ) === 1 ) {
7419  
7420							uv.x = Math.ceil( uv.x ) - uv.x;
7421  
7422						} else {
7423  
7424							uv.x = uv.x - Math.floor( uv.x );
7425  
7426						}
7427						break;
7428  
7429				}
7430  
7431			}
7432  
7433			if ( uv.y < 0 || uv.y > 1 ) {
7434  
7435				switch ( this.wrapT ) {
7436  
7437					case RepeatWrapping:
7438  
7439						uv.y = uv.y - Math.floor( uv.y );
7440						break;
7441  
7442					case ClampToEdgeWrapping:
7443  
7444						uv.y = uv.y < 0 ? 0 : 1;
7445						break;
7446  
7447					case MirroredRepeatWrapping:
7448  
7449						if ( Math.abs( Math.floor( uv.y ) % 2 ) === 1 ) {
7450  
7451							uv.y = Math.ceil( uv.y ) - uv.y;
7452  
7453						} else {
7454  
7455							uv.y = uv.y - Math.floor( uv.y );
7456  
7457						}
7458						break;
7459  
7460				}
7461  
7462			}
7463  
7464			if ( this.flipY ) {
7465  
7466				uv.y = 1 - uv.y;
7467  
7468			}
7469  
7470		}
7471  
7472	} );
7473  
7474	Object.defineProperty( Texture.prototype, "needsUpdate", {
7475  
7476		set: function ( value ) {
7477  
7478			if ( value === true ) this.version ++;
7479  
7480		}
7481  
7482	} );
7483  
7484	/**
7485	 * @author supereggbert / http://www.paulbrunt.co.uk/
7486	 * @author philogb / http://blog.thejit.org/
7487	 * @author mikael emtinger / http://gomo.se/
7488	 * @author egraether / http://egraether.com/
7489	 * @author WestLangley / http://github.com/WestLangley
7490	 */
7491  
7492	function Vector4( x, y, z, w ) {
7493  
7494		this.x = x || 0;
7495		this.y = y || 0;
7496		this.z = z || 0;
7497		this.w = ( w !== undefined ) ? w : 1;
7498  
7499	}
7500  
7501	Object.assign( Vector4.prototype, {
7502  
7503		isVector4: true,
7504  
7505		set: function ( x, y, z, w ) {
7506  
7507			this.x = x;
7508			this.y = y;
7509			this.z = z;
7510			this.w = w;
7511  
7512			return this;
7513  
7514		},
7515  
7516		setScalar: function ( scalar ) {
7517  
7518			this.x = scalar;
7519			this.y = scalar;
7520			this.z = scalar;
7521			this.w = scalar;
7522  
7523			return this;
7524  
7525		},
7526  
7527		setX: function ( x ) {
7528  
7529			this.x = x;
7530  
7531			return this;
7532  
7533		},
7534  
7535		setY: function ( y ) {
7536  
7537			this.y = y;
7538  
7539			return this;
7540  
7541		},
7542  
7543		setZ: function ( z ) {
7544  
7545			this.z = z;
7546  
7547			return this;
7548  
7549		},
7550  
7551		setW: function ( w ) {
7552  
7553			this.w = w;
7554  
7555			return this;
7556  
7557		},
7558  
7559		setComponent: function ( index, value ) {
7560  
7561			switch ( index ) {
7562  
7563				case 0: this.x = value; break;
7564				case 1: this.y = value; break;
7565				case 2: this.z = value; break;
7566				case 3: this.w = value; break;
7567				default: throw new Error( 'index is out of range: ' + index );
7568  
7569			}
7570  
7571			return this;
7572  
7573		},
7574  
7575		getComponent: function ( index ) {
7576  
7577			switch ( index ) {
7578  
7579				case 0: return this.x;
7580				case 1: return this.y;
7581				case 2: return this.z;
7582				case 3: return this.w;
7583				default: throw new Error( 'index is out of range: ' + index );
7584  
7585			}
7586  
7587		},
7588  
7589		clone: function () {
7590  
7591			return new this.constructor( this.x, this.y, this.z, this.w );
7592  
7593		},
7594  
7595		copy: function ( v ) {
7596  
7597			this.x = v.x;
7598			this.y = v.y;
7599			this.z = v.z;
7600			this.w = ( v.w !== undefined ) ? v.w : 1;
7601  
7602			return this;
7603  
7604		},
7605  
7606		add: function ( v, w ) {
7607  
7608			if ( w !== undefined ) {
7609  
7610				console.warn( 'THREE.Vector4: .add() now only accepts one argument. Use .addVectors( a, b ) instead.' );
7611				return this.addVectors( v, w );
7612  
7613			}
7614  
7615			this.x += v.x;
7616			this.y += v.y;
7617			this.z += v.z;
7618			this.w += v.w;
7619  
7620			return this;
7621  
7622		},
7623  
7624		addScalar: function ( s ) {
7625  
7626			this.x += s;
7627			this.y += s;
7628			this.z += s;
7629			this.w += s;
7630  
7631			return this;
7632  
7633		},
7634  
7635		addVectors: function ( a, b ) {
7636  
7637			this.x = a.x + b.x;
7638			this.y = a.y + b.y;
7639			this.z = a.z + b.z;
7640			this.w = a.w + b.w;
7641  
7642			return this;
7643  
7644		},
7645  
7646		addScaledVector: function ( v, s ) {
7647  
7648			this.x += v.x * s;
7649			this.y += v.y * s;
7650			this.z += v.z * s;
7651			this.w += v.w * s;
7652  
7653			return this;
7654  
7655		},
7656  
7657		sub: function ( v, w ) {
7658  
7659			if ( w !== undefined ) {
7660  
7661				console.warn( 'THREE.Vector4: .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' );
7662				return this.subVectors( v, w );
7663  
7664			}
7665  
7666			this.x -= v.x;
7667			this.y -= v.y;
7668			this.z -= v.z;
7669			this.w -= v.w;
7670  
7671			return this;
7672  
7673		},
7674  
7675		subScalar: function ( s ) {
7676  
7677			this.x -= s;
7678			this.y -= s;
7679			this.z -= s;
7680			this.w -= s;
7681  
7682			return this;
7683  
7684		},
7685  
7686		subVectors: function ( a, b ) {
7687  
7688			this.x = a.x - b.x;
7689			this.y = a.y - b.y;
7690			this.z = a.z - b.z;
7691			this.w = a.w - b.w;
7692  
7693			return this;
7694  
7695		},
7696  
7697		multiplyScalar: function ( scalar ) {
7698  
7699			this.x *= scalar;
7700			this.y *= scalar;
7701			this.z *= scalar;
7702			this.w *= scalar;
7703  
7704			return this;
7705  
7706		},
7707  
7708		applyMatrix4: function ( m ) {
7709  
7710			var x = this.x, y = this.y, z = this.z, w = this.w;
7711			var e = m.elements;
7712  
7713			this.x = e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z + e[ 12 ] * w;
7714			this.y = e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z + e[ 13 ] * w;
7715			this.z = e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z + e[ 14 ] * w;
7716			this.w = e[ 3 ] * x + e[ 7 ] * y + e[ 11 ] * z + e[ 15 ] * w;
7717  
7718			return this;
7719  
7720		},
7721  
7722		divideScalar: function ( scalar ) {
7723  
7724			return this.multiplyScalar( 1 / scalar );
7725  
7726		},
7727  
7728		setAxisAngleFromQuaternion: function ( q ) {
7729  
7730			// http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToAngle/index.htm
7731  
7732			// q is assumed to be normalized
7733  
7734			this.w = 2 * Math.acos( q.w );
7735  
7736			var s = Math.sqrt( 1 - q.w * q.w );
7737  
7738			if ( s < 0.0001 ) {
7739  
7740				this.x = 1;
7741				this.y = 0;
7742				this.z = 0;
7743  
7744			} else {
7745  
7746				this.x = q.x / s;
7747				this.y = q.y / s;
7748				this.z = q.z / s;
7749  
7750			}
7751  
7752			return this;
7753  
7754		},
7755  
7756		setAxisAngleFromRotationMatrix: function ( m ) {
7757  
7758			// http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToAngle/index.htm
7759  
7760			// assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)
7761  
7762			var angle, x, y, z,		// variables for result
7763				epsilon = 0.01,		// margin to allow for rounding errors
7764				epsilon2 = 0.1,		// margin to distinguish between 0 and 180 degrees
7765  
7766				te = m.elements,
7767  
7768				m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ],
7769				m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ],
7770				m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ];
7771  
7772			if ( ( Math.abs( m12 - m21 ) < epsilon ) &&
7773				 ( Math.abs( m13 - m31 ) < epsilon ) &&
7774				 ( Math.abs( m23 - m32 ) < epsilon ) ) {
7775  
7776				// singularity found
7777				// first check for identity matrix which must have +1 for all terms
7778				// in leading diagonal and zero in other terms
7779  
7780				if ( ( Math.abs( m12 + m21 ) < epsilon2 ) &&
7781					 ( Math.abs( m13 + m31 ) < epsilon2 ) &&
7782					 ( Math.abs( m23 + m32 ) < epsilon2 ) &&
7783					 ( Math.abs( m11 + m22 + m33 - 3 ) < epsilon2 ) ) {
7784  
7785					// this singularity is identity matrix so angle = 0
7786  
7787					this.set( 1, 0, 0, 0 );
7788  
7789					return this; // zero angle, arbitrary axis
7790  
7791				}
7792  
7793				// otherwise this singularity is angle = 180
7794  
7795				angle = Math.PI;
7796  
7797				var xx = ( m11 + 1 ) / 2;
7798				var yy = ( m22 + 1 ) / 2;
7799				var zz = ( m33 + 1 ) / 2;
7800				var xy = ( m12 + m21 ) / 4;
7801				var xz = ( m13 + m31 ) / 4;
7802				var yz = ( m23 + m32 ) / 4;
7803  
7804				if ( ( xx > yy ) && ( xx > zz ) ) {
7805  
7806					// m11 is the largest diagonal term
7807  
7808					if ( xx < epsilon ) {
7809  
7810						x = 0;
7811						y = 0.707106781;
7812						z = 0.707106781;
7813  
7814					} else {
7815  
7816						x = Math.sqrt( xx );
7817						y = xy / x;
7818						z = xz / x;
7819  
7820					}
7821  
7822				} else if ( yy > zz ) {
7823  
7824					// m22 is the largest diagonal term
7825  
7826					if ( yy < epsilon ) {
7827  
7828						x = 0.707106781;
7829						y = 0;
7830						z = 0.707106781;
7831  
7832					} else {
7833  
7834						y = Math.sqrt( yy );
7835						x = xy / y;
7836						z = yz / y;
7837  
7838					}
7839  
7840				} else {
7841  
7842					// m33 is the largest diagonal term so base result on this
7843  
7844					if ( zz < epsilon ) {
7845  
7846						x = 0.707106781;
7847						y = 0.707106781;
7848						z = 0;
7849  
7850					} else {
7851  
7852						z = Math.sqrt( zz );
7853						x = xz / z;
7854						y = yz / z;
7855  
7856					}
7857  
7858				}
7859  
7860				this.set( x, y, z, angle );
7861  
7862				return this; // return 180 deg rotation
7863  
7864			}
7865  
7866			// as we have reached here there are no singularities so we can handle normally
7867  
7868			var s = Math.sqrt( ( m32 - m23 ) * ( m32 - m23 ) +
7869							   ( m13 - m31 ) * ( m13 - m31 ) +
7870							   ( m21 - m12 ) * ( m21 - m12 ) ); // used to normalize
7871  
7872			if ( Math.abs( s ) < 0.001 ) s = 1;
7873  
7874			// prevent divide by zero, should not happen if matrix is orthogonal and should be
7875			// caught by singularity test above, but I've left it in just in case
7876  
7877			this.x = ( m32 - m23 ) / s;
7878			this.y = ( m13 - m31 ) / s;
7879			this.z = ( m21 - m12 ) / s;
7880			this.w = Math.acos( ( m11 + m22 + m33 - 1 ) / 2 );
7881  
7882			return this;
7883  
7884		},
7885  
7886		min: function ( v ) {
7887  
7888			this.x = Math.min( this.x, v.x );
7889			this.y = Math.min( this.y, v.y );
7890			this.z = Math.min( this.z, v.z );
7891			this.w = Math.min( this.w, v.w );
7892  
7893			return this;
7894  
7895		},
7896  
7897		max: function ( v ) {
7898  
7899			this.x = Math.max( this.x, v.x );
7900			this.y = Math.max( this.y, v.y );
7901			this.z = Math.max( this.z, v.z );
7902			this.w = Math.max( this.w, v.w );
7903  
7904			return this;
7905  
7906		},
7907  
7908		clamp: function ( min, max ) {
7909  
7910			// assumes min < max, componentwise
7911  
7912			this.x = Math.max( min.x, Math.min( max.x, this.x ) );
7913			this.y = Math.max( min.y, Math.min( max.y, this.y ) );
7914			this.z = Math.max( min.z, Math.min( max.z, this.z ) );
7915			this.w = Math.max( min.w, Math.min( max.w, this.w ) );
7916  
7917			return this;
7918  
7919		},
7920  
7921		clampScalar: function () {
7922  
7923			var min, max;
7924  
7925			return function clampScalar( minVal, maxVal ) {
7926  
7927				if ( min === undefined ) {
7928  
7929					min = new Vector4();
7930					max = new Vector4();
7931  
7932				}
7933  
7934				min.set( minVal, minVal, minVal, minVal );
7935				max.set( maxVal, maxVal, maxVal, maxVal );
7936  
7937				return this.clamp( min, max );
7938  
7939			};
7940  
7941		}(),
7942  
7943		clampLength: function ( min, max ) {
7944  
7945			var length = this.length();
7946  
7947			return this.divideScalar( length || 1 ).multiplyScalar( Math.max( min, Math.min( max, length ) ) );
7948  
7949		},
7950  
7951		floor: function () {
7952  
7953			this.x = Math.floor( this.x );
7954			this.y = Math.floor( this.y );
7955			this.z = Math.floor( this.z );
7956			this.w = Math.floor( this.w );
7957  
7958			return this;
7959  
7960		},
7961  
7962		ceil: function () {
7963  
7964			this.x = Math.ceil( this.x );
7965			this.y = Math.ceil( this.y );
7966			this.z = Math.ceil( this.z );
7967			this.w = Math.ceil( this.w );
7968  
7969			return this;
7970  
7971		},
7972  
7973		round: function () {
7974  
7975			this.x = Math.round( this.x );
7976			this.y = Math.round( this.y );
7977			this.z = Math.round( this.z );
7978			this.w = Math.round( this.w );
7979  
7980			return this;
7981  
7982		},
7983  
7984		roundToZero: function () {
7985  
7986			this.x = ( this.x < 0 ) ? Math.ceil( this.x ) : Math.floor( this.x );
7987			this.y = ( this.y < 0 ) ? Math.ceil( this.y ) : Math.floor( this.y );
7988			this.z = ( this.z < 0 ) ? Math.ceil( this.z ) : Math.floor( this.z );
7989			this.w = ( this.w < 0 ) ? Math.ceil( this.w ) : Math.floor( this.w );
7990  
7991			return this;
7992  
7993		},
7994  
7995		negate: function () {
7996  
7997			this.x = - this.x;
7998			this.y = - this.y;
7999			this.z = - this.z;
8000			this.w = - this.w;
8001  
8002			return this;
8003  
8004		},
8005  
8006		dot: function ( v ) {
8007  
8008			return this.x * v.x + this.y * v.y + this.z * v.z + this.w * v.w;
8009  
8010		},
8011  
8012		lengthSq: function () {
8013  
8014			return this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w;
8015  
8016		},
8017  
8018		length: function () {
8019  
8020			return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w );
8021  
8022		},
8023  
8024		manhattanLength: function () {
8025  
8026			return Math.abs( this.x ) + Math.abs( this.y ) + Math.abs( this.z ) + Math.abs( this.w );
8027  
8028		},
8029  
8030		normalize: function () {
8031  
8032			return this.divideScalar( this.length() || 1 );
8033  
8034		},
8035  
8036		setLength: function ( length ) {
8037  
8038			return this.normalize().multiplyScalar( length );
8039  
8040		},
8041  
8042		lerp: function ( v, alpha ) {
8043  
8044			this.x += ( v.x - this.x ) * alpha;
8045			this.y += ( v.y - this.y ) * alpha;
8046			this.z += ( v.z - this.z ) * alpha;
8047			this.w += ( v.w - this.w ) * alpha;
8048  
8049			return this;
8050  
8051		},
8052  
8053		lerpVectors: function ( v1, v2, alpha ) {
8054  
8055			return this.subVectors( v2, v1 ).multiplyScalar( alpha ).add( v1 );
8056  
8057		},
8058  
8059		equals: function ( v ) {
8060  
8061			return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) && ( v.w === this.w ) );
8062  
8063		},
8064  
8065		fromArray: function ( array, offset ) {
8066  
8067			if ( offset === undefined ) offset = 0;
8068  
8069			this.x = array[ offset ];
8070			this.y = array[ offset + 1 ];
8071			this.z = array[ offset + 2 ];
8072			this.w = array[ offset + 3 ];
8073  
8074			return this;
8075  
8076		},
8077  
8078		toArray: function ( array, offset ) {
8079  
8080			if ( array === undefined ) array = [];
8081			if ( offset === undefined ) offset = 0;
8082  
8083			array[ offset ] = this.x;
8084			array[ offset + 1 ] = this.y;
8085			array[ offset + 2 ] = this.z;
8086			array[ offset + 3 ] = this.w;
8087  
8088			return array;
8089  
8090		},
8091  
8092		fromBufferAttribute: function ( attribute, index, offset ) {
8093  
8094			if ( offset !== undefined ) {
8095  
8096				console.warn( 'THREE.Vector4: offset has been removed from .fromBufferAttribute().' );
8097  
8098			}
8099  
8100			this.x = attribute.getX( index );
8101			this.y = attribute.getY( index );
8102			this.z = attribute.getZ( index );
8103			this.w = attribute.getW( index );
8104  
8105			return this;
8106  
8107		}
8108  
8109	} );
8110  
8111	/**
8112	 * @author szimek / https://github.com/szimek/
8113	 * @author alteredq / http://alteredqualia.com/
8114	 * @author Marius Kintel / https://github.com/kintel
8115	 */
8116  
8117	/*
8118	 In options, we can specify:
8119	 * Texture parameters for an auto-generated target texture
8120	 * depthBuffer/stencilBuffer: Booleans to indicate if we should generate these buffers
8121	*/
8122	function WebGLRenderTarget( width, height, options ) {
8123  
8124		this.width = width;
8125		this.height = height;
8126  
8127		this.scissor = new Vector4( 0, 0, width, height );
8128		this.scissorTest = false;
8129  
8130		this.viewport = new Vector4( 0, 0, width, height );
8131  
8132		options = options || {};
8133  
8134		if ( options.minFilter === undefined ) options.minFilter = LinearFilter;
8135  
8136		this.texture = new Texture( undefined, undefined, options.wrapS, options.wrapT, options.magFilter, options.minFilter, options.format, options.type, options.anisotropy, options.encoding );
8137  
8138		this.texture.generateMipmaps = options.generateMipmaps !== undefined ? options.generateMipmaps : true;
8139  
8140		this.depthBuffer = options.depthBuffer !== undefined ? options.depthBuffer : true;
8141		this.stencilBuffer = options.stencilBuffer !== undefined ? options.stencilBuffer : true;
8142		this.depthTexture = options.depthTexture !== undefined ? options.depthTexture : null;
8143  
8144	}
8145  
8146	WebGLRenderTarget.prototype = Object.assign( Object.create( EventDispatcher.prototype ), {
8147  
8148		constructor: WebGLRenderTarget,
8149  
8150		isWebGLRenderTarget: true,
8151  
8152		setSize: function ( width, height ) {
8153  
8154			if ( this.width !== width || this.height !== height ) {
8155  
8156				this.width = width;
8157				this.height = height;
8158  
8159				this.dispose();
8160  
8161			}
8162  
8163			this.viewport.set( 0, 0, width, height );
8164			this.scissor.set( 0, 0, width, height );
8165  
8166		},
8167  
8168		clone: function () {
8169  
8170			return new this.constructor().copy( this );
8171  
8172		},
8173  
8174		copy: function ( source ) {
8175  
8176			this.width = source.width;
8177			this.height = source.height;
8178  
8179			this.viewport.copy( source.viewport );
8180  
8181			this.texture = source.texture.clone();
8182  
8183			this.depthBuffer = source.depthBuffer;
8184			this.stencilBuffer = source.stencilBuffer;
8185			this.depthTexture = source.depthTexture;
8186  
8187			return this;
8188  
8189		},
8190  
8191		dispose: function () {
8192  
8193			this.dispatchEvent( { type: 'dispose' } );
8194  
8195		}
8196  
8197	} );
8198  
8199	/**
8200	 * @author alteredq / http://alteredqualia.com
8201	 */
8202  
8203	function WebGLRenderTargetCube( width, height, options ) {
8204  
8205		WebGLRenderTarget.call( this, width, height, options );
8206  
8207		this.activeCubeFace = 0; // PX 0, NX 1, PY 2, NY 3, PZ 4, NZ 5
8208		this.activeMipMapLevel = 0;
8209  
8210	}
8211  
8212	WebGLRenderTargetCube.prototype = Object.create( WebGLRenderTarget.prototype );
8213	WebGLRenderTargetCube.prototype.constructor = WebGLRenderTargetCube;
8214  
8215	WebGLRenderTargetCube.prototype.isWebGLRenderTargetCube = true;
8216  
8217	/**
8218	 * @author alteredq / http://alteredqualia.com/
8219	 */
8220  
8221	function DataTexture( data, width, height, format, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy, encoding ) {
8222  
8223		Texture.call( this, null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding );
8224  
8225		this.image = { data: data, width: width, height: height };
8226  
8227		this.magFilter = magFilter !== undefined ? magFilter : NearestFilter;
8228		this.minFilter = minFilter !== undefined ? minFilter : NearestFilter;
8229  
8230		this.generateMipmaps = false;
8231		this.flipY = false;
8232		this.unpackAlignment = 1;
8233  
8234	}
8235  
8236	DataTexture.prototype = Object.create( Texture.prototype );
8237	DataTexture.prototype.constructor = DataTexture;
8238  
8239	DataTexture.prototype.isDataTexture = true;
8240  
8241	/**
8242	 * @author bhouston / http://clara.io
8243	 * @author WestLangley / http://github.com/WestLangley
8244	 */
8245  
8246	function Box3( min, max ) {
8247  
8248		this.min = ( min !== undefined ) ? min : new Vector3( + Infinity, + Infinity, + Infinity );
8249		this.max = ( max !== undefined ) ? max : new Vector3( - Infinity, - Infinity, - Infinity );
8250  
8251	}
8252  
8253	Object.assign( Box3.prototype, {
8254  
8255		isBox3: true,
8256  
8257		set: function ( min, max ) {
8258  
8259			this.min.copy( min );
8260			this.max.copy( max );
8261  
8262			return this;
8263  
8264		},
8265  
8266		setFromArray: function ( array ) {
8267  
8268			var minX = + Infinity;
8269			var minY = + Infinity;
8270			var minZ = + Infinity;
8271  
8272			var maxX = - Infinity;
8273			var maxY = - Infinity;
8274			var maxZ = - Infinity;
8275  
8276			for ( var i = 0, l = array.length; i < l; i += 3 ) {
8277  
8278				var x = array[ i ];
8279				var y = array[ i + 1 ];
8280				var z = array[ i + 2 ];
8281  
8282				if ( x < minX ) minX = x;
8283				if ( y < minY ) minY = y;
8284				if ( z < minZ ) minZ = z;
8285  
8286				if ( x > maxX ) maxX = x;
8287				if ( y > maxY ) maxY = y;
8288				if ( z > maxZ ) maxZ = z;
8289  
8290			}
8291  
8292			this.min.set( minX, minY, minZ );
8293			this.max.set( maxX, maxY, maxZ );
8294  
8295			return this;
8296  
8297		},
8298  
8299		setFromBufferAttribute: function ( attribute ) {
8300  
8301			var minX = + Infinity;
8302			var minY = + Infinity;
8303			var minZ = + Infinity;
8304  
8305			var maxX = - Infinity;
8306			var maxY = - Infinity;
8307			var maxZ = - Infinity;
8308  
8309			for ( var i = 0, l = attribute.count; i < l; i ++ ) {
8310  
8311				var x = attribute.getX( i );
8312				var y = attribute.getY( i );
8313				var z = attribute.getZ( i );
8314  
8315				if ( x < minX ) minX = x;
8316				if ( y < minY ) minY = y;
8317				if ( z < minZ ) minZ = z;
8318  
8319				if ( x > maxX ) maxX = x;
8320				if ( y > maxY ) maxY = y;
8321				if ( z > maxZ ) maxZ = z;
8322  
8323			}
8324  
8325			this.min.set( minX, minY, minZ );
8326			this.max.set( maxX, maxY, maxZ );
8327  
8328			return this;
8329  
8330		},
8331  
8332		setFromPoints: function ( points ) {
8333  
8334			this.makeEmpty();
8335  
8336			for ( var i = 0, il = points.length; i < il; i ++ ) {
8337  
8338				this.expandByPoint( points[ i ] );
8339  
8340			}
8341  
8342			return this;
8343  
8344		},
8345  
8346		setFromCenterAndSize: function () {
8347  
8348			var v1 = new Vector3();
8349  
8350			return function setFromCenterAndSize( center, size ) {
8351  
8352				var halfSize = v1.copy( size ).multiplyScalar( 0.5 );
8353  
8354				this.min.copy( center ).sub( halfSize );
8355				this.max.copy( center ).add( halfSize );
8356  
8357				return this;
8358  
8359			};
8360  
8361		}(),
8362  
8363		setFromObject: function ( object ) {
8364  
8365			this.makeEmpty();
8366  
8367			return this.expandByObject( object );
8368  
8369		},
8370  
8371		clone: function () {
8372  
8373			return new this.constructor().copy( this );
8374  
8375		},
8376  
8377		copy: function ( box ) {
8378  
8379			this.min.copy( box.min );
8380			this.max.copy( box.max );
8381  
8382			return this;
8383  
8384		},
8385  
8386		makeEmpty: function () {
8387  
8388			this.min.x = this.min.y = this.min.z = + Infinity;
8389			this.max.x = this.max.y = this.max.z = - Infinity;
8390  
8391			return this;
8392  
8393		},
8394  
8395		isEmpty: function () {
8396  
8397			// this is a more robust check for empty than ( volume <= 0 ) because volume can get positive with two negative axes
8398  
8399			return ( this.max.x < this.min.x ) || ( this.max.y < this.min.y ) || ( this.max.z < this.min.z );
8400  
8401		},
8402  
8403		getCenter: function ( target ) {
8404  
8405			if ( target === undefined ) {
8406  
8407				console.warn( 'THREE.Box3: .getCenter() target is now required' );
8408				target = new Vector3();
8409  
8410			}
8411  
8412			return this.isEmpty() ? target.set( 0, 0, 0 ) : target.addVectors( this.min, this.max ).multiplyScalar( 0.5 );
8413  
8414		},
8415  
8416		getSize: function ( target ) {
8417  
8418			if ( target === undefined ) {
8419  
8420				console.warn( 'THREE.Box3: .getSize() target is now required' );
8421				target = new Vector3();
8422  
8423			}
8424  
8425			return this.isEmpty() ? target.set( 0, 0, 0 ) : target.subVectors( this.max, this.min );
8426  
8427		},
8428  
8429		expandByPoint: function ( point ) {
8430  
8431			this.min.min( point );
8432			this.max.max( point );
8433  
8434			return this;
8435  
8436		},
8437  
8438		expandByVector: function ( vector ) {
8439  
8440			this.min.sub( vector );
8441			this.max.add( vector );
8442  
8443			return this;
8444  
8445		},
8446  
8447		expandByScalar: function ( scalar ) {
8448  
8449			this.min.addScalar( - scalar );
8450			this.max.addScalar( scalar );
8451  
8452			return this;
8453  
8454		},
8455  
8456		expandByObject: function () {
8457  
8458			// Computes the world-axis-aligned bounding box of an object (including its children),
8459			// accounting for both the object's, and children's, world transforms
8460  
8461			var scope, i, l;
8462  
8463			var v1 = new Vector3();
8464  
8465			function traverse( node ) {
8466  
8467				var geometry = node.geometry;
8468  
8469				if ( geometry !== undefined ) {
8470  
8471					if ( geometry.isGeometry ) {
8472  
8473						var vertices = geometry.vertices;
8474  
8475						for ( i = 0, l = vertices.length; i < l; i ++ ) {
8476  
8477							v1.copy( vertices[ i ] );
8478							v1.applyMatrix4( node.matrixWorld );
8479  
8480							scope.expandByPoint( v1 );
8481  
8482						}
8483  
8484					} else if ( geometry.isBufferGeometry ) {
8485  
8486						var attribute = geometry.attributes.position;
8487  
8488						if ( attribute !== undefined ) {
8489  
8490							for ( i = 0, l = attribute.count; i < l; i ++ ) {
8491  
8492								v1.fromBufferAttribute( attribute, i ).applyMatrix4( node.matrixWorld );
8493  
8494								scope.expandByPoint( v1 );
8495  
8496							}
8497  
8498						}
8499  
8500					}
8501  
8502				}
8503  
8504			}
8505  
8506			return function expandByObject( object ) {
8507  
8508				scope = this;
8509  
8510				object.updateMatrixWorld( true );
8511  
8512				object.traverse( traverse );
8513  
8514				return this;
8515  
8516			};
8517  
8518		}(),
8519  
8520		containsPoint: function ( point ) {
8521  
8522			return point.x < this.min.x || point.x > this.max.x ||
8523				point.y < this.min.y || point.y > this.max.y ||
8524				point.z < this.min.z || point.z > this.max.z ? false : true;
8525  
8526		},
8527  
8528		containsBox: function ( box ) {
8529  
8530			return this.min.x <= box.min.x && box.max.x <= this.max.x &&
8531				this.min.y <= box.min.y && box.max.y <= this.max.y &&
8532				this.min.z <= box.min.z && box.max.z <= this.max.z;
8533  
8534		},
8535  
8536		getParameter: function ( point, target ) {
8537  
8538			// This can potentially have a divide by zero if the box
8539			// has a size dimension of 0.
8540  
8541			if ( target === undefined ) {
8542  
8543				console.warn( 'THREE.Box3: .getParameter() target is now required' );
8544				target = new Vector3();
8545  
8546			}
8547  
8548			return target.set(
8549				( point.x - this.min.x ) / ( this.max.x - this.min.x ),
8550				( point.y - this.min.y ) / ( this.max.y - this.min.y ),
8551				( point.z - this.min.z ) / ( this.max.z - this.min.z )
8552			);
8553  
8554		},
8555  
8556		intersectsBox: function ( box ) {
8557  
8558			// using 6 splitting planes to rule out intersections.
8559			return box.max.x < this.min.x || box.min.x > this.max.x ||
8560				box.max.y < this.min.y || box.min.y > this.max.y ||
8561				box.max.z < this.min.z || box.min.z > this.max.z ? false : true;
8562  
8563		},
8564  
8565		intersectsSphere: ( function () {
8566  
8567			var closestPoint = new Vector3();
8568  
8569			return function intersectsSphere( sphere ) {
8570  
8571				// Find the point on the AABB closest to the sphere center.
8572				this.clampPoint( sphere.center, closestPoint );
8573  
8574				// If that point is inside the sphere, the AABB and sphere intersect.
8575				return closestPoint.distanceToSquared( sphere.center ) <= ( sphere.radius * sphere.radius );
8576  
8577			};
8578  
8579		} )(),
8580  
8581		intersectsPlane: function ( plane ) {
8582  
8583			// We compute the minimum and maximum dot product values. If those values
8584			// are on the same side (back or front) of the plane, then there is no intersection.
8585  
8586			var min, max;
8587  
8588			if ( plane.normal.x > 0 ) {
8589  
8590				min = plane.normal.x * this.min.x;
8591				max = plane.normal.x * this.max.x;
8592  
8593			} else {
8594  
8595				min = plane.normal.x * this.max.x;
8596				max = plane.normal.x * this.min.x;
8597  
8598			}
8599  
8600			if ( plane.normal.y > 0 ) {
8601  
8602				min += plane.normal.y * this.min.y;
8603				max += plane.normal.y * this.max.y;
8604  
8605			} else {
8606  
8607				min += plane.normal.y * this.max.y;
8608				max += plane.normal.y * this.min.y;
8609  
8610			}
8611  
8612			if ( plane.normal.z > 0 ) {
8613  
8614				min += plane.normal.z * this.min.z;
8615				max += plane.normal.z * this.max.z;
8616  
8617			} else {
8618  
8619				min += plane.normal.z * this.max.z;
8620				max += plane.normal.z * this.min.z;
8621  
8622			}
8623  
8624			return ( min <= plane.constant && max >= plane.constant );
8625  
8626		},
8627  
8628		intersectsTriangle: ( function () {
8629  
8630			// triangle centered vertices
8631			var v0 = new Vector3();
8632			var v1 = new Vector3();
8633			var v2 = new Vector3();
8634  
8635			// triangle edge vectors
8636			var f0 = new Vector3();
8637			var f1 = new Vector3();
8638			var f2 = new Vector3();
8639  
8640			var testAxis = new Vector3();
8641  
8642			var center = new Vector3();
8643			var extents = new Vector3();
8644  
8645			var triangleNormal = new Vector3();
8646  
8647			function satForAxes( axes ) {
8648  
8649				var i, j;
8650  
8651				for ( i = 0, j = axes.length - 3; i <= j; i += 3 ) {
8652  
8653					testAxis.fromArray( axes, i );
8654					// project the aabb onto the seperating axis
8655					var r = extents.x * Math.abs( testAxis.x ) + extents.y * Math.abs( testAxis.y ) + extents.z * Math.abs( testAxis.z );
8656					// project all 3 vertices of the triangle onto the seperating axis
8657					var p0 = v0.dot( testAxis );
8658					var p1 = v1.dot( testAxis );
8659					var p2 = v2.dot( testAxis );
8660					// actual test, basically see if either of the most extreme of the triangle points intersects r
8661					if ( Math.max( - Math.max( p0, p1, p2 ), Math.min( p0, p1, p2 ) ) > r ) {
8662  
8663						// points of the projected triangle are outside the projected half-length of the aabb
8664						// the axis is seperating and we can exit
8665						return false;
8666  
8667					}
8668  
8669				}
8670  
8671				return true;
8672  
8673			}
8674  
8675			return function intersectsTriangle( triangle ) {
8676  
8677				if ( this.isEmpty() ) {
8678  
8679					return false;
8680  
8681				}
8682  
8683				// compute box center and extents
8684				this.getCenter( center );
8685				extents.subVectors( this.max, center );
8686  
8687				// translate triangle to aabb origin
8688				v0.subVectors( triangle.a, center );
8689				v1.subVectors( triangle.b, center );
8690				v2.subVectors( triangle.c, center );
8691  
8692				// compute edge vectors for triangle
8693				f0.subVectors( v1, v0 );
8694				f1.subVectors( v2, v1 );
8695				f2.subVectors( v0, v2 );
8696  
8697				// test against axes that are given by cross product combinations of the edges of the triangle and the edges of the aabb
8698				// 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
8699				// axis_ij = u_i x f_j (u0, u1, u2 = face normals of aabb = x,y,z axes vectors since aabb is axis aligned)
8700				var axes = [
8701					0, - f0.z, f0.y, 0, - f1.z, f1.y, 0, - f2.z, f2.y,
8702					f0.z, 0, - f0.x, f1.z, 0, - f1.x, f2.z, 0, - f2.x,
8703					- f0.y, f0.x, 0, - f1.y, f1.x, 0, - f2.y, f2.x, 0
8704				];
8705				if ( ! satForAxes( axes ) ) {
8706  
8707					return false;
8708  
8709				}
8710  
8711				// test 3 face normals from the aabb
8712				axes = [ 1, 0, 0, 0, 1, 0, 0, 0, 1 ];
8713				if ( ! satForAxes( axes ) ) {
8714  
8715					return false;
8716  
8717				}
8718  
8719				// finally testing the face normal of the triangle
8720				// use already existing triangle edge vectors here
8721				triangleNormal.crossVectors( f0, f1 );
8722				axes = [ triangleNormal.x, triangleNormal.y, triangleNormal.z ];
8723				return satForAxes( axes );
8724  
8725			};
8726  
8727		} )(),
8728  
8729		clampPoint: function ( point, target ) {
8730  
8731			if ( target === undefined ) {
8732  
8733				console.warn( 'THREE.Box3: .clampPoint() target is now required' );
8734				target = new Vector3();
8735  
8736			}
8737  
8738			return target.copy( point ).clamp( this.min, this.max );
8739  
8740		},
8741  
8742		distanceToPoint: function () {
8743  
8744			var v1 = new Vector3();
8745  
8746			return function distanceToPoint( point ) {
8747  
8748				var clampedPoint = v1.copy( point ).clamp( this.min, this.max );
8749				return clampedPoint.sub( point ).length();
8750  
8751			};
8752  
8753		}(),
8754  
8755		getBoundingSphere: function () {
8756  
8757			var v1 = new Vector3();
8758  
8759			return function getBoundingSphere( target ) {
8760  
8761				if ( target === undefined ) {
8762  
8763					console.warn( 'THREE.Box3: .getBoundingSphere() target is now required' );
8764					target = new Sphere();
8765  
8766				}
8767  
8768				this.getCenter( target.center );
8769  
8770				target.radius = this.getSize( v1 ).length() * 0.5;
8771  
8772				return target;
8773  
8774			};
8775  
8776		}(),
8777  
8778		intersect: function ( box ) {
8779  
8780			this.min.max( box.min );
8781			this.max.min( box.max );
8782  
8783			// 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.
8784			if ( this.isEmpty() ) this.makeEmpty();
8785  
8786			return this;
8787  
8788		},
8789  
8790		union: function ( box ) {
8791  
8792			this.min.min( box.min );
8793			this.max.max( box.max );
8794  
8795			return this;
8796  
8797		},
8798  
8799		applyMatrix4: function ( matrix ) {
8800  
8801			// transform of empty box is an empty box.
8802			if ( this.isEmpty( ) ) return this;
8803  
8804			var m = matrix.elements;
8805  
8806			var xax = m[ 0 ] * this.min.x, xay = m[ 1 ] * this.min.x, xaz = m[ 2 ] * this.min.x;
8807			var xbx = m[ 0 ] * this.max.x, xby = m[ 1 ] * this.max.x, xbz = m[ 2 ] * this.max.x;
8808			var yax = m[ 4 ] * this.min.y, yay = m[ 5 ] * this.min.y, yaz = m[ 6 ] * this.min.y;
8809			var ybx = m[ 4 ] * this.max.y, yby = m[ 5 ] * this.max.y, ybz = m[ 6 ] * this.max.y;
8810			var zax = m[ 8 ] * this.min.z, zay = m[ 9 ] * this.min.z, zaz = m[ 10 ] * this.min.z;
8811			var zbx = m[ 8 ] * this.max.z, zby = m[ 9 ] * this.max.z, zbz = m[ 10 ] * this.max.z;
8812  
8813			this.min.x = Math.min( xax, xbx ) + Math.min( yax, ybx ) + Math.min( zax, zbx ) + m[ 12 ];
8814			this.min.y = Math.min( xay, xby ) + Math.min( yay, yby ) + Math.min( zay, zby ) + m[ 13 ];
8815			this.min.z = Math.min( xaz, xbz ) + Math.min( yaz, ybz ) + Math.min( zaz, zbz ) + m[ 14 ];
8816			this.max.x = Math.max( xax, xbx ) + Math.max( yax, ybx ) + Math.max( zax, zbx ) + m[ 12 ];
8817			this.max.y = Math.max( xay, xby ) + Math.max( yay, yby ) + Math.max( zay, zby ) + m[ 13 ];
8818			this.max.z = Math.max( xaz, xbz ) + Math.max( yaz, ybz ) + Math.max( zaz, zbz ) + m[ 14 ];
8819  
8820			return this;
8821  
8822		},
8823  
8824		translate: function ( offset ) {
8825  
8826			this.min.add( offset );
8827			this.max.add( offset );
8828  
8829			return this;
8830  
8831		},
8832  
8833		equals: function ( box ) {
8834  
8835			return box.min.equals( this.min ) && box.max.equals( this.max );
8836  
8837		}
8838  
8839	} );
8840  
8841	/**
8842	 * @author bhouston / http://clara.io
8843	 * @author mrdoob / http://mrdoob.com/
8844	 */
8845  
8846	function Sphere( center, radius ) {
8847  
8848		this.center = ( center !== undefined ) ? center : new Vector3();
8849		this.radius = ( radius !== undefined ) ? radius : 0;
8850  
8851	}
8852  
8853	Object.assign( Sphere.prototype, {
8854  
vendor: 7,519 bytes, lines 8855-9247
8855		set: function ( center, radius ) {
8856  
8857			this.center.copy( center );
8858			this.radius = radius;
8859  
8860			return this;
8861  
8862		},
8863  
8864		setFromPoints: function () {
8865  
8866			var box = new Box3();
8867  
8868			return function setFromPoints( points, optionalCenter ) {
8869  
8870				var center = this.center;
8871  
8872				if ( optionalCenter !== undefined ) {
8873  
8874					center.copy( optionalCenter );
8875  
8876				} else {
8877  
8878					box.setFromPoints( points ).getCenter( center );
8879  
8880				}
8881  
8882				var maxRadiusSq = 0;
8883  
8884				for ( var i = 0, il = points.length; i < il; i ++ ) {
8885  
8886					maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( points[ i ] ) );
8887  
8888				}
8889  
8890				this.radius = Math.sqrt( maxRadiusSq );
8891  
8892				return this;
8893  
8894			};
8895  
8896		}(),
8897  
8898		clone: function () {
8899  
8900			return new this.constructor().copy( this );
8901  
8902		},
8903  
8904		copy: function ( sphere ) {
8905  
8906			this.center.copy( sphere.center );
8907			this.radius = sphere.radius;
8908  
8909			return this;
8910  
8911		},
8912  
8913		empty: function () {
8914  
8915			return ( this.radius <= 0 );
8916  
8917		},
8918  
8919		containsPoint: function ( point ) {
8920  
8921			return ( point.distanceToSquared( this.center ) <= ( this.radius * this.radius ) );
8922  
8923		},
8924  
8925		distanceToPoint: function ( point ) {
8926  
8927			return ( point.distanceTo( this.center ) - this.radius );
8928  
8929		},
8930  
8931		intersectsSphere: function ( sphere ) {
8932  
8933			var radiusSum = this.radius + sphere.radius;
8934  
8935			return sphere.center.distanceToSquared( this.center ) <= ( radiusSum * radiusSum );
8936  
8937		},
8938  
8939		intersectsBox: function ( box ) {
8940  
8941			return box.intersectsSphere( this );
8942  
8943		},
8944  
8945		intersectsPlane: function ( plane ) {
8946  
8947			return Math.abs( plane.distanceToPoint( this.center ) ) <= this.radius;
8948  
8949		},
8950  
8951		clampPoint: function ( point, target ) {
8952  
8953			var deltaLengthSq = this.center.distanceToSquared( point );
8954  
8955			if ( target === undefined ) {
8956  
8957				console.warn( 'THREE.Sphere: .clampPoint() target is now required' );
8958				target = new Vector3();
8959  
8960			}
8961  
8962			target.copy( point );
8963  
8964			if ( deltaLengthSq > ( this.radius * this.radius ) ) {
8965  
8966				target.sub( this.center ).normalize();
8967				target.multiplyScalar( this.radius ).add( this.center );
8968  
8969			}
8970  
8971			return target;
8972  
8973		},
8974  
8975		getBoundingBox: function ( target ) {
8976  
8977			if ( target === undefined ) {
8978  
8979				console.warn( 'THREE.Sphere: .getBoundingBox() target is now required' );
8980				target = new Box3();
8981  
8982			}
8983  
8984			target.set( this.center, this.center );
8985			target.expandByScalar( this.radius );
8986  
8987			return target;
8988  
8989		},
8990  
8991		applyMatrix4: function ( matrix ) {
8992  
8993			this.center.applyMatrix4( matrix );
8994			this.radius = this.radius * matrix.getMaxScaleOnAxis();
8995  
8996			return this;
8997  
8998		},
8999  
9000		translate: function ( offset ) {
9001  
9002			this.center.add( offset );
9003  
9004			return this;
9005  
9006		},
9007  
9008		equals: function ( sphere ) {
9009  
9010			return sphere.center.equals( this.center ) && ( sphere.radius === this.radius );
9011  
9012		}
9013  
9014	} );
9015  
9016	/**
9017	 * @author bhouston / http://clara.io
9018	 */
9019  
9020	function Plane( normal, constant ) {
9021  
9022		// normal is assumed to be normalized
9023  
9024		this.normal = ( normal !== undefined ) ? normal : new Vector3( 1, 0, 0 );
9025		this.constant = ( constant !== undefined ) ? constant : 0;
9026  
9027	}
9028  
9029	Object.assign( Plane.prototype, {
9030  
9031		set: function ( normal, constant ) {
9032  
9033			this.normal.copy( normal );
9034			this.constant = constant;
9035  
9036			return this;
9037  
9038		},
9039  
9040		setComponents: function ( x, y, z, w ) {
9041  
9042			this.normal.set( x, y, z );
9043			this.constant = w;
9044  
9045			return this;
9046  
9047		},
9048  
9049		setFromNormalAndCoplanarPoint: function ( normal, point ) {
9050  
9051			this.normal.copy( normal );
9052			this.constant = - point.dot( this.normal );
9053  
9054			return this;
9055  
9056		},
9057  
9058		setFromCoplanarPoints: function () {
9059  
9060			var v1 = new Vector3();
9061			var v2 = new Vector3();
9062  
9063			return function setFromCoplanarPoints( a, b, c ) {
9064  
9065				var normal = v1.subVectors( c, b ).cross( v2.subVectors( a, b ) ).normalize();
9066  
9067				// Q: should an error be thrown if normal is zero (e.g. degenerate plane)?
9068  
9069				this.setFromNormalAndCoplanarPoint( normal, a );
9070  
9071				return this;
9072  
9073			};
9074  
9075		}(),
9076  
9077		clone: function () {
9078  
9079			return new this.constructor().copy( this );
9080  
9081		},
9082  
9083		copy: function ( plane ) {
9084  
9085			this.normal.copy( plane.normal );
9086			this.constant = plane.constant;
9087  
9088			return this;
9089  
9090		},
9091  
9092		normalize: function () {
9093  
9094			// Note: will lead to a divide by zero if the plane is invalid.
9095  
9096			var inverseNormalLength = 1.0 / this.normal.length();
9097			this.normal.multiplyScalar( inverseNormalLength );
9098			this.constant *= inverseNormalLength;
9099  
9100			return this;
9101  
9102		},
9103  
9104		negate: function () {
9105  
9106			this.constant *= - 1;
9107			this.normal.negate();
9108  
9109			return this;
9110  
9111		},
9112  
9113		distanceToPoint: function ( point ) {
9114  
9115			return this.normal.dot( point ) + this.constant;
9116  
9117		},
9118  
9119		distanceToSphere: function ( sphere ) {
9120  
9121			return this.distanceToPoint( sphere.center ) - sphere.radius;
9122  
9123		},
9124  
9125		projectPoint: function ( point, target ) {
9126  
9127			if ( target === undefined ) {
9128  
9129				console.warn( 'THREE.Plane: .projectPoint() target is now required' );
9130				target = new Vector3();
9131  
9132			}
9133  
9134			return target.copy( this.normal ).multiplyScalar( - this.distanceToPoint( point ) ).add( point );
9135  
9136		},
9137  
9138		intersectLine: function () {
9139  
9140			var v1 = new Vector3();
9141  
9142			return function intersectLine( line, target ) {
9143  
9144				if ( target === undefined ) {
9145  
9146					console.warn( 'THREE.Plane: .intersectLine() target is now required' );
9147					target = new Vector3();
9148  
9149				}
9150  
9151				var direction = line.delta( v1 );
9152  
9153				var denominator = this.normal.dot( direction );
9154  
9155				if ( denominator === 0 ) {
9156  
9157					// line is coplanar, return origin
9158					if ( this.distanceToPoint( line.start ) === 0 ) {
9159  
9160						return target.copy( line.start );
9161  
9162					}
9163  
9164					// Unsure if this is the correct method to handle this case.
9165					return undefined;
9166  
9167				}
9168  
9169				var t = - ( line.start.dot( this.normal ) + this.constant ) / denominator;
9170  
9171				if ( t < 0 || t > 1 ) {
9172  
9173					return undefined;
9174  
9175				}
9176  
9177				return target.copy( direction ).multiplyScalar( t ).add( line.start );
9178  
9179			};
9180  
9181		}(),
9182  
9183		intersectsLine: function ( line ) {
9184  
9185			// Note: this tests if a line intersects the plane, not whether it (or its end-points) are coplanar with it.
9186  
9187			var startSign = this.distanceToPoint( line.start );
9188			var endSign = this.distanceToPoint( line.end );
9189  
9190			return ( startSign < 0 && endSign > 0 ) || ( endSign < 0 && startSign > 0 );
9191  
9192		},
9193  
9194		intersectsBox: function ( box ) {
9195  
9196			return box.intersectsPlane( this );
9197  
9198		},
9199  
9200		intersectsSphere: function ( sphere ) {
9201  
9202			return sphere.intersectsPlane( this );
9203  
9204		},
9205  
9206		coplanarPoint: function ( target ) {
9207  
9208			if ( target === undefined ) {
9209  
9210				console.warn( 'THREE.Plane: .coplanarPoint() target is now required' );
9211				target = new Vector3();
9212  
9213			}
9214  
9215			return target.copy( this.normal ).multiplyScalar( - this.constant );
9216  
9217		},
9218  
9219		applyMatrix4: function () {
9220  
9221			var v1 = new Vector3();
9222			var m1 = new Matrix3();
9223  
9224			return function applyMatrix4( matrix, optionalNormalMatrix ) {
9225  
9226				var normalMatrix = optionalNormalMatrix || m1.getNormalMatrix( matrix );
9227  
9228				var referencePoint = this.coplanarPoint( v1 ).applyMatrix4( matrix );
9229  
9230				var normal = this.normal.applyMatrix3( normalMatrix ).normalize();
9231  
9232				this.constant = - referencePoint.dot( normal );
9233  
9234				return this;
9235  
9236			};
9237  
9238		}(),
9239  
9240		translate: function ( offset ) {
9241  
9242			this.constant -= offset.dot( this.normal );
9243  
9244			return this;
9245  
9246		},
9247  
vendor: 4,243 bytes, lines 9248-9439
9248		equals: function ( plane ) {
9249  
9250			return plane.normal.equals( this.normal ) && ( plane.constant === this.constant );
9251  
9252		}
9253  
9254	} );
9255  
9256	/**
9257	 * @author mrdoob / http://mrdoob.com/
9258	 * @author alteredq / http://alteredqualia.com/
9259	 * @author bhouston / http://clara.io
9260	 */
9261  
9262	function Frustum( p0, p1, p2, p3, p4, p5 ) {
9263  
9264		this.planes = [
9265  
9266			( p0 !== undefined ) ? p0 : new Plane(),
9267			( p1 !== undefined ) ? p1 : new Plane(),
9268			( p2 !== undefined ) ? p2 : new Plane(),
9269			( p3 !== undefined ) ? p3 : new Plane(),
9270			( p4 !== undefined ) ? p4 : new Plane(),
9271			( p5 !== undefined ) ? p5 : new Plane()
9272  
9273		];
9274  
9275	}
9276  
9277	Object.assign( Frustum.prototype, {
9278  
9279		set: function ( p0, p1, p2, p3, p4, p5 ) {
9280  
9281			var planes = this.planes;
9282  
9283			planes[ 0 ].copy( p0 );
9284			planes[ 1 ].copy( p1 );
9285			planes[ 2 ].copy( p2 );
9286			planes[ 3 ].copy( p3 );
9287			planes[ 4 ].copy( p4 );
9288			planes[ 5 ].copy( p5 );
9289  
9290			return this;
9291  
9292		},
9293  
9294		clone: function () {
9295  
9296			return new this.constructor().copy( this );
9297  
9298		},
9299  
9300		copy: function ( frustum ) {
9301  
9302			var planes = this.planes;
9303  
9304			for ( var i = 0; i < 6; i ++ ) {
9305  
9306				planes[ i ].copy( frustum.planes[ i ] );
9307  
9308			}
9309  
9310			return this;
9311  
9312		},
9313  
9314		setFromMatrix: function ( m ) {
9315  
9316			var planes = this.planes;
9317			var me = m.elements;
9318			var me0 = me[ 0 ], me1 = me[ 1 ], me2 = me[ 2 ], me3 = me[ 3 ];
9319			var me4 = me[ 4 ], me5 = me[ 5 ], me6 = me[ 6 ], me7 = me[ 7 ];
9320			var me8 = me[ 8 ], me9 = me[ 9 ], me10 = me[ 10 ], me11 = me[ 11 ];
9321			var me12 = me[ 12 ], me13 = me[ 13 ], me14 = me[ 14 ], me15 = me[ 15 ];
9322  
9323			planes[ 0 ].setComponents( me3 - me0, me7 - me4, me11 - me8, me15 - me12 ).normalize();
9324			planes[ 1 ].setComponents( me3 + me0, me7 + me4, me11 + me8, me15 + me12 ).normalize();
9325			planes[ 2 ].setComponents( me3 + me1, me7 + me5, me11 + me9, me15 + me13 ).normalize();
9326			planes[ 3 ].setComponents( me3 - me1, me7 - me5, me11 - me9, me15 - me13 ).normalize();
9327			planes[ 4 ].setComponents( me3 - me2, me7 - me6, me11 - me10, me15 - me14 ).normalize();
9328			planes[ 5 ].setComponents( me3 + me2, me7 + me6, me11 + me10, me15 + me14 ).normalize();
9329  
9330			return this;
9331  
9332		},
9333  
9334		intersectsObject: function () {
9335  
9336			var sphere = new Sphere();
9337  
9338			return function intersectsObject( object ) {
9339  
9340				var geometry = object.geometry;
9341  
9342				if ( geometry.boundingSphere === null )
9343					geometry.computeBoundingSphere();
9344  
9345				sphere.copy( geometry.boundingSphere )
9346					.applyMatrix4( object.matrixWorld );
9347  
9348				return this.intersectsSphere( sphere );
9349  
9350			};
9351  
9352		}(),
9353  
9354		intersectsSprite: function () {
9355  
9356			var sphere = new Sphere();
9357  
9358			return function intersectsSprite( sprite ) {
9359  
9360				sphere.center.set( 0, 0, 0 );
9361				sphere.radius = 0.7071067811865476;
9362				sphere.applyMatrix4( sprite.matrixWorld );
9363  
9364				return this.intersectsSphere( sphere );
9365  
9366			};
9367  
9368		}(),
9369  
9370		intersectsSphere: function ( sphere ) {
9371  
9372			var planes = this.planes;
9373			var center = sphere.center;
9374			var negRadius = - sphere.radius;
9375  
9376			for ( var i = 0; i < 6; i ++ ) {
9377  
9378				var distance = planes[ i ].distanceToPoint( center );
9379  
9380				if ( distance < negRadius ) {
9381  
9382					return false;
9383  
9384				}
9385  
9386			}
9387  
9388			return true;
9389  
9390		},
9391  
9392		intersectsBox: function () {
9393  
9394			var p1 = new Vector3(),
9395				p2 = new Vector3();
9396  
9397			return function intersectsBox( box ) {
9398  
9399				var planes = this.planes;
9400  
9401				for ( var i = 0; i < 6; i ++ ) {
9402  
9403					var plane = planes[ i ];
9404  
9405					p1.x = plane.normal.x > 0 ? box.min.x : box.max.x;
9406					p2.x = plane.normal.x > 0 ? box.max.x : box.min.x;
9407					p1.y = plane.normal.y > 0 ? box.min.y : box.max.y;
9408					p2.y = plane.normal.y > 0 ? box.max.y : box.min.y;
9409					p1.z = plane.normal.z > 0 ? box.min.z : box.max.z;
9410					p2.z = plane.normal.z > 0 ? box.max.z : box.min.z;
9411  
9412					var d1 = plane.distanceToPoint( p1 );
9413					var d2 = plane.distanceToPoint( p2 );
9414  
9415					// if both outside plane, no intersection
9416  
9417					if ( d1 < 0 && d2 < 0 ) {
9418  
9419						return false;
9420  
9421					}
9422  
9423				}
9424  
9425				return true;
9426  
9427			};
9428  
9429		}(),
9430  
9431		containsPoint: function ( point ) {
9432  
9433			var planes = this.planes;
9434  
9435			for ( var i = 0; i < 6; i ++ ) {
9436  
9437				if ( planes[ i ].distanceToPoint( point ) < 0 ) {
9438  
9439					return false;
9440  
9441				}
9442  
9443			}
9444  
9445			return true;
9446  
9447		}
9448  
9449	} );
9450  
9451	var alphamap_fragment = "#ifdef USE_ALPHAMAP\n\tdiffuseColor.a *= texture2D( alphaMap, vUv ).g;\n#endif\n";
9452  
9453	var alphamap_pars_fragment = "#ifdef USE_ALPHAMAP\n\tuniform sampler2D alphaMap;\n#endif\n";
9454  
9455	var alphatest_fragment = "#ifdef ALPHATEST\n\tif ( diffuseColor.a < ALPHATEST ) discard;\n#endif\n";
9456  
9457	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";
9458  
9459	var aomap_pars_fragment = "#ifdef USE_AOMAP\n\tuniform sampler2D aoMap;\n\tuniform float aoMapIntensity;\n#endif";
9460  
9461	var begin_vertex = "\nvec3 transformed = vec3( position );\n";
9462  
9463	var beginnormal_vertex = "\nvec3 objectNormal = vec3( normal );\n";
9464  
9465	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;
9465\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 );
9465\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";
9466  
9467	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}
9467\n\tvec3 perturbNormalArb( vec3 surf_pos, vec3 surf_norm, vec2 dHdxy ) {\n\t\tvec3 vSigmaX = vec3( dFdx( surf_pos.x ), dFdx( surf_pos.y ), dFdx( surf_pos.z ) );\n\t\tvec3 vSigmaY = vec3( dFdy( surf_pos.x ), dFdy( surf_pos.y ), dFdy( surf_pos.z ) );\n\t\tvec3 vN = surf_norm;\n\t\tvec3 R1 = cross( vSigmaY, vN );\n\t\tvec3 R2 = cross( vN, vSigmaX );\n\t\tfloat fDet = dot( vSigmaX, R1 );\n\t\tfDet *= ( float( gl_FrontFacing ) * 2.0 - 1.0 );\n\t\tvec3 vGrad = sign( fDet ) * ( dHdxy.x * R1 + dHdxy.y * R2 );\n\t\treturn normalize( abs( fDet ) * surf_norm - vGrad );\n\t}\n#endif\n";
9468  
9469	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";
9470  
9471	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";
9472  
9473	var clipping_planes_pars_vertex = "#if NUM_CLIPPING_PLANES > 0 && ! defined( PHYSICAL ) && ! defined( PHONG )\n\tvarying vec3 vViewPosition;\n#endif\n";
9474  
9475	var clipping_planes_vertex = "#if NUM_CLIPPING_PLANES > 0 && ! defined( PHYSICAL ) && ! defined( PHONG )\n\tvViewPosition = - mvPosition.xyz;\n#endif\n";
9476  
9477	var color_fragment = "#ifdef USE_COLOR\n\tdiffuseColor.rgb *= vColor;\n#endif";
9478  
9479	var color_pars_fragment = "#ifdef USE_COLOR\n\tvarying vec3 vColor;\n#endif\n";
9480  
9481	var color_pars_vertex = "#ifdef USE_COLOR\n\tvarying vec3 vColor;\n#endif";
9482  
9483	var color_vertex = "#ifdef USE_COLOR\n\tvColor.xyz = color.xyz;\n#endif";
9484  
9485	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";
9486  
9487	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);
9487\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";
9488  
9489	var defaultnormal_vertex = "vec3 transformedNormal = normalMatrix * objectNormal;\n#ifdef FLIP_SIDED\n\ttransformedNormal = - transformedNormal;\n#endif\n";
9490  
9491	var displacementmap_pars_vertex = "#ifdef USE_DISPLACEMENTMAP\n\tuniform sampler2D displacementMap;\n\tuniform float displacementScale;\n\tuniform float displacementBias;\n#endif\n";
9492  
9493	var displacementmap_vertex = "#ifdef USE_DISPLACEMENTMAP\n\ttransformed += normalize( objectNormal ) * ( texture2D( displacementMap, uv ).x * displacementScale + displacementBias );\n#endif\n";
9494  
9495	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";
9496  
9497	var emissivemap_pars_fragment = "#ifdef USE_EMISSIVEMAP\n\tuniform sampler2D emissiveMap;\n#endif\n";
9498  
9499	var encodings_fragment = "  gl_FragColor = linearToOutputTexel( gl_FragColor );\n";
9500  
9501	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}
9501\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";
9502  
9503	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";
9504  
9505	var envmap_pars_fragment = "#if defined( USE_ENVMAP ) || defined( PHYSICAL )\n\tuniform float reflectivity;\n\tuniform float envMapIntensity;\n#endif\n#ifdef USE_ENVMAP\n\t#if ! defined( PHYSICAL ) && ( defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG ) )\n\t\tvarying vec3 vWorldPosition;\n\t#endif\n\t#ifdef ENVMAP_TYPE_CUBE\n\t\tuniform samplerCube envMap;\n\t#else\n\t\tuniform sampler2D envMap;\n\t#endif\n\tuniform float flipEnvMap;\n\tuniform int maxMipLevel;\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG ) || defined( PHYSICAL )\n\t\tuniform float refractionRatio;\n\t#else\n\t\tvarying vec3 vReflect;\n\t#endif\n#endif\n";
9506  
9507	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";
9508  
9509	var envmap_vertex = "#ifdef USE_ENVMAP\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG )\n\t\tvWorldPosition = worldPosition.xyz;
9509\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";
9510  
9511	var fog_vertex = "\n#ifdef USE_FOG\nfogDepth = -mvPosition.z;\n#endif";
9512  
9513	var fog_pars_vertex = "#ifdef USE_FOG\n  varying float fogDepth;\n#endif\n";
9514  
9515	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";
9516  
9517	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";
9518  
9519	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";
9520  
9521	var lightmap_fragment = "#ifdef USE_LIGHTMAP\n\treflectedLight.indirectDiffuse += PI * texture2D( lightMap, vUv2 ).xyz * lightMapIntensity;\n#endif\n";
9522  
9523	var lightmap_pars_fragment = "#ifdef USE_LIGHTMAP\n\tuniform sampler2D lightMap;\n\tuniform float lightMapIntensity;\n#endif";
9524  
9525	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";
9526  
9527	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}
9527\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";
9528  
9529	var lights_pars_maps = "#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(blinnShinine
9529ssExponent));\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";
9530  
9531	var lights_phong_fragment = "BlinnPhongMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb;\nmaterial.specularColor = specular;\nmaterial.specularShininess = shininess;\nmaterial.specularStrength = specularStrength;\n";
9532  
9533	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";
9534  
9535	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";
9536  
9537	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;
9537\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";
9538  
9539	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}
9539\n#endif\n#if ( NUM_SPOT_LIGHTS > 0 ) && defined( RE_Direct )\n\tSpotLight spotLight;\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {\n\t\tspotLight = spotLights[ i ];\n\t\tgetSpotDirectLightIrradiance( spotLight, geometry, directLight );\n\t\t#ifdef USE_SHADOWMAP\n\t\tdirectLight.color *= all( bvec2( spotLight.shadow, directLight.visible ) ) ? getShadow( spotShadowMap[ i ], spotLight.shadowMapSize, spotLight.shadowBias, spotLight.shadowRadius, vSpotShadowCoord[ i ] ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometry, material, reflectedLight );\n\t}\n#endif\n#if ( NUM_DIR_LIGHTS > 0 ) && defined( RE_Direct )\n\tDirectionalLight directionalLight;\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\n\t\tdirectionalLight = directionalLights[ i ];\n\t\tgetDirectionalDirectLightIrradiance( directionalLight, geometry, directLight );\n\t\t#ifdef USE_SHADOWMAP\n\t\tdirectLight.color *= all( bvec2( directionalLight.shadow, directLight.visible ) ) ? getShadow( directionalShadowMap[ i ], directionalLight.shadowMapSize, directionalLight.shadowBias, directionalLight.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometry, material, reflectedLight );\n\t}\n#endif\n#if ( NUM_RECT_AREA_LIGHTS > 0 ) && defined( RE_Direct_RectArea )\n\tRectAreaLight rectAreaLight;\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_RECT_AREA_LIGHTS; i ++ ) {\n\t\trectAreaLight = rectAreaLights[ i ];\n\t\tRE_Direct_RectArea( rectAreaLight, geometry, material, reflectedLight );\n\t}\n#endif\n#if defined( RE_IndirectDiffuse )\n\tvec3 irradiance = getAmbientLightIrradiance( ambientLightColor );\n\t#if ( NUM_HEMI_LIGHTS > 0 )\n\t\t#pragma unroll_loop\n\t\tfor ( int i = 0; i < NUM_HEMI_LIGHTS; i ++ ) {\n\t\t\tirradiance += getHemisphereLightIrradiance( hemisphereLights[ i ], geometry );\n\t\t}\n\t#endif\n#endif\n#if defined( RE_IndirectSpecular )\n\tvec3 radiance = vec3( 0.0 );\n\tvec3 clearCoatRadiance = vec3( 0.0 );\n#endif\n";
9540  
9541	var lights_fragment_maps = "#if defined( RE_IndirectDiffuse )\n\t#ifdef USE_LIGHTMAP\n\t\tvec3 lightMapIrradiance = texture2D( lightMap, vUv2 ).xyz * lightMapIntensity;\n\t\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\t\tlightMapIrradiance *= PI;\n\t\t#endif\n\t\tirradiance += lightMapIrradiance;\n\t#endif\n\t#if defined( USE_ENVMAP ) && defined( PHYSICAL ) && defined( ENVMAP_TYPE_CUBE_UV )\n\t\tirradiance += getLightProbeIndirectIrradiance( geometry, maxMipLevel );\n\t#endif\n#endif\n#if defined( USE_ENVMAP ) && defined( RE_IndirectSpecular )\n\tradiance += getLightProbeIndirectRadiance( geometry, Material_BlinnShininessExponent( material ), maxMipLevel );\n\t#ifndef STANDARD\n\t\tclearCoatRadiance += getLightProbeIndirectRadiance( geometry, Material_ClearCoat_BlinnShininessExponent( material ), maxMipLevel );\n\t#endif\n#endif\n";
9542  
9543	var lights_fragment_end = "#if defined( RE_IndirectDiffuse )\n\tRE_IndirectDiffuse( irradiance, geometry, material, reflectedLight );\n#endif\n#if defined( RE_IndirectSpecular )\n\tRE_IndirectSpecular( radiance, clearCoatRadiance, geometry, material, reflectedLight );\n#endif\n";
9544  
9545	var logdepthbuf_fragment = "#if defined( USE_LOGDEPTHBUF ) && defined( USE_LOGDEPTHBUF_EXT )\n\tgl_FragDepthEXT = log2( vFragDepth ) * logDepthBufFC * 0.5;\n#endif";
9546  
9547	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";
9548  
9549	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";
9550  
9551	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";
9552  
9553	var map_fragment = "#ifdef USE_MAP\n\tvec4 texelColor = texture2D( map, vUv );\n\ttexelColor = mapTexelToLinear( texelColor );\n\tdiffuseColor *= texelColor;\n#endif\n";
9554  
9555	var map_pars_fragment = "#ifdef USE_MAP\n\tuniform sampler2D map;\n#endif\n";
9556  
9557	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";
9558  
9559	var map_particle_pars_fragment = "#ifdef USE_MAP\n\tuniform mat3 uvTransform;\n\tuniform sampler2D map;\n#endif\n";
9560  
9561	var metalnessmap_fragment = "float metalnessFactor = metalness;\n#ifdef USE_METALNESSMAP\n\tvec4 texelMetalness = texture2D( metalnessMap, vUv );\n\tmetalnessFactor *= texelMetalness.b;\n#endif\n";
9562  
9563	var metalnessmap_pars_fragment = "#ifdef USE_METALNESSMAP\n\tuniform sampler2D metalnessMap;\n#endif";
9564  
9565	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";
9566  
9567	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";
9568  
9569	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";
9570  
9571	var normal_fragment_begin = "#ifdef FLAT_SHADED\n\tvec3 fdx = vec3( dFdx( vViewPosition.x ), dFdx( vViewPosition.y ), dFdx( vViewPosition.z ) );\n\tvec3 fdy = vec3( dFdy( vViewPosition.x ), dFdy( vViewPosition.y ), dFdy( vViewPosition.z ) );\n\tvec3 normal = normalize( cross( fdx, fdy ) );\n#else\n\tvec3 normal = normalize( vNormal );\n\t#ifdef DOUBLE_SIDED\n\t\tnormal = normal * ( float( gl_FrontFacing ) * 2.0 - 1.0 );\n\t#endif\n#endif\n";
9572  
9573	var normal_fragment_maps = "#ifdef USE_NORMALMAP\n\tnormal = perturbN
9573ormal2Arb( -vViewPosition, normal );\n#elif defined( USE_BUMPMAP )\n\tnormal = perturbNormalArb( -vViewPosition, normal, dHdxy_fwd() );\n#endif\n";
9574  
9575	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\tfloat scale = sign( st1.t * st0.s - st0.t * st1.s );\n\t\tvec3 S = normalize( ( q0 * st1.t - q1 * st0.t ) * scale );\n\t\tvec3 T = normalize( ( - q0 * st1.s + q1 * st0.s ) * scale );\n\t\tvec3 N = normalize( surf_norm );\n\t\tmat3 tsn = mat3( S, T, N );\n\t\tvec3 mapN = texture2D( normalMap, vUv ).xyz * 2.0 - 1.0;\n\t\tmapN.xy *= normalScale;\n\t\tmapN.xy *= ( float( gl_FrontFacing ) * 2.0 - 1.0 );\n\t\treturn normalize( tsn * mapN );\n\t}\n#endif\n";
9576  
9577	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";
9578  
9579	var premultiplied_alpha_fragment = "#ifdef PREMULTIPLIED_ALPHA\n\tgl_FragColor.rgb *= gl_FragColor.a;\n#endif\n";
9580  
9581	var project_vertex = "vec4 mvPosition = modelViewMatrix * vec4( transformed, 1.0 );\ngl_Position = projectionMatrix * mvPosition;\n";
9582  
9583	var dithering_fragment = "#if defined( DITHERING )\n  gl_FragColor.rgb = dithering( gl_FragColor.rgb );\n#endif\n";
9584  
9585	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";
9586  
9587	var roughnessmap_fragment = "float roughnessFactor = roughness;\n#ifdef USE_ROUGHNESSMAP\n\tvec4 texelRoughness = texture2D( roughnessMap, vUv );\n\troughnessFactor *= texelRoughness.g;\n#endif\n";
9588  
9589	var roughnessmap_pars_fragment = "#ifdef USE_ROUGHNESSMAP\n\tuniform sampler2D roughnessMap;\n#endif";
9590  
9591	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 );
9591\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";
9592  
9593	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";
9594  
9595	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";
9596  
9597	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";
9598  
9599	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";
9600  
9601	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";
9602  
9603	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";
9604  
9605	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;
9605\n\tskinMatrix  = bindMatrixInverse * skinMatrix * bindMatrix;\n\tobjectNormal = vec4( skinMatrix * vec4( objectNormal, 0.0 ) ).xyz;\n#endif\n";
9606  
9607	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";
9608  
9609	var specularmap_pars_fragment = "#ifdef USE_SPECULARMAP\n\tuniform sampler2D specularMap;\n#endif";
9610  
9611	var tonemapping_fragment = "#if defined( TONE_MAPPING )\n  gl_FragColor.rgb = toneMapping( gl_FragColor.rgb );\n#endif\n";
9612  
9613	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";
9614  
9615	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";
9616  
9617	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";
9618  
9619	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";
9620  
9621	var uv2_pars_fragment = "#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\tvarying vec2 vUv2;\n#endif";
9622  
9623	var uv2_pars_vertex = "#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\tattribute vec2 uv2;\n\tvarying vec2 vUv2;\n#endif";
9624  
9625	var uv2_vertex = "#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\tvUv2 = uv2;\n#endif";
9626  
9627	var worldpos_vertex = "#if defined( USE_ENVMAP ) || defined( DISTANCE ) || defined ( USE_SHADOWMAP )\n\tvec4 worldPosition = modelMatrix * vec4( transformed, 1.0 );\n#endif\n";
9628  
9629	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";
9630  
9631	var cube_vert = "varying vec3 vWorldPosition;\n#include <common>\nvoid main() {\n\tvWorldPosition = transformDirection( position, modelMatrix );\n\t#include <begin_vertex>\n\t#include <project_vertex>\n\tgl_Position.z = gl_Position.w;\n}\n";
9632  
9633	var depth_frag = "#if DEPTH_PACKING == 3200\n\tuniform float opacity;\n#endif\n#include <common>\n#include <packing>\n#include <uv_pars_fragment>\n#include <map_pars_fragment>\n#include <alphamap_pars_fragment>\n#include <logdepthbuf_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvoid main() {\n\t#include <clipping_planes_fragment>\n\tvec4 diffuseColor = vec4( 1.0 );\n\t#if DEPTH_PACKING == 3200\n\t\tdiffuseColor.a = opacity;\n\t#endif\n\t#include <map_fragment>\n\t#include <alphamap_fragment>\n\t#include <alphatest_fragment>\n\t#include <logdepthbuf_fragment>\n\t#if DEPTH_PACKING == 3200\n\t\tgl_FragColor = vec4( vec3( 1.0 - gl_FragCoord.z ), opacity );\n\t#elif DEPTH_PACKING == 3201\n\t\tgl_FragColor = packDepthToRGBA( gl_FragCoord.z );\n\t#endif\n}\n";
9634  
9635	var depth_vert = "#include <common>\n#include <uv_pars_vertex>\n#include <displacementmap_pars_vertex>\n#include <morphtarget_pars_vertex>\n#include <skinning_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\t#include <uv_vertex>\n\t#include <skinbase_vertex>\n\t#ifdef USE_DISPLACEMENTMAP\n\t\t#include <beginnormal_vertex>\n\t\t#include <morphnormal_vertex>\n\t\t#include <skinnormal_vertex>\n\t#endif\n\t#include <begin_vertex>\n\t#include <morphtarget_vertex>\n\t#include <skinning_vertex>\n\t#include <displacementmap_vertex>\n\t#include <project_vertex>\n\t#include <logdepthbuf_vertex>\n\t#include <clipping_planes_vertex>\n}\n";
9636  
9637	var distanceRGBA_frag = "#define DISTANCE\nuniform vec3 referencePosition;\nuniform float nearDistance;\nuniform float farDistance;\nvarying vec3 vWorldPosition;\n#include <common>\n#include <packing>\n#include <uv_pars_fragment>\n#include <map_pars_fragment>\n#include <alphamap_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvoid main () {\n\t#include <clipping_planes_fragment>\n\tvec4 diffuseColor = vec4( 1.0 );\n\t#include <map_fragment>\n\t#include <alphamap_fragment>\n\t#include <alphatest_fragment>\n\tfloat dist = length( vWorldPosition - referencePosition );\n\tdist = ( dist - nearDistance ) / ( farDistance - nearDistance );\n\tdist = saturate( dist );\n\tgl_FragColor = packDepthToRGBA( dist );\n}\n";
9638  
9639	var distanceRGBA_vert = "#define DISTANCE\nvarying vec3 vWorldPosition;\n#include <common>\n#include <uv_pars_vertex>\n#include <displacementmap_pars_vertex>\n#include <morphtarget_pars_vertex>\n#include <skinning_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\t#include <uv_vertex>\n\t#include <skinbase_vertex>\n\t#ifdef USE_DISPLACEMENTMAP\n\t\t#include <beginnormal_vertex>\n\t\t#include <morphnormal_vertex>\n\t\t#include <skinnormal_vertex>\n\t#endif\n\t#include <begin_vertex>\n\t#include <morphtarget_vertex>\n\t#include <skinning_vertex>\n\t#include <displacementmap_vertex>\n\t#include <project_vertex>\n\t#include <worldpos_vertex>\n\t#include <clipping_planes_vertex>\n\tvWorldPosition = worldPosition.xyz;\n}\n";
9640  
9641	var equirect_frag = "uniform sampler2D tEquirect;\nvarying vec3 vWorldPosition;\n#include <common>\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";
9642  
9643	var equirect_vert = "varying vec3 vWorldPosition;\n#include <common>\nvoid main() {\n\tvWorldPosition = transformDirection( position, modelMatrix );\n\t#include <begin_vertex>\n\t#include <project_vertex>\n}\n";
9644  
9645	var linedashed_frag = "uniform vec3 diffuse;\nuniform float opacity;\nuniform float dashSize;\nuniform float totalSize;\nvarying float vLineDistance;\n#include <common>\n#include <color_pars_fragment>\n#include <fog_pars_fragment>\n#include <logdepthbuf_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvoid main() {\n\t#include <clipping_planes_fragment>\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 <logdepthbuf_fragment>\n\t#include <color_fragment>\n\toutgoingLight = diffuseColor.rgb;\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include <premultiplied_alpha_fragment>\n\t#include <tonemapping_fragment>\n\t#include <encodings_fragment>\n\t#include <fog_fragment>\n}\n";
9646  
9647	var linedashed_vert = "uniform float scale;\nattribute float lineDistance;\nvarying float vLineDistance;\n#include <common>\n#include <color_pars_vertex>\n#include <fog_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\t#include <color_vertex>\n\tvLineDistance = scale * lineDistance;\n\tvec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );\n\tgl_Position = projectionMatrix * mvPosition;\n\t#include <logdepthbuf_vertex>\n\t#include <clipping_planes_vertex>\n\t#include <fog_vertex>\n}\n";
9648  
9649	var meshbasic_frag = "uniform vec3 diffuse;\nuniform float opacity;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include <common>\n#include <color_pars_fragment>\n#include <uv_pars_fragment>\n#include <uv2_pars_fragment>\n#include <map_pars_fragment>\n#include <alphamap_pars_fragment>\n#include <aomap_pars_fragment>\n#include <lightmap_pars_fragment>\n#include <envmap_pars_fragment>\n#include <fog_pars_fragment>\n#include <specularmap_pars_fragment>\n#include <logdepthbuf_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvoid main() {\n\t#include <clipping_planes_fragment>\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include <logdepthbuf_fragment>\n\t#include <map_fragment>\n\t#include <color_fragment>\n\t#include <alphamap_fragment>\n\t#include <alphatest_fragment>\n\t#include <specularmap_fragment>\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 <aomap_fragment>\n\treflectedLight.indirectDiffuse *= diffuseColor.rgb;\n\tvec3 outgoingLight = reflectedLight.indirectDiffuse;\n\t#include <envmap_fragment>\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include <premultiplied_alpha_fragment>\n\t#include <tonemapping_fragment>\n\t#include <encodings_fragment>\n\t#include <fog_fragment>\n}\n";
9650  
9651	var meshbasic_vert = "#include <common>\n#include <uv_pars_vertex>\n#include <uv2_pars_vertex>\n#include <envmap_pars_vertex>\n#include <color_pars_vertex>\n#include <fog_pars_vertex>\n#include <morphtarget_pars_vertex>\n#include <skinning_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\t#include <uv_vertex>\n\t#include <uv2_vertex>\n\t#include <color_vertex>\n\t#include <skinbase_vertex>\n\t#ifdef USE_ENVMAP\n\t#include <beginnormal_vertex>\n\t#include <morphnormal_vertex>\n\t#include <skinnormal_vertex>\n\t#include <defaultnormal_vertex>\n\t#endif\n\t#include <begin_vertex>\n\t#include <morphtarget_vertex>\n\t#include <skinning_vertex>\n\t#include <project_vertex>\n\t#include <logdepthbuf_vertex>\n\t#include <worldpos_vertex>\n\t#include <clipping_planes_vertex>\n\t#include <envmap_vertex>\n\t#include <fog_vertex>\n}\n";
9652  
9653	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 <common>\n#include <packing>\n#include <dithering_pars_fragment>\n#include <color_pars_fragment>\n#include <uv_pars_fragment>\n#include <uv2_pars_fragment>\n#include <map_pars_fragment>\n#include <alphamap_pars_fragment>\n#include <aomap_pars_fragment>\n#include <lightmap_pars_fragment>\n#include <emissivemap_pars_fragment>\n#include <envmap_pars_fragment>\n#include <bsdfs>\n#include <lights_pars_begin>\n#include <lights_pars_maps>\n#include <fog_pars_fragment>\n#include <shadowmap_pars_fragment>\n#include <shadowmask_pars_fragment>\n#include <specularmap_pars_fragment>\n#include <logdepthbuf_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvoid main() {\n\t#include <clipping_planes_fragment>\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 <logdepthbuf_fragment>\n\t#include <map_fragment>\n\t#include <color_fragment>\n\t#include <alphamap_fragment>\n\t#include <alphatest_fragment>\n\t#include <specularmap_fragment>\n\t#include <emissivemap_fragment>\n\treflectedLight.indirectDiffuse = getAmbientLightIrradiance( ambientLightColor );\n\t#include <lightmap_fragment>\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 <aomap_fragment>\n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + totalEmissiveRadiance;\n\t#include <envmap_fragment>\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include <tonemapping_fragment>\n\t#include <encodings_fragment>\n\t#include <fog_fragment>\n\t#include <premultiplied_alpha_fragment>\n\t#include <dithering_fragment>\n}\n";
9654  
9655	var meshlambert_vert = "#define LAMBERT\nvarying vec3 vLightFront;\n#ifdef DOUBLE_SIDED\n\tvarying vec3 vLightBack;\n#endif\n#include <common>\n#include <uv_pars_vertex>\n#include <uv2_pars_vertex>\n#include <envmap_pars_vertex>\n#include <bsdfs>\n#include <lights_pars_begin>\n#include <lights_pars_maps>\n#include <color_pars_vertex>\n#include <fog_pars_vertex>\n#include <morphtarget_pars_vertex>\n#include <skinning_pars_vertex>\n#include <shadowmap_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\t#include <uv_vertex>\n\t#include <uv2_vertex>\n\t#include <color_vertex>\n\t#include <beginnormal_vertex>\n\t#include <morphnormal_vertex>\n\t#include <skinbase_vertex>\n\t#include <skinnormal_vertex>\n\t#include <defaultnormal_vertex>\n\t#include <begin_vertex>\n\t#include <morphtarget_vertex>\n\t#include <skinning_vertex>\n\t#include <project_vertex>\n\t#include <logdepthbuf_vertex>\n\t#include <clipping_planes_vertex>\n\t#include <worldpos_vertex>\n\t#include <envmap_vertex>\n\t#include <lights_lambert_vertex>\n\t#include <shadowmap_vertex>\n\t#include <fog_vertex>\n}\n";
9656  
9657	var meshphong_frag = "#define PHONG\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform vec3 specular;\nuniform float shininess;\nuniform float opacity;\n#include <common>\n#include <packing>\n#include <dithering_pars_fragment>\n#include <color_pars_fragment>\n#include <uv_pars_fragment>\n#include <uv2_pars_fragment>\n#include <map_pars_fragment>\n#include <alphamap_pars_fragment>\n#include <aomap_pars_fragment>\n#include <lightmap_pars_fragment>\n#include <emissivemap_pars_fragment>\n#include <envmap_pars_fragment>\n#include <gradientmap_pars_fragment>\n#include <fog_pars_fragment>\n#include <bsdfs>\n#include <lights_pars_begin>\n#include <lights_pars_maps>\n#include <lights_phong_pars_fragment>\n#include <shadowmap_pars_fragment>\n#include <bumpmap_pars_fragment>\n#include <normalmap_pars_fragment>\n#include <specularmap_pars_fragment>\n#include <logdepthbuf_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvoid main() {\n\t#include <clipping_planes_fragment>\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 <logdepthbuf_fragment>\n\t#include <map_fragment>\n\t#include <color_fragment>\n\t#include <alphamap_fragment>\n\t#include <alphatest_fragment>\n\t#include <specularmap_fragment>\n\t#include <normal_fragment_begin>\n\t#include <normal_fragment_maps>\n\t#include <emissivemap_fragment>\n\t#include <lights_phong_fragment>\n\t#include <lights_fragment_begin>\n\t#include <lights_fragment_maps>\n\t#include <lights_fragment_end>\n\t#include <aomap_fragment>\n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular + totalEmissiveRadiance;\n\t#include <envmap_fragment>\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include <tonemapping_fragment>\n\t#include <encodings_fragment>\n\t#include <fog_fragment>\n\t#include <premultiplied_alpha_fragment>\n\t#include <dithering_fragment>\n}\n";
9658  
9659	var meshphong_vert = "#define PHONG\nvarying vec3 vView
9659Position;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include <common>\n#include <uv_pars_vertex>\n#include <uv2_pars_vertex>\n#include <displacementmap_pars_vertex>\n#include <envmap_pars_vertex>\n#include <color_pars_vertex>\n#include <fog_pars_vertex>\n#include <morphtarget_pars_vertex>\n#include <skinning_pars_vertex>\n#include <shadowmap_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\t#include <uv_vertex>\n\t#include <uv2_vertex>\n\t#include <color_vertex>\n\t#include <beginnormal_vertex>\n\t#include <morphnormal_vertex>\n\t#include <skinbase_vertex>\n\t#include <skinnormal_vertex>\n\t#include <defaultnormal_vertex>\n#ifndef FLAT_SHADED\n\tvNormal = normalize( transformedNormal );\n#endif\n\t#include <begin_vertex>\n\t#include <morphtarget_vertex>\n\t#include <skinning_vertex>\n\t#include <displacementmap_vertex>\n\t#include <project_vertex>\n\t#include <logdepthbuf_vertex>\n\t#include <clipping_planes_vertex>\n\tvViewPosition = - mvPosition.xyz;\n\t#include <worldpos_vertex>\n\t#include <envmap_vertex>\n\t#include <shadowmap_vertex>\n\t#include <fog_vertex>\n}\n";
9660  
9661	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 <common>\n#include <packing>\n#include <dithering_pars_fragment>\n#include <color_pars_fragment>\n#include <uv_pars_fragment>\n#include <uv2_pars_fragment>\n#include <map_pars_fragment>\n#include <alphamap_pars_fragment>\n#include <aomap_pars_fragment>\n#include <lightmap_pars_fragment>\n#include <emissivemap_pars_fragment>\n#include <envmap_pars_fragment>\n#include <fog_pars_fragment>\n#include <bsdfs>\n#include <cube_uv_reflection_fragment>\n#include <lights_pars_begin>\n#include <lights_pars_maps>\n#include <lights_physical_pars_fragment>\n#include <shadowmap_pars_fragment>\n#include <bumpmap_pars_fragment>\n#include <normalmap_pars_fragment>\n#include <roughnessmap_pars_fragment>\n#include <metalnessmap_pars_fragment>\n#include <logdepthbuf_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvoid main() {\n\t#include <clipping_planes_fragment>\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 <logdepthbuf_fragment>\n\t#include <map_fragment>\n\t#include <color_fragment>\n\t#include <alphamap_fragment>\n\t#include <alphatest_fragment>\n\t#include <roughnessmap_fragment>\n\t#include <metalnessmap_fragment>\n\t#include <normal_fragment_begin>\n\t#include <normal_fragment_maps>\n\t#include <emissivemap_fragment>\n\t#include <lights_physical_fragment>\n\t#include <lights_fragment_begin>\n\t#include <lights_fragment_maps>\n\t#include <lights_fragment_end>\n\t#include <aomap_fragment>\n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular + totalEmissiveRadiance;\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include <tonemapping_fragment>\n\t#include <encodings_fragment>\n\t#include <fog_fragment>\n\t#include <premultiplied_alpha_fragment>\n\t#include <dithering_fragment>\n}\n";
9662  
9663	var meshphysical_vert = "#define PHYSICAL\nvarying vec3 vViewPosition;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include <common>\n#include <uv_pars_vertex>\n#include <uv2_pars_vertex>\n#include <displacementmap_pars_vertex>\n#include <color_pars_vertex>\n#include <fog_pars_vertex>\n#include <morphtarget_pars_vertex>\n#include <skinning_pars_vertex>\n#include <shadowmap_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\t#include <uv_vertex>\n\t#include <uv2_vertex>\n\t#include <color_vertex>\n\t#include <beginnormal_vertex>\n\t#include <morphnormal_vertex>\n\t#include <skinbase_vertex>\n\t#include <skinnormal_vertex>\n\t#include <defaultnormal_vertex>\n#ifndef FLAT_SHADED\n\tvNormal = normalize( transformedNormal );\n#endif\n\t#include <begin_vertex>\n\t#include <morphtarget_vertex>\n\t#include <skinning_vertex>\n\t#include <displacementmap_vertex>\n\t#include <project_vertex>\n\t#include <logdepthbuf_vertex>\n\t#include <clipping_planes_vertex>\n\tvViewPosition = - mvPosition.xyz;\n\t#include <worldpos_vertex>\n\t#include <shadowmap_vertex>\n\t#include <fog_vertex>\n}\n";
9664  
9665	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 <packing>\n#include <uv_pars_fragment>\n#include <bumpmap_pars_fragment>\n#include <normalmap_pars_fragment>\n#include <logdepthbuf_pars_fragment>\nvoid main() {\n\t#include <logdepthbuf_fragment>\n\t#include <normal_fragment_begin>\n\t#include <normal_fragment_maps>\n\tgl_FragColor = vec4( packNormalToRGB( normal ), opacity );\n}\n";
9666  
9667	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 <uv_pars_vertex>\n#include <displacementmap_pars_vertex>\n#include <morphtarget_pars_vertex>\n#include <skinning_pars_vertex>\n#include <logdepthbuf_pars_vertex>\nvoid main() {\n\t#include <uv_vertex>\n\t#include <beginnormal_vertex>\n\t#include <morphnormal_vertex>\n\t#include <skinbase_vertex>\n\t#include <skinnormal_vertex>\n\t#include <defaultnormal_vertex>\n#ifndef FLAT_SHADED\n\tvNormal = normalize( transformedNormal );\n#endif\n\t#include <begin_vertex>\n\t#include <morphtarget_vertex>\n\t#include <skinning_vertex>\n\t#include <displacementmap_vertex>\n\t#include <project_vertex>\n\t#include <logdepthbuf_vertex>\n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP )\n\tvViewPosition = - mvPosition.xyz;\n#endif\n}\n";
9668  
9669	var points_frag = "uniform vec3 diffuse;\nuniform float opacity;\n#include <common>\n#include <packing>\n#include <color_pars_fragment>\n#include <map_particle_pars_fragment>\n#include <fog_pars_fragment>\n#include <logdepthbuf_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvoid main() {\n\t#include <clipping_planes_fragment>\n\tvec3 outgoingLight = vec3( 0.0 );\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include <logdepthbuf_fragment>\n\t#include <map_particle_fragment>\n\t#include <color_fragment>\n\t#include <alphatest_fragment>\n\toutgoingLight = diffuseColor.rgb;\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include <premultiplied_alpha_fragment>\n\t#include <tonemapping_fragment>\n\t#include <encodings_fragment>\n\t#include <fog_fragment>\n}\n";
9670  
9671	var points_vert = "uniform float size;\nuniform float scale;\n#include <common>\n#include <color_pars_vertex>\n#include <fog_pars_vertex>\n#include <morphtarget_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\t#include <color_vertex>\n\t#include <begin_vertex>\n\t#include <morphtarget_vertex>\n\t#include <project_vertex>\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 <logdepthbuf_vertex>\n\t#include <clipping_planes_vertex>\n\t#include <worldpos_vertex>\n\t#include <fog_vertex>\n}\n";
9672  
9673	var shadow_frag = "uniform vec3 color;\nuniform float opacity;\n#include <common>\n#include <packing>\n#include <fog_pars_fragment>\n#include <bsdfs>\n#include <lights_pars_begin>\n#include <shadowmap_pars_fragment>\n#include <shadowmask_pars_fragment>\nvoid main() {\n\tgl_FragColor = vec4( color, opacity * ( 1.0 - getShadowMask() ) );\n\t#include <fog_fragment>\n}\n";
9674  
9675	var shadow_vert = "#include <fog_pars_vertex>\n#include <shadowmap_pars_vertex>\nvoid main() {\n\t#include <begin_vertex>\n\t#include <project_vertex>\n\t#include <worldpos_vertex>\n\t#include <shadowmap_vertex>\n\t#include <fog_vertex>\n}\n";
9676  
9677	var ShaderChunk = {
9678		alphamap_fragment: alphamap_fragment,
9679		alphamap_pars_fragment: alphamap_pars_fragment,
9680		alphatest_fragment: alphatest_fragment,
9681		aomap_fragment: aomap_fragment,
9682		aomap_pars_fragment: aomap_pars_fragment,
9683		begin_vertex: begin_vertex,
9684		beginnormal_vertex: beginnormal_vertex,
9685		bsdfs: bsdfs,
9686		bumpmap_pars_fragment: bumpmap_pars_fragment,
9687		clipping_planes_fragment: clipping_planes_fragment,
9688		clipping_planes_pars_fragment: clipping_planes_pars_fragment,
9689		clipping_planes_pars_vertex: clipping_planes_pars_vertex,
9690		clipping_planes_vertex: clipping_planes_vertex,
9691		color_fragment: color_fragment,
9692		color_pars_fragment: color_pars_fragment,
9693		color_pars_vertex: color_pars_vertex,
9694		color_vertex: color_vertex,
9695		common: common,
9696		cube_uv_reflection_fragment: cube_uv_reflection_fragment,
9697		defaultnormal_vertex: defaultnormal_vertex,
9698		displacementmap_pars_vertex: displacementmap_pars_vertex,
9699		displacementmap_vertex: displacementmap_vertex,
9700		emissivemap_fragment: emissivemap_fragment,
9701		emissivemap_pars_fragment: emissivemap_pars_fragment,
9702		encodings_fragment: encodings_fragment,
9703		encodings_pars_fragment: encodings_pars_fragment,
9704		envmap_fragment: envmap_fragment,
9705		envmap_pars_fragment: envmap_pars_fragment,
9706		envmap_pars_vertex: envmap_pars_vertex,
9707		envmap_vertex: envmap_vertex,
9708		fog_vertex: fog_vertex,
9709		fog_pars_vertex: fog_pars_vertex,
9710		fog_fragment: fog_fragment,
9711		fog_pars_fragment: fog_pars_fragment,
9712		gradientmap_pars_fragment: gradientmap_pars_fragment,
9713		lightmap_fragment: lightmap_fragment,
9714		lightmap_pars_fragment: lightmap_pars_fragment,
9715		lights_lambert_vertex: lights_lambert_vertex,
9716		lights_pars_begin: lights_pars_begin,
9717		lights_pars_maps: lights_pars_maps,
9718		lights_phong_fragment: lights_phong_fragment,
9719		lights_phong_pars_fragment: lights_phong_pars_fragment,
9720		lights_physical_fragment: lights_physical_fragment,
9721		lights_physical_pars_fragment: lights_physical_pars_fragment,
9722		lights_fragment_begin: lights_fragment_begin,
9723		lights_fragment_maps: lights_fragment_maps,
9724		lights_fragment_end: lights_fragment_end,
9725		logdepthbuf_fragment: logdepthbuf_fragment,
9726		logdepthbuf_pars_fragment: logdepthbuf_pars_fragment,
9727		logdepthbuf_pars_vertex: logdepthbuf_pars_vertex,
9728		logdepthbuf_vertex: logdepthbuf_vertex,
9729		map_fragment: map_fragment,
9730		map_pars_fragment: map_pars_fragment,
9731		map_particle_fragment: map_particle_fragment,
9732		map_particle_pars_fragment: map_particle_pars_fragment,
9733		metalnessmap_fragment: metalnessmap_fragment,
9734		metalnessmap_pars_fragment: metalnessmap_pars_fragment,
9735		morphnormal_vertex: morphnormal_vertex,
9736		morphtarget_pars_vertex: morphtarget_pars_vertex,
9737		morphtarget_vertex: morphtarget_vertex,
9738		normal_fragment_begin: normal_fragment_begin,
9739		normal_fragment_maps: normal_fragment_maps,
9740		normalmap_pars_fragment: normalmap_pars_fragment,
9741		packing: packing,
9742		premultiplied_alpha_fragment: premultiplied_alpha_fragment,
9743		project_vertex: project_vertex,
9744		dithering_fragment: dithering_fragment,
9745		dithering_pars_fragment: dithering_pars_fragment,
9746		roughnessmap_fragment: roughnessmap_fragment,
9747		roughnessmap_pars_fragment: roughnessmap_pars_fragment,
9748		shadowmap_pars_fragment: shadowmap_pars_fragment,
9749		shadowmap_pars_vertex: shadowmap_pars_vertex,
9750		shadowmap_vertex: shadowmap_vertex,
9751		shadowmask_pars_fragment: shadowmask_pars_fragment,
9752		skinbase_vertex: skinbase_vertex,
9753		skinning_pars_vertex: skinning_pars_vertex,
9754		skinning_vertex: skinning_vertex,
9755		skinnormal_vertex: skinnormal_vertex,
9756		specularmap_fragment: specularmap_fragment,
9757		specularmap_pars_fragment: specularmap_pars_fragment,
9758		tonemapping_fragment: tonemapping_fragment,
9759		tonemapping_pars_fragment: tonemapping_pars_fragment,
9760		uv_pars_fragment: uv_pars_fragment,
9761		uv_pars_vertex: uv_pars_vertex,
9762		uv_vertex: uv_vertex,
9763		uv2_pars_fragment: uv2_pars_fragment,
9764		uv2_pars_vertex: uv2_pars_vertex,
9765		uv2_vertex: uv2_vertex,
9766		worldpos_vertex: worldpos_vertex,
9767  
9768		cube_frag: cube_frag,
9769		cube_vert: cube_vert,
9770		depth_frag: depth_frag,
9771		depth_vert: depth_vert,
9772		distanceRGBA_frag: distanceRGBA_frag,
9773		distanceRGBA_vert: distanceRGBA_vert,
9774		equirect_frag: equirect_frag,
9775		equirect_vert: equirect_vert,
9776		linedashed_frag: linedashed_frag,
9777		linedashed_vert: linedashed_vert,
9778		meshbasic_frag: meshbasic_frag,
9779		meshbasic_vert: meshbasic_vert,
9780		meshlambert_frag: meshlambert_frag,
9781		meshlambert_vert: meshlambert_vert,
9782		meshphong_frag: meshphong_frag,
9783		meshphong_vert: meshphong_vert,
9784		meshphysical_frag: meshphysical_frag,
9785		meshphysical_vert: meshphysical_vert,
9786		normal_frag: normal_frag,
9787		normal_vert: normal_vert,
9788		points_frag: points_frag,
9789		points_vert: points_vert,
9790		shadow_frag: shadow_frag,
9791		shadow_vert: shadow_vert
9792	};
9793  
9794	/**
9795	 * Uniform Utilities
9796	 */
9797  
9798	var UniformsUtils = {
9799  
9800		merge: function ( uniforms ) {
9801  
9802			var merged = {};
9803  
9804			for ( var u = 0; u < uniforms.length; u ++ ) {
9805  
9806				var tmp = this.clone( uniforms[ u ] );
9807  
9808				for ( var p in tmp ) {
9809  
9810					merged[ p ] = tmp[ p ];
9811  
9812				}
9813  
9814			}
9815  
9816			return merged;
9817  
9818		},
9819  
vendor: 16,770 bytes, lines 9820-10585
9820		clone: function ( uniforms_src ) {
9821  
9822			var uniforms_dst = {};
9823  
9824			for ( var u in uniforms_src ) {
9825  
9826				uniforms_dst[ u ] = {};
9827  
9828				for ( var p in uniforms_src[ u ] ) {
9829  
9830					var parameter_src = uniforms_src[ u ][ p ];
9831  
9832					if ( parameter_src && ( parameter_src.isColor ||
9833						parameter_src.isMatrix3 || parameter_src.isMatrix4 ||
9834						parameter_src.isVector2 || parameter_src.isVector3 || parameter_src.isVector4 ||
9835						parameter_src.isTexture ) ) {
9836  
9837						uniforms_dst[ u ][ p ] = parameter_src.clone();
9838  
9839					} else if ( Array.isArray( parameter_src ) ) {
9840  
9841						uniforms_dst[ u ][ p ] = parameter_src.slice();
9842  
9843					} else {
9844  
9845						uniforms_dst[ u ][ p ] = parameter_src;
9846  
9847					}
9848  
9849				}
9850  
9851			}
9852  
9853			return uniforms_dst;
9854  
9855		}
9856  
9857	};
9858  
9859	/**
9860	 * @author mrdoob / http://mrdoob.com/
9861	 */
9862  
9863	var ColorKeywords = { 'aliceblue': 0xF0F8FF, 'antiquewhite': 0xFAEBD7, 'aqua': 0x00FFFF, 'aquamarine': 0x7FFFD4, 'azure': 0xF0FFFF,
9864		'beige': 0xF5F5DC, 'bisque': 0xFFE4C4, 'black': 0x000000, 'blanchedalmond': 0xFFEBCD, 'blue': 0x0000FF, 'blueviolet': 0x8A2BE2,
9865		'brown': 0xA52A2A, 'burlywood': 0xDEB887, 'cadetblue': 0x5F9EA0, 'chartreuse': 0x7FFF00, 'chocolate': 0xD2691E, 'coral': 0xFF7F50,
9866		'cornflowerblue': 0x6495ED, 'cornsilk': 0xFFF8DC, 'crimson': 0xDC143C, 'cyan': 0x00FFFF, 'darkblue': 0x00008B, 'darkcyan': 0x008B8B,
9867		'darkgoldenrod': 0xB8860B, 'darkgray': 0xA9A9A9, 'darkgreen': 0x006400, 'darkgrey': 0xA9A9A9, 'darkkhaki': 0xBDB76B, 'darkmagenta': 0x8B008B,
9868		'darkolivegreen': 0x556B2F, 'darkorange': 0xFF8C00, 'darkorchid': 0x9932CC, 'darkred': 0x8B0000, 'darksalmon': 0xE9967A, 'darkseagreen': 0x8FBC8F,
9869		'darkslateblue': 0x483D8B, 'darkslategray': 0x2F4F4F, 'darkslategrey': 0x2F4F4F, 'darkturquoise': 0x00CED1, 'darkviolet': 0x9400D3,
9870		'deeppink': 0xFF1493, 'deepskyblue': 0x00BFFF, 'dimgray': 0x696969, 'dimgrey': 0x696969, 'dodgerblue': 0x1E90FF, 'firebrick': 0xB22222,
9871		'floralwhite': 0xFFFAF0, 'forestgreen': 0x228B22, 'fuchsia': 0xFF00FF, 'gainsboro': 0xDCDCDC, 'ghostwhite': 0xF8F8FF, 'gold': 0xFFD700,
9872		'goldenrod': 0xDAA520, 'gray': 0x808080, 'green': 0x008000, 'greenyellow': 0xADFF2F, 'grey': 0x808080, 'honeydew': 0xF0FFF0, 'hotpink': 0xFF69B4,
9873		'indianred': 0xCD5C5C, 'indigo': 0x4B0082, 'ivory': 0xFFFFF0, 'khaki': 0xF0E68C, 'lavender': 0xE6E6FA, 'lavenderblush': 0xFFF0F5, 'lawngreen': 0x7CFC00,
9874		'lemonchiffon': 0xFFFACD, 'lightblue': 0xADD8E6, 'lightcoral': 0xF08080, 'lightcyan': 0xE0FFFF, 'lightgoldenrodyellow': 0xFAFAD2, 'lightgray': 0xD3D3D3,
9875		'lightgreen': 0x90EE90, 'lightgrey': 0xD3D3D3, 'lightpink': 0xFFB6C1, 'lightsalmon': 0xFFA07A, 'lightseagreen': 0x20B2AA, 'lightskyblue': 0x87CEFA,
9876		'lightslategray': 0x778899, 'lightslategrey': 0x778899, 'lightsteelblue': 0xB0C4DE, 'lightyellow': 0xFFFFE0, 'lime': 0x00FF00, 'limegreen': 0x32CD32,
9877		'linen': 0xFAF0E6, 'magenta': 0xFF00FF, 'maroon': 0x800000, 'mediumaquamarine': 0x66CDAA, 'mediumblue': 0x0000CD, 'mediumorchid': 0xBA55D3,
9878		'mediumpurple': 0x9370DB, 'mediumseagreen': 0x3CB371, 'mediumslateblue': 0x7B68EE, 'mediumspringgreen': 0x00FA9A, 'mediumturquoise': 0x48D1CC,
9879		'mediumvioletred': 0xC71585, 'midnightblue': 0x191970, 'mintcream': 0xF5FFFA, 'mistyrose': 0xFFE4E1, 'moccasin': 0xFFE4B5, 'navajowhite': 0xFFDEAD,
9880		'navy': 0x000080, 'oldlace': 0xFDF5E6, 'olive': 0x808000, 'olivedrab': 0x6B8E23, 'orange': 0xFFA500, 'orangered': 0xFF4500, 'orchid': 0xDA70D6,
9881		'palegoldenrod': 0xEEE8AA, 'palegreen': 0x98FB98, 'paleturquoise': 0xAFEEEE, 'palevioletred': 0xDB7093, 'papayawhip': 0xFFEFD5, 'peachpuff': 0xFFDAB9,
9882		'peru': 0xCD853F, 'pink': 0xFFC0CB, 'plum': 0xDDA0DD, 'powderblue': 0xB0E0E6, 'purple': 0x800080, 'rebeccapurple': 0x663399, 'red': 0xFF0000, 'rosybrown': 0xBC8F8F,
9883		'royalblue': 0x4169E1, 'saddlebrown': 0x8B4513, 'salmon': 0xFA8072, 'sandybrown': 0xF4A460, 'seagreen': 0x2E8B57, 'seashell': 0xFFF5EE,
9884		'sienna': 0xA0522D, 'silver': 0xC0C0C0, 'skyblue': 0x87CEEB, 'slateblue': 0x6A5ACD, 'slategray': 0x708090, 'slategrey': 0x708090, 'snow': 0xFFFAFA,
9885		'springgreen': 0x00FF7F, 'steelblue': 0x4682B4, 'tan': 0xD2B48C, 'teal': 0x008080, 'thistle': 0xD8BFD8, 'tomato': 0xFF6347, 'turquoise': 0x40E0D0,
9886		'violet': 0xEE82EE, 'wheat': 0xF5DEB3, 'white': 0xFFFFFF, 'whitesmoke': 0xF5F5F5, 'yellow': 0xFFFF00, 'yellowgreen': 0x9ACD32 };
9887  
9888	function Color( r, g, b ) {
9889  
9890		if ( g === undefined && b === undefined ) {
9891  
9892			// r is THREE.Color, hex or string
9893			return this.set( r );
9894  
9895		}
9896  
9897		return this.setRGB( r, g, b );
9898  
9899	}
9900  
9901	Object.assign( Color.prototype, {
9902  
9903		isColor: true,
9904  
9905		r: 1, g: 1, b: 1,
9906  
9907		set: function ( value ) {
9908  
9909			if ( value && value.isColor ) {
9910  
9911				this.copy( value );
9912  
9913			} else if ( typeof value === 'number' ) {
9914  
9915				this.setHex( value );
9916  
9917			} else if ( typeof value === 'string' ) {
9918  
9919				this.setStyle( value );
9920  
9921			}
9922  
9923			return this;
9924  
9925		},
9926  
9927		setScalar: function ( scalar ) {
9928  
9929			this.r = scalar;
9930			this.g = scalar;
9931			this.b = scalar;
9932  
9933			return this;
9934  
9935		},
9936  
9937		setHex: function ( hex ) {
9938  
9939			hex = Math.floor( hex );
9940  
9941			this.r = ( hex >> 16 & 255 ) / 255;
9942			this.g = ( hex >> 8 & 255 ) / 255;
9943			this.b = ( hex & 255 ) / 255;
9944  
9945			return this;
9946  
9947		},
9948  
9949		setRGB: function ( r, g, b ) {
9950  
9951			this.r = r;
9952			this.g = g;
9953			this.b = b;
9954  
9955			return this;
9956  
9957		},
9958  
9959		setHSL: function () {
9960  
9961			function hue2rgb( p, q, t ) {
9962  
9963				if ( t < 0 ) t += 1;
9964				if ( t > 1 ) t -= 1;
9965				if ( t < 1 / 6 ) return p + ( q - p ) * 6 * t;
9966				if ( t < 1 / 2 ) return q;
9967				if ( t < 2 / 3 ) return p + ( q - p ) * 6 * ( 2 / 3 - t );
9968				return p;
9969  
9970			}
9971  
9972			return function setHSL( h, s, l ) {
9973  
9974				// h,s,l ranges are in 0.0 - 1.0
9975				h = _Math.euclideanModulo( h, 1 );
9976				s = _Math.clamp( s, 0, 1 );
9977				l = _Math.clamp( l, 0, 1 );
9978  
9979				if ( s === 0 ) {
9980  
9981					this.r = this.g = this.b = l;
9982  
9983				} else {
9984  
9985					var p = l <= 0.5 ? l * ( 1 + s ) : l + s - ( l * s );
9986					var q = ( 2 * l ) - p;
9987  
9988					this.r = hue2rgb( q, p, h + 1 / 3 );
9989					this.g = hue2rgb( q, p, h );
9990					this.b = hue2rgb( q, p, h - 1 / 3 );
9991  
9992				}
9993  
9994				return this;
9995  
9996			};
9997  
9998		}(),
9999  
10000		setStyle: function ( style ) {
10001  
10002			function handleAlpha( string ) {
10003  
10004				if ( string === undefined ) return;
10005  
10006				if ( parseFloat( string ) < 1 ) {
10007  
10008					console.warn( 'THREE.Color: Alpha component of ' + style + ' will be ignored.' );
10009  
10010				}
10011  
10012			}
10013  
10014  
10015			var m;
10016  
10017			if ( m = /^((?:rgb|hsl)a?)\(\s*([^\)]*)\)/.exec( style ) ) {
10018  
10019				// rgb / hsl
10020  
10021				var color;
10022				var name = m[ 1 ];
10023				var components = m[ 2 ];
10024  
10025				switch ( name ) {
10026  
10027					case 'rgb':
10028					case 'rgba':
10029  
10030						if ( color = /^(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(,\s*([0-9]*\.?[0-9]+)\s*)?$/.exec( components ) ) {
10031  
10032							// rgb(255,0,0) rgba(255,0,0,0.5)
10033							this.r = Math.min( 255, parseInt( color[ 1 ], 10 ) ) / 255;
10034							this.g = Math.min( 255, parseInt( color[ 2 ], 10 ) ) / 255;
10035							this.b = Math.min( 255, parseInt( color[ 3 ], 10 ) ) / 255;
10036  
10037							handleAlpha( color[ 5 ] );
10038  
10039							return this;
10040  
10041						}
10042  
10043						if ( color = /^(\d+)\%\s*,\s*(\d+)\%\s*,\s*(\d+)\%\s*(,\s*([0-9]*\.?[0-9]+)\s*)?$/.exec( components ) ) {
10044  
10045							// rgb(100%,0%,0%) rgba(100%,0%,0%,0.5)
10046							this.r = Math.min( 100, parseInt( color[ 1 ], 10 ) ) / 100;
10047							this.g = Math.min( 100, parseInt( color[ 2 ], 10 ) ) / 100;
10048							this.b = Math.min( 100, parseInt( color[ 3 ], 10 ) ) / 100;
10049  
10050							handleAlpha( color[ 5 ] );
10051  
10052							return this;
10053  
10054						}
10055  
10056						break;
10057  
10058					case 'hsl':
10059					case 'hsla':
10060  
10061						if ( color = /^([0-9]*\.?[0-9]+)\s*,\s*(\d+)\%\s*,\s*(\d+)\%\s*(,\s*([0-9]*\.?[0-9]+)\s*)?$/.exec( components ) ) {
10062  
10063							// hsl(120,50%,50%) hsla(120,50%,50%,0.5)
10064							var h = parseFloat( color[ 1 ] ) / 360;
10065							var s = parseInt( color[ 2 ], 10 ) / 100;
10066							var l = parseInt( color[ 3 ], 10 ) / 100;
10067  
10068							handleAlpha( color[ 5 ] );
10069  
10070							return this.setHSL( h, s, l );
10071  
10072						}
10073  
10074						break;
10075  
10076				}
10077  
10078			} else if ( m = /^\#([A-Fa-f0-9]+)$/.exec( style ) ) {
10079  
10080				// hex color
10081  
10082				var hex = m[ 1 ];
10083				var size = hex.length;
10084  
10085				if ( size === 3 ) {
10086  
10087					// #ff0
10088					this.r = parseInt( hex.charAt( 0 ) + hex.charAt( 0 ), 16 ) / 255;
10089					this.g = parseInt( hex.charAt( 1 ) + hex.charAt( 1 ), 16 ) / 255;
10090					this.b = parseInt( hex.charAt( 2 ) + hex.charAt( 2 ), 16 ) / 255;
10091  
10092					return this;
10093  
10094				} else if ( size === 6 ) {
10095  
10096					// #ff0000
10097					this.r = parseInt( hex.charAt( 0 ) + hex.charAt( 1 ), 16 ) / 255;
10098					this.g = parseInt( hex.charAt( 2 ) + hex.charAt( 3 ), 16 ) / 255;
10099					this.b = parseInt( hex.charAt( 4 ) + hex.charAt( 5 ), 16 ) / 255;
10100  
10101					return this;
10102  
10103				}
10104  
10105			}
10106  
10107			if ( style && style.length > 0 ) {
10108  
10109				// color keywords
10110				var hex = ColorKeywords[ style ];
10111  
10112				if ( hex !== undefined ) {
10113  
10114					// red
10115					this.setHex( hex );
10116  
10117				} else {
10118  
10119					// unknown color
10120					console.warn( 'THREE.Color: Unknown color ' + style );
10121  
10122				}
10123  
10124			}
10125  
10126			return this;
10127  
10128		},
10129  
10130		clone: function () {
10131  
10132			return new this.constructor( this.r, this.g, this.b );
10133  
10134		},
10135  
10136		copy: function ( color ) {
10137  
10138			this.r = color.r;
10139			this.g = color.g;
10140			this.b = color.b;
10141  
10142			return this;
10143  
10144		},
10145  
10146		copyGammaToLinear: function ( color, gammaFactor ) {
10147  
10148			if ( gammaFactor === undefined ) gammaFactor = 2.0;
10149  
10150			this.r = Math.pow( color.r, gammaFactor );
10151			this.g = Math.pow( color.g, gammaFactor );
10152			this.b = Math.pow( color.b, gammaFactor );
10153  
10154			return this;
10155  
10156		},
10157  
10158		copyLinearToGamma: function ( color, gammaFactor ) {
10159  
10160			if ( gammaFactor === undefined ) gammaFactor = 2.0;
10161  
10162			var safeInverse = ( gammaFactor > 0 ) ? ( 1.0 / gammaFactor ) : 1.0;
10163  
10164			this.r = Math.pow( color.r, safeInverse );
10165			this.g = Math.pow( color.g, safeInverse );
10166			this.b = Math.pow( color.b, safeInverse );
10167  
10168			return this;
10169  
10170		},
10171  
10172		convertGammaToLinear: function ( gammaFactor ) {
10173  
10174			this.copyGammaToLinear( this, gammaFactor );
10175  
10176			return this;
10177  
10178		},
10179  
10180		convertLinearToGamma: function ( gammaFactor ) {
10181  
10182			this.copyLinearToGamma( this, gammaFactor );
10183  
10184			return this;
10185  
10186		},
10187  
10188		getHex: function () {
10189  
10190			return ( this.r * 255 ) << 16 ^ ( this.g * 255 ) << 8 ^ ( this.b * 255 ) << 0;
10191  
10192		},
10193  
10194		getHexString: function () {
10195  
10196			return ( '000000' + this.getHex().toString( 16 ) ).slice( - 6 );
10197  
10198		},
10199  
10200		getHSL: function ( target ) {
10201  
10202			// h,s,l ranges are in 0.0 - 1.0
10203  
10204			if ( target === undefined ) {
10205  
10206				console.warn( 'THREE.Color: .getHSL() target is now required' );
10207				target = { h: 0, s: 0, l: 0 };
10208  
10209			}
10210  
10211			var r = this.r, g = this.g, b = this.b;
10212  
10213			var max = Math.max( r, g, b );
10214			var min = Math.min( r, g, b );
10215  
10216			var hue, saturation;
10217			var lightness = ( min + max ) / 2.0;
10218  
10219			if ( min === max ) {
10220  
10221				hue = 0;
10222				saturation = 0;
10223  
10224			} else {
10225  
10226				var delta = max - min;
10227  
10228				saturation = lightness <= 0.5 ? delta / ( max + min ) : delta / ( 2 - max - min );
10229  
10230				switch ( max ) {
10231  
10232					case r: hue = ( g - b ) / delta + ( g < b ? 6 : 0 ); break;
10233					case g: hue = ( b - r ) / delta + 2; break;
10234					case b: hue = ( r - g ) / delta + 4; break;
10235  
10236				}
10237  
10238				hue /= 6;
10239  
10240			}
10241  
10242			target.h = hue;
10243			target.s = saturation;
10244			target.l = lightness;
10245  
10246			return target;
10247  
10248		},
10249  
10250		getStyle: function () {
10251  
10252			return 'rgb(' + ( ( this.r * 255 ) | 0 ) + ',' + ( ( this.g * 255 ) | 0 ) + ',' + ( ( this.b * 255 ) | 0 ) + ')';
10253  
10254		},
10255  
10256		offsetHSL: function () {
10257  
10258			var hsl = {};
10259  
10260			return function ( h, s, l ) {
10261  
10262				this.getHSL( hsl );
10263  
10264				hsl.h += h; hsl.s += s; hsl.l += l;
10265  
10266				this.setHSL( hsl.h, hsl.s, hsl.l );
10267  
10268				return this;
10269  
10270			};
10271  
10272		}(),
10273  
10274		add: function ( color ) {
10275  
10276			this.r += color.r;
10277			this.g += color.g;
10278			this.b += color.b;
10279  
10280			return this;
10281  
10282		},
10283  
10284		addColors: function ( color1, color2 ) {
10285  
10286			this.r = color1.r + color2.r;
10287			this.g = color1.g + color2.g;
10288			this.b = color1.b + color2.b;
10289  
10290			return this;
10291  
10292		},
10293  
10294		addScalar: function ( s ) {
10295  
10296			this.r += s;
10297			this.g += s;
10298			this.b += s;
10299  
10300			return this;
10301  
10302		},
10303  
10304		sub: function ( color ) {
10305  
10306			this.r = Math.max( 0, this.r - color.r );
10307			this.g = Math.max( 0, this.g - color.g );
10308			this.b = Math.max( 0, this.b - color.b );
10309  
10310			return this;
10311  
10312		},
10313  
10314		multiply: function ( color ) {
10315  
10316			this.r *= color.r;
10317			this.g *= color.g;
10318			this.b *= color.b;
10319  
10320			return this;
10321  
10322		},
10323  
10324		multiplyScalar: function ( s ) {
10325  
10326			this.r *= s;
10327			this.g *= s;
10328			this.b *= s;
10329  
10330			return this;
10331  
10332		},
10333  
10334		lerp: function ( color, alpha ) {
10335  
10336			this.r += ( color.r - this.r ) * alpha;
10337			this.g += ( color.g - this.g ) * alpha;
10338			this.b += ( color.b - this.b ) * alpha;
10339  
10340			return this;
10341  
10342		},
10343  
10344		equals: function ( c ) {
10345  
10346			return ( c.r === this.r ) && ( c.g === this.g ) && ( c.b === this.b );
10347  
10348		},
10349  
10350		fromArray: function ( array, offset ) {
10351  
10352			if ( offset === undefined ) offset = 0;
10353  
10354			this.r = array[ offset ];
10355			this.g = array[ offset + 1 ];
10356			this.b = array[ offset + 2 ];
10357  
10358			return this;
10359  
10360		},
10361  
10362		toArray: function ( array, offset ) {
10363  
10364			if ( array === undefined ) array = [];
10365			if ( offset === undefined ) offset = 0;
10366  
10367			array[ offset ] = this.r;
10368			array[ offset + 1 ] = this.g;
10369			array[ offset + 2 ] = this.b;
10370  
10371			return array;
10372  
10373		},
10374  
10375		toJSON: function () {
10376  
10377			return this.getHex();
10378  
10379		}
10380  
10381	} );
10382  
10383	/**
10384	 * Uniforms library for shared webgl shaders
10385	 */
10386  
10387	var UniformsLib = {
10388  
10389		common: {
10390  
10391			diffuse: { value: new Color( 0xeeeeee ) },
10392			opacity: { value: 1.0 },
10393  
10394			map: { value: null },
10395			uvTransform: { value: new Matrix3() },
10396  
10397			alphaMap: { value: null },
10398  
10399		},
10400  
10401		specularmap: {
10402  
10403			specularMap: { value: null },
10404  
10405		},
10406  
10407		envmap: {
10408  
10409			envMap: { value: null },
10410			flipEnvMap: { value: - 1 },
10411			reflectivity: { value: 1.0 },
10412			refractionRatio: { value: 0.98 },
10413			maxMipLevel: { value: 0 }
10414  
10415		},
10416  
10417		aomap: {
10418  
10419			aoMap: { value: null },
10420			aoMapIntensity: { value: 1 }
10421  
10422		},
10423  
10424		lightmap: {
10425  
10426			lightMap: { value: null },
10427			lightMapIntensity: { value: 1 }
10428  
10429		},
10430  
10431		emissivemap: {
10432  
10433			emissiveMap: { value: null }
10434  
10435		},
10436  
10437		bumpmap: {
10438  
10439			bumpMap: { value: null },
10440			bumpScale: { value: 1 }
10441  
10442		},
10443  
10444		normalmap: {
10445  
10446			normalMap: { value: null },
10447			normalScale: { value: new Vector2( 1, 1 ) }
10448  
10449		},
10450  
10451		displacementmap: {
10452  
10453			displacementMap: { value: null },
10454			displacementScale: { value: 1 },
10455			displacementBias: { value: 0 }
10456  
10457		},
10458  
10459		roughnessmap: {
10460  
10461			roughnessMap: { value: null }
10462  
10463		},
10464  
10465		metalnessmap: {
10466  
10467			metalnessMap: { value: null }
10468  
10469		},
10470  
10471		gradientmap: {
10472  
10473			gradientMap: { value: null }
10474  
10475		},
10476  
10477		fog: {
10478  
10479			fogDensity: { value: 0.00025 },
10480			fogNear: { value: 1 },
10481			fogFar: { value: 2000 },
10482			fogColor: { value: new Color( 0xffffff ) }
10483  
10484		},
10485  
10486		lights: {
10487  
10488			ambientLightColor: { value: [] },
10489  
10490			directionalLights: { value: [], properties: {
10491				direction: {},
10492				color: {},
10493  
10494				shadow: {},
10495				shadowBias: {},
10496				shadowRadius: {},
10497				shadowMapSize: {}
10498			} },
10499  
10500			directionalShadowMap: { value: [] },
10501			directionalShadowMatrix: { value: [] },
10502  
10503			spotLights: { value: [], properties: {
10504				color: {},
10505				position: {},
10506				direction: {},
10507				distance: {},
10508				coneCos: {},
10509				penumbraCos: {},
10510				decay: {},
10511  
10512				shadow: {},
10513				shadowBias: {},
10514				shadowRadius: {},
10515				shadowMapSize: {}
10516			} },
10517  
10518			spotShadowMap: { value: [] },
10519			spotShadowMatrix: { value: [] },
10520  
10521			pointLights: { value: [], properties: {
10522				color: {},
10523				position: {},
10524				decay: {},
10525				distance: {},
10526  
10527				shadow: {},
10528				shadowBias: {},
10529				shadowRadius: {},
10530				shadowMapSize: {},
10531				shadowCameraNear: {},
10532				shadowCameraFar: {}
10533			} },
10534  
10535			pointShadowMap: { value: [] },
10536			pointShadowMatrix: { value: [] },
10537  
10538			hemisphereLights: { value: [], properties: {
10539				direction: {},
10540				skyColor: {},
10541				groundColor: {}
10542			} },
10543  
10544			// TODO (abelnation): RectAreaLight BRDF data needs to be moved from example to main src
10545			rectAreaLights: { value: [], properties: {
10546				color: {},
10547				position: {},
10548				width: {},
10549				height: {}
10550			} }
10551  
10552		},
10553  
10554		points: {
10555  
10556			diffuse: { value: new Color( 0xeeeeee ) },
10557			opacity: { value: 1.0 },
10558			size: { value: 1.0 },
10559			scale: { value: 1.0 },
10560			map: { value: null },
10561			uvTransform: { value: new Matrix3() }
10562  
10563		}
10564  
10565	};
10566  
10567	/**
10568	 * @author alteredq / http://alteredqualia.com/
10569	 * @author mrdoob / http://mrdoob.com/
10570	 * @author mikael emtinger / http://gomo.se/
10571	 */
10572  
10573	var ShaderLib = {
10574  
10575		basic: {
10576  
10577			uniforms: UniformsUtils.merge( [
10578				UniformsLib.common,
10579				UniformsLib.specularmap,
10580				UniformsLib.envmap,
10581				UniformsLib.aomap,
10582				UniformsLib.lightmap,
10583				UniformsLib.fog
10584			] ),
10585  
10586			vertexShader: ShaderChunk.meshbasic_vert,
10587			fragmentShader: ShaderChunk.meshbasic_frag
10588  
10589		},
10590  
10591		lambert: {
10592  
10593			uniforms: UniformsUtils.merge( [
10594				UniformsLib.common,
10595				UniformsLib.specularmap,
10596				UniformsLib.envmap,
10597				UniformsLib.aomap,
10598				UniformsLib.lightmap,
10599				UniformsLib.emissivemap,
10600				UniformsLib.fog,
10601				UniformsLib.lights,
10602				{
10603					emissive: { value: new Color( 0x000000 ) }
10604				}
10605			] ),
10606  
10607			vertexShader: ShaderChunk.meshlambert_vert,
10608			fragmentShader: ShaderChunk.meshlambert_frag
10609  
10610		},
10611  
10612		phong: {
10613  
10614			uniforms: UniformsUtils.merge( [
10615				UniformsLib.common,
10616				UniformsLib.specularmap,
10617				UniformsLib.envmap,
10618				UniformsLib.aomap,
10619				UniformsLib.lightmap,
10620				UniformsLib.emissivemap,
10621				UniformsLib.bumpmap,
10622				UniformsLib.normalmap,
10623				UniformsLib.displacementmap,
10624				UniformsLib.gradientmap,
10625				UniformsLib.fog,
10626				UniformsLib.lights,
10627				{
10628					emissive: { value: new Color( 0x000000 ) },
10629					specular: { value: new Color( 0x111111 ) },
10630					shininess: { value: 30 }
10631				}
10632			] ),
10633  
10634			vertexShader: ShaderChunk.meshphong_vert,
10635			fragmentShader: ShaderChunk.meshphong_frag
10636  
10637		},
10638  
10639		standard: {
10640  
10641			uniforms: UniformsUtils.merge( [
10642				UniformsLib.common,
10643				UniformsLib.envmap,
10644				UniformsLib.aomap,
10645				UniformsLib.lightmap,
10646				UniformsLib.emissivemap,
10647				UniformsLib.bumpmap,
10648				UniformsLib.normalmap,
10649				UniformsLib.displacementmap,
10650				UniformsLib.roughnessmap,
10651				UniformsLib.metalnessmap,
10652				UniformsLib.fog,
10653				UniformsLib.lights,
10654				{
10655					emissive: { value: new Color( 0x000000 ) },
10656					roughness: { value: 0.5 },
10657					metalness: { value: 0.5 },
10658					envMapIntensity: { value: 1 } // temporary
10659				}
10660			] ),
10661  
10662			vertexShader: ShaderChunk.meshphysical_vert,
10663			fragmentShader: ShaderChunk.meshphysical_frag
10664  
10665		},
10666  
10667		points: {
10668  
10669			uniforms: UniformsUtils.merge( [
10670				UniformsLib.points,
10671				UniformsLib.fog
10672			] ),
10673  
vendor: 2,046 bytes, lines 10674-10780
10674			vertexShader: ShaderChunk.points_vert,
10675			fragmentShader: ShaderChunk.points_frag
10676  
10677		},
10678  
10679		dashed: {
10680  
10681			uniforms: UniformsUtils.merge( [
10682				UniformsLib.common,
10683				UniformsLib.fog,
10684				{
10685					scale: { value: 1 },
10686					dashSize: { value: 1 },
10687					totalSize: { value: 2 }
10688				}
10689			] ),
10690  
10691			vertexShader: ShaderChunk.linedashed_vert,
10692			fragmentShader: ShaderChunk.linedashed_frag
10693  
10694		},
10695  
10696		depth: {
10697  
10698			uniforms: UniformsUtils.merge( [
10699				UniformsLib.common,
10700				UniformsLib.displacementmap
10701			] ),
10702  
10703			vertexShader: ShaderChunk.depth_vert,
10704			fragmentShader: ShaderChunk.depth_frag
10705  
10706		},
10707  
10708		normal: {
10709  
10710			uniforms: UniformsUtils.merge( [
10711				UniformsLib.common,
10712				UniformsLib.bumpmap,
10713				UniformsLib.normalmap,
10714				UniformsLib.displacementmap,
10715				{
10716					opacity: { value: 1.0 }
10717				}
10718			] ),
10719  
10720			vertexShader: ShaderChunk.normal_vert,
10721			fragmentShader: ShaderChunk.normal_frag
10722  
10723		},
10724  
10725		/* -------------------------------------------------------------------------
10726		//	Cube map shader
10727		 ------------------------------------------------------------------------- */
10728  
10729		cube: {
10730  
10731			uniforms: {
10732				tCube: { value: null },
10733				tFlip: { value: - 1 },
10734				opacity: { value: 1.0 }
10735			},
10736  
10737			vertexShader: ShaderChunk.cube_vert,
10738			fragmentShader: ShaderChunk.cube_frag
10739  
10740		},
10741  
10742		equirect: {
10743  
10744			uniforms: {
10745				tEquirect: { value: null },
10746			},
10747  
10748			vertexShader: ShaderChunk.equirect_vert,
10749			fragmentShader: ShaderChunk.equirect_frag
10750  
10751		},
10752  
10753		distanceRGBA: {
10754  
10755			uniforms: UniformsUtils.merge( [
10756				UniformsLib.common,
10757				UniformsLib.displacementmap,
10758				{
10759					referencePosition: { value: new Vector3() },
10760					nearDistance: { value: 1 },
10761					farDistance: { value: 1000 }
10762				}
10763			] ),
10764  
10765			vertexShader: ShaderChunk.distanceRGBA_vert,
10766			fragmentShader: ShaderChunk.distanceRGBA_frag
10767  
10768		},
10769  
10770		shadow: {
10771  
10772			uniforms: UniformsUtils.merge( [
10773				UniformsLib.lights,
10774				UniformsLib.fog,
10775				{
10776					color: { value: new Color( 0x00000 ) },
10777					opacity: { value: 1.0 }
10778				},
10779			] ),
10780  
vendor: 15,977 bytes, lines 10781-11681
10781			vertexShader: ShaderChunk.shadow_vert,
10782			fragmentShader: ShaderChunk.shadow_frag
10783  
10784		}
10785  
10786	};
10787  
10788	ShaderLib.physical = {
10789  
10790		uniforms: UniformsUtils.merge( [
10791			ShaderLib.standard.uniforms,
10792			{
10793				clearCoat: { value: 0 },
10794				clearCoatRoughness: { value: 0 }
10795			}
10796		] ),
10797  
10798		vertexShader: ShaderChunk.meshphysical_vert,
10799		fragmentShader: ShaderChunk.meshphysical_frag
10800  
10801	};
10802  
10803	/**
10804	 * @author mrdoob / http://mrdoob.com/
10805	 */
10806  
10807	function WebGLAnimation() {
10808  
10809		var context = null;
10810		var isAnimating = false;
10811		var animationLoop = null;
10812  
10813		function onAnimationFrame( time, frame ) {
10814  
10815			if ( isAnimating === false ) return;
10816  
10817			animationLoop( time, frame );
10818  
10819			context.requestAnimationFrame( onAnimationFrame );
10820  
10821		}
10822  
10823		return {
10824  
10825			start: function () {
10826  
10827				if ( isAnimating === true ) return;
10828				if ( animationLoop === null ) return;
10829  
10830				context.requestAnimationFrame( onAnimationFrame );
10831  
10832				isAnimating = true;
10833  
10834			},
10835  
10836			stop: function () {
10837  
10838				isAnimating = false;
10839  
10840			},
10841  
10842			setAnimationLoop: function ( callback ) {
10843  
10844				animationLoop = callback;
10845  
10846			},
10847  
10848			setContext: function ( value ) {
10849  
10850				context = value;
10851  
10852			}
10853  
10854		};
10855  
10856	}
10857  
10858	/**
10859	 * @author mrdoob / http://mrdoob.com/
10860	 */
10861  
10862	function WebGLAttributes( gl ) {
10863  
10864		var buffers = new WeakMap();
10865  
10866		function createBuffer( attribute, bufferType ) {
10867  
10868			var array = attribute.array;
10869			var usage = attribute.dynamic ? gl.DYNAMIC_DRAW : gl.STATIC_DRAW;
10870  
10871			var buffer = gl.createBuffer();
10872  
10873			gl.bindBuffer( bufferType, buffer );
10874			gl.bufferData( bufferType, array, usage );
10875  
10876			attribute.onUploadCallback();
10877  
10878			var type = gl.FLOAT;
10879  
10880			if ( array instanceof Float32Array ) {
10881  
10882				type = gl.FLOAT;
10883  
10884			} else if ( array instanceof Float64Array ) {
10885  
10886				console.warn( 'THREE.WebGLAttributes: Unsupported data buffer format: Float64Array.' );
10887  
10888			} else if ( array instanceof Uint16Array ) {
10889  
10890				type = gl.UNSIGNED_SHORT;
10891  
10892			} else if ( array instanceof Int16Array ) {
10893  
10894				type = gl.SHORT;
10895  
10896			} else if ( array instanceof Uint32Array ) {
10897  
10898				type = gl.UNSIGNED_INT;
10899  
10900			} else if ( array instanceof Int32Array ) {
10901  
10902				type = gl.INT;
10903  
10904			} else if ( array instanceof Int8Array ) {
10905  
10906				type = gl.BYTE;
10907  
10908			} else if ( array instanceof Uint8Array ) {
10909  
10910				type = gl.UNSIGNED_BYTE;
10911  
10912			}
10913  
10914			return {
10915				buffer: buffer,
10916				type: type,
10917				bytesPerElement: array.BYTES_PER_ELEMENT,
10918				version: attribute.version
10919			};
10920  
10921		}
10922  
10923		function updateBuffer( buffer, attribute, bufferType ) {
10924  
10925			var array = attribute.array;
10926			var updateRange = attribute.updateRange;
10927  
10928			gl.bindBuffer( bufferType, buffer );
10929  
10930			if ( attribute.dynamic === false ) {
10931  
10932				gl.bufferData( bufferType, array, gl.STATIC_DRAW );
10933  
10934			} else if ( updateRange.count === - 1 ) {
10935  
10936				// Not using update ranges
10937  
10938				gl.bufferSubData( bufferType, 0, array );
10939  
10940			} else if ( updateRange.count === 0 ) {
10941  
10942				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.' );
10943  
10944			} else {
10945  
10946				gl.bufferSubData( bufferType, updateRange.offset * array.BYTES_PER_ELEMENT,
10947					array.subarray( updateRange.offset, updateRange.offset + updateRange.count ) );
10948  
10949				updateRange.count = - 1; // reset range
10950  
10951			}
10952  
10953		}
10954  
10955		//
10956  
10957		function get( attribute ) {
10958  
10959			if ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data;
10960  
10961			return buffers.get( attribute );
10962  
10963		}
10964  
10965		function remove( attribute ) {
10966  
10967			if ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data;
10968  
10969			var data = buffers.get( attribute );
10970  
10971			if ( data ) {
10972  
10973				gl.deleteBuffer( data.buffer );
10974  
10975				buffers.delete( attribute );
10976  
10977			}
10978  
10979		}
10980  
10981		function update( attribute, bufferType ) {
10982  
10983			if ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data;
10984  
10985			var data = buffers.get( attribute );
10986  
10987			if ( data === undefined ) {
10988  
10989				buffers.set( attribute, createBuffer( attribute, bufferType ) );
10990  
10991			} else if ( data.version < attribute.version ) {
10992  
10993				updateBuffer( data.buffer, attribute, bufferType );
10994  
10995				data.version = attribute.version;
10996  
10997			}
10998  
10999		}
11000  
11001		return {
11002  
11003			get: get,
11004			remove: remove,
11005			update: update
11006  
11007		};
11008  
11009	}
11010  
11011	/**
11012	 * @author mrdoob / http://mrdoob.com/
11013	 * @author WestLangley / http://github.com/WestLangley
11014	 * @author bhouston / http://clara.io
11015	 */
11016  
11017	function Euler( x, y, z, order ) {
11018  
11019		this._x = x || 0;
11020		this._y = y || 0;
11021		this._z = z || 0;
11022		this._order = order || Euler.DefaultOrder;
11023  
11024	}
11025  
11026	Euler.RotationOrders = [ 'XYZ', 'YZX', 'ZXY', 'XZY', 'YXZ', 'ZYX' ];
11027  
11028	Euler.DefaultOrder = 'XYZ';
11029  
11030	Object.defineProperties( Euler.prototype, {
11031  
11032		x: {
11033  
11034			get: function () {
11035  
11036				return this._x;
11037  
11038			},
11039  
11040			set: function ( value ) {
11041  
11042				this._x = value;
11043				this.onChangeCallback();
11044  
11045			}
11046  
11047		},
11048  
11049		y: {
11050  
11051			get: function () {
11052  
11053				return this._y;
11054  
11055			},
11056  
11057			set: function ( value ) {
11058  
11059				this._y = value;
11060				this.onChangeCallback();
11061  
11062			}
11063  
11064		},
11065  
11066		z: {
11067  
11068			get: function () {
11069  
11070				return this._z;
11071  
11072			},
11073  
11074			set: function ( value ) {
11075  
11076				this._z = value;
11077				this.onChangeCallback();
11078  
11079			}
11080  
11081		},
11082  
11083		order: {
11084  
11085			get: function () {
11086  
11087				return this._order;
11088  
11089			},
11090  
11091			set: function ( value ) {
11092  
11093				this._order = value;
11094				this.onChangeCallback();
11095  
11096			}
11097  
11098		}
11099  
11100	} );
11101  
11102	Object.assign( Euler.prototype, {
11103  
11104		isEuler: true,
11105  
11106		set: function ( x, y, z, order ) {
11107  
11108			this._x = x;
11109			this._y = y;
11110			this._z = z;
11111			this._order = order || this._order;
11112  
11113			this.onChangeCallback();
11114  
11115			return this;
11116  
11117		},
11118  
11119		clone: function () {
11120  
11121			return new this.constructor( this._x, this._y, this._z, this._order );
11122  
11123		},
11124  
11125		copy: function ( euler ) {
11126  
11127			this._x = euler._x;
11128			this._y = euler._y;
11129			this._z = euler._z;
11130			this._order = euler._order;
11131  
11132			this.onChangeCallback();
11133  
11134			return this;
11135  
11136		},
11137  
11138		setFromRotationMatrix: function ( m, order, update ) {
11139  
11140			var clamp = _Math.clamp;
11141  
11142			// assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)
11143  
11144			var te = m.elements;
11145			var m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ];
11146			var m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ];
11147			var m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ];
11148  
11149			order = order || this._order;
11150  
11151			if ( order === 'XYZ' ) {
11152  
11153				this._y = Math.asin( clamp( m13, - 1, 1 ) );
11154  
11155				if ( Math.abs( m13 ) < 0.99999 ) {
11156  
11157					this._x = Math.atan2( - m23, m33 );
11158					this._z = Math.atan2( - m12, m11 );
11159  
11160				} else {
11161  
11162					this._x = Math.atan2( m32, m22 );
11163					this._z = 0;
11164  
11165				}
11166  
11167			} else if ( order === 'YXZ' ) {
11168  
11169				this._x = Math.asin( - clamp( m23, - 1, 1 ) );
11170  
11171				if ( Math.abs( m23 ) < 0.99999 ) {
11172  
11173					this._y = Math.atan2( m13, m33 );
11174					this._z = Math.atan2( m21, m22 );
11175  
11176				} else {
11177  
11178					this._y = Math.atan2( - m31, m11 );
11179					this._z = 0;
11180  
11181				}
11182  
11183			} else if ( order === 'ZXY' ) {
11184  
11185				this._x = Math.asin( clamp( m32, - 1, 1 ) );
11186  
11187				if ( Math.abs( m32 ) < 0.99999 ) {
11188  
11189					this._y = Math.atan2( - m31, m33 );
11190					this._z = Math.atan2( - m12, m22 );
11191  
11192				} else {
11193  
11194					this._y = 0;
11195					this._z = Math.atan2( m21, m11 );
11196  
11197				}
11198  
11199			} else if ( order === 'ZYX' ) {
11200  
11201				this._y = Math.asin( - clamp( m31, - 1, 1 ) );
11202  
11203				if ( Math.abs( m31 ) < 0.99999 ) {
11204  
11205					this._x = Math.atan2( m32, m33 );
11206					this._z = Math.atan2( m21, m11 );
11207  
11208				} else {
11209  
11210					this._x = 0;
11211					this._z = Math.atan2( - m12, m22 );
11212  
11213				}
11214  
11215			} else if ( order === 'YZX' ) {
11216  
11217				this._z = Math.asin( clamp( m21, - 1, 1 ) );
11218  
11219				if ( Math.abs( m21 ) < 0.99999 ) {
11220  
11221					this._x = Math.atan2( - m23, m22 );
11222					this._y = Math.atan2( - m31, m11 );
11223  
11224				} else {
11225  
11226					this._x = 0;
11227					this._y = Math.atan2( m13, m33 );
11228  
11229				}
11230  
11231			} else if ( order === 'XZY' ) {
11232  
11233				this._z = Math.asin( - clamp( m12, - 1, 1 ) );
11234  
11235				if ( Math.abs( m12 ) < 0.99999 ) {
11236  
11237					this._x = Math.atan2( m32, m22 );
11238					this._y = Math.atan2( m13, m11 );
11239  
11240				} else {
11241  
11242					this._x = Math.atan2( - m23, m33 );
11243					this._y = 0;
11244  
11245				}
11246  
11247			} else {
11248  
11249				console.warn( 'THREE.Euler: .setFromRotationMatrix() given unsupported order: ' + order );
11250  
11251			}
11252  
11253			this._order = order;
11254  
11255			if ( update !== false ) this.onChangeCallback();
11256  
11257			return this;
11258  
11259		},
11260  
11261		setFromQuaternion: function () {
11262  
11263			var matrix = new Matrix4();
11264  
11265			return function setFromQuaternion( q, order, update ) {
11266  
11267				matrix.makeRotationFromQuaternion( q );
11268  
11269				return this.setFromRotationMatrix( matrix, order, update );
11270  
11271			};
11272  
11273		}(),
11274  
11275		setFromVector3: function ( v, order ) {
11276  
11277			return this.set( v.x, v.y, v.z, order || this._order );
11278  
11279		},
11280  
11281		reorder: function () {
11282  
11283			// WARNING: this discards revolution information -bhouston
11284  
11285			var q = new Quaternion();
11286  
11287			return function reorder( newOrder ) {
11288  
11289				q.setFromEuler( this );
11290  
11291				return this.setFromQuaternion( q, newOrder );
11292  
11293			};
11294  
11295		}(),
11296  
11297		equals: function ( euler ) {
11298  
11299			return ( euler._x === this._x ) && ( euler._y === this._y ) && ( euler._z === this._z ) && ( euler._order === this._order );
11300  
11301		},
11302  
11303		fromArray: function ( array ) {
11304  
11305			this._x = array[ 0 ];
11306			this._y = array[ 1 ];
11307			this._z = array[ 2 ];
11308			if ( array[ 3 ] !== undefined ) this._order = array[ 3 ];
11309  
11310			this.onChangeCallback();
11311  
11312			return this;
11313  
11314		},
11315  
11316		toArray: function ( array, offset ) {
11317  
11318			if ( array === undefined ) array = [];
11319			if ( offset === undefined ) offset = 0;
11320  
11321			array[ offset ] = this._x;
11322			array[ offset + 1 ] = this._y;
11323			array[ offset + 2 ] = this._z;
11324			array[ offset + 3 ] = this._order;
11325  
11326			return array;
11327  
11328		},
11329  
11330		toVector3: function ( optionalResult ) {
11331  
11332			if ( optionalResult ) {
11333  
11334				return optionalResult.set( this._x, this._y, this._z );
11335  
11336			} else {
11337  
11338				return new Vector3( this._x, this._y, this._z );
11339  
11340			}
11341  
11342		},
11343  
11344		onChange: function ( callback ) {
11345  
11346			this.onChangeCallback = callback;
11347  
11348			return this;
11349  
11350		},
11351  
11352		onChangeCallback: function () {}
11353  
11354	} );
11355  
11356	/**
11357	 * @author mrdoob / http://mrdoob.com/
11358	 */
11359  
11360	function Layers() {
11361  
11362		this.mask = 1 | 0;
11363  
11364	}
11365  
11366	Object.assign( Layers.prototype, {
11367  
11368		set: function ( channel ) {
11369  
11370			this.mask = 1 << channel | 0;
11371  
11372		},
11373  
11374		enable: function ( channel ) {
11375  
11376			this.mask |= 1 << channel | 0;
11377  
11378		},
11379  
11380		toggle: function ( channel ) {
11381  
11382			this.mask ^= 1 << channel | 0;
11383  
11384		},
11385  
11386		disable: function ( channel ) {
11387  
11388			this.mask &= ~ ( 1 << channel | 0 );
11389  
11390		},
11391  
11392		test: function ( layers ) {
11393  
11394			return ( this.mask & layers.mask ) !== 0;
11395  
11396		}
11397  
11398	} );
11399  
11400	/**
11401	 * @author mrdoob / http://mrdoob.com/
11402	 * @author mikael emtinger / http://gomo.se/
11403	 * @author alteredq / http://alteredqualia.com/
11404	 * @author WestLangley / http://github.com/WestLangley
11405	 * @author elephantatwork / www.elephantatwork.ch
11406	 */
11407  
11408	var object3DId = 0;
11409  
11410	function Object3D() {
11411  
11412		Object.defineProperty( this, 'id', { value: object3DId ++ } );
11413  
11414		this.uuid = _Math.generateUUID();
11415  
11416		this.name = '';
11417		this.type = 'Object3D';
11418  
11419		this.parent = null;
11420		this.children = [];
11421  
11422		this.up = Object3D.DefaultUp.clone();
11423  
11424		var position = new Vector3();
11425		var rotation = new Euler();
11426		var quaternion = new Quaternion();
11427		var scale = new Vector3( 1, 1, 1 );
11428  
11429		function onRotationChange() {
11430  
11431			quaternion.setFromEuler( rotation, false );
11432  
11433		}
11434  
11435		function onQuaternionChange() {
11436  
11437			rotation.setFromQuaternion( quaternion, undefined, false );
11438  
11439		}
11440  
11441		rotation.onChange( onRotationChange );
11442		quaternion.onChange( onQuaternionChange );
11443  
11444		Object.defineProperties( this, {
11445			position: {
11446				enumerable: true,
11447				value: position
11448			},
11449			rotation: {
11450				enumerable: true,
11451				value: rotation
11452			},
11453			quaternion: {
11454				enumerable: true,
11455				value: quaternion
11456			},
11457			scale: {
11458				enumerable: true,
11459				value: scale
11460			},
11461			modelViewMatrix: {
11462				value: new Matrix4()
11463			},
11464			normalMatrix: {
11465				value: new Matrix3()
11466			}
11467		} );
11468  
11469		this.matrix = new Matrix4();
11470		this.matrixWorld = new Matrix4();
11471  
11472		this.matrixAutoUpdate = Object3D.DefaultMatrixAutoUpdate;
11473		this.matrixWorldNeedsUpdate = false;
11474  
11475		this.layers = new Layers();
11476		this.visible = true;
11477  
11478		this.castShadow = false;
11479		this.receiveShadow = false;
11480  
11481		this.frustumCulled = true;
11482		this.renderOrder = 0;
11483  
11484		this.userData = {};
11485  
11486	}
11487  
11488	Object3D.DefaultUp = new Vector3( 0, 1, 0 );
11489	Object3D.DefaultMatrixAutoUpdate = true;
11490  
11491	Object3D.prototype = Object.assign( Object.create( EventDispatcher.prototype ), {
11492  
11493		constructor: Object3D,
11494  
11495		isObject3D: true,
11496  
11497		onBeforeRender: function () {},
11498		onAfterRender: function () {},
11499  
11500		applyMatrix: function ( matrix ) {
11501  
11502			this.matrix.multiplyMatrices( matrix, this.matrix );
11503  
11504			this.matrix.decompose( this.position, this.quaternion, this.scale );
11505  
11506		},
11507  
11508		applyQuaternion: function ( q ) {
11509  
11510			this.quaternion.premultiply( q );
11511  
11512			return this;
11513  
11514		},
11515  
11516		setRotationFromAxisAngle: function ( axis, angle ) {
11517  
11518			// assumes axis is normalized
11519  
11520			this.quaternion.setFromAxisAngle( axis, angle );
11521  
11522		},
11523  
11524		setRotationFromEuler: function ( euler ) {
11525  
11526			this.quaternion.setFromEuler( euler, true );
11527  
11528		},
11529  
11530		setRotationFromMatrix: function ( m ) {
11531  
11532			// assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)
11533  
11534			this.quaternion.setFromRotationMatrix( m );
11535  
11536		},
11537  
11538		setRotationFromQuaternion: function ( q ) {
11539  
11540			// assumes q is normalized
11541  
11542			this.quaternion.copy( q );
11543  
11544		},
11545  
11546		rotateOnAxis: function () {
11547  
11548			// rotate object on axis in object space
11549			// axis is assumed to be normalized
11550  
11551			var q1 = new Quaternion();
11552  
11553			return function rotateOnAxis( axis, angle ) {
11554  
11555				q1.setFromAxisAngle( axis, angle );
11556  
11557				this.quaternion.multiply( q1 );
11558  
11559				return this;
11560  
11561			};
11562  
11563		}(),
11564  
11565		rotateOnWorldAxis: function () {
11566  
11567			// rotate object on axis in world space
11568			// axis is assumed to be normalized
11569			// method assumes no rotated parent
11570  
11571			var q1 = new Quaternion();
11572  
11573			return function rotateOnWorldAxis( axis, angle ) {
11574  
11575				q1.setFromAxisAngle( axis, angle );
11576  
11577				this.quaternion.premultiply( q1 );
11578  
11579				return this;
11580  
11581			};
11582  
11583		}(),
11584  
11585		rotateX: function () {
11586  
11587			var v1 = new Vector3( 1, 0, 0 );
11588  
11589			return function rotateX( angle ) {
11590  
11591				return this.rotateOnAxis( v1, angle );
11592  
11593			};
11594  
11595		}(),
11596  
11597		rotateY: function () {
11598  
11599			var v1 = new Vector3( 0, 1, 0 );
11600  
11601			return function rotateY( angle ) {
11602  
11603				return this.rotateOnAxis( v1, angle );
11604  
11605			};
11606  
11607		}(),
11608  
11609		rotateZ: function () {
11610  
11611			var v1 = new Vector3( 0, 0, 1 );
11612  
11613			return function rotateZ( angle ) {
11614  
11615				return this.rotateOnAxis( v1, angle );
11616  
11617			};
11618  
11619		}(),
11620  
11621		translateOnAxis: function () {
11622  
11623			// translate object by distance along axis in object space
11624			// axis is assumed to be normalized
11625  
11626			var v1 = new Vector3();
11627  
11628			return function translateOnAxis( axis, distance ) {
11629  
11630				v1.copy( axis ).applyQuaternion( this.quaternion );
11631  
11632				this.position.add( v1.multiplyScalar( distance ) );
11633  
11634				return this;
11635  
11636			};
11637  
11638		}(),
11639  
11640		translateX: function () {
11641  
11642			var v1 = new Vector3( 1, 0, 0 );
11643  
11644			return function translateX( distance ) {
11645  
11646				return this.translateOnAxis( v1, distance );
11647  
11648			};
11649  
11650		}(),
11651  
11652		translateY: function () {
11653  
11654			var v1 = new Vector3( 0, 1, 0 );
11655  
11656			return function translateY( distance ) {
11657  
11658				return this.translateOnAxis( v1, distance );
11659  
11660			};
11661  
11662		}(),
11663  
11664		translateZ: function () {
11665  
11666			var v1 = new Vector3( 0, 0, 1 );
11667  
11668			return function translateZ( distance ) {
11669  
11670				return this.translateOnAxis( v1, distance );
11671  
11672			};
11673  
11674		}(),
11675  
11676		localToWorld: function ( vector ) {
11677  
11678			return vector.applyMatrix4( this.matrixWorld );
11679  
11680		},
11681  
11682		worldToLocal: function () {
11683  
11684			var m1 = new Matrix4();
11685  
11686			return function worldToLocal( vector ) {
11687  
11688				return vector.applyMatrix4( m1.getInverse( this.matrixWorld ) );
11689  
11690			};
11691  
11692		}(),
11693  
11694		lookAt: function () {
11695  
11696			// This method does not support objects with rotated and/or translated parent(s)
11697  
11698			var m1 = new Matrix4();
11699			var vector = new Vector3();
11700  
11701			return function lookAt( x, y, z ) {
11702  
11703				if ( x.isVector3 ) {
11704  
11705					vector.copy( x );
11706  
11707				} else {
11708  
11709					vector.set( x, y, z );
11710  
11711				}
11712  
11713				if ( this.isCamera ) {
11714  
11715					m1.lookAt( this.position, vector, this.up );
11716  
11717				} else {
11718  
11719					m1.lookAt( vector, this.position, this.up );
11720  
11721				}
11722  
11723				this.quaternion.setFromRotationMatrix( m1 );
11724  
11725			};
11726  
11727		}(),
11728  
11729		add: function ( object ) {
11730  
11731			if ( arguments.length > 1 ) {
11732  
11733				for ( var i = 0; i < arguments.length; i ++ ) {
11734  
11735					this.add( arguments[ i ] );
11736  
11737				}
11738  
11739				return this;
11740  
11741			}
11742  
11743			if ( object === this ) {
11744  
11745				console.error( "THREE.Object3D.add: object can't be added as a child of itself.", object );
11746				return this;
11747  
11748			}
11749  
11750			if ( ( object && object.isObject3D ) ) {
11751  
11752				if ( object.parent !== null ) {
11753  
11754					object.parent.remove( object );
11755  
11756				}
11757  
11758				object.parent = this;
11759				object.dispatchEvent( { type: 'added' } );
11760  
11761				this.children.push( object );
11762  
11763			} else {
11764  
11765				console.error( "THREE.Object3D.add: object not an instance of THREE.Object3D.", object );
11766  
11767			}
11768  
11769			return this;
11770  
11771		},
11772  
11773		remove: function ( object ) {
11774  
11775			if ( arguments.length > 1 ) {
11776  
11777				for ( var i = 0; i < arguments.length; i ++ ) {
11778  
11779					this.remove( arguments[ i ] );
11780  
11781				}
11782  
11783				return this;
11784  
11785			}
11786  
11787			var index = this.children.indexOf( object );
11788  
11789			if ( index !== - 1 ) {
11790  
11791				object.parent = null;
11792  
11793				object.dispatchEvent( { type: 'removed' } );
11794  
11795				this.children.splice( index, 1 );
11796  
11797			}
11798  
11799			return this;
11800  
11801		},
11802  
11803		getObjectById: function ( id ) {
11804  
11805			return this.getObjectByProperty( 'id', id );
11806  
11807		},
11808  
11809		getObjectByName: function ( name ) {
11810  
11811			return this.getObjectByProperty( 'name', name );
11812  
11813		},
11814  
11815		getObjectByProperty: function ( name, value ) {
11816  
11817			if ( this[ name ] === value ) return this;
11818  
11819			for ( var i = 0, l = this.children.length; i < l; i ++ ) {
11820  
11821				var child = this.children[ i ];
11822				var object = child.getObjectByProperty( name, value );
11823  
11824				if ( object !== undefined ) {
11825  
11826					return object;
11827  
11828				}
11829  
11830			}
11831  
11832			return undefined;
11833  
11834		},
11835  
11836		getWorldPosition: function ( target ) {
11837  
11838			if ( target === undefined ) {
11839  
11840				console.warn( 'THREE.Object3D: .getWorldPosition() target is now required' );
11841				target = new Vector3();
11842  
11843			}
11844  
11845			this.updateMatrixWorld( true );
11846  
11847			return target.setFromMatrixPosition( this.matrixWorld );
11848  
11849		},
11850  
11851		getWorldQuaternion: function () {
11852  
11853			var position = new Vector3();
11854			var scale = new Vector3();
11855  
11856			return function getWorldQuaternion( target ) {
11857  
11858				if ( target === undefined ) {
11859  
11860					console.warn( 'THREE.Object3D: .getWorldQuaternion() target is now required' );
11861					target = new Quaternion();
11862  
11863				}
11864  
11865				this.updateMatrixWorld( true );
11866  
11867				this.matrixWorld.decompose( position, target, scale );
11868  
11869				return target;
11870  
11871			};
11872  
11873		}(),
11874  
11875		getWorldScale: function () {
11876  
11877			var position = new Vector3();
11878			var quaternion = new Quaternion();
11879  
11880			return function getWorldScale( target ) {
11881  
11882				if ( target === undefined ) {
11883  
11884					console.warn( 'THREE.Object3D: .getWorldScale() target is now required' );
11885					target = new Vector3();
11886  
11887				}
11888  
11889				this.updateMatrixWorld( true );
11890  
11891				this.matrixWorld.decompose( position, quaternion, target );
11892  
11893				return target;
11894  
11895			};
11896  
11897		}(),
11898  
11899		getWorldDirection: function () {
11900  
11901			var quaternion = new Quaternion();
11902  
11903			return function getWorldDirection( target ) {
11904  
11905				if ( target === undefined ) {
11906  
11907					console.warn( 'THREE.Object3D: .getWorldDirection() target is now required' );
11908					target = new Vector3();
11909  
11910				}
11911  
11912				this.getWorldQuaternion( quaternion );
11913  
11914				return target.set( 0, 0, 1 ).applyQuaternion( quaternion );
11915  
11916			};
11917  
11918		}(),
11919  
11920		raycast: function () {},
11921  
11922		traverse: function ( callback ) {
11923  
11924			callback( this );
11925  
11926			var children = this.children;
11927  
11928			for ( var i = 0, l = children.length; i < l; i ++ ) {
11929  
11930				children[ i ].traverse( callback );
11931  
11932			}
11933  
11934		},
11935  
vendor: 11,333 bytes, lines 11936-12460
11936		traverseVisible: function ( callback ) {
11937  
11938			if ( this.visible === false ) return;
11939  
11940			callback( this );
11941  
11942			var children = this.children;
11943  
11944			for ( var i = 0, l = children.length; i < l; i ++ ) {
11945  
11946				children[ i ].traverseVisible( callback );
11947  
11948			}
11949  
11950		},
11951  
11952		traverseAncestors: function ( callback ) {
11953  
11954			var parent = this.parent;
11955  
11956			if ( parent !== null ) {
11957  
11958				callback( parent );
11959  
11960				parent.traverseAncestors( callback );
11961  
11962			}
11963  
11964		},
11965  
11966		updateMatrix: function () {
11967  
11968			this.matrix.compose( this.position, this.quaternion, this.scale );
11969  
11970			this.matrixWorldNeedsUpdate = true;
11971  
11972		},
11973  
11974		updateMatrixWorld: function ( force ) {
11975  
11976			if ( this.matrixAutoUpdate ) this.updateMatrix();
11977  
11978			if ( this.matrixWorldNeedsUpdate || force ) {
11979  
11980				if ( this.parent === null ) {
11981  
11982					this.matrixWorld.copy( this.matrix );
11983  
11984				} else {
11985  
11986					this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix );
11987  
11988				}
11989  
11990				this.matrixWorldNeedsUpdate = false;
11991  
11992				force = true;
11993  
11994			}
11995  
11996			// update children
11997  
11998			var children = this.children;
11999  
12000			for ( var i = 0, l = children.length; i < l; i ++ ) {
12001  
12002				children[ i ].updateMatrixWorld( force );
12003  
12004			}
12005  
12006		},
12007  
12008		toJSON: function ( meta ) {
12009  
12010			// meta is a string when called from JSON.stringify
12011			var isRootObject = ( meta === undefined || typeof meta === 'string' );
12012  
12013			var output = {};
12014  
12015			// meta is a hash used to collect geometries, materials.
12016			// not providing it implies that this is the root object
12017			// being serialized.
12018			if ( isRootObject ) {
12019  
12020				// initialize meta obj
12021				meta = {
12022					geometries: {},
12023					materials: {},
12024					textures: {},
12025					images: {},
12026					shapes: {}
12027				};
12028  
12029				output.metadata = {
12030					version: 4.5,
12031					type: 'Object',
12032					generator: 'Object3D.toJSON'
12033				};
12034  
12035			}
12036  
12037			// standard Object3D serialization
12038  
12039			var object = {};
12040  
12041			object.uuid = this.uuid;
12042			object.type = this.type;
12043  
12044			if ( this.name !== '' ) object.name = this.name;
12045			if ( this.castShadow === true ) object.castShadow = true;
12046			if ( this.receiveShadow === true ) object.receiveShadow = true;
12047			if ( this.visible === false ) object.visible = false;
12048			if ( this.frustumCulled === false ) object.frustumCulled = false;
12049			if ( this.renderOrder !== 0 ) object.renderOrder = this.renderOrder;
12050			if ( JSON.stringify( this.userData ) !== '{}' ) object.userData = this.userData;
12051  
12052			object.matrix = this.matrix.toArray();
12053  
12054			if ( this.matrixAutoUpdate === false ) object.matrixAutoUpdate = false;
12055  
12056			//
12057  
12058			function serialize( library, element ) {
12059  
12060				if ( library[ element.uuid ] === undefined ) {
12061  
12062					library[ element.uuid ] = element.toJSON( meta );
12063  
12064				}
12065  
12066				return element.uuid;
12067  
12068			}
12069  
12070			if ( this.geometry !== undefined ) {
12071  
12072				object.geometry = serialize( meta.geometries, this.geometry );
12073  
12074				var parameters = this.geometry.parameters;
12075  
12076				if ( parameters !== undefined && parameters.shapes !== undefined ) {
12077  
12078					var shapes = parameters.shapes;
12079  
12080					if ( Array.isArray( shapes ) ) {
12081  
12082						for ( var i = 0, l = shapes.length; i < l; i ++ ) {
12083  
12084							var shape = shapes[ i ];
12085  
12086							serialize( meta.shapes, shape );
12087  
12088						}
12089  
12090					} else {
12091  
12092						serialize( meta.shapes, shapes );
12093  
12094					}
12095  
12096				}
12097  
12098			}
12099  
12100			if ( this.material !== undefined ) {
12101  
12102				if ( Array.isArray( this.material ) ) {
12103  
12104					var uuids = [];
12105  
12106					for ( var i = 0, l = this.material.length; i < l; i ++ ) {
12107  
12108						uuids.push( serialize( meta.materials, this.material[ i ] ) );
12109  
12110					}
12111  
12112					object.material = uuids;
12113  
12114				} else {
12115  
12116					object.material = serialize( meta.materials, this.material );
12117  
12118				}
12119  
12120			}
12121  
12122			//
12123  
12124			if ( this.children.length > 0 ) {
12125  
12126				object.children = [];
12127  
12128				for ( var i = 0; i < this.children.length; i ++ ) {
12129  
12130					object.children.push( this.children[ i ].toJSON( meta ).object );
12131  
12132				}
12133  
12134			}
12135  
12136			if ( isRootObject ) {
12137  
12138				var geometries = extractFromCache( meta.geometries );
12139				var materials = extractFromCache( meta.materials );
12140				var textures = extractFromCache( meta.textures );
12141				var images = extractFromCache( meta.images );
12142				var shapes = extractFromCache( meta.shapes );
12143  
12144				if ( geometries.length > 0 ) output.geometries = geometries;
12145				if ( materials.length > 0 ) output.materials = materials;
12146				if ( textures.length > 0 ) output.textures = textures;
12147				if ( images.length > 0 ) output.images = images;
12148				if ( shapes.length > 0 ) output.shapes = shapes;
12149  
12150			}
12151  
12152			output.object = object;
12153  
12154			return output;
12155  
12156			// extract data from the cache hash
12157			// remove metadata on each item
12158			// and return as array
12159			function extractFromCache( cache ) {
12160  
12161				var values = [];
12162				for ( var key in cache ) {
12163  
12164					var data = cache[ key ];
12165					delete data.metadata;
12166					values.push( data );
12167  
12168				}
12169				return values;
12170  
12171			}
12172  
12173		},
12174  
12175		clone: function ( recursive ) {
12176  
12177			return new this.constructor().copy( this, recursive );
12178  
12179		},
12180  
12181		copy: function ( source, recursive ) {
12182  
12183			if ( recursive === undefined ) recursive = true;
12184  
12185			this.name = source.name;
12186  
12187			this.up.copy( source.up );
12188  
12189			this.position.copy( source.position );
12190			this.quaternion.copy( source.quaternion );
12191			this.scale.copy( source.scale );
12192  
12193			this.matrix.copy( source.matrix );
12194			this.matrixWorld.copy( source.matrixWorld );
12195  
12196			this.matrixAutoUpdate = source.matrixAutoUpdate;
12197			this.matrixWorldNeedsUpdate = source.matrixWorldNeedsUpdate;
12198  
12199			this.layers.mask = source.layers.mask;
12200			this.visible = source.visible;
12201  
12202			this.castShadow = source.castShadow;
12203			this.receiveShadow = source.receiveShadow;
12204  
12205			this.frustumCulled = source.frustumCulled;
12206			this.renderOrder = source.renderOrder;
12207  
12208			this.userData = JSON.parse( JSON.stringify( source.userData ) );
12209  
12210			if ( recursive === true ) {
12211  
12212				for ( var i = 0; i < source.children.length; i ++ ) {
12213  
12214					var child = source.children[ i ];
12215					this.add( child.clone() );
12216  
12217				}
12218  
12219			}
12220  
12221			return this;
12222  
12223		}
12224  
12225	} );
12226  
12227	/**
12228	 * @author mrdoob / http://mrdoob.com/
12229	 * @author mikael emtinger / http://gomo.se/
12230	 * @author WestLangley / http://github.com/WestLangley
12231	*/
12232  
12233	function Camera() {
12234  
12235		Object3D.call( this );
12236  
12237		this.type = 'Camera';
12238  
12239		this.matrixWorldInverse = new Matrix4();
12240		this.projectionMatrix = new Matrix4();
12241  
12242	}
12243  
12244	Camera.prototype = Object.assign( Object.create( Object3D.prototype ), {
12245  
12246		constructor: Camera,
12247  
12248		isCamera: true,
12249  
12250		copy: function ( source, recursive ) {
12251  
12252			Object3D.prototype.copy.call( this, source, recursive );
12253  
12254			this.matrixWorldInverse.copy( source.matrixWorldInverse );
12255			this.projectionMatrix.copy( source.projectionMatrix );
12256  
12257			return this;
12258  
12259		},
12260  
12261		getWorldDirection: function () {
12262  
12263			var quaternion = new Quaternion();
12264  
12265			return function getWorldDirection( target ) {
12266  
12267				if ( target === undefined ) {
12268  
12269					console.warn( 'THREE.Camera: .getWorldDirection() target is now required' );
12270					target = new Vector3();
12271  
12272				}
12273  
12274				this.getWorldQuaternion( quaternion );
12275  
12276				return target.set( 0, 0, - 1 ).applyQuaternion( quaternion );
12277  
12278			};
12279  
12280		}(),
12281  
12282		updateMatrixWorld: function ( force ) {
12283  
12284			Object3D.prototype.updateMatrixWorld.call( this, force );
12285  
12286			this.matrixWorldInverse.getInverse( this.matrixWorld );
12287  
12288		},
12289  
12290		clone: function () {
12291  
12292			return new this.constructor().copy( this );
12293  
12294		}
12295  
12296	} );
12297  
12298	/**
12299	 * @author alteredq / http://alteredqualia.com/
12300	 * @author arose / http://github.com/arose
12301	 */
12302  
12303	function OrthographicCamera( left, right, top, bottom, near, far ) {
12304  
12305		Camera.call( this );
12306  
12307		this.type = 'OrthographicCamera';
12308  
12309		this.zoom = 1;
12310		this.view = null;
12311  
12312		this.left = left;
12313		this.right = right;
12314		this.top = top;
12315		this.bottom = bottom;
12316  
12317		this.near = ( near !== undefined ) ? near : 0.1;
12318		this.far = ( far !== undefined ) ? far : 2000;
12319  
12320		this.updateProjectionMatrix();
12321  
12322	}
12323  
12324	OrthographicCamera.prototype = Object.assign( Object.create( Camera.prototype ), {
12325  
12326		constructor: OrthographicCamera,
12327  
12328		isOrthographicCamera: true,
12329  
12330		copy: function ( source, recursive ) {
12331  
12332			Camera.prototype.copy.call( this, source, recursive );
12333  
12334			this.left = source.left;
12335			this.right = source.right;
12336			this.top = source.top;
12337			this.bottom = source.bottom;
12338			this.near = source.near;
12339			this.far = source.far;
12340  
12341			this.zoom = source.zoom;
12342			this.view = source.view === null ? null : Object.assign( {}, source.view );
12343  
12344			return this;
12345  
12346		},
12347  
12348		setViewOffset: function ( fullWidth, fullHeight, x, y, width, height ) {
12349  
12350			if ( this.view === null ) {
12351  
12352				this.view = {
12353					enabled: true,
12354					fullWidth: 1,
12355					fullHeight: 1,
12356					offsetX: 0,
12357					offsetY: 0,
12358					width: 1,
12359					height: 1
12360				};
12361  
12362			}
12363  
12364			this.view.enabled = true;
12365			this.view.fullWidth = fullWidth;
12366			this.view.fullHeight = fullHeight;
12367			this.view.offsetX = x;
12368			this.view.offsetY = y;
12369			this.view.width = width;
12370			this.view.height = height;
12371  
12372			this.updateProjectionMatrix();
12373  
12374		},
12375  
12376		clearViewOffset: function () {
12377  
12378			if ( this.view !== null ) {
12379  
12380				this.view.enabled = false;
12381  
12382			}
12383  
12384			this.updateProjectionMatrix();
12385  
12386		},
12387  
12388		updateProjectionMatrix: function () {
12389  
12390			var dx = ( this.right - this.left ) / ( 2 * this.zoom );
12391			var dy = ( this.top - this.bottom ) / ( 2 * this.zoom );
12392			var cx = ( this.right + this.left ) / 2;
12393			var cy = ( this.top + this.bottom ) / 2;
12394  
12395			var left = cx - dx;
12396			var right = cx + dx;
12397			var top = cy + dy;
12398			var bottom = cy - dy;
12399  
12400			if ( this.view !== null && this.view.enabled ) {
12401  
12402				var zoomW = this.zoom / ( this.view.width / this.view.fullWidth );
12403				var zoomH = this.zoom / ( this.view.height / this.view.fullHeight );
12404				var scaleW = ( this.right - this.left ) / this.view.width;
12405				var scaleH = ( this.top - this.bottom ) / this.view.height;
12406  
12407				left += scaleW * ( this.view.offsetX / zoomW );
12408				right = left + scaleW * ( this.view.width / zoomW );
12409				top -= scaleH * ( this.view.offsetY / zoomH );
12410				bottom = top - scaleH * ( this.view.height / zoomH );
12411  
12412			}
12413  
12414			this.projectionMatrix.makeOrthographic( left, right, top, bottom, this.near, this.far );
12415  
12416		},
12417  
12418		toJSON: function ( meta ) {
12419  
12420			var data = Object3D.prototype.toJSON.call( this, meta );
12421  
12422			data.object.zoom = this.zoom;
12423			data.object.left = this.left;
12424			data.object.right = this.right;
12425			data.object.top = this.top;
12426			data.object.bottom = this.bottom;
12427			data.object.near = this.near;
12428			data.object.far = this.far;
12429  
12430			if ( this.view !== null ) data.object.view = Object.assign( {}, this.view );
12431  
12432			return data;
12433  
12434		}
12435  
12436	} );
12437  
12438	/**
12439	 * @author mrdoob / http://mrdoob.com/
12440	 * @author alteredq / http://alteredqualia.com/
12441	 */
12442  
12443	function Face3( a, b, c, normal, color, materialIndex ) {
12444  
12445		this.a = a;
12446		this.b = b;
12447		this.c = c;
12448  
12449		this.normal = ( normal && normal.isVector3 ) ? normal : new Vector3();
12450		this.vertexNormals = Array.isArray( normal ) ? normal : [];
12451  
12452		this.color = ( color && color.isColor ) ? color : new Color();
12453		this.vertexColors = Array.isArray( color ) ? color : [];
12454  
12455		this.materialIndex = materialIndex !== undefined ? materialIndex : 0;
12456  
12457	}
12458  
12459	Object.assign( Face3.prototype, {
12460  
vendor: 5,662 bytes, lines 12461-12750
12461		clone: function () {
12462  
12463			return new this.constructor().copy( this );
12464  
12465		},
12466  
12467		copy: function ( source ) {
12468  
12469			this.a = source.a;
12470			this.b = source.b;
12471			this.c = source.c;
12472  
12473			this.normal.copy( source.normal );
12474			this.color.copy( source.color );
12475  
12476			this.materialIndex = source.materialIndex;
12477  
12478			for ( var i = 0, il = source.vertexNormals.length; i < il; i ++ ) {
12479  
12480				this.vertexNormals[ i ] = source.vertexNormals[ i ].clone();
12481  
12482			}
12483  
12484			for ( var i = 0, il = source.vertexColors.length; i < il; i ++ ) {
12485  
12486				this.vertexColors[ i ] = source.vertexColors[ i ].clone();
12487  
12488			}
12489  
12490			return this;
12491  
12492		}
12493  
12494	} );
12495  
12496	/**
12497	 * @author mrdoob / http://mrdoob.com/
12498	 * @author kile / http://kile.stravaganza.org/
12499	 * @author alteredq / http://alteredqualia.com/
12500	 * @author mikael emtinger / http://gomo.se/
12501	 * @author zz85 / http://www.lab4games.net/zz85/blog
12502	 * @author bhouston / http://clara.io
12503	 */
12504  
12505	var geometryId = 0; // Geometry uses even numbers as Id
12506  
12507	function Geometry() {
12508  
12509		Object.defineProperty( this, 'id', { value: geometryId += 2 } );
12510  
12511		this.uuid = _Math.generateUUID();
12512  
12513		this.name = '';
12514		this.type = 'Geometry';
12515  
12516		this.vertices = [];
12517		this.colors = [];
12518		this.faces = [];
12519		this.faceVertexUvs = [[]];
12520  
12521		this.morphTargets = [];
12522		this.morphNormals = [];
12523  
12524		this.skinWeights = [];
12525		this.skinIndices = [];
12526  
12527		this.lineDistances = [];
12528  
12529		this.boundingBox = null;
12530		this.boundingSphere = null;
12531  
12532		// update flags
12533  
12534		this.elementsNeedUpdate = false;
12535		this.verticesNeedUpdate = false;
12536		this.uvsNeedUpdate = false;
12537		this.normalsNeedUpdate = false;
12538		this.colorsNeedUpdate = false;
12539		this.lineDistancesNeedUpdate = false;
12540		this.groupsNeedUpdate = false;
12541  
12542	}
12543  
12544	Geometry.prototype = Object.assign( Object.create( EventDispatcher.prototype ), {
12545  
12546		constructor: Geometry,
12547  
12548		isGeometry: true,
12549  
12550		applyMatrix: function ( matrix ) {
12551  
12552			var normalMatrix = new Matrix3().getNormalMatrix( matrix );
12553  
12554			for ( var i = 0, il = this.vertices.length; i < il; i ++ ) {
12555  
12556				var vertex = this.vertices[ i ];
12557				vertex.applyMatrix4( matrix );
12558  
12559			}
12560  
12561			for ( var i = 0, il = this.faces.length; i < il; i ++ ) {
12562  
12563				var face = this.faces[ i ];
12564				face.normal.applyMatrix3( normalMatrix ).normalize();
12565  
12566				for ( var j = 0, jl = face.vertexNormals.length; j < jl; j ++ ) {
12567  
12568					face.vertexNormals[ j ].applyMatrix3( normalMatrix ).normalize();
12569  
12570				}
12571  
12572			}
12573  
12574			if ( this.boundingBox !== null ) {
12575  
12576				this.computeBoundingBox();
12577  
12578			}
12579  
12580			if ( this.boundingSphere !== null ) {
12581  
12582				this.computeBoundingSphere();
12583  
12584			}
12585  
12586			this.verticesNeedUpdate = true;
12587			this.normalsNeedUpdate = true;
12588  
12589			return this;
12590  
12591		},
12592  
12593		rotateX: function () {
12594  
12595			// rotate geometry around world x-axis
12596  
12597			var m1 = new Matrix4();
12598  
12599			return function rotateX( angle ) {
12600  
12601				m1.makeRotationX( angle );
12602  
12603				this.applyMatrix( m1 );
12604  
12605				return this;
12606  
12607			};
12608  
12609		}(),
12610  
12611		rotateY: function () {
12612  
12613			// rotate geometry around world y-axis
12614  
12615			var m1 = new Matrix4();
12616  
12617			return function rotateY( angle ) {
12618  
12619				m1.makeRotationY( angle );
12620  
12621				this.applyMatrix( m1 );
12622  
12623				return this;
12624  
12625			};
12626  
12627		}(),
12628  
12629		rotateZ: function () {
12630  
12631			// rotate geometry around world z-axis
12632  
12633			var m1 = new Matrix4();
12634  
12635			return function rotateZ( angle ) {
12636  
12637				m1.makeRotationZ( angle );
12638  
12639				this.applyMatrix( m1 );
12640  
12641				return this;
12642  
12643			};
12644  
12645		}(),
12646  
12647		translate: function () {
12648  
12649			// translate geometry
12650  
12651			var m1 = new Matrix4();
12652  
12653			return function translate( x, y, z ) {
12654  
12655				m1.makeTranslation( x, y, z );
12656  
12657				this.applyMatrix( m1 );
12658  
12659				return this;
12660  
12661			};
12662  
12663		}(),
12664  
12665		scale: function () {
12666  
12667			// scale geometry
12668  
12669			var m1 = new Matrix4();
12670  
12671			return function scale( x, y, z ) {
12672  
12673				m1.makeScale( x, y, z );
12674  
12675				this.applyMatrix( m1 );
12676  
12677				return this;
12678  
12679			};
12680  
12681		}(),
12682  
12683		lookAt: function () {
12684  
12685			var obj = new Object3D();
12686  
12687			return function lookAt( vector ) {
12688  
12689				obj.lookAt( vector );
12690  
12691				obj.updateMatrix();
12692  
12693				this.applyMatrix( obj.matrix );
12694  
12695			};
12696  
12697		}(),
12698  
12699		fromBufferGeometry: function ( geometry ) {
12700  
12701			var scope = this;
12702  
12703			var indices = geometry.index !== null ? geometry.index.array : undefined;
12704			var attributes = geometry.attributes;
12705  
12706			var positions = attributes.position.array;
12707			var normals = attributes.normal !== undefined ? attributes.normal.array : undefined;
12708			var colors = attributes.color !== undefined ? attributes.color.array : undefined;
12709			var uvs = attributes.uv !== undefined ? attributes.uv.array : undefined;
12710			var uvs2 = attributes.uv2 !== undefined ? attributes.uv2.array : undefined;
12711  
12712			if ( uvs2 !== undefined ) this.faceVertexUvs[ 1 ] = [];
12713  
12714			var tempNormals = [];
12715			var tempUVs = [];
12716			var tempUVs2 = [];
12717  
12718			for ( var i = 0, j = 0; i < positions.length; i += 3, j += 2 ) {
12719  
12720				scope.vertices.push( new Vector3( positions[ i ], positions[ i + 1 ], positions[ i + 2 ] ) );
12721  
12722				if ( normals !== undefined ) {
12723  
12724					tempNormals.push( new Vector3( normals[ i ], normals[ i + 1 ], normals[ i + 2 ] ) );
12725  
12726				}
12727  
12728				if ( colors !== undefined ) {
12729  
12730					scope.colors.push( new Color( colors[ i ], colors[ i + 1 ], colors[ i + 2 ] ) );
12731  
12732				}
12733  
12734				if ( uvs !== undefined ) {
12735  
12736					tempUVs.push( new Vector2( uvs[ j ], uvs[ j + 1 ] ) );
12737  
12738				}
12739  
12740				if ( uvs2 !== undefined ) {
12741  
12742					tempUVs2.push( new Vector2( uvs2[ j ], uvs2[ j + 1 ] ) );
12743  
12744				}
12745  
12746			}
12747  
12748			function addFace( a, b, c, materialIndex ) {
12749  
12750				var vertexNormals = normals !== undefined ? [ tempNormals[ a ].clone(), tempNormals[ b ].
vendor: 89,242 bytes, lines 12750-16884
12750clone(), tempNormals[ c ].clone() ] : [];
12751				var vertexColors = colors !== undefined ? [ scope.colors[ a ].clone(), scope.colors[ b ].clone(), scope.colors[ c ].clone() ] : [];
12752  
12753				var face = new Face3( a, b, c, vertexNormals, vertexColors, materialIndex );
12754  
12755				scope.faces.push( face );
12756  
12757				if ( uvs !== undefined ) {
12758  
12759					scope.faceVertexUvs[ 0 ].push( [ tempUVs[ a ].clone(), tempUVs[ b ].clone(), tempUVs[ c ].clone() ] );
12760  
12761				}
12762  
12763				if ( uvs2 !== undefined ) {
12764  
12765					scope.faceVertexUvs[ 1 ].push( [ tempUVs2[ a ].clone(), tempUVs2[ b ].clone(), tempUVs2[ c ].clone() ] );
12766  
12767				}
12768  
12769			}
12770  
12771			var groups = geometry.groups;
12772  
12773			if ( groups.length > 0 ) {
12774  
12775				for ( var i = 0; i < groups.length; i ++ ) {
12776  
12777					var group = groups[ i ];
12778  
12779					var start = group.start;
12780					var count = group.count;
12781  
12782					for ( var j = start, jl = start + count; j < jl; j += 3 ) {
12783  
12784						if ( indices !== undefined ) {
12785  
12786							addFace( indices[ j ], indices[ j + 1 ], indices[ j + 2 ], group.materialIndex );
12787  
12788						} else {
12789  
12790							addFace( j, j + 1, j + 2, group.materialIndex );
12791  
12792						}
12793  
12794					}
12795  
12796				}
12797  
12798			} else {
12799  
12800				if ( indices !== undefined ) {
12801  
12802					for ( var i = 0; i < indices.length; i += 3 ) {
12803  
12804						addFace( indices[ i ], indices[ i + 1 ], indices[ i + 2 ] );
12805  
12806					}
12807  
12808				} else {
12809  
12810					for ( var i = 0; i < positions.length / 3; i += 3 ) {
12811  
12812						addFace( i, i + 1, i + 2 );
12813  
12814					}
12815  
12816				}
12817  
12818			}
12819  
12820			this.computeFaceNormals();
12821  
12822			if ( geometry.boundingBox !== null ) {
12823  
12824				this.boundingBox = geometry.boundingBox.clone();
12825  
12826			}
12827  
12828			if ( geometry.boundingSphere !== null ) {
12829  
12830				this.boundingSphere = geometry.boundingSphere.clone();
12831  
12832			}
12833  
12834			return this;
12835  
12836		},
12837  
12838		center: function () {
12839  
12840			var offset = new Vector3();
12841  
12842			return function center() {
12843  
12844				this.computeBoundingBox();
12845  
12846				this.boundingBox.getCenter( offset ).negate();
12847  
12848				this.translate( offset.x, offset.y, offset.z );
12849  
12850				return this;
12851  
12852			};
12853  
12854		}(),
12855  
12856		normalize: function () {
12857  
12858			this.computeBoundingSphere();
12859  
12860			var center = this.boundingSphere.center;
12861			var radius = this.boundingSphere.radius;
12862  
12863			var s = radius === 0 ? 1 : 1.0 / radius;
12864  
12865			var matrix = new Matrix4();
12866			matrix.set(
12867				s, 0, 0, - s * center.x,
12868				0, s, 0, - s * center.y,
12869				0, 0, s, - s * center.z,
12870				0, 0, 0, 1
12871			);
12872  
12873			this.applyMatrix( matrix );
12874  
12875			return this;
12876  
12877		},
12878  
12879		computeFaceNormals: function () {
12880  
12881			var cb = new Vector3(), ab = new Vector3();
12882  
12883			for ( var f = 0, fl = this.faces.length; f < fl; f ++ ) {
12884  
12885				var face = this.faces[ f ];
12886  
12887				var vA = this.vertices[ face.a ];
12888				var vB = this.vertices[ face.b ];
12889				var vC = this.vertices[ face.c ];
12890  
12891				cb.subVectors( vC, vB );
12892				ab.subVectors( vA, vB );
12893				cb.cross( ab );
12894  
12895				cb.normalize();
12896  
12897				face.normal.copy( cb );
12898  
12899			}
12900  
12901		},
12902  
12903		computeVertexNormals: function ( areaWeighted ) {
12904  
12905			if ( areaWeighted === undefined ) areaWeighted = true;
12906  
12907			var v, vl, f, fl, face, vertices;
12908  
12909			vertices = new Array( this.vertices.length );
12910  
12911			for ( v = 0, vl = this.vertices.length; v < vl; v ++ ) {
12912  
12913				vertices[ v ] = new Vector3();
12914  
12915			}
12916  
12917			if ( areaWeighted ) {
12918  
12919				// vertex normals weighted by triangle areas
12920				// http://www.iquilezles.org/www/articles/normals/normals.htm
12921  
12922				var vA, vB, vC;
12923				var cb = new Vector3(), ab = new Vector3();
12924  
12925				for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {
12926  
12927					face = this.faces[ f ];
12928  
12929					vA = this.vertices[ face.a ];
12930					vB = this.vertices[ face.b ];
12931					vC = this.vertices[ face.c ];
12932  
12933					cb.subVectors( vC, vB );
12934					ab.subVectors( vA, vB );
12935					cb.cross( ab );
12936  
12937					vertices[ face.a ].add( cb );
12938					vertices[ face.b ].add( cb );
12939					vertices[ face.c ].add( cb );
12940  
12941				}
12942  
12943			} else {
12944  
12945				this.computeFaceNormals();
12946  
12947				for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {
12948  
12949					face = this.faces[ f ];
12950  
12951					vertices[ face.a ].add( face.normal );
12952					vertices[ face.b ].add( face.normal );
12953					vertices[ face.c ].add( face.normal );
12954  
12955				}
12956  
12957			}
12958  
12959			for ( v = 0, vl = this.vertices.length; v < vl; v ++ ) {
12960  
12961				vertices[ v ].normalize();
12962  
12963			}
12964  
12965			for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {
12966  
12967				face = this.faces[ f ];
12968  
12969				var vertexNormals = face.vertexNormals;
12970  
12971				if ( vertexNormals.length === 3 ) {
12972  
12973					vertexNormals[ 0 ].copy( vertices[ face.a ] );
12974					vertexNormals[ 1 ].copy( vertices[ face.b ] );
12975					vertexNormals[ 2 ].copy( vertices[ face.c ] );
12976  
12977				} else {
12978  
12979					vertexNormals[ 0 ] = vertices[ face.a ].clone();
12980					vertexNormals[ 1 ] = vertices[ face.b ].clone();
12981					vertexNormals[ 2 ] = vertices[ face.c ].clone();
12982  
12983				}
12984  
12985			}
12986  
12987			if ( this.faces.length > 0 ) {
12988  
12989				this.normalsNeedUpdate = true;
12990  
12991			}
12992  
12993		},
12994  
12995		computeFlatVertexNormals: function () {
12996  
12997			var f, fl, face;
12998  
12999			this.computeFaceNormals();
13000  
13001			for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {
13002  
13003				face = this.faces[ f ];
13004  
13005				var vertexNormals = face.vertexNormals;
13006  
13007				if ( vertexNormals.length === 3 ) {
13008  
13009					vertexNormals[ 0 ].copy( face.normal );
13010					vertexNormals[ 1 ].copy( face.normal );
13011					vertexNormals[ 2 ].copy( face.normal );
13012  
13013				} else {
13014  
13015					vertexNormals[ 0 ] = face.normal.clone();
13016					vertexNormals[ 1 ] = face.normal.clone();
13017					vertexNormals[ 2 ] = face.normal.clone();
13018  
13019				}
13020  
13021			}
13022  
13023			if ( this.faces.length > 0 ) {
13024  
13025				this.normalsNeedUpdate = true;
13026  
13027			}
13028  
13029		},
13030  
13031		computeMorphNormals: function () {
13032  
13033			var i, il, f, fl, face;
13034  
13035			// save original normals
13036			// - create temp variables on first access
13037			//   otherwise just copy (for faster repeated calls)
13038  
13039			for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {
13040  
13041				face = this.faces[ f ];
13042  
13043				if ( ! face.__originalFaceNormal ) {
13044  
13045					face.__originalFaceNormal = face.normal.clone();
13046  
13047				} else {
13048  
13049					face.__originalFaceNormal.copy( face.normal );
13050  
13051				}
13052  
13053				if ( ! face.__originalVertexNormals ) face.__originalVertexNormals = [];
13054  
13055				for ( i = 0, il = face.vertexNormals.length; i < il; i ++ ) {
13056  
13057					if ( ! face.__originalVertexNormals[ i ] ) {
13058  
13059						face.__originalVertexNormals[ i ] = face.vertexNormals[ i ].clone();
13060  
13061					} else {
13062  
13063						face.__originalVertexNormals[ i ].copy( face.vertexNormals[ i ] );
13064  
13065					}
13066  
13067				}
13068  
13069			}
13070  
13071			// use temp geometry to compute face and vertex normals for each morph
13072  
13073			var tmpGeo = new Geometry();
13074			tmpGeo.faces = this.faces;
13075  
13076			for ( i = 0, il = this.morphTargets.length; i < il; i ++ ) {
13077  
13078				// create on first access
13079  
13080				if ( ! this.morphNormals[ i ] ) {
13081  
13082					this.morphNormals[ i ] = {};
13083					this.morphNormals[ i ].faceNormals = [];
13084					this.morphNormals[ i ].vertexNormals = [];
13085  
13086					var dstNormalsFace = this.morphNormals[ i ].faceNormals;
13087					var dstNormalsVertex = this.morphNormals[ i ].vertexNormals;
13088  
13089					var faceNormal, vertexNormals;
13090  
13091					for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {
13092  
13093						faceNormal = new Vector3();
13094						vertexNormals = { a: new Vector3(), b: new Vector3(), c: new Vector3() };
13095  
13096						dstNormalsFace.push( faceNormal );
13097						dstNormalsVertex.push( vertexNormals );
13098  
13099					}
13100  
13101				}
13102  
13103				var morphNormals = this.morphNormals[ i ];
13104  
13105				// set vertices to morph target
13106  
13107				tmpGeo.vertices = this.morphTargets[ i ].vertices;
13108  
13109				// compute morph normals
13110  
13111				tmpGeo.computeFaceNormals();
13112				tmpGeo.computeVertexNormals();
13113  
13114				// store morph normals
13115  
13116				var faceNormal, vertexNormals;
13117  
13118				for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {
13119  
13120					face = this.faces[ f ];
13121  
13122					faceNormal = morphNormals.faceNormals[ f ];
13123					vertexNormals = morphNormals.vertexNormals[ f ];
13124  
13125					faceNormal.copy( face.normal );
13126  
13127					vertexNormals.a.copy( face.vertexNormals[ 0 ] );
13128					vertexNormals.b.copy( face.vertexNormals[ 1 ] );
13129					vertexNormals.c.copy( face.vertexNormals[ 2 ] );
13130  
13131				}
13132  
13133			}
13134  
13135			// restore original normals
13136  
13137			for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {
13138  
13139				face = this.faces[ f ];
13140  
13141				face.normal = face.__originalFaceNormal;
13142				face.vertexNormals = face.__originalVertexNormals;
13143  
13144			}
13145  
13146		},
13147  
13148		computeBoundingBox: function () {
13149  
13150			if ( this.boundingBox === null ) {
13151  
13152				this.boundingBox = new Box3();
13153  
13154			}
13155  
13156			this.boundingBox.setFromPoints( this.vertices );
13157  
13158		},
13159  
13160		computeBoundingSphere: function () {
13161  
13162			if ( this.boundingSphere === null ) {
13163  
13164				this.boundingSphere = new Sphere();
13165  
13166			}
13167  
13168			this.boundingSphere.setFromPoints( this.vertices );
13169  
13170		},
13171  
13172		merge: function ( geometry, matrix, materialIndexOffset ) {
13173  
13174			if ( ! ( geometry && geometry.isGeometry ) ) {
13175  
13176				console.error( 'THREE.Geometry.merge(): geometry not an instance of THREE.Geometry.', geometry );
13177				return;
13178  
13179			}
13180  
13181			var normalMatrix,
13182				vertexOffset = this.vertices.length,
13183				vertices1 = this.vertices,
13184				vertices2 = geometry.vertices,
13185				faces1 = this.faces,
13186				faces2 = geometry.faces,
13187				uvs1 = this.faceVertexUvs[ 0 ],
13188				uvs2 = geometry.faceVertexUvs[ 0 ],
13189				colors1 = this.colors,
13190				colors2 = geometry.colors;
13191  
13192			if ( materialIndexOffset === undefined ) materialIndexOffset = 0;
13193  
13194			if ( matrix !== undefined ) {
13195  
13196				normalMatrix = new Matrix3().getNormalMatrix( matrix );
13197  
13198			}
13199  
13200			// vertices
13201  
13202			for ( var i = 0, il = vertices2.length; i < il; i ++ ) {
13203  
13204				var vertex = vertices2[ i ];
13205  
13206				var vertexCopy = vertex.clone();
13207  
13208				if ( matrix !== undefined ) vertexCopy.applyMatrix4( matrix );
13209  
13210				vertices1.push( vertexCopy );
13211  
13212			}
13213  
13214			// colors
13215  
13216			for ( var i = 0, il = colors2.length; i < il; i ++ ) {
13217  
13218				colors1.push( colors2[ i ].clone() );
13219  
13220			}
13221  
13222			// faces
13223  
13224			for ( i = 0, il = faces2.length; i < il; i ++ ) {
13225  
13226				var face = faces2[ i ], faceCopy, normal, color,
13227					faceVertexNormals = face.vertexNormals,
13228					faceVertexColors = face.vertexColors;
13229  
13230				faceCopy = new Face3( face.a + vertexOffset, face.b + vertexOffset, face.c + vertexOffset );
13231				faceCopy.normal.copy( face.normal );
13232  
13233				if ( normalMatrix !== undefined ) {
13234  
13235					faceCopy.normal.applyMatrix3( normalMatrix ).normalize();
13236  
13237				}
13238  
13239				for ( var j = 0, jl = faceVertexNormals.length; j < jl; j ++ ) {
13240  
13241					normal = faceVertexNormals[ j ].clone();
13242  
13243					if ( normalMatrix !== undefined ) {
13244  
13245						normal.applyMatrix3( normalMatrix ).normalize();
13246  
13247					}
13248  
13249					faceCopy.vertexNormals.push( normal );
13250  
13251				}
13252  
13253				faceCopy.color.copy( face.color );
13254  
13255				for ( var j = 0, jl = faceVertexColors.length; j < jl; j ++ ) {
13256  
13257					color = faceVertexColors[ j ];
13258					faceCopy.vertexColors.push( color.clone() );
13259  
13260				}
13261  
13262				faceCopy.materialIndex = face.materialIndex + materialIndexOffset;
13263  
13264				faces1.push( faceCopy );
13265  
13266			}
13267  
13268			// uvs
13269  
13270			for ( i = 0, il = uvs2.length; i < il; i ++ ) {
13271  
13272				var uv = uvs2[ i ], uvCopy = [];
13273  
13274				if ( uv === undefined ) {
13275  
13276					continue;
13277  
13278				}
13279  
13280				for ( var j = 0, jl = uv.length; j < jl; j ++ ) {
13281  
13282					uvCopy.push( uv[ j ].clone() );
13283  
13284				}
13285  
13286				uvs1.push( uvCopy );
13287  
13288			}
13289  
13290		},
13291  
13292		mergeMesh: function ( mesh ) {
13293  
13294			if ( ! ( mesh && mesh.isMesh ) ) {
13295  
13296				console.error( 'THREE.Geometry.mergeMesh(): mesh not an instance of THREE.Mesh.', mesh );
13297				return;
13298  
13299			}
13300  
13301			if ( mesh.matrixAutoUpdate ) mesh.updateMatrix();
13302  
13303			this.merge( mesh.geometry, mesh.matrix );
13304  
13305		},
13306  
13307		/*
13308		 * Checks for duplicate vertices with hashmap.
13309		 * Duplicated vertices are removed
13310		 * and faces' vertices are updated.
13311		 */
13312  
13313		mergeVertices: function () {
13314  
13315			var verticesMap = {}; // Hashmap for looking up vertices by position coordinates (and making sure they are unique)
13316			var unique = [], changes = [];
13317  
13318			var v, key;
13319			var precisionPoints = 4; // number of decimal points, e.g. 4 for epsilon of 0.0001
13320			var precision = Math.pow( 10, precisionPoints );
13321			var i, il, face;
13322			var indices, j, jl;
13323  
13324			for ( i = 0, il = this.vertices.length; i < il; i ++ ) {
13325  
13326				v = this.vertices[ i ];
13327				key = Math.round( v.x * precision ) + '_' + Math.round( v.y * precision ) + '_' + Math.round( v.z * precision );
13328  
13329				if ( verticesMap[ key ] === undefined ) {
13330  
13331					verticesMap[ key ] = i;
13332					unique.push( this.vertices[ i ] );
13333					changes[ i ] = unique.length - 1;
13334  
13335				} else {
13336  
13337					//console.log('Duplicate vertex found. ', i, ' could be using ', verticesMap[key]);
13338					changes[ i ] = changes[ verticesMap[ key ] ];
13339  
13340				}
13341  
13342			}
13343  
13344  
13345			// if faces are completely degenerate after merging vertices, we
13346			// have to remove them from the geometry.
13347			var faceIndicesToRemove = [];
13348  
13349			for ( i = 0, il = this.faces.length; i < il; i ++ ) {
13350  
13351				face = this.faces[ i ];
13352  
13353				face.a = changes[ face.a ];
13354				face.b = changes[ face.b ];
13355				face.c = changes[ face.c ];
13356  
13357				indices = [ face.a, face.b, face.c ];
13358  
13359				// if any duplicate vertices are found in a Face3
13360				// we have to remove the face as nothing can be saved
13361				for ( var n = 0; n < 3; n ++ ) {
13362  
13363					if ( indices[ n ] === indices[ ( n + 1 ) % 3 ] ) {
13364  
13365						faceIndicesToRemove.push( i );
13366						break;
13367  
13368					}
13369  
13370				}
13371  
13372			}
13373  
13374			for ( i = faceIndicesToRemove.length - 1; i >= 0; i -- ) {
13375  
13376				var idx = faceIndicesToRemove[ i ];
13377  
13378				this.faces.splice( idx, 1 );
13379  
13380				for ( j = 0, jl = this.faceVertexUvs.length; j < jl; j ++ ) {
13381  
13382					this.faceVertexUvs[ j ].splice( idx, 1 );
13383  
13384				}
13385  
13386			}
13387  
13388			// Use unique set of vertices
13389  
13390			var diff = this.vertices.length - unique.length;
13391			this.vertices = unique;
13392			return diff;
13393  
13394		},
13395  
13396		setFromPoints: function ( points ) {
13397  
13398			this.vertices = [];
13399  
13400			for ( var i = 0, l = points.length; i < l; i ++ ) {
13401  
13402				var point = points[ i ];
13403				this.vertices.push( new Vector3( point.x, point.y, point.z || 0 ) );
13404  
13405			}
13406  
13407			return this;
13408  
13409		},
13410  
13411		sortFacesByMaterialIndex: function () {
13412  
13413			var faces = this.faces;
13414			var length = faces.length;
13415  
13416			// tag faces
13417  
13418			for ( var i = 0; i < length; i ++ ) {
13419  
13420				faces[ i ]._id = i;
13421  
13422			}
13423  
13424			// sort faces
13425  
13426			function materialIndexSort( a, b ) {
13427  
13428				return a.materialIndex - b.materialIndex;
13429  
13430			}
13431  
13432			faces.sort( materialIndexSort );
13433  
13434			// sort uvs
13435  
13436			var uvs1 = this.faceVertexUvs[ 0 ];
13437			var uvs2 = this.faceVertexUvs[ 1 ];
13438  
13439			var newUvs1, newUvs2;
13440  
13441			if ( uvs1 && uvs1.length === length ) newUvs1 = [];
13442			if ( uvs2 && uvs2.length === length ) newUvs2 = [];
13443  
13444			for ( var i = 0; i < length; i ++ ) {
13445  
13446				var id = faces[ i ]._id;
13447  
13448				if ( newUvs1 ) newUvs1.push( uvs1[ id ] );
13449				if ( newUvs2 ) newUvs2.push( uvs2[ id ] );
13450  
13451			}
13452  
13453			if ( newUvs1 ) this.faceVertexUvs[ 0 ] = newUvs1;
13454			if ( newUvs2 ) this.faceVertexUvs[ 1 ] = newUvs2;
13455  
13456		},
13457  
13458		toJSON: function () {
13459  
13460			var data = {
13461				metadata: {
13462					version: 4.5,
13463					type: 'Geometry',
13464					generator: 'Geometry.toJSON'
13465				}
13466			};
13467  
13468			// standard Geometry serialization
13469  
13470			data.uuid = this.uuid;
13471			data.type = this.type;
13472			if ( this.name !== '' ) data.name = this.name;
13473  
13474			if ( this.parameters !== undefined ) {
13475  
13476				var parameters = this.parameters;
13477  
13478				for ( var key in parameters ) {
13479  
13480					if ( parameters[ key ] !== undefined ) data[ key ] = parameters[ key ];
13481  
13482				}
13483  
13484				return data;
13485  
13486			}
13487  
13488			var vertices = [];
13489  
13490			for ( var i = 0; i < this.vertices.length; i ++ ) {
13491  
13492				var vertex = this.vertices[ i ];
13493				vertices.push( vertex.x, vertex.y, vertex.z );
13494  
13495			}
13496  
13497			var faces = [];
13498			var normals = [];
13499			var normalsHash = {};
13500			var colors = [];
13501			var colorsHash = {};
13502			var uvs = [];
13503			var uvsHash = {};
13504  
13505			for ( var i = 0; i < this.faces.length; i ++ ) {
13506  
13507				var face = this.faces[ i ];
13508  
13509				var hasMaterial = true;
13510				var hasFaceUv = false; // deprecated
13511				var hasFaceVertexUv = this.faceVertexUvs[ 0 ][ i ] !== undefined;
13512				var hasFaceNormal = face.normal.length() > 0;
13513				var hasFaceVertexNormal = face.vertexNormals.length > 0;
13514				var hasFaceColor = face.color.r !== 1 || face.color.g !== 1 || face.color.b !== 1;
13515				var hasFaceVertexColor = face.vertexColors.length > 0;
13516  
13517				var faceType = 0;
13518  
13519				faceType = setBit( faceType, 0, 0 ); // isQuad
13520				faceType = setBit( faceType, 1, hasMaterial );
13521				faceType = setBit( faceType, 2, hasFaceUv );
13522				faceType = setBit( faceType, 3, hasFaceVertexUv );
13523				faceType = setBit( faceType, 4, hasFaceNormal );
13524				faceType = setBit( faceType, 5, hasFaceVertexNormal );
13525				faceType = setBit( faceType, 6, hasFaceColor );
13526				faceType = setBit( faceType, 7, hasFaceVertexColor );
13527  
13528				faces.push( faceType );
13529				faces.push( face.a, face.b, face.c );
13530				faces.push( face.materialIndex );
13531  
13532				if ( hasFaceVertexUv ) {
13533  
13534					var faceVertexUvs = this.faceVertexUvs[ 0 ][ i ];
13535  
13536					faces.push(
13537						getUvIndex( faceVertexUvs[ 0 ] ),
13538						getUvIndex( faceVertexUvs[ 1 ] ),
13539						getUvIndex( faceVertexUvs[ 2 ] )
13540					);
13541  
13542				}
13543  
13544				if ( hasFaceNormal ) {
13545  
13546					faces.push( getNormalIndex( face.normal ) );
13547  
13548				}
13549  
13550				if ( hasFaceVertexNormal ) {
13551  
13552					var vertexNormals = face.vertexNormals;
13553  
13554					faces.push(
13555						getNormalIndex( vertexNormals[ 0 ] ),
13556						getNormalIndex( vertexNormals[ 1 ] ),
13557						getNormalIndex( vertexNormals[ 2 ] )
13558					);
13559  
13560				}
13561  
13562				if ( hasFaceColor ) {
13563  
13564					faces.push( getColorIndex( face.color ) );
13565  
13566				}
13567  
13568				if ( hasFaceVertexColor ) {
13569  
13570					var vertexColors = face.vertexColors;
13571  
13572					faces.push(
13573						getColorIndex( vertexColors[ 0 ] ),
13574						getColorIndex( vertexColors[ 1 ] ),
13575						getColorIndex( vertexColors[ 2 ] )
13576					);
13577  
13578				}
13579  
13580			}
13581  
13582			function setBit( value, position, enabled ) {
13583  
13584				return enabled ? value | ( 1 << position ) : value & ( ~ ( 1 << position ) );
13585  
13586			}
13587  
13588			function getNormalIndex( normal ) {
13589  
13590				var hash = normal.x.toString() + normal.y.toString() + normal.z.toString();
13591  
13592				if ( normalsHash[ hash ] !== undefined ) {
13593  
13594					return normalsHash[ hash ];
13595  
13596				}
13597  
13598				normalsHash[ hash ] = normals.length / 3;
13599				normals.push( normal.x, normal.y, normal.z );
13600  
13601				return normalsHash[ hash ];
13602  
13603			}
13604  
13605			function getColorIndex( color ) {
13606  
13607				var hash = color.r.toString() + color.g.toString() + color.b.toString();
13608  
13609				if ( colorsHash[ hash ] !== undefined ) {
13610  
13611					return colorsHash[ hash ];
13612  
13613				}
13614  
13615				colorsHash[ hash ] = colors.length;
13616				colors.push( color.getHex() );
13617  
13618				return colorsHash[ hash ];
13619  
13620			}
13621  
13622			function getUvIndex( uv ) {
13623  
13624				var hash = uv.x.toString() + uv.y.toString();
13625  
13626				if ( uvsHash[ hash ] !== undefined ) {
13627  
13628					return uvsHash[ hash ];
13629  
13630				}
13631  
13632				uvsHash[ hash ] = uvs.length / 2;
13633				uvs.push( uv.x, uv.y );
13634  
13635				return uvsHash[ hash ];
13636  
13637			}
13638  
13639			data.data = {};
13640  
13641			data.data.vertices = vertices;
13642			data.data.normals = normals;
13643			if ( colors.length > 0 ) data.data.colors = colors;
13644			if ( uvs.length > 0 ) data.data.uvs = [ uvs ]; // temporal backward compatibility
13645			data.data.faces = faces;
13646  
13647			return data;
13648  
13649		},
13650  
13651		clone: function () {
13652  
13653			/*
13654			 // Handle primitives
13655  
13656			 var parameters = this.parameters;
13657  
13658			 if ( parameters !== undefined ) {
13659  
13660			 var values = [];
13661  
13662			 for ( var key in parameters ) {
13663  
13664			 values.push( parameters[ key ] );
13665  
13666			 }
13667  
13668			 var geometry = Object.create( this.constructor.prototype );
13669			 this.constructor.apply( geometry, values );
13670			 return geometry;
13671  
13672			 }
13673  
13674			 return new this.constructor().copy( this );
13675			 */
13676  
13677			return new Geometry().copy( this );
13678  
13679		},
13680  
13681		copy: function ( source ) {
13682  
13683			var i, il, j, jl, k, kl;
13684  
13685			// reset
13686  
13687			this.vertices = [];
13688			this.colors = [];
13689			this.faces = [];
13690			this.faceVertexUvs = [[]];
13691			this.morphTargets = [];
13692			this.morphNormals = [];
13693			this.skinWeights = [];
13694			this.skinIndices = [];
13695			this.lineDistances = [];
13696			this.boundingBox = null;
13697			this.boundingSphere = null;
13698  
13699			// name
13700  
13701			this.name = source.name;
13702  
13703			// vertices
13704  
13705			var vertices = source.vertices;
13706  
13707			for ( i = 0, il = vertices.length; i < il; i ++ ) {
13708  
13709				this.vertices.push( vertices[ i ].clone() );
13710  
13711			}
13712  
13713			// colors
13714  
13715			var colors = source.colors;
13716  
13717			for ( i = 0, il = colors.length; i < il; i ++ ) {
13718  
13719				this.colors.push( colors[ i ].clone() );
13720  
13721			}
13722  
13723			// faces
13724  
13725			var faces = source.faces;
13726  
13727			for ( i = 0, il = faces.length; i < il; i ++ ) {
13728  
13729				this.faces.push( faces[ i ].clone() );
13730  
13731			}
13732  
13733			// face vertex uvs
13734  
13735			for ( i = 0, il = source.faceVertexUvs.length; i < il; i ++ ) {
13736  
13737				var faceVertexUvs = source.faceVertexUvs[ i ];
13738  
13739				if ( this.faceVertexUvs[ i ] === undefined ) {
13740  
13741					this.faceVertexUvs[ i ] = [];
13742  
13743				}
13744  
13745				for ( j = 0, jl = faceVertexUvs.length; j < jl; j ++ ) {
13746  
13747					var uvs = faceVertexUvs[ j ], uvsCopy = [];
13748  
13749					for ( k = 0, kl = uvs.length; k < kl; k ++ ) {
13750  
13751						var uv = uvs[ k ];
13752  
13753						uvsCopy.push( uv.clone() );
13754  
13755					}
13756  
13757					this.faceVertexUvs[ i ].push( uvsCopy );
13758  
13759				}
13760  
13761			}
13762  
13763			// morph targets
13764  
13765			var morphTargets = source.morphTargets;
13766  
13767			for ( i = 0, il = morphTargets.length; i < il; i ++ ) {
13768  
13769				var morphTarget = {};
13770				morphTarget.name = morphTargets[ i ].name;
13771  
13772				// vertices
13773  
13774				if ( morphTargets[ i ].vertices !== undefined ) {
13775  
13776					morphTarget.vertices = [];
13777  
13778					for ( j = 0, jl = morphTargets[ i ].vertices.length; j < jl; j ++ ) {
13779  
13780						morphTarget.vertices.push( morphTargets[ i ].vertices[ j ].clone() );
13781  
13782					}
13783  
13784				}
13785  
13786				// normals
13787  
13788				if ( morphTargets[ i ].normals !== undefined ) {
13789  
13790					morphTarget.normals = [];
13791  
13792					for ( j = 0, jl = morphTargets[ i ].normals.length; j < jl; j ++ ) {
13793  
13794						morphTarget.normals.push( morphTargets[ i ].normals[ j ].clone() );
13795  
13796					}
13797  
13798				}
13799  
13800				this.morphTargets.push( morphTarget );
13801  
13802			}
13803  
13804			// morph normals
13805  
13806			var morphNormals = source.morphNormals;
13807  
13808			for ( i = 0, il = morphNormals.length; i < il; i ++ ) {
13809  
13810				var morphNormal = {};
13811  
13812				// vertex normals
13813  
13814				if ( morphNormals[ i ].vertexNormals !== undefined ) {
13815  
13816					morphNormal.vertexNormals = [];
13817  
13818					for ( j = 0, jl = morphNormals[ i ].vertexNormals.length; j < jl; j ++ ) {
13819  
13820						var srcVertexNormal = morphNormals[ i ].vertexNormals[ j ];
13821						var destVertexNormal = {};
13822  
13823						destVertexNormal.a = srcVertexNormal.a.clone();
13824						destVertexNormal.b = srcVertexNormal.b.clone();
13825						destVertexNormal.c = srcVertexNormal.c.clone();
13826  
13827						morphNormal.vertexNormals.push( destVertexNormal );
13828  
13829					}
13830  
13831				}
13832  
13833				// face normals
13834  
13835				if ( morphNormals[ i ].faceNormals !== undefined ) {
13836  
13837					morphNormal.faceNormals = [];
13838  
13839					for ( j = 0, jl = morphNormals[ i ].faceNormals.length; j < jl; j ++ ) {
13840  
13841						morphNormal.faceNormals.push( morphNormals[ i ].faceNormals[ j ].clone() );
13842  
13843					}
13844  
13845				}
13846  
13847				this.morphNormals.push( morphNormal );
13848  
13849			}
13850  
13851			// skin weights
13852  
13853			var skinWeights = source.skinWeights;
13854  
13855			for ( i = 0, il = skinWeights.length; i < il; i ++ ) {
13856  
13857				this.skinWeights.push( skinWeights[ i ].clone() );
13858  
13859			}
13860  
13861			// skin indices
13862  
13863			var skinIndices = source.skinIndices;
13864  
13865			for ( i = 0, il = skinIndices.length; i < il; i ++ ) {
13866  
13867				this.skinIndices.push( skinIndices[ i ].clone() );
13868  
13869			}
13870  
13871			// line distances
13872  
13873			var lineDistances = source.lineDistances;
13874  
13875			for ( i = 0, il = lineDistances.length; i < il; i ++ ) {
13876  
13877				this.lineDistances.push( lineDistances[ i ] );
13878  
13879			}
13880  
13881			// bounding box
13882  
13883			var boundingBox = source.boundingBox;
13884  
13885			if ( boundingBox !== null ) {
13886  
13887				this.boundingBox = boundingBox.clone();
13888  
13889			}
13890  
13891			// bounding sphere
13892  
13893			var boundingSphere = source.boundingSphere;
13894  
13895			if ( boundingSphere !== null ) {
13896  
13897				this.boundingSphere = boundingSphere.clone();
13898  
13899			}
13900  
13901			// update flags
13902  
13903			this.elementsNeedUpdate = source.elementsNeedUpdate;
13904			this.verticesNeedUpdate = source.verticesNeedUpdate;
13905			this.uvsNeedUpdate = source.uvsNeedUpdate;
13906			this.normalsNeedUpdate = source.normalsNeedUpdate;
13907			this.colorsNeedUpdate = source.colorsNeedUpdate;
13908			this.lineDistancesNeedUpdate = source.lineDistancesNeedUpdate;
13909			this.groupsNeedUpdate = source.groupsNeedUpdate;
13910  
13911			return this;
13912  
13913		},
13914  
13915		dispose: function () {
13916  
13917			this.dispatchEvent( { type: 'dispose' } );
13918  
13919		}
13920  
13921	} );
13922  
13923	/**
13924	 * @author mrdoob / http://mrdoob.com/
13925	 */
13926  
13927	function BufferAttribute( array, itemSize, normalized ) {
13928  
13929		if ( Array.isArray( array ) ) {
13930  
13931			throw new TypeError( 'THREE.BufferAttribute: array should be a Typed Array.' );
13932  
13933		}
13934  
13935		this.name = '';
13936  
13937		this.array = array;
13938		this.itemSize = itemSize;
13939		this.count = array !== undefined ? array.length / itemSize : 0;
13940		this.normalized = normalized === true;
13941  
13942		this.dynamic = false;
13943		this.updateRange = { offset: 0, count: - 1 };
13944  
13945		this.version = 0;
13946  
13947	}
13948  
13949	Object.defineProperty( BufferAttribute.prototype, 'needsUpdate', {
13950  
13951		set: function ( value ) {
13952  
13953			if ( value === true ) this.version ++;
13954  
13955		}
13956  
13957	} );
13958  
13959	Object.assign( BufferAttribute.prototype, {
13960  
13961		isBufferAttribute: true,
13962  
13963		onUploadCallback: function () {},
13964  
13965		setArray: function ( array ) {
13966  
13967			if ( Array.isArray( array ) ) {
13968  
13969				throw new TypeError( 'THREE.BufferAttribute: array should be a Typed Array.' );
13970  
13971			}
13972  
13973			this.count = array !== undefined ? array.length / this.itemSize : 0;
13974			this.array = array;
13975  
13976			return this;
13977  
13978		},
13979  
13980		setDynamic: function ( value ) {
13981  
13982			this.dynamic = value;
13983  
13984			return this;
13985  
13986		},
13987  
13988		copy: function ( source ) {
13989  
13990			this.name = source.name;
13991			this.array = new source.array.constructor( source.array );
13992			this.itemSize = source.itemSize;
13993			this.count = source.count;
13994			this.normalized = source.normalized;
13995  
13996			this.dynamic = source.dynamic;
13997  
13998			return this;
13999  
14000		},
14001  
14002		copyAt: function ( index1, attribute, index2 ) {
14003  
14004			index1 *= this.itemSize;
14005			index2 *= attribute.itemSize;
14006  
14007			for ( var i = 0, l = this.itemSize; i < l; i ++ ) {
14008  
14009				this.array[ index1 + i ] = attribute.array[ index2 + i ];
14010  
14011			}
14012  
14013			return this;
14014  
14015		},
14016  
14017		copyArray: function ( array ) {
14018  
14019			this.array.set( array );
14020  
14021			return this;
14022  
14023		},
14024  
14025		copyColorsArray: function ( colors ) {
14026  
14027			var array = this.array, offset = 0;
14028  
14029			for ( var i = 0, l = colors.length; i < l; i ++ ) {
14030  
14031				var color = colors[ i ];
14032  
14033				if ( color === undefined ) {
14034  
14035					console.warn( 'THREE.BufferAttribute.copyColorsArray(): color is undefined', i );
14036					color = new Color();
14037  
14038				}
14039  
14040				array[ offset ++ ] = color.r;
14041				array[ offset ++ ] = color.g;
14042				array[ offset ++ ] = color.b;
14043  
14044			}
14045  
14046			return this;
14047  
14048		},
14049  
14050		copyVector2sArray: function ( vectors ) {
14051  
14052			var array = this.array, offset = 0;
14053  
14054			for ( var i = 0, l = vectors.length; i < l; i ++ ) {
14055  
14056				var vector = vectors[ i ];
14057  
14058				if ( vector === undefined ) {
14059  
14060					console.warn( 'THREE.BufferAttribute.copyVector2sArray(): vector is undefined', i );
14061					vector = new Vector2();
14062  
14063				}
14064  
14065				array[ offset ++ ] = vector.x;
14066				array[ offset ++ ] = vector.y;
14067  
14068			}
14069  
14070			return this;
14071  
14072		},
14073  
14074		copyVector3sArray: function ( vectors ) {
14075  
14076			var array = this.array, offset = 0;
14077  
14078			for ( var i = 0, l = vectors.length; i < l; i ++ ) {
14079  
14080				var vector = vectors[ i ];
14081  
14082				if ( vector === undefined ) {
14083  
14084					console.warn( 'THREE.BufferAttribute.copyVector3sArray(): vector is undefined', i );
14085					vector = new Vector3();
14086  
14087				}
14088  
14089				array[ offset ++ ] = vector.x;
14090				array[ offset ++ ] = vector.y;
14091				array[ offset ++ ] = vector.z;
14092  
14093			}
14094  
14095			return this;
14096  
14097		},
14098  
14099		copyVector4sArray: function ( vectors ) {
14100  
14101			var array = this.array, offset = 0;
14102  
14103			for ( var i = 0, l = vectors.length; i < l; i ++ ) {
14104  
14105				var vector = vectors[ i ];
14106  
14107				if ( vector === undefined ) {
14108  
14109					console.warn( 'THREE.BufferAttribute.copyVector4sArray(): vector is undefined', i );
14110					vector = new Vector4();
14111  
14112				}
14113  
14114				array[ offset ++ ] = vector.x;
14115				array[ offset ++ ] = vector.y;
14116				array[ offset ++ ] = vector.z;
14117				array[ offset ++ ] = vector.w;
14118  
14119			}
14120  
14121			return this;
14122  
14123		},
14124  
14125		set: function ( value, offset ) {
14126  
14127			if ( offset === undefined ) offset = 0;
14128  
14129			this.array.set( value, offset );
14130  
14131			return this;
14132  
14133		},
14134  
14135		getX: function ( index ) {
14136  
14137			return this.array[ index * this.itemSize ];
14138  
14139		},
14140  
14141		setX: function ( index, x ) {
14142  
14143			this.array[ index * this.itemSize ] = x;
14144  
14145			return this;
14146  
14147		},
14148  
14149		getY: function ( index ) {
14150  
14151			return this.array[ index * this.itemSize + 1 ];
14152  
14153		},
14154  
14155		setY: function ( index, y ) {
14156  
14157			this.array[ index * this.itemSize + 1 ] = y;
14158  
14159			return this;
14160  
14161		},
14162  
14163		getZ: function ( index ) {
14164  
14165			return this.array[ index * this.itemSize + 2 ];
14166  
14167		},
14168  
14169		setZ: function ( index, z ) {
14170  
14171			this.array[ index * this.itemSize + 2 ] = z;
14172  
14173			return this;
14174  
14175		},
14176  
14177		getW: function ( index ) {
14178  
14179			return this.array[ index * this.itemSize + 3 ];
14180  
14181		},
14182  
14183		setW: function ( index, w ) {
14184  
14185			this.array[ index * this.itemSize + 3 ] = w;
14186  
14187			return this;
14188  
14189		},
14190  
14191		setXY: function ( index, x, y ) {
14192  
14193			index *= this.itemSize;
14194  
14195			this.array[ index + 0 ] = x;
14196			this.array[ index + 1 ] = y;
14197  
14198			return this;
14199  
14200		},
14201  
14202		setXYZ: function ( index, x, y, z ) {
14203  
14204			index *= this.itemSize;
14205  
14206			this.array[ index + 0 ] = x;
14207			this.array[ index + 1 ] = y;
14208			this.array[ index + 2 ] = z;
14209  
14210			return this;
14211  
14212		},
14213  
14214		setXYZW: function ( index, x, y, z, w ) {
14215  
14216			index *= this.itemSize;
14217  
14218			this.array[ index + 0 ] = x;
14219			this.array[ index + 1 ] = y;
14220			this.array[ index + 2 ] = z;
14221			this.array[ index + 3 ] = w;
14222  
14223			return this;
14224  
14225		},
14226  
14227		onUpload: function ( callback ) {
14228  
14229			this.onUploadCallback = callback;
14230  
14231			return this;
14232  
14233		},
14234  
14235		clone: function () {
14236  
14237			return new this.constructor( this.array, this.itemSize ).copy( this );
14238  
14239		}
14240  
14241	} );
14242  
14243	//
14244  
14245	function Int8BufferAttribute( array, itemSize, normalized ) {
14246  
14247		BufferAttribute.call( this, new Int8Array( array ), itemSize, normalized );
14248  
14249	}
14250  
14251	Int8BufferAttribute.prototype = Object.create( BufferAttribute.prototype );
14252	Int8BufferAttribute.prototype.constructor = Int8BufferAttribute;
14253  
14254  
14255	function Uint8BufferAttribute( array, itemSize, normalized ) {
14256  
14257		BufferAttribute.call( this, new Uint8Array( array ), itemSize, normalized );
14258  
14259	}
14260  
14261	Uint8BufferAttribute.prototype = Object.create( BufferAttribute.prototype );
14262	Uint8BufferAttribute.prototype.constructor = Uint8BufferAttribute;
14263  
14264  
14265	function Uint8ClampedBufferAttribute( array, itemSize, normalized ) {
14266  
14267		BufferAttribute.call( this, new Uint8ClampedArray( array ), itemSize, normalized );
14268  
14269	}
14270  
14271	Uint8ClampedBufferAttribute.prototype = Object.create( BufferAttribute.prototype );
14272	Uint8ClampedBufferAttribute.prototype.constructor = Uint8ClampedBufferAttribute;
14273  
14274  
14275	function Int16BufferAttribute( array, itemSize, normalized ) {
14276  
14277		BufferAttribute.call( this, new Int16Array( array ), itemSize, normalized );
14278  
14279	}
14280  
14281	Int16BufferAttribute.prototype = Object.create( BufferAttribute.prototype );
14282	Int16BufferAttribute.prototype.constructor = Int16BufferAttribute;
14283  
14284  
14285	function Uint16BufferAttribute( array, itemSize, normalized ) {
14286  
14287		BufferAttribute.call( this, new Uint16Array( array ), itemSize, normalized );
14288  
14289	}
14290  
14291	Uint16BufferAttribute.prototype = Object.create( BufferAttribute.prototype );
14292	Uint16BufferAttribute.prototype.constructor = Uint16BufferAttribute;
14293  
14294  
14295	function Int32BufferAttribute( array, itemSize, normalized ) {
14296  
14297		BufferAttribute.call( this, new Int32Array( array ), itemSize, normalized );
14298  
14299	}
14300  
14301	Int32BufferAttribute.prototype = Object.create( BufferAttribute.prototype );
14302	Int32BufferAttribute.prototype.constructor = Int32BufferAttribute;
14303  
14304  
14305	function Uint32BufferAttribute( array, itemSize, normalized ) {
14306  
14307		BufferAttribute.call( this, new Uint32Array( array ), itemSize, normalized );
14308  
14309	}
14310  
14311	Uint32BufferAttribute.prototype = Object.create( BufferAttribute.prototype );
14312	Uint32BufferAttribute.prototype.constructor = Uint32BufferAttribute;
14313  
14314  
14315	function Float32BufferAttribute( array, itemSize, normalized ) {
14316  
14317		BufferAttribute.call( this, new Float32Array( array ), itemSize, normalized );
14318  
14319	}
14320  
14321	Float32BufferAttribute.prototype = Object.create( BufferAttribute.prototype );
14322	Float32BufferAttribute.prototype.constructor = Float32BufferAttribute;
14323  
14324  
14325	function Float64BufferAttribute( array, itemSize, normalized ) {
14326  
14327		BufferAttribute.call( this, new Float64Array( array ), itemSize, normalized );
14328  
14329	}
14330  
14331	Float64BufferAttribute.prototype = Object.create( BufferAttribute.prototype );
14332	Float64BufferAttribute.prototype.constructor = Float64BufferAttribute;
14333  
14334	/**
14335	 * @author mrdoob / http://mrdoob.com/
14336	 */
14337  
14338	function DirectGeometry() {
14339  
14340		this.vertices = [];
14341		this.normals = [];
14342		this.colors = [];
14343		this.uvs = [];
14344		this.uvs2 = [];
14345  
14346		this.groups = [];
14347  
14348		this.morphTargets = {};
14349  
14350		this.skinWeights = [];
14351		this.skinIndices = [];
14352  
14353		// this.lineDistances = [];
14354  
14355		this.boundingBox = null;
14356		this.boundingSphere = null;
14357  
14358		// update flags
14359  
14360		this.verticesNeedUpdate = false;
14361		this.normalsNeedUpdate = false;
14362		this.colorsNeedUpdate = false;
14363		this.uvsNeedUpdate = false;
14364		this.groupsNeedUpdate = false;
14365  
14366	}
14367  
14368	Object.assign( DirectGeometry.prototype, {
14369  
14370		computeGroups: function ( geometry ) {
14371  
14372			var group;
14373			var groups = [];
14374			var materialIndex = undefined;
14375  
14376			var faces = geometry.faces;
14377  
14378			for ( var i = 0; i < faces.length; i ++ ) {
14379  
14380				var face = faces[ i ];
14381  
14382				// materials
14383  
14384				if ( face.materialIndex !== materialIndex ) {
14385  
14386					materialIndex = face.materialIndex;
14387  
14388					if ( group !== undefined ) {
14389  
14390						group.count = ( i * 3 ) - group.start;
14391						groups.push( group );
14392  
14393					}
14394  
14395					group = {
14396						start: i * 3,
14397						materialIndex: materialIndex
14398					};
14399  
14400				}
14401  
14402			}
14403  
14404			if ( group !== undefined ) {
14405  
14406				group.count = ( i * 3 ) - group.start;
14407				groups.push( group );
14408  
14409			}
14410  
14411			this.groups = groups;
14412  
14413		},
14414  
14415		fromGeometry: function ( geometry ) {
14416  
14417			var faces = geometry.faces;
14418			var vertices = geometry.vertices;
14419			var faceVertexUvs = geometry.faceVertexUvs;
14420  
14421			var hasFaceVertexUv = faceVertexUvs[ 0 ] && faceVertexUvs[ 0 ].length > 0;
14422			var hasFaceVertexUv2 = faceVertexUvs[ 1 ] && faceVertexUvs[ 1 ].length > 0;
14423  
14424			// morphs
14425  
14426			var morphTargets = geometry.morphTargets;
14427			var morphTargetsLength = morphTargets.length;
14428  
14429			var morphTargetsPosition;
14430  
14431			if ( morphTargetsLength > 0 ) {
14432  
14433				morphTargetsPosition = [];
14434  
14435				for ( var i = 0; i < morphTargetsLength; i ++ ) {
14436  
14437					morphTargetsPosition[ i ] = [];
14438  
14439				}
14440  
14441				this.morphTargets.position = morphTargetsPosition;
14442  
14443			}
14444  
14445			var morphNormals = geometry.morphNormals;
14446			var morphNormalsLength = morphNormals.length;
14447  
14448			var morphTargetsNormal;
14449  
14450			if ( morphNormalsLength > 0 ) {
14451  
14452				morphTargetsNormal = [];
14453  
14454				for ( var i = 0; i < morphNormalsLength; i ++ ) {
14455  
14456					morphTargetsNormal[ i ] = [];
14457  
14458				}
14459  
14460				this.morphTargets.normal = morphTargetsNormal;
14461  
14462			}
14463  
14464			// skins
14465  
14466			var skinIndices = geometry.skinIndices;
14467			var skinWeights = geometry.skinWeights;
14468  
14469			var hasSkinIndices = skinIndices.length === vertices.length;
14470			var hasSkinWeights = skinWeights.length === vertices.length;
14471  
14472			//
14473  
14474			if ( faces.length === 0 ) {
14475  
14476				console.error( 'THREE.DirectGeometry: Faceless geometries are not supported.' );
14477  
14478			}
14479  
14480			for ( var i = 0; i < faces.length; i ++ ) {
14481  
14482				var face = faces[ i ];
14483  
14484				this.vertices.push( vertices[ face.a ], vertices[ face.b ], vertices[ face.c ] );
14485  
14486				var vertexNormals = face.vertexNormals;
14487  
14488				if ( vertexNormals.length === 3 ) {
14489  
14490					this.normals.push( vertexNormals[ 0 ], vertexNormals[ 1 ], vertexNormals[ 2 ] );
14491  
14492				} else {
14493  
14494					var normal = face.normal;
14495  
14496					this.normals.push( normal, normal, normal );
14497  
14498				}
14499  
14500				var vertexColors = face.vertexColors;
14501  
14502				if ( vertexColors.length === 3 ) {
14503  
14504					this.colors.push( vertexColors[ 0 ], vertexColors[ 1 ], vertexColors[ 2 ] );
14505  
14506				} else {
14507  
14508					var color = face.color;
14509  
14510					this.colors.push( color, color, color );
14511  
14512				}
14513  
14514				if ( hasFaceVertexUv === true ) {
14515  
14516					var vertexUvs = faceVertexUvs[ 0 ][ i ];
14517  
14518					if ( vertexUvs !== undefined ) {
14519  
14520						this.uvs.push( vertexUvs[ 0 ], vertexUvs[ 1 ], vertexUvs[ 2 ] );
14521  
14522					} else {
14523  
14524						console.warn( 'THREE.DirectGeometry.fromGeometry(): Undefined vertexUv ', i );
14525  
14526						this.uvs.push( new Vector2(), new Vector2(), new Vector2() );
14527  
14528					}
14529  
14530				}
14531  
14532				if ( hasFaceVertexUv2 === true ) {
14533  
14534					var vertexUvs = faceVertexUvs[ 1 ][ i ];
14535  
14536					if ( vertexUvs !== undefined ) {
14537  
14538						this.uvs2.push( vertexUvs[ 0 ], vertexUvs[ 1 ], vertexUvs[ 2 ] );
14539  
14540					} else {
14541  
14542						console.warn( 'THREE.DirectGeometry.fromGeometry(): Undefined vertexUv2 ', i );
14543  
14544						this.uvs2.push( new Vector2(), new Vector2(), new Vector2() );
14545  
14546					}
14547  
14548				}
14549  
14550				// morphs
14551  
14552				for ( var j = 0; j < morphTargetsLength; j ++ ) {
14553  
14554					var morphTarget = morphTargets[ j ].vertices;
14555  
14556					morphTargetsPosition[ j ].push( morphTarget[ face.a ], morphTarget[ face.b ], morphTarget[ face.c ] );
14557  
14558				}
14559  
14560				for ( var j = 0; j < morphNormalsLength; j ++ ) {
14561  
14562					var morphNormal = morphNormals[ j ].vertexNormals[ i ];
14563  
14564					morphTargetsNormal[ j ].push( morphNormal.a, morphNormal.b, morphNormal.c );
14565  
14566				}
14567  
14568				// skins
14569  
14570				if ( hasSkinIndices ) {
14571  
14572					this.skinIndices.push( skinIndices[ face.a ], skinIndices[ face.b ], skinIndices[ face.c ] );
14573  
14574				}
14575  
14576				if ( hasSkinWeights ) {
14577  
14578					this.skinWeights.push( skinWeights[ face.a ], skinWeights[ face.b ], skinWeights[ face.c ] );
14579  
14580				}
14581  
14582			}
14583  
14584			this.computeGroups( geometry );
14585  
14586			this.verticesNeedUpdate = geometry.verticesNeedUpdate;
14587			this.normalsNeedUpdate = geometry.normalsNeedUpdate;
14588			this.colorsNeedUpdate = geometry.colorsNeedUpdate;
14589			this.uvsNeedUpdate = geometry.uvsNeedUpdate;
14590			this.groupsNeedUpdate = geometry.groupsNeedUpdate;
14591  
14592			return this;
14593  
14594		}
14595  
14596	} );
14597  
14598	/**
14599	 * @author mrdoob / http://mrdoob.com/
14600	 */
14601  
14602	function arrayMax( array ) {
14603  
14604		if ( array.length === 0 ) return - Infinity;
14605  
14606		var max = array[ 0 ];
14607  
14608		for ( var i = 1, l = array.length; i < l; ++ i ) {
14609  
14610			if ( array[ i ] > max ) max = array[ i ];
14611  
14612		}
14613  
14614		return max;
14615  
14616	}
14617  
14618	/**
14619	 * @author alteredq / http://alteredqualia.com/
14620	 * @author mrdoob / http://mrdoob.com/
14621	 */
14622  
14623	var bufferGeometryId = 1; // BufferGeometry uses odd numbers as Id
14624  
14625	function BufferGeometry() {
14626  
14627		Object.defineProperty( this, 'id', { value: bufferGeometryId += 2 } );
14628  
14629		this.uuid = _Math.generateUUID();
14630  
14631		this.name = '';
14632		this.type = 'BufferGeometry';
14633  
14634		this.index = null;
14635		this.attributes = {};
14636  
14637		this.morphAttributes = {};
14638  
14639		this.groups = [];
14640  
14641		this.boundingBox = null;
14642		this.boundingSphere = null;
14643  
14644		this.drawRange = { start: 0, count: Infinity };
14645  
14646		this.userData = {};
14647  
14648	}
14649  
14650	BufferGeometry.prototype = Object.assign( Object.create( EventDispatcher.prototype ), {
14651  
14652		constructor: BufferGeometry,
14653  
14654		isBufferGeometry: true,
14655  
14656		getIndex: function () {
14657  
14658			return this.index;
14659  
14660		},
14661  
14662		setIndex: function ( index ) {
14663  
14664			if ( Array.isArray( index ) ) {
14665  
14666				this.index = new ( arrayMax( index ) > 65535 ? Uint32BufferAttribute : Uint16BufferAttribute )( index, 1 );
14667  
14668			} else {
14669  
14670				this.index = index;
14671  
14672			}
14673  
14674		},
14675  
14676		addAttribute: function ( name, attribute ) {
14677  
14678			if ( ! ( attribute && attribute.isBufferAttribute ) && ! ( attribute && attribute.isInterleavedBufferAttribute ) ) {
14679  
14680				console.warn( 'THREE.BufferGeometry: .addAttribute() now expects ( name, attribute ).' );
14681  
14682				return this.addAttribute( name, new BufferAttribute( arguments[ 1 ], arguments[ 2 ] ) );
14683  
14684			}
14685  
14686			if ( name === 'index' ) {
14687  
14688				console.warn( 'THREE.BufferGeometry.addAttribute: Use .setIndex() for index attribute.' );
14689				this.setIndex( attribute );
14690  
14691				return this;
14692  
14693			}
14694  
14695			this.attributes[ name ] = attribute;
14696  
14697			return this;
14698  
14699		},
14700  
14701		getAttribute: function ( name ) {
14702  
14703			return this.attributes[ name ];
14704  
14705		},
14706  
14707		removeAttribute: function ( name ) {
14708  
14709			delete this.attributes[ name ];
14710  
14711			return this;
14712  
14713		},
14714  
14715		addGroup: function ( start, count, materialIndex ) {
14716  
14717			this.groups.push( {
14718  
14719				start: start,
14720				count: count,
14721				materialIndex: materialIndex !== undefined ? materialIndex : 0
14722  
14723			} );
14724  
14725		},
14726  
14727		clearGroups: function () {
14728  
14729			this.groups = [];
14730  
14731		},
14732  
14733		setDrawRange: function ( start, count ) {
14734  
14735			this.drawRange.start = start;
14736			this.drawRange.count = count;
14737  
14738		},
14739  
14740		applyMatrix: function ( matrix ) {
14741  
14742			var position = this.attributes.position;
14743  
14744			if ( position !== undefined ) {
14745  
14746				matrix.applyToBufferAttribute( position );
14747				position.needsUpdate = true;
14748  
14749			}
14750  
14751			var normal = this.attributes.normal;
14752  
14753			if ( normal !== undefined ) {
14754  
14755				var normalMatrix = new Matrix3().getNormalMatrix( matrix );
14756  
14757				normalMatrix.applyToBufferAttribute( normal );
14758				normal.needsUpdate = true;
14759  
14760			}
14761  
14762			if ( this.boundingBox !== null ) {
14763  
14764				this.computeBoundingBox();
14765  
14766			}
14767  
14768			if ( this.boundingSphere !== null ) {
14769  
14770				this.computeBoundingSphere();
14771  
14772			}
14773  
14774			return this;
14775  
14776		},
14777  
14778		rotateX: function () {
14779  
14780			// rotate geometry around world x-axis
14781  
14782			var m1 = new Matrix4();
14783  
14784			return function rotateX( angle ) {
14785  
14786				m1.makeRotationX( angle );
14787  
14788				this.applyMatrix( m1 );
14789  
14790				return this;
14791  
14792			};
14793  
14794		}(),
14795  
14796		rotateY: function () {
14797  
14798			// rotate geometry around world y-axis
14799  
14800			var m1 = new Matrix4();
14801  
14802			return function rotateY( angle ) {
14803  
14804				m1.makeRotationY( angle );
14805  
14806				this.applyMatrix( m1 );
14807  
14808				return this;
14809  
14810			};
14811  
14812		}(),
14813  
14814		rotateZ: function () {
14815  
14816			// rotate geometry around world z-axis
14817  
14818			var m1 = new Matrix4();
14819  
14820			return function rotateZ( angle ) {
14821  
14822				m1.makeRotationZ( angle );
14823  
14824				this.applyMatrix( m1 );
14825  
14826				return this;
14827  
14828			};
14829  
14830		}(),
14831  
14832		translate: function () {
14833  
14834			// translate geometry
14835  
14836			var m1 = new Matrix4();
14837  
14838			return function translate( x, y, z ) {
14839  
14840				m1.makeTranslation( x, y, z );
14841  
14842				this.applyMatrix( m1 );
14843  
14844				return this;
14845  
14846			};
14847  
14848		}(),
14849  
14850		scale: function () {
14851  
14852			// scale geometry
14853  
14854			var m1 = new Matrix4();
14855  
14856			return function scale( x, y, z ) {
14857  
14858				m1.makeScale( x, y, z );
14859  
14860				this.applyMatrix( m1 );
14861  
14862				return this;
14863  
14864			};
14865  
14866		}(),
14867  
14868		lookAt: function () {
14869  
14870			var obj = new Object3D();
14871  
14872			return function lookAt( vector ) {
14873  
14874				obj.lookAt( vector );
14875  
14876				obj.updateMatrix();
14877  
14878				this.applyMatrix( obj.matrix );
14879  
14880			};
14881  
14882		}(),
14883  
14884		center: function () {
14885  
14886			var offset = new Vector3();
14887  
14888			return function center() {
14889  
14890				this.computeBoundingBox();
14891  
14892				this.boundingBox.getCenter( offset ).negate();
14893  
14894				this.translate( offset.x, offset.y, offset.z );
14895  
14896				return this;
14897  
14898			};
14899  
14900		}(),
14901  
14902		setFromObject: function ( object ) {
14903  
14904			// console.log( 'THREE.BufferGeometry.setFromObject(). Converting', object, this );
14905  
14906			var geometry = object.geometry;
14907  
14908			if ( object.isPoints || object.isLine ) {
14909  
14910				var positions = new Float32BufferAttribute( geometry.vertices.length * 3, 3 );
14911				var colors = new Float32BufferAttribute( geometry.colors.length * 3, 3 );
14912  
14913				this.addAttribute( 'position', positions.copyVector3sArray( geometry.vertices ) );
14914				this.addAttribute( 'color', colors.copyColorsArray( geometry.colors ) );
14915  
14916				if ( geometry.lineDistances && geometry.lineDistances.length === geometry.vertices.length ) {
14917  
14918					var lineDistances = new Float32BufferAttribute( geometry.lineDistances.length, 1 );
14919  
14920					this.addAttribute( 'lineDistance', lineDistances.copyArray( geometry.lineDistances ) );
14921  
14922				}
14923  
14924				if ( geometry.boundingSphere !== null ) {
14925  
14926					this.boundingSphere = geometry.boundingSphere.clone();
14927  
14928				}
14929  
14930				if ( geometry.boundingBox !== null ) {
14931  
14932					this.boundingBox = geometry.boundingBox.clone();
14933  
14934				}
14935  
14936			} else if ( object.isMesh ) {
14937  
14938				if ( geometry && geometry.isGeometry ) {
14939  
14940					this.fromGeometry( geometry );
14941  
14942				}
14943  
14944			}
14945  
14946			return this;
14947  
14948		},
14949  
14950		setFromPoints: function ( points ) {
14951  
14952			var position = [];
14953  
14954			for ( var i = 0, l = points.length; i < l; i ++ ) {
14955  
14956				var point = points[ i ];
14957				position.push( point.x, point.y, point.z || 0 );
14958  
14959			}
14960  
14961			this.addAttribute( 'position', new Float32BufferAttribute( position, 3 ) );
14962  
14963			return this;
14964  
14965		},
14966  
14967		updateFromObject: function ( object ) {
14968  
14969			var geometry = object.geometry;
14970  
14971			if ( object.isMesh ) {
14972  
14973				var direct = geometry.__directGeometry;
14974  
14975				if ( geometry.elementsNeedUpdate === true ) {
14976  
14977					direct = undefined;
14978					geometry.elementsNeedUpdate = false;
14979  
14980				}
14981  
14982				if ( direct === undefined ) {
14983  
14984					return this.fromGeometry( geometry );
14985  
14986				}
14987  
14988				direct.verticesNeedUpdate = geometry.verticesNeedUpdate;
14989				direct.normalsNeedUpdate = geometry.normalsNeedUpdate;
14990				direct.colorsNeedUpdate = geometry.colorsNeedUpdate;
14991				direct.uvsNeedUpdate = geometry.uvsNeedUpdate;
14992				direct.groupsNeedUpdate = geometry.groupsNeedUpdate;
14993  
14994				geometry.verticesNeedUpdate = false;
14995				geometry.normalsNeedUpdate = false;
14996				geometry.colorsNeedUpdate = false;
14997				geometry.uvsNeedUpdate = false;
14998				geometry.groupsNeedUpdate = false;
14999  
15000				geometry = direct;
15001  
15002			}
15003  
15004			var attribute;
15005  
15006			if ( geometry.verticesNeedUpdate === true ) {
15007  
15008				attribute = this.attributes.position;
15009  
15010				if ( attribute !== undefined ) {
15011  
15012					attribute.copyVector3sArray( geometry.vertices );
15013					attribute.needsUpdate = true;
15014  
15015				}
15016  
15017				geometry.verticesNeedUpdate = false;
15018  
15019			}
15020  
15021			if ( geometry.normalsNeedUpdate === true ) {
15022  
15023				attribute = this.attributes.normal;
15024  
15025				if ( attribute !== undefined ) {
15026  
15027					attribute.copyVector3sArray( geometry.normals );
15028					attribute.needsUpdate = true;
15029  
15030				}
15031  
15032				geometry.normalsNeedUpdate = false;
15033  
15034			}
15035  
15036			if ( geometry.colorsNeedUpdate === true ) {
15037  
15038				attribute = this.attributes.color;
15039  
15040				if ( attribute !== undefined ) {
15041  
15042					attribute.copyColorsArray( geometry.colors );
15043					attribute.needsUpdate = true;
15044  
15045				}
15046  
15047				geometry.colorsNeedUpdate = false;
15048  
15049			}
15050  
15051			if ( geometry.uvsNeedUpdate ) {
15052  
15053				attribute = this.attributes.uv;
15054  
15055				if ( attribute !== undefined ) {
15056  
15057					attribute.copyVector2sArray( geometry.uvs );
15058					attribute.needsUpdate = true;
15059  
15060				}
15061  
15062				geometry.uvsNeedUpdate = false;
15063  
15064			}
15065  
15066			if ( geometry.lineDistancesNeedUpdate ) {
15067  
15068				attribute = this.attributes.lineDistance;
15069  
15070				if ( attribute !== undefined ) {
15071  
15072					attribute.copyArray( geometry.lineDistances );
15073					attribute.needsUpdate = true;
15074  
15075				}
15076  
15077				geometry.lineDistancesNeedUpdate = false;
15078  
15079			}
15080  
15081			if ( geometry.groupsNeedUpdate ) {
15082  
15083				geometry.computeGroups( object.geometry );
15084				this.groups = geometry.groups;
15085  
15086				geometry.groupsNeedUpdate = false;
15087  
15088			}
15089  
15090			return this;
15091  
15092		},
15093  
15094		fromGeometry: function ( geometry ) {
15095  
15096			geometry.__directGeometry = new DirectGeometry().fromGeometry( geometry );
15097  
15098			return this.fromDirectGeometry( geometry.__directGeometry );
15099  
15100		},
15101  
15102		fromDirectGeometry: function ( geometry ) {
15103  
15104			var positions = new Float32Array( geometry.vertices.length * 3 );
15105			this.addAttribute( 'position', new BufferAttribute( positions, 3 ).copyVector3sArray( geometry.vertices ) );
15106  
15107			if ( geometry.normals.length > 0 ) {
15108  
15109				var normals = new Float32Array( geometry.normals.length * 3 );
15110				this.addAttribute( 'normal', new BufferAttribute( normals, 3 ).copyVector3sArray( geometry.normals ) );
15111  
15112			}
15113  
15114			if ( geometry.colors.length > 0 ) {
15115  
15116				var colors = new Float32Array( geometry.colors.length * 3 );
15117				this.addAttribute( 'color', new BufferAttribute( colors, 3 ).copyColorsArray( geometry.colors ) );
15118  
15119			}
15120  
15121			if ( geometry.uvs.length > 0 ) {
15122  
15123				var uvs = new Float32Array( geometry.uvs.length * 2 );
15124				this.addAttribute( 'uv', new BufferAttribute( uvs, 2 ).copyVector2sArray( geometry.uvs ) );
15125  
15126			}
15127  
15128			if ( geometry.uvs2.length > 0 ) {
15129  
15130				var uvs2 = new Float32Array( geometry.uvs2.length * 2 );
15131				this.addAttribute( 'uv2', new BufferAttribute( uvs2, 2 ).copyVector2sArray( geometry.uvs2 ) );
15132  
15133			}
15134  
15135			// groups
15136  
15137			this.groups = geometry.groups;
15138  
15139			// morphs
15140  
15141			for ( var name in geometry.morphTargets ) {
15142  
15143				var array = [];
15144				var morphTargets = geometry.morphTargets[ name ];
15145  
15146				for ( var i = 0, l = morphTargets.length; i < l; i ++ ) {
15147  
15148					var morphTarget = morphTargets[ i ];
15149  
15150					var attribute = new Float32BufferAttribute( morphTarget.length * 3, 3 );
15151  
15152					array.push( attribute.copyVector3sArray( morphTarget ) );
15153  
15154				}
15155  
15156				this.morphAttributes[ name ] = array;
15157  
15158			}
15159  
15160			// skinning
15161  
15162			if ( geometry.skinIndices.length > 0 ) {
15163  
15164				var skinIndices = new Float32BufferAttribute( geometry.skinIndices.length * 4, 4 );
15165				this.addAttribute( 'skinIndex', skinIndices.copyVector4sArray( geometry.skinIndices ) );
15166  
15167			}
15168  
15169			if ( geometry.skinWeights.length > 0 ) {
15170  
15171				var skinWeights = new Float32BufferAttribute( geometry.skinWeights.length * 4, 4 );
15172				this.addAttribute( 'skinWeight', skinWeights.copyVector4sArray( geometry.skinWeights ) );
15173  
15174			}
15175  
15176			//
15177  
15178			if ( geometry.boundingSphere !== null ) {
15179  
15180				this.boundingSphere = geometry.boundingSphere.clone();
15181  
15182			}
15183  
15184			if ( geometry.boundingBox !== null ) {
15185  
15186				this.boundingBox = geometry.boundingBox.clone();
15187  
15188			}
15189  
15190			return this;
15191  
15192		},
15193  
15194		computeBoundingBox: function () {
15195  
15196			if ( this.boundingBox === null ) {
15197  
15198				this.boundingBox = new Box3();
15199  
15200			}
15201  
15202			var position = this.attributes.position;
15203  
15204			if ( position !== undefined ) {
15205  
15206				this.boundingBox.setFromBufferAttribute( position );
15207  
15208			} else {
15209  
15210				this.boundingBox.makeEmpty();
15211  
15212			}
15213  
15214			if ( isNaN( this.boundingBox.min.x ) || isNaN( this.boundingBox.min.y ) || isNaN( this.boundingBox.min.z ) ) {
15215  
15216				console.error( 'THREE.BufferGeometry.computeBoundingBox: Computed min/max have NaN values. The "position" attribute is likely to have NaN values.', this );
15217  
15218			}
15219  
15220		},
15221  
15222		computeBoundingSphere: function () {
15223  
15224			var box = new Box3();
15225			var vector = new Vector3();
15226  
15227			return function computeBoundingSphere() {
15228  
15229				if ( this.boundingSphere === null ) {
15230  
15231					this.boundingSphere = new Sphere();
15232  
15233				}
15234  
15235				var position = this.attributes.position;
15236  
15237				if ( position ) {
15238  
15239					var center = this.boundingSphere.center;
15240  
15241					box.setFromBufferAttribute( position );
15242					box.getCenter( center );
15243  
15244					// hoping to find a boundingSphere with a radius smaller than the
15245					// boundingSphere of the boundingBox: sqrt(3) smaller in the best case
15246  
15247					var maxRadiusSq = 0;
15248  
15249					for ( var i = 0, il = position.count; i < il; i ++ ) {
15250  
15251						vector.x = position.getX( i );
15252						vector.y = position.getY( i );
15253						vector.z = position.getZ( i );
15254						maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( vector ) );
15255  
15256					}
15257  
15258					this.boundingSphere.radius = Math.sqrt( maxRadiusSq );
15259  
15260					if ( isNaN( this.boundingSphere.radius ) ) {
15261  
15262						console.error( 'THREE.BufferGeometry.computeBoundingSphere(): Computed radius is NaN. The "position" attribute is likely to have NaN values.', this );
15263  
15264					}
15265  
15266				}
15267  
15268			};
15269  
15270		}(),
15271  
15272		computeFaceNormals: function () {
15273  
15274			// backwards compatibility
15275  
15276		},
15277  
15278		computeVertexNormals: function () {
15279  
15280			var index = this.index;
15281			var attributes = this.attributes;
15282			var groups = this.groups;
15283  
15284			if ( attributes.position ) {
15285  
15286				var positions = attributes.position.array;
15287  
15288				if ( attributes.normal === undefined ) {
15289  
15290					this.addAttribute( 'normal', new BufferAttribute( new Float32Array( positions.length ), 3 ) );
15291  
15292				} else {
15293  
15294					// reset existing normals to zero
15295  
15296					var array = attributes.normal.array;
15297  
15298					for ( var i = 0, il = array.length; i < il; i ++ ) {
15299  
15300						array[ i ] = 0;
15301  
15302					}
15303  
15304				}
15305  
15306				var normals = attributes.normal.array;
15307  
15308				var vA, vB, vC;
15309				var pA = new Vector3(), pB = new Vector3(), pC = new Vector3();
15310				var cb = new Vector3(), ab = new Vector3();
15311  
15312				// indexed elements
15313  
15314				if ( index ) {
15315  
15316					var indices = index.array;
15317  
15318					if ( groups.length === 0 ) {
15319  
15320						this.addGroup( 0, indices.length );
15321  
15322					}
15323  
15324					for ( var j = 0, jl = groups.length; j < jl; ++ j ) {
15325  
15326						var group = groups[ j ];
15327  
15328						var start = group.start;
15329						var count = group.count;
15330  
15331						for ( var i = start, il = start + count; i < il; i += 3 ) {
15332  
15333							vA = indices[ i + 0 ] * 3;
15334							vB = indices[ i + 1 ] * 3;
15335							vC = indices[ i + 2 ] * 3;
15336  
15337							pA.fromArray( positions, vA );
15338							pB.fromArray( positions, vB );
15339							pC.fromArray( positions, vC );
15340  
15341							cb.subVectors( pC, pB );
15342							ab.subVectors( pA, pB );
15343							cb.cross( ab );
15344  
15345							normals[ vA ] += cb.x;
15346							normals[ vA + 1 ] += cb.y;
15347							normals[ vA + 2 ] += cb.z;
15348  
15349							normals[ vB ] += cb.x;
15350							normals[ vB + 1 ] += cb.y;
15351							normals[ vB + 2 ] += cb.z;
15352  
15353							normals[ vC ] += cb.x;
15354							normals[ vC + 1 ] += cb.y;
15355							normals[ vC + 2 ] += cb.z;
15356  
15357						}
15358  
15359					}
15360  
15361				} else {
15362  
15363					// non-indexed elements (unconnected triangle soup)
15364  
15365					for ( var i = 0, il = positions.length; i < il; i += 9 ) {
15366  
15367						pA.fromArray( positions, i );
15368						pB.fromArray( positions, i + 3 );
15369						pC.fromArray( positions, i + 6 );
15370  
15371						cb.subVectors( pC, pB );
15372						ab.subVectors( pA, pB );
15373						cb.cross( ab );
15374  
15375						normals[ i ] = cb.x;
15376						normals[ i + 1 ] = cb.y;
15377						normals[ i + 2 ] = cb.z;
15378  
15379						normals[ i + 3 ] = cb.x;
15380						normals[ i + 4 ] = cb.y;
15381						normals[ i + 5 ] = cb.z;
15382  
15383						normals[ i + 6 ] = cb.x;
15384						normals[ i + 7 ] = cb.y;
15385						normals[ i + 8 ] = cb.z;
15386  
15387					}
15388  
15389				}
15390  
15391				this.normalizeNormals();
15392  
15393				attributes.normal.needsUpdate = true;
15394  
15395			}
15396  
15397		},
15398  
15399		merge: function ( geometry, offset ) {
15400  
15401			if ( ! ( geometry && geometry.isBufferGeometry ) ) {
15402  
15403				console.error( 'THREE.BufferGeometry.merge(): geometry not an instance of THREE.BufferGeometry.', geometry );
15404				return;
15405  
15406			}
15407  
15408			if ( offset === undefined ) {
15409  
15410				offset = 0;
15411  
15412				console.warn(
15413					'THREE.BufferGeometry.merge(): Overwriting original geometry, starting at offset=0. '
15414					+ 'Use BufferGeometryUtils.mergeBufferGeometries() for lossless merge.'
15415				);
15416  
15417			}
15418  
15419			var attributes = this.attributes;
15420  
15421			for ( var key in attributes ) {
15422  
15423				if ( geometry.attributes[ key ] === undefined ) continue;
15424  
15425				var attribute1 = attributes[ key ];
15426				var attributeArray1 = attribute1.array;
15427  
15428				var attribute2 = geometry.attributes[ key ];
15429				var attributeArray2 = attribute2.array;
15430  
15431				var attributeSize = attribute2.itemSize;
15432  
15433				for ( var i = 0, j = attributeSize * offset; i < attributeArray2.length; i ++, j ++ ) {
15434  
15435					attributeArray1[ j ] = attributeArray2[ i ];
15436  
15437				}
15438  
15439			}
15440  
15441			return this;
15442  
15443		},
15444  
15445		normalizeNormals: function () {
15446  
15447			var vector = new Vector3();
15448  
15449			return function normalizeNormals() {
15450  
15451				var normals = this.attributes.normal;
15452  
15453				for ( var i = 0, il = normals.count; i < il; i ++ ) {
15454  
15455					vector.x = normals.getX( i );
15456					vector.y = normals.getY( i );
15457					vector.z = normals.getZ( i );
15458  
15459					vector.normalize();
15460  
15461					normals.setXYZ( i, vector.x, vector.y, vector.z );
15462  
15463				}
15464  
15465			};
15466  
15467		}(),
15468  
15469		toNonIndexed: function () {
15470  
15471			if ( this.index === null ) {
15472  
15473				console.warn( 'THREE.BufferGeometry.toNonIndexed(): Geometry is already non-indexed.' );
15474				return this;
15475  
15476			}
15477  
15478			var geometry2 = new BufferGeometry();
15479  
15480			var indices = this.index.array;
15481			var attributes = this.attributes;
15482  
15483			for ( var name in attributes ) {
15484  
15485				var attribute = attributes[ name ];
15486  
15487				var array = attribute.array;
15488				var itemSize = attribute.itemSize;
15489  
15490				var array2 = new array.constructor( indices.length * itemSize );
15491  
15492				var index = 0, index2 = 0;
15493  
15494				for ( var i = 0, l = indices.length; i < l; i ++ ) {
15495  
15496					index = indices[ i ] * itemSize;
15497  
15498					for ( var j = 0; j < itemSize; j ++ ) {
15499  
15500						array2[ index2 ++ ] = array[ index ++ ];
15501  
15502					}
15503  
15504				}
15505  
15506				geometry2.addAttribute( name, new BufferAttribute( array2, itemSize ) );
15507  
15508			}
15509  
15510			var groups = this.groups;
15511  
15512			for ( var i = 0, l = groups.length; i < l; i ++ ) {
15513  
15514				var group = groups[ i ];
15515				geometry2.addGroup( group.start, group.count, group.materialIndex );
15516  
15517			}
15518  
15519			return geometry2;
15520  
15521		},
15522  
15523		toJSON: function () {
15524  
15525			var data = {
15526				metadata: {
15527					version: 4.5,
15528					type: 'BufferGeometry',
15529					generator: 'BufferGeometry.toJSON'
15530				}
15531			};
15532  
15533			// standard BufferGeometry serialization
15534  
15535			data.uuid = this.uuid;
15536			data.type = this.type;
15537			if ( this.name !== '' ) data.name = this.name;
15538			if ( Object.keys( this.userData ).length > 0 ) data.userData = this.userData;
15539  
15540			if ( this.parameters !== undefined ) {
15541  
15542				var parameters = this.parameters;
15543  
15544				for ( var key in parameters ) {
15545  
15546					if ( parameters[ key ] !== undefined ) data[ key ] = parameters[ key ];
15547  
15548				}
15549  
15550				return data;
15551  
15552			}
15553  
15554			data.data = { attributes: {} };
15555  
15556			var index = this.index;
15557  
15558			if ( index !== null ) {
15559  
15560				var array = Array.prototype.slice.call( index.array );
15561  
15562				data.data.index = {
15563					type: index.array.constructor.name,
15564					array: array
15565				};
15566  
15567			}
15568  
15569			var attributes = this.attributes;
15570  
15571			for ( var key in attributes ) {
15572  
15573				var attribute = attributes[ key ];
15574  
15575				var array = Array.prototype.slice.call( attribute.array );
15576  
15577				data.data.attributes[ key ] = {
15578					itemSize: attribute.itemSize,
15579					type: attribute.array.constructor.name,
15580					array: array,
15581					normalized: attribute.normalized
15582				};
15583  
15584			}
15585  
15586			var groups = this.groups;
15587  
15588			if ( groups.length > 0 ) {
15589  
15590				data.data.groups = JSON.parse( JSON.stringify( groups ) );
15591  
15592			}
15593  
15594			var boundingSphere = this.boundingSphere;
15595  
15596			if ( boundingSphere !== null ) {
15597  
15598				data.data.boundingSphere = {
15599					center: boundingSphere.center.toArray(),
15600					radius: boundingSphere.radius
15601				};
15602  
15603			}
15604  
15605			return data;
15606  
15607		},
15608  
15609		clone: function () {
15610  
15611			/*
15612			 // Handle primitives
15613  
15614			 var parameters = this.parameters;
15615  
15616			 if ( parameters !== undefined ) {
15617  
15618			 var values = [];
15619  
15620			 for ( var key in parameters ) {
15621  
15622			 values.push( parameters[ key ] );
15623  
15624			 }
15625  
15626			 var geometry = Object.create( this.constructor.prototype );
15627			 this.constructor.apply( geometry, values );
15628			 return geometry;
15629  
15630			 }
15631  
15632			 return new this.constructor().copy( this );
15633			 */
15634  
15635			return new BufferGeometry().copy( this );
15636  
15637		},
15638  
15639		copy: function ( source ) {
15640  
15641			var name, i, l;
15642  
15643			// reset
15644  
15645			this.index = null;
15646			this.attributes = {};
15647			this.morphAttributes = {};
15648			this.groups = [];
15649			this.boundingBox = null;
15650			this.boundingSphere = null;
15651  
15652			// name
15653  
15654			this.name = source.name;
15655  
15656			// index
15657  
15658			var index = source.index;
15659  
15660			if ( index !== null ) {
15661  
15662				this.setIndex( index.clone() );
15663  
15664			}
15665  
15666			// attributes
15667  
15668			var attributes = source.attributes;
15669  
15670			for ( name in attributes ) {
15671  
15672				var attribute = attributes[ name ];
15673				this.addAttribute( name, attribute.clone() );
15674  
15675			}
15676  
15677			// morph attributes
15678  
15679			var morphAttributes = source.morphAttributes;
15680  
15681			for ( name in morphAttributes ) {
15682  
15683				var array = [];
15684				var morphAttribute = morphAttributes[ name ]; // morphAttribute: array of Float32BufferAttributes
15685  
15686				for ( i = 0, l = morphAttribute.length; i < l; i ++ ) {
15687  
15688					array.push( morphAttribute[ i ].clone() );
15689  
15690				}
15691  
15692				this.morphAttributes[ name ] = array;
15693  
15694			}
15695  
15696			// groups
15697  
15698			var groups = source.groups;
15699  
15700			for ( i = 0, l = groups.length; i < l; i ++ ) {
15701  
15702				var group = groups[ i ];
15703				this.addGroup( group.start, group.count, group.materialIndex );
15704  
15705			}
15706  
15707			// bounding box
15708  
15709			var boundingBox = source.boundingBox;
15710  
15711			if ( boundingBox !== null ) {
15712  
15713				this.boundingBox = boundingBox.clone();
15714  
15715			}
15716  
15717			// bounding sphere
15718  
15719			var boundingSphere = source.boundingSphere;
15720  
15721			if ( boundingSphere !== null ) {
15722  
15723				this.boundingSphere = boundingSphere.clone();
15724  
15725			}
15726  
15727			// draw range
15728  
15729			this.drawRange.start = source.drawRange.start;
15730			this.drawRange.count = source.drawRange.count;
15731  
15732			// user data
15733  
15734			this.userData = source.userData;
15735  
15736			return this;
15737  
15738		},
15739  
15740		dispose: function () {
15741  
15742			this.dispatchEvent( { type: 'dispose' } );
15743  
15744		}
15745  
15746	} );
15747  
15748	/**
15749	 * @author mrdoob / http://mrdoob.com/
15750	 * @author Mugen87 / https://github.com/Mugen87
15751	 */
15752  
15753	// BoxGeometry
15754  
15755	function BoxGeometry( width, height, depth, widthSegments, heightSegments, depthSegments ) {
15756  
15757		Geometry.call( this );
15758  
15759		this.type = 'BoxGeometry';
15760  
15761		this.parameters = {
15762			width: width,
15763			height: height,
15764			depth: depth,
15765			widthSegments: widthSegments,
15766			heightSegments: heightSegments,
15767			depthSegments: depthSegments
15768		};
15769  
15770		this.fromBufferGeometry( new BoxBufferGeometry( width, height, depth, widthSegments, heightSegments, depthSegments ) );
15771		this.mergeVertices();
15772  
15773	}
15774  
15775	BoxGeometry.prototype = Object.create( Geometry.prototype );
15776	BoxGeometry.prototype.constructor = BoxGeometry;
15777  
15778	// BoxBufferGeometry
15779  
15780	function BoxBufferGeometry( width, height, depth, widthSegments, heightSegments, depthSegments ) {
15781  
15782		BufferGeometry.call( this );
15783  
15784		this.type = 'BoxBufferGeometry';
15785  
15786		this.parameters = {
15787			width: width,
15788			height: height,
15789			depth: depth,
15790			widthSegments: widthSegments,
15791			heightSegments: heightSegments,
15792			depthSegments: depthSegments
15793		};
15794  
15795		var scope = this;
15796  
15797		width = width || 1;
15798		height = height || 1;
15799		depth = depth || 1;
15800  
15801		// segments
15802  
15803		widthSegments = Math.floor( widthSegments ) || 1;
15804		heightSegments = Math.floor( heightSegments ) || 1;
15805		depthSegments = Math.floor( depthSegments ) || 1;
15806  
15807		// buffers
15808  
15809		var indices = [];
15810		var vertices = [];
15811		var normals = [];
15812		var uvs = [];
15813  
15814		// helper variables
15815  
15816		var numberOfVertices = 0;
15817		var groupStart = 0;
15818  
15819		// build each side of the box geometry
15820  
15821		buildPlane( 'z', 'y', 'x', - 1, - 1, depth, height, width, depthSegments, heightSegments, 0 ); // px
15822		buildPlane( 'z', 'y', 'x', 1, - 1, depth, height, - width, depthSegments, heightSegments, 1 ); // nx
15823		buildPlane( 'x', 'z', 'y', 1, 1, width, depth, height, widthSegments, depthSegments, 2 ); // py
15824		buildPlane( 'x', 'z', 'y', 1, - 1, width, depth, - height, widthSegments, depthSegments, 3 ); // ny
15825		buildPlane( 'x', 'y', 'z', 1, - 1, width, height, depth, widthSegments, heightSegments, 4 ); // pz
15826		buildPlane( 'x', 'y', 'z', - 1, - 1, width, height, - depth, widthSegments, heightSegments, 5 ); // nz
15827  
15828		// build geometry
15829  
15830		this.setIndex( indices );
15831		this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
15832		this.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
15833		this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
15834  
15835		function buildPlane( u, v, w, udir, vdir, width, height, depth, gridX, gridY, materialIndex ) {
15836  
15837			var segmentWidth = width / gridX;
15838			var segmentHeight = height / gridY;
15839  
15840			var widthHalf = width / 2;
15841			var heightHalf = height / 2;
15842			var depthHalf = depth / 2;
15843  
15844			var gridX1 = gridX + 1;
15845			var gridY1 = gridY + 1;
15846  
15847			var vertexCounter = 0;
15848			var groupCount = 0;
15849  
15850			var ix, iy;
15851  
15852			var vector = new Vector3();
15853  
15854			// generate vertices, normals and uvs
15855  
15856			for ( iy = 0; iy < gridY1; iy ++ ) {
15857  
15858				var y = iy * segmentHeight - heightHalf;
15859  
15860				for ( ix = 0; ix < gridX1; ix ++ ) {
15861  
15862					var x = ix * segmentWidth - widthHalf;
15863  
15864					// set values to correct vector component
15865  
15866					vector[ u ] = x * udir;
15867					vector[ v ] = y * vdir;
15868					vector[ w ] = depthHalf;
15869  
15870					// now apply vector to vertex buffer
15871  
15872					vertices.push( vector.x, vector.y, vector.z );
15873  
15874					// set values to correct vector component
15875  
15876					vector[ u ] = 0;
15877					vector[ v ] = 0;
15878					vector[ w ] = depth > 0 ? 1 : - 1;
15879  
15880					// now apply vector to normal buffer
15881  
15882					normals.push( vector.x, vector.y, vector.z );
15883  
15884					// uvs
15885  
15886					uvs.push( ix / gridX );
15887					uvs.push( 1 - ( iy / gridY ) );
15888  
15889					// counters
15890  
15891					vertexCounter += 1;
15892  
15893				}
15894  
15895			}
15896  
15897			// indices
15898  
15899			// 1. you need three indices to draw a single face
15900			// 2. a single segment consists of two faces
15901			// 3. so we need to generate six (2*3) indices per segment
15902  
15903			for ( iy = 0; iy < gridY; iy ++ ) {
15904  
15905				for ( ix = 0; ix < gridX; ix ++ ) {
15906  
15907					var a = numberOfVertices + ix + gridX1 * iy;
15908					var b = numberOfVertices + ix + gridX1 * ( iy + 1 );
15909					var c = numberOfVertices + ( ix + 1 ) + gridX1 * ( iy + 1 );
15910					var d = numberOfVertices + ( ix + 1 ) + gridX1 * iy;
15911  
15912					// faces
15913  
15914					indices.push( a, b, d );
15915					indices.push( b, c, d );
15916  
15917					// increase counter
15918  
15919					groupCount += 6;
15920  
15921				}
15922  
15923			}
15924  
15925			// add a group to the geometry. this will ensure multi material support
15926  
15927			scope.addGroup( groupStart, groupCount, materialIndex );
15928  
15929			// calculate new start value for groups
15930  
15931			groupStart += groupCount;
15932  
15933			// update total number of vertices
15934  
15935			numberOfVertices += vertexCounter;
15936  
15937		}
15938  
15939	}
15940  
15941	BoxBufferGeometry.prototype = Object.create( BufferGeometry.prototype );
15942	BoxBufferGeometry.prototype.constructor = BoxBufferGeometry;
15943  
15944	/**
15945	 * @author mrdoob / http://mrdoob.com/
15946	 * @author Mugen87 / https://github.com/Mugen87
15947	 */
15948  
15949	// PlaneGeometry
15950  
15951	function PlaneGeometry( width, height, widthSegments, heightSegments ) {
15952  
15953		Geometry.call( this );
15954  
15955		this.type = 'PlaneGeometry';
15956  
15957		this.parameters = {
15958			width: width,
15959			height: height,
15960			widthSegments: widthSegments,
15961			heightSegments: heightSegments
15962		};
15963  
15964		this.fromBufferGeometry( new PlaneBufferGeometry( width, height, widthSegments, heightSegments ) );
15965		this.mergeVertices();
15966  
15967	}
15968  
15969	PlaneGeometry.prototype = Object.create( Geometry.prototype );
15970	PlaneGeometry.prototype.constructor = PlaneGeometry;
15971  
15972	// PlaneBufferGeometry
15973  
15974	function PlaneBufferGeometry( width, height, widthSegments, heightSegments ) {
15975  
15976		BufferGeometry.call( this );
15977  
15978		this.type = 'PlaneBufferGeometry';
15979  
15980		this.parameters = {
15981			width: width,
15982			height: height,
15983			widthSegments: widthSegments,
15984			heightSegments: heightSegments
15985		};
15986  
15987		width = width || 1;
15988		height = height || 1;
15989  
15990		var width_half = width / 2;
15991		var height_half = height / 2;
15992  
15993		var gridX = Math.floor( widthSegments ) || 1;
15994		var gridY = Math.floor( heightSegments ) || 1;
15995  
15996		var gridX1 = gridX + 1;
15997		var gridY1 = gridY + 1;
15998  
15999		var segment_width = width / gridX;
16000		var segment_height = height / gridY;
16001  
16002		var ix, iy;
16003  
16004		// buffers
16005  
16006		var indices = [];
16007		var vertices = [];
16008		var normals = [];
16009		var uvs = [];
16010  
16011		// generate vertices, normals and uvs
16012  
16013		for ( iy = 0; iy < gridY1; iy ++ ) {
16014  
16015			var y = iy * segment_height - height_half;
16016  
16017			for ( ix = 0; ix < gridX1; ix ++ ) {
16018  
16019				var x = ix * segment_width - width_half;
16020  
16021				vertices.push( x, - y, 0 );
16022  
16023				normals.push( 0, 0, 1 );
16024  
16025				uvs.push( ix / gridX );
16026				uvs.push( 1 - ( iy / gridY ) );
16027  
16028			}
16029  
16030		}
16031  
16032		// indices
16033  
16034		for ( iy = 0; iy < gridY; iy ++ ) {
16035  
16036			for ( ix = 0; ix < gridX; ix ++ ) {
16037  
16038				var a = ix + gridX1 * iy;
16039				var b = ix + gridX1 * ( iy + 1 );
16040				var c = ( ix + 1 ) + gridX1 * ( iy + 1 );
16041				var d = ( ix + 1 ) + gridX1 * iy;
16042  
16043				// faces
16044  
16045				indices.push( a, b, d );
16046				indices.push( b, c, d );
16047  
16048			}
16049  
16050		}
16051  
16052		// build geometry
16053  
16054		this.setIndex( indices );
16055		this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
16056		this.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
16057		this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
16058  
16059	}
16060  
16061	PlaneBufferGeometry.prototype = Object.create( BufferGeometry.prototype );
16062	PlaneBufferGeometry.prototype.constructor = PlaneBufferGeometry;
16063  
16064	/**
16065	 * @author mrdoob / http://mrdoob.com/
16066	 * @author alteredq / http://alteredqualia.com/
16067	 */
16068  
16069	var materialId = 0;
16070  
16071	function Material() {
16072  
16073		Object.defineProperty( this, 'id', { value: materialId ++ } );
16074  
16075		this.uuid = _Math.generateUUID();
16076  
16077		this.name = '';
16078		this.type = 'Material';
16079  
16080		this.fog = true;
16081		this.lights = true;
16082  
16083		this.blending = NormalBlending;
16084		this.side = FrontSide;
16085		this.flatShading = false;
16086		this.vertexColors = NoColors; // THREE.NoColors, THREE.VertexColors, THREE.FaceColors
16087  
16088		this.opacity = 1;
16089		this.transparent = false;
16090  
16091		this.blendSrc = SrcAlphaFactor;
16092		this.blendDst = OneMinusSrcAlphaFactor;
16093		this.blendEquation = AddEquation;
16094		this.blendSrcAlpha = null;
16095		this.blendDstAlpha = null;
16096		this.blendEquationAlpha = null;
16097  
16098		this.depthFunc = LessEqualDepth;
16099		this.depthTest = true;
16100		this.depthWrite = true;
16101  
16102		this.clippingPlanes = null;
16103		this.clipIntersection = false;
16104		this.clipShadows = false;
16105  
16106		this.shadowSide = null;
16107  
16108		this.colorWrite = true;
16109  
16110		this.precision = null; // override the renderer's default precision for this material
16111  
16112		this.polygonOffset = false;
16113		this.polygonOffsetFactor = 0;
16114		this.polygonOffsetUnits = 0;
16115  
16116		this.dithering = false;
16117  
16118		this.alphaTest = 0;
16119		this.premultipliedAlpha = false;
16120  
16121		this.overdraw = 0; // Overdrawn pixels (typically between 0 and 1) for fixing antialiasing gaps in CanvasRenderer
16122  
16123		this.visible = true;
16124  
16125		this.userData = {};
16126  
16127		this.needsUpdate = true;
16128  
16129	}
16130  
16131	Material.prototype = Object.assign( Object.create( EventDispatcher.prototype ), {
16132  
16133		constructor: Material,
16134  
16135		isMaterial: true,
16136  
16137		onBeforeCompile: function () {},
16138  
16139		setValues: function ( values ) {
16140  
16141			if ( values === undefined ) return;
16142  
16143			for ( var key in values ) {
16144  
16145				var newValue = values[ key ];
16146  
16147				if ( newValue === undefined ) {
16148  
16149					console.warn( "THREE.Material: '" + key + "' parameter is undefined." );
16150					continue;
16151  
16152				}
16153  
16154				// for backward compatability if shading is set in the constructor
16155				if ( key === 'shading' ) {
16156  
16157					console.warn( 'THREE.' + this.type + ': .shading has been removed. Use the boolean .flatShading instead.' );
16158					this.flatShading = ( newValue === FlatShading ) ? true : false;
16159					continue;
16160  
16161				}
16162  
16163				var currentValue = this[ key ];
16164  
16165				if ( currentValue === undefined ) {
16166  
16167					console.warn( "THREE." + this.type + ": '" + key + "' is not a property of this material." );
16168					continue;
16169  
16170				}
16171  
16172				if ( currentValue && currentValue.isColor ) {
16173  
16174					currentValue.set( newValue );
16175  
16176				} else if ( ( currentValue && currentValue.isVector3 ) && ( newValue && newValue.isVector3 ) ) {
16177  
16178					currentValue.copy( newValue );
16179  
16180				} else if ( key === 'overdraw' ) {
16181  
16182					// ensure overdraw is backwards-compatible with legacy boolean type
16183					this[ key ] = Number( newValue );
16184  
16185				} else {
16186  
16187					this[ key ] = newValue;
16188  
16189				}
16190  
16191			}
16192  
16193		},
16194  
16195		toJSON: function ( meta ) {
16196  
16197			var isRoot = ( meta === undefined || typeof meta === 'string' );
16198  
16199			if ( isRoot ) {
16200  
16201				meta = {
16202					textures: {},
16203					images: {}
16204				};
16205  
16206			}
16207  
16208			var data = {
16209				metadata: {
16210					version: 4.5,
16211					type: 'Material',
16212					generator: 'Material.toJSON'
16213				}
16214			};
16215  
16216			// standard Material serialization
16217			data.uuid = this.uuid;
16218			data.type = this.type;
16219  
16220			if ( this.name !== '' ) data.name = this.name;
16221  
16222			if ( this.color && this.color.isColor ) data.color = this.color.getHex();
16223  
16224			if ( this.roughness !== undefined ) data.roughness = this.roughness;
16225			if ( this.metalness !== undefined ) data.metalness = this.metalness;
16226  
16227			if ( this.emissive && this.emissive.isColor ) data.emissive = this.emissive.getHex();
16228			if ( this.emissiveIntensity !== 1 ) data.emissiveIntensity = this.emissiveIntensity;
16229  
16230			if ( this.specular && this.specular.isColor ) data.specular = this.specular.getHex();
16231			if ( this.shininess !== undefined ) data.shininess = this.shininess;
16232			if ( this.clearCoat !== undefined ) data.clearCoat = this.clearCoat;
16233			if ( this.clearCoatRoughness !== undefined ) data.clearCoatRoughness = this.clearCoatRoughness;
16234  
16235			if ( this.map && this.map.isTexture ) data.map = this.map.toJSON( meta ).uuid;
16236			if ( this.alphaMap && this.alphaMap.isTexture ) data.alphaMap = this.alphaMap.toJSON( meta ).uuid;
16237			if ( this.lightMap && this.lightMap.isTexture ) data.lightMap = this.lightMap.toJSON( meta ).uuid;
16238  
16239			if ( this.aoMap && this.aoMap.isTexture ) {
16240  
16241				data.aoMap = this.aoMap.toJSON( meta ).uuid;
16242				data.aoMapIntensity = this.aoMapIntensity;
16243  
16244			}
16245  
16246			if ( this.bumpMap && this.bumpMap.isTexture ) {
16247  
16248				data.bumpMap = this.bumpMap.toJSON( meta ).uuid;
16249				data.bumpScale = this.bumpScale;
16250  
16251			}
16252  
16253			if ( this.normalMap && this.normalMap.isTexture ) {
16254  
16255				data.normalMap = this.normalMap.toJSON( meta ).uuid;
16256				data.normalScale = this.normalScale.toArray();
16257  
16258			}
16259  
16260			if ( this.displacementMap && this.displacementMap.isTexture ) {
16261  
16262				data.displacementMap = this.displacementMap.toJSON( meta ).uuid;
16263				data.displacementScale = this.displacementScale;
16264				data.displacementBias = this.displacementBias;
16265  
16266			}
16267  
16268			if ( this.roughnessMap && this.roughnessMap.isTexture ) data.roughnessMap = this.roughnessMap.toJSON( meta ).uuid;
16269			if ( this.metalnessMap && this.metalnessMap.isTexture ) data.metalnessMap = this.metalnessMap.toJSON( meta ).uuid;
16270  
16271			if ( this.emissiveMap && this.emissiveMap.isTexture ) data.emissiveMap = this.emissiveMap.toJSON( meta ).uuid;
16272			if ( this.specularMap && this.specularMap.isTexture ) data.specularMap = this.specularMap.toJSON( meta ).uuid;
16273  
16274			if ( this.envMap && this.envMap.isTexture ) {
16275  
16276				data.envMap = this.envMap.toJSON( meta ).uuid;
16277				data.reflectivity = this.reflectivity; // Scale behind envMap
16278  
16279			}
16280  
16281			if ( this.gradientMap && this.gradientMap.isTexture ) {
16282  
16283				data.gradientMap = this.gradientMap.toJSON( meta ).uuid;
16284  
16285			}
16286  
16287			if ( this.size !== undefined ) data.size = this.size;
16288			if ( this.sizeAttenuation !== undefined ) data.sizeAttenuation = this.sizeAttenuation;
16289  
16290			if ( this.blending !== NormalBlending ) data.blending = this.blending;
16291			if ( this.flatShading === true ) data.flatShading = this.flatShading;
16292			if ( this.side !== FrontSide ) data.side = this.side;
16293			if ( this.vertexColors !== NoColors ) data.vertexColors = this.vertexColors;
16294  
16295			if ( this.opacity < 1 ) data.opacity = this.opacity;
16296			if ( this.transparent === true ) data.transparent = this.transparent;
16297  
16298			data.depthFunc = this.depthFunc;
16299			data.depthTest = this.depthTest;
16300			data.depthWrite = this.depthWrite;
16301  
16302			// rotation (SpriteMaterial)
16303			if ( this.rotation !== 0 ) data.rotation = this.rotation;
16304  
16305			if ( this.linewidth !== 1 ) data.linewidth = this.linewidth;
16306			if ( this.dashSize !== undefined ) data.dashSize = this.dashSize;
16307			if ( this.gapSize !== undefined ) data.gapSize = this.gapSize;
16308			if ( this.scale !== undefined ) data.scale = this.scale;
16309  
16310			if ( this.dithering === true ) data.dithering = true;
16311  
16312			if ( this.alphaTest > 0 ) data.alphaTest = this.alphaTest;
16313			if ( this.premultipliedAlpha === true ) data.premultipliedAlpha = this.premultipliedAlpha;
16314  
16315			if ( this.wireframe === true ) data.wireframe = this.wireframe;
16316			if ( this.wireframeLinewidth > 1 ) data.wireframeLinewidth = this.wireframeLinewidth;
16317			if ( this.wireframeLinecap !== 'round' ) data.wireframeLinecap = this.wireframeLinecap;
16318			if ( this.wireframeLinejoin !== 'round' ) data.wireframeLinejoin = this.wireframeLinejoin;
16319  
16320			if ( this.morphTargets === true ) data.morphTargets = true;
16321			if ( this.skinning === true ) data.skinning = true;
16322  
16323			if ( this.visible === false ) data.visible = false;
16324			if ( JSON.stringify( this.userData ) !== '{}' ) data.userData = this.userData;
16325  
16326			// TODO: Copied from Object3D.toJSON
16327  
16328			function extractFromCache( cache ) {
16329  
16330				var values = [];
16331  
16332				for ( var key in cache ) {
16333  
16334					var data = cache[ key ];
16335					delete data.metadata;
16336					values.push( data );
16337  
16338				}
16339  
16340				return values;
16341  
16342			}
16343  
16344			if ( isRoot ) {
16345  
16346				var textures = extractFromCache( meta.textures );
16347				var images = extractFromCache( meta.images );
16348  
16349				if ( textures.length > 0 ) data.textures = textures;
16350				if ( images.length > 0 ) data.images = images;
16351  
16352			}
16353  
16354			return data;
16355  
16356		},
16357  
16358		clone: function () {
16359  
16360			return new this.constructor().copy( this );
16361  
16362		},
16363  
16364		copy: function ( source ) {
16365  
16366			this.name = source.name;
16367  
16368			this.fog = source.fog;
16369			this.lights = source.lights;
16370  
16371			this.blending = source.blending;
16372			this.side = source.side;
16373			this.flatShading = source.flatShading;
16374			this.vertexColors = source.vertexColors;
16375  
16376			this.opacity = source.opacity;
16377			this.transparent = source.transparent;
16378  
16379			this.blendSrc = source.blendSrc;
16380			this.blendDst = source.blendDst;
16381			this.blendEquation = source.blendEquation;
16382			this.blendSrcAlpha = source.blendSrcAlpha;
16383			this.blendDstAlpha = source.blendDstAlpha;
16384			this.blendEquationAlpha = source.blendEquationAlpha;
16385  
16386			this.depthFunc = source.depthFunc;
16387			this.depthTest = source.depthTest;
16388			this.depthWrite = source.depthWrite;
16389  
16390			this.colorWrite = source.colorWrite;
16391  
16392			this.precision = source.precision;
16393  
16394			this.polygonOffset = source.polygonOffset;
16395			this.polygonOffsetFactor = source.polygonOffsetFactor;
16396			this.polygonOffsetUnits = source.polygonOffsetUnits;
16397  
16398			this.dithering = source.dithering;
16399  
16400			this.alphaTest = source.alphaTest;
16401			this.premultipliedAlpha = source.premultipliedAlpha;
16402  
16403			this.overdraw = source.overdraw;
16404  
16405			this.visible = source.visible;
16406			this.userData = JSON.parse( JSON.stringify( source.userData ) );
16407  
16408			this.clipShadows = source.clipShadows;
16409			this.clipIntersection = source.clipIntersection;
16410  
16411			var srcPlanes = source.clippingPlanes,
16412				dstPlanes = null;
16413  
16414			if ( srcPlanes !== null ) {
16415  
16416				var n = srcPlanes.length;
16417				dstPlanes = new Array( n );
16418  
16419				for ( var i = 0; i !== n; ++ i )
16420					dstPlanes[ i ] = srcPlanes[ i ].clone();
16421  
16422			}
16423  
16424			this.clippingPlanes = dstPlanes;
16425  
16426			this.shadowSide = source.shadowSide;
16427  
16428			return this;
16429  
16430		},
16431  
16432		dispose: function () {
16433  
16434			this.dispatchEvent( { type: 'dispose' } );
16435  
16436		}
16437  
16438	} );
16439  
16440	/**
16441	 * @author mrdoob / http://mrdoob.com/
16442	 * @author alteredq / http://alteredqualia.com/
16443	 *
16444	 * parameters = {
16445	 *  color: <hex>,
16446	 *  opacity: <float>,
16447	 *  map: new THREE.Texture( <Image> ),
16448	 *
16449	 *  lightMap: new THREE.Texture( <Image> ),
16450	 *  lightMapIntensity: <float>
16451	 *
16452	 *  aoMap: new THREE.Texture( <Image> ),
16453	 *  aoMapIntensity: <float>
16454	 *
16455	 *  specularMap: new THREE.Texture( <Image> ),
16456	 *
16457	 *  alphaMap: new THREE.Texture( <Image> ),
16458	 *
16459	 *  envMap: new THREE.CubeTexture( [posx, negx, posy, negy, posz, negz] ),
16460	 *  combine: THREE.Multiply,
16461	 *  reflectivity: <float>,
16462	 *  refractionRatio: <float>,
16463	 *
16464	 *  depthTest: <bool>,
16465	 *  depthWrite: <bool>,
16466	 *
16467	 *  wireframe: <boolean>,
16468	 *  wireframeLinewidth: <float>,
16469	 *
16470	 *  skinning: <bool>,
16471	 *  morphTargets: <bool>
16472	 * }
16473	 */
16474  
16475	function MeshBasicMaterial( parameters ) {
16476  
16477		Material.call( this );
16478  
16479		this.type = 'MeshBasicMaterial';
16480  
16481		this.color = new Color( 0xffffff ); // emissive
16482  
16483		this.map = null;
16484  
16485		this.lightMap = null;
16486		this.lightMapIntensity = 1.0;
16487  
16488		this.aoMap = null;
16489		this.aoMapIntensity = 1.0;
16490  
16491		this.specularMap = null;
16492  
16493		this.alphaMap = null;
16494  
16495		this.envMap = null;
16496		this.combine = MultiplyOperation;
16497		this.reflectivity = 1;
16498		this.refractionRatio = 0.98;
16499  
16500		this.wireframe = false;
16501		this.wireframeLinewidth = 1;
16502		this.wireframeLinecap = 'round';
16503		this.wireframeLinejoin = 'round';
16504  
16505		this.skinning = false;
16506		this.morphTargets = false;
16507  
16508		this.lights = false;
16509  
16510		this.setValues( parameters );
16511  
16512	}
16513  
16514	MeshBasicMaterial.prototype = Object.create( Material.prototype );
16515	MeshBasicMaterial.prototype.constructor = MeshBasicMaterial;
16516  
16517	MeshBasicMaterial.prototype.isMeshBasicMaterial = true;
16518  
16519	MeshBasicMaterial.prototype.copy = function ( source ) {
16520  
16521		Material.prototype.copy.call( this, source );
16522  
16523		this.color.copy( source.color );
16524  
16525		this.map = source.map;
16526  
16527		this.lightMap = source.lightMap;
16528		this.lightMapIntensity = source.lightMapIntensity;
16529  
16530		this.aoMap = source.aoMap;
16531		this.aoMapIntensity = source.aoMapIntensity;
16532  
16533		this.specularMap = source.specularMap;
16534  
16535		this.alphaMap = source.alphaMap;
16536  
16537		this.envMap = source.envMap;
16538		this.combine = source.combine;
16539		this.reflectivity = source.reflectivity;
16540		this.refractionRatio = source.refractionRatio;
16541  
16542		this.wireframe = source.wireframe;
16543		this.wireframeLinewidth = source.wireframeLinewidth;
16544		this.wireframeLinecap = source.wireframeLinecap;
16545		this.wireframeLinejoin = source.wireframeLinejoin;
16546  
16547		this.skinning = source.skinning;
16548		this.morphTargets = source.morphTargets;
16549  
16550		return this;
16551  
16552	};
16553  
16554	/**
16555	 * @author alteredq / http://alteredqualia.com/
16556	 *
16557	 * parameters = {
16558	 *  defines: { "label" : "value" },
16559	 *  uniforms: { "parameter1": { value: 1.0 }, "parameter2": { value2: 2 } },
16560	 *
16561	 *  fragmentShader: <string>,
16562	 *  vertexShader: <string>,
16563	 *
16564	 *  wireframe: <boolean>,
16565	 *  wireframeLinewidth: <float>,
16566	 *
16567	 *  lights: <bool>,
16568	 *
16569	 *  skinning: <bool>,
16570	 *  morphTargets: <bool>,
16571	 *  morphNormals: <bool>
16572	 * }
16573	 */
16574  
16575	function ShaderMaterial( parameters ) {
16576  
16577		Material.call( this );
16578  
16579		this.type = 'ShaderMaterial';
16580  
16581		this.defines = {};
16582		this.uniforms = {};
16583  
16584		this.vertexShader = 'void main() {\n\tgl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n}';
16585		this.fragmentShader = 'void main() {\n\tgl_FragColor = vec4( 1.0, 0.0, 0.0, 1.0 );\n}';
16586  
16587		this.linewidth = 1;
16588  
16589		this.wireframe = false;
16590		this.wireframeLinewidth = 1;
16591  
16592		this.fog = false; // set to use scene fog
16593		this.lights = false; // set to use scene lights
16594		this.clipping = false; // set to use user-defined clipping planes
16595  
16596		this.skinning = false; // set to use skinning attribute streams
16597		this.morphTargets = false; // set to use morph targets
16598		this.morphNormals = false; // set to use morph normals
16599  
16600		this.extensions = {
16601			derivatives: false, // set to use derivatives
16602			fragDepth: false, // set to use fragment depth values
16603			drawBuffers: false, // set to use draw buffers
16604			shaderTextureLOD: false // set to use shader texture LOD
16605		};
16606  
16607		// When rendered geometry doesn't include these attributes but the material does,
16608		// use these default values in WebGL. This avoids errors when buffer data is missing.
16609		this.defaultAttributeValues = {
16610			'color': [ 1, 1, 1 ],
16611			'uv': [ 0, 0 ],
16612			'uv2': [ 0, 0 ]
16613		};
16614  
16615		this.index0AttributeName = undefined;
16616		this.uniformsNeedUpdate = false;
16617  
16618		if ( parameters !== undefined ) {
16619  
16620			if ( parameters.attributes !== undefined ) {
16621  
16622				console.error( 'THREE.ShaderMaterial: attributes should now be defined in THREE.BufferGeometry instead.' );
16623  
16624			}
16625  
16626			this.setValues( parameters );
16627  
16628		}
16629  
16630	}
16631  
16632	ShaderMaterial.prototype = Object.create( Material.prototype );
16633	ShaderMaterial.prototype.constructor = ShaderMaterial;
16634  
16635	ShaderMaterial.prototype.isShaderMaterial = true;
16636  
16637	ShaderMaterial.prototype.copy = function ( source ) {
16638  
16639		Material.prototype.copy.call( this, source );
16640  
16641		this.fragmentShader = source.fragmentShader;
16642		this.vertexShader = source.vertexShader;
16643  
16644		this.uniforms = UniformsUtils.clone( source.uniforms );
16645  
16646		this.defines = Object.assign( {}, source.defines );
16647  
16648		this.wireframe = source.wireframe;
16649		this.wireframeLinewidth = source.wireframeLinewidth;
16650  
16651		this.lights = source.lights;
16652		this.clipping = source.clipping;
16653  
16654		this.skinning = source.skinning;
16655  
16656		this.morphTargets = source.morphTargets;
16657		this.morphNormals = source.morphNormals;
16658  
16659		this.extensions = source.extensions;
16660  
16661		return this;
16662  
16663	};
16664  
16665	ShaderMaterial.prototype.toJSON = function ( meta ) {
16666  
16667		var data = Material.prototype.toJSON.call( this, meta );
16668  
16669		data.uniforms = this.uniforms;
16670		data.vertexShader = this.vertexShader;
16671		data.fragmentShader = this.fragmentShader;
16672  
16673		return data;
16674  
16675	};
16676  
16677	/**
16678	 * @author bhouston / http://clara.io
16679	 */
16680  
16681	function Ray( origin, direction ) {
16682  
16683		this.origin = ( origin !== undefined ) ? origin : new Vector3();
16684		this.direction = ( direction !== undefined ) ? direction : new Vector3();
16685  
16686	}
16687  
16688	Object.assign( Ray.prototype, {
16689  
16690		set: function ( origin, direction ) {
16691  
16692			this.origin.copy( origin );
16693			this.direction.copy( direction );
16694  
16695			return this;
16696  
16697		},
16698  
16699		clone: function () {
16700  
16701			return new this.constructor().copy( this );
16702  
16703		},
16704  
16705		copy: function ( ray ) {
16706  
16707			this.origin.copy( ray.origin );
16708			this.direction.copy( ray.direction );
16709  
16710			return this;
16711  
16712		},
16713  
16714		at: function ( t, target ) {
16715  
16716			if ( target === undefined ) {
16717  
16718				console.warn( 'THREE.Ray: .at() target is now required' );
16719				target = new Vector3();
16720  
16721			}
16722  
16723			return target.copy( this.direction ).multiplyScalar( t ).add( this.origin );
16724  
16725		},
16726  
16727		lookAt: function ( v ) {
16728  
16729			this.direction.copy( v ).sub( this.origin ).normalize();
16730  
16731			return this;
16732  
16733		},
16734  
16735		recast: function () {
16736  
16737			var v1 = new Vector3();
16738  
16739			return function recast( t ) {
16740  
16741				this.origin.copy( this.at( t, v1 ) );
16742  
16743				return this;
16744  
16745			};
16746  
16747		}(),
16748  
16749		closestPointToPoint: function ( point, target ) {
16750  
16751			if ( target === undefined ) {
16752  
16753				console.warn( 'THREE.Ray: .closestPointToPoint() target is now required' );
16754				target = new Vector3();
16755  
16756			}
16757  
16758			target.subVectors( point, this.origin );
16759  
16760			var directionDistance = target.dot( this.direction );
16761  
16762			if ( directionDistance < 0 ) {
16763  
16764				return target.copy( this.origin );
16765  
16766			}
16767  
16768			return target.copy( this.direction ).multiplyScalar( directionDistance ).add( this.origin );
16769  
16770		},
16771  
16772		distanceToPoint: function ( point ) {
16773  
16774			return Math.sqrt( this.distanceSqToPoint( point ) );
16775  
16776		},
16777  
16778		distanceSqToPoint: function () {
16779  
16780			var v1 = new Vector3();
16781  
16782			return function distanceSqToPoint( point ) {
16783  
16784				var directionDistance = v1.subVectors( point, this.origin ).dot( this.direction );
16785  
16786				// point behind the ray
16787  
16788				if ( directionDistance < 0 ) {
16789  
16790					return this.origin.distanceToSquared( point );
16791  
16792				}
16793  
16794				v1.copy( this.direction ).multiplyScalar( directionDistance ).add( this.origin );
16795  
16796				return v1.distanceToSquared( point );
16797  
16798			};
16799  
16800		}(),
16801  
16802		distanceSqToSegment: function () {
16803  
16804			var segCenter = new Vector3();
16805			var segDir = new Vector3();
16806			var diff = new Vector3();
16807  
16808			return function distanceSqToSegment( v0, v1, optionalPointOnRay, optionalPointOnSegment ) {
16809  
16810				// from http://www.geometrictools.com/GTEngine/Include/Mathematics/GteDistRaySegment.h
16811				// It returns the min distance between the ray and the segment
16812				// defined by v0 and v1
16813				// It can also set two optional targets :
16814				// - The closest point on the ray
16815				// - The closest point on the segment
16816  
16817				segCenter.copy( v0 ).add( v1 ).multiplyScalar( 0.5 );
16818				segDir.copy( v1 ).sub( v0 ).normalize();
16819				diff.copy( this.origin ).sub( segCenter );
16820  
16821				var segExtent = v0.distanceTo( v1 ) * 0.5;
16822				var a01 = - this.direction.dot( segDir );
16823				var b0 = diff.dot( this.direction );
16824				var b1 = - diff.dot( segDir );
16825				var c = diff.lengthSq();
16826				var det = Math.abs( 1 - a01 * a01 );
16827				var s0, s1, sqrDist, extDet;
16828  
16829				if ( det > 0 ) {
16830  
16831					// The ray and segment are not parallel.
16832  
16833					s0 = a01 * b1 - b0;
16834					s1 = a01 * b0 - b1;
16835					extDet = segExtent * det;
16836  
16837					if ( s0 >= 0 ) {
16838  
16839						if ( s1 >= - extDet ) {
16840  
16841							if ( s1 <= extDet ) {
16842  
16843								// region 0
16844								// Minimum at interior points of ray and segment.
16845  
16846								var invDet = 1 / det;
16847								s0 *= invDet;
16848								s1 *= invDet;
16849								sqrDist = s0 * ( s0 + a01 * s1 + 2 * b0 ) + s1 * ( a01 * s0 + s1 + 2 * b1 ) + c;
16850  
16851							} else {
16852  
16853								// region 1
16854  
16855								s1 = segExtent;
16856								s0 = Math.max( 0, - ( a01 * s1 + b0 ) );
16857								sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;
16858  
16859							}
16860  
16861						} else {
16862  
16863							// region 5
16864  
16865							s1 = - segExtent;
16866							s0 = Math.max( 0, - ( a01 * s1 + b0 ) );
16867							sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;
16868  
16869						}
16870  
16871					} else {
16872  
16873						if ( s1 <= - extDet ) {
16874  
16875							// region 4
16876  
16877							s0 = Math.max( 0, - ( - a01 * segExtent + b0 ) );
16878							s1 = ( s0 > 0 ) ? - segExtent : Math.min( Math.max( - segExtent, - b1 ), segExtent );
16879							sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;
16880  
16881						} else if ( s1 <= extDet ) {
16882  
16883							// region 3
16884  
vendor: 4,199 bytes, lines 16885-17074
16885							s0 = 0;
16886							s1 = Math.min( Math.max( - segExtent, - b1 ), segExtent );
16887							sqrDist = s1 * ( s1 + 2 * b1 ) + c;
16888  
16889						} else {
16890  
16891							// region 2
16892  
16893							s0 = Math.max( 0, - ( a01 * segExtent + b0 ) );
16894							s1 = ( s0 > 0 ) ? segExtent : Math.min( Math.max( - segExtent, - b1 ), segExtent );
16895							sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;
16896  
16897						}
16898  
16899					}
16900  
16901				} else {
16902  
16903					// Ray and segment are parallel.
16904  
16905					s1 = ( a01 > 0 ) ? - segExtent : segExtent;
16906					s0 = Math.max( 0, - ( a01 * s1 + b0 ) );
16907					sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;
16908  
16909				}
16910  
16911				if ( optionalPointOnRay ) {
16912  
16913					optionalPointOnRay.copy( this.direction ).multiplyScalar( s0 ).add( this.origin );
16914  
16915				}
16916  
16917				if ( optionalPointOnSegment ) {
16918  
16919					optionalPointOnSegment.copy( segDir ).multiplyScalar( s1 ).add( segCenter );
16920  
16921				}
16922  
16923				return sqrDist;
16924  
16925			};
16926  
16927		}(),
16928  
16929		intersectSphere: function () {
16930  
16931			var v1 = new Vector3();
16932  
16933			return function intersectSphere( sphere, target ) {
16934  
16935				v1.subVectors( sphere.center, this.origin );
16936				var tca = v1.dot( this.direction );
16937				var d2 = v1.dot( v1 ) - tca * tca;
16938				var radius2 = sphere.radius * sphere.radius;
16939  
16940				if ( d2 > radius2 ) return null;
16941  
16942				var thc = Math.sqrt( radius2 - d2 );
16943  
16944				// t0 = first intersect point - entrance on front of sphere
16945				var t0 = tca - thc;
16946  
16947				// t1 = second intersect point - exit point on back of sphere
16948				var t1 = tca + thc;
16949  
16950				// test to see if both t0 and t1 are behind the ray - if so, return null
16951				if ( t0 < 0 && t1 < 0 ) return null;
16952  
16953				// test to see if t0 is behind the ray:
16954				// if it is, the ray is inside the sphere, so return the second exit point scaled by t1,
16955				// in order to always return an intersect point that is in front of the ray.
16956				if ( t0 < 0 ) return this.at( t1, target );
16957  
16958				// else t0 is in front of the ray, so return the first collision point scaled by t0
16959				return this.at( t0, target );
16960  
16961			};
16962  
16963		}(),
16964  
16965		intersectsSphere: function ( sphere ) {
16966  
16967			return this.distanceToPoint( sphere.center ) <= sphere.radius;
16968  
16969		},
16970  
16971		distanceToPlane: function ( plane ) {
16972  
16973			var denominator = plane.normal.dot( this.direction );
16974  
16975			if ( denominator === 0 ) {
16976  
16977				// line is coplanar, return origin
16978				if ( plane.distanceToPoint( this.origin ) === 0 ) {
16979  
16980					return 0;
16981  
16982				}
16983  
16984				// Null is preferable to undefined since undefined means.... it is undefined
16985  
16986				return null;
16987  
16988			}
16989  
16990			var t = - ( this.origin.dot( plane.normal ) + plane.constant ) / denominator;
16991  
16992			// Return if the ray never intersects the plane
16993  
16994			return t >= 0 ? t : null;
16995  
16996		},
16997  
16998		intersectPlane: function ( plane, target ) {
16999  
17000			var t = this.distanceToPlane( plane );
17001  
17002			if ( t === null ) {
17003  
17004				return null;
17005  
17006			}
17007  
17008			return this.at( t, target );
17009  
17010		},
17011  
17012		intersectsPlane: function ( plane ) {
17013  
17014			// check if the ray lies on the plane first
17015  
17016			var distToPoint = plane.distanceToPoint( this.origin );
17017  
17018			if ( distToPoint === 0 ) {
17019  
17020				return true;
17021  
17022			}
17023  
17024			var denominator = plane.normal.dot( this.direction );
17025  
17026			if ( denominator * distToPoint < 0 ) {
17027  
17028				return true;
17029  
17030			}
17031  
17032			// ray origin is behind the plane (and is pointing behind it)
17033  
17034			return false;
17035  
17036		},
17037  
17038		intersectBox: function ( box, target ) {
17039  
17040			var tmin, tmax, tymin, tymax, tzmin, tzmax;
17041  
17042			var invdirx = 1 / this.direction.x,
17043				invdiry = 1 / this.direction.y,
17044				invdirz = 1 / this.direction.z;
17045  
17046			var origin = this.origin;
17047  
17048			if ( invdirx >= 0 ) {
17049  
17050				tmin = ( box.min.x - origin.x ) * invdirx;
17051				tmax = ( box.max.x - origin.x ) * invdirx;
17052  
17053			} else {
17054  
17055				tmin = ( box.max.x - origin.x ) * invdirx;
17056				tmax = ( box.min.x - origin.x ) * invdirx;
17057  
17058			}
17059  
17060			if ( invdiry >= 0 ) {
17061  
17062				tymin = ( box.min.y - origin.y ) * invdiry;
17063				tymax = ( box.max.y - origin.y ) * invdiry;
17064  
17065			} else {
17066  
17067				tymin = ( box.max.y - origin.y ) * invdiry;
17068				tymax = ( box.min.y - origin.y ) * invdiry;
17069  
17070			}
17071  
17072			if ( ( tmin > tymax ) || ( tymin > tmax ) ) return null;
17073  
17074			// These lines also handle the case where tmin or tmax is NaN
vendor: 7,806 bytes, lines 17075-17452
17075			// (result of 0 * Infinity). x !== x returns true if x is NaN
17076  
17077			if ( tymin > tmin || tmin !== tmin ) tmin = tymin;
17078  
17079			if ( tymax < tmax || tmax !== tmax ) tmax = tymax;
17080  
17081			if ( invdirz >= 0 ) {
17082  
17083				tzmin = ( box.min.z - origin.z ) * invdirz;
17084				tzmax = ( box.max.z - origin.z ) * invdirz;
17085  
17086			} else {
17087  
17088				tzmin = ( box.max.z - origin.z ) * invdirz;
17089				tzmax = ( box.min.z - origin.z ) * invdirz;
17090  
17091			}
17092  
17093			if ( ( tmin > tzmax ) || ( tzmin > tmax ) ) return null;
17094  
17095			if ( tzmin > tmin || tmin !== tmin ) tmin = tzmin;
17096  
17097			if ( tzmax < tmax || tmax !== tmax ) tmax = tzmax;
17098  
17099			//return point closest to the ray (positive side)
17100  
17101			if ( tmax < 0 ) return null;
17102  
17103			return this.at( tmin >= 0 ? tmin : tmax, target );
17104  
17105		},
17106  
17107		intersectsBox: ( function () {
17108  
17109			var v = new Vector3();
17110  
17111			return function intersectsBox( box ) {
17112  
17113				return this.intersectBox( box, v ) !== null;
17114  
17115			};
17116  
17117		} )(),
17118  
17119		intersectTriangle: function () {
17120  
17121			// Compute the offset origin, edges, and normal.
17122			var diff = new Vector3();
17123			var edge1 = new Vector3();
17124			var edge2 = new Vector3();
17125			var normal = new Vector3();
17126  
17127			return function intersectTriangle( a, b, c, backfaceCulling, target ) {
17128  
17129				// from http://www.geometrictools.com/GTEngine/Include/Mathematics/GteIntrRay3Triangle3.h
17130  
17131				edge1.subVectors( b, a );
17132				edge2.subVectors( c, a );
17133				normal.crossVectors( edge1, edge2 );
17134  
17135				// Solve Q + t*D = b1*E1 + b2*E2 (Q = kDiff, D = ray direction,
17136				// E1 = kEdge1, E2 = kEdge2, N = Cross(E1,E2)) by
17137				//   |Dot(D,N)|*b1 = sign(Dot(D,N))*Dot(D,Cross(Q,E2))
17138				//   |Dot(D,N)|*b2 = sign(Dot(D,N))*Dot(D,Cross(E1,Q))
17139				//   |Dot(D,N)|*t = -sign(Dot(D,N))*Dot(Q,N)
17140				var DdN = this.direction.dot( normal );
17141				var sign;
17142  
17143				if ( DdN > 0 ) {
17144  
17145					if ( backfaceCulling ) return null;
17146					sign = 1;
17147  
17148				} else if ( DdN < 0 ) {
17149  
17150					sign = - 1;
17151					DdN = - DdN;
17152  
17153				} else {
17154  
17155					return null;
17156  
17157				}
17158  
17159				diff.subVectors( this.origin, a );
17160				var DdQxE2 = sign * this.direction.dot( edge2.crossVectors( diff, edge2 ) );
17161  
17162				// b1 < 0, no intersection
17163				if ( DdQxE2 < 0 ) {
17164  
17165					return null;
17166  
17167				}
17168  
17169				var DdE1xQ = sign * this.direction.dot( edge1.cross( diff ) );
17170  
17171				// b2 < 0, no intersection
17172				if ( DdE1xQ < 0 ) {
17173  
17174					return null;
17175  
17176				}
17177  
17178				// b1+b2 > 1, no intersection
17179				if ( DdQxE2 + DdE1xQ > DdN ) {
17180  
17181					return null;
17182  
17183				}
17184  
17185				// Line intersects triangle, check if ray does.
17186				var QdN = - sign * diff.dot( normal );
17187  
17188				// t < 0, no intersection
17189				if ( QdN < 0 ) {
17190  
17191					return null;
17192  
17193				}
17194  
17195				// Ray intersects triangle.
17196				return this.at( QdN / DdN, target );
17197  
17198			};
17199  
17200		}(),
17201  
17202		applyMatrix4: function ( matrix4 ) {
17203  
17204			this.origin.applyMatrix4( matrix4 );
17205			this.direction.transformDirection( matrix4 );
17206  
17207			return this;
17208  
17209		},
17210  
17211		equals: function ( ray ) {
17212  
17213			return ray.origin.equals( this.origin ) && ray.direction.equals( this.direction );
17214  
17215		}
17216  
17217	} );
17218  
17219	/**
17220	 * @author bhouston / http://clara.io
17221	 */
17222  
17223	function Line3( start, end ) {
17224  
17225		this.start = ( start !== undefined ) ? start : new Vector3();
17226		this.end = ( end !== undefined ) ? end : new Vector3();
17227  
17228	}
17229  
17230	Object.assign( Line3.prototype, {
17231  
17232		set: function ( start, end ) {
17233  
17234			this.start.copy( start );
17235			this.end.copy( end );
17236  
17237			return this;
17238  
17239		},
17240  
17241		clone: function () {
17242  
17243			return new this.constructor().copy( this );
17244  
17245		},
17246  
17247		copy: function ( line ) {
17248  
17249			this.start.copy( line.start );
17250			this.end.copy( line.end );
17251  
17252			return this;
17253  
17254		},
17255  
17256		getCenter: function ( target ) {
17257  
17258			if ( target === undefined ) {
17259  
17260				console.warn( 'THREE.Line3: .getCenter() target is now required' );
17261				target = new Vector3();
17262  
17263			}
17264  
17265			return target.addVectors( this.start, this.end ).multiplyScalar( 0.5 );
17266  
17267		},
17268  
17269		delta: function ( target ) {
17270  
17271			if ( target === undefined ) {
17272  
17273				console.warn( 'THREE.Line3: .delta() target is now required' );
17274				target = new Vector3();
17275  
17276			}
17277  
17278			return target.subVectors( this.end, this.start );
17279  
17280		},
17281  
17282		distanceSq: function () {
17283  
17284			return this.start.distanceToSquared( this.end );
17285  
17286		},
17287  
17288		distance: function () {
17289  
17290			return this.start.distanceTo( this.end );
17291  
17292		},
17293  
17294		at: function ( t, target ) {
17295  
17296			if ( target === undefined ) {
17297  
17298				console.warn( 'THREE.Line3: .at() target is now required' );
17299				target = new Vector3();
17300  
17301			}
17302  
17303			return this.delta( target ).multiplyScalar( t ).add( this.start );
17304  
17305		},
17306  
17307		closestPointToPointParameter: function () {
17308  
17309			var startP = new Vector3();
17310			var startEnd = new Vector3();
17311  
17312			return function closestPointToPointParameter( point, clampToLine ) {
17313  
17314				startP.subVectors( point, this.start );
17315				startEnd.subVectors( this.end, this.start );
17316  
17317				var startEnd2 = startEnd.dot( startEnd );
17318				var startEnd_startP = startEnd.dot( startP );
17319  
17320				var t = startEnd_startP / startEnd2;
17321  
17322				if ( clampToLine ) {
17323  
17324					t = _Math.clamp( t, 0, 1 );
17325  
17326				}
17327  
17328				return t;
17329  
17330			};
17331  
17332		}(),
17333  
17334		closestPointToPoint: function ( point, clampToLine, target ) {
17335  
17336			var t = this.closestPointToPointParameter( point, clampToLine );
17337  
17338			if ( target === undefined ) {
17339  
17340				console.warn( 'THREE.Line3: .closestPointToPoint() target is now required' );
17341				target = new Vector3();
17342  
17343			}
17344  
17345			return this.delta( target ).multiplyScalar( t ).add( this.start );
17346  
17347		},
17348  
17349		applyMatrix4: function ( matrix ) {
17350  
17351			this.start.applyMatrix4( matrix );
17352			this.end.applyMatrix4( matrix );
17353  
17354			return this;
17355  
17356		},
17357  
17358		equals: function ( line ) {
17359  
17360			return line.start.equals( this.start ) && line.end.equals( this.end );
17361  
17362		}
17363  
17364	} );
17365  
17366	/**
17367	 * @author bhouston / http://clara.io
17368	 * @author mrdoob / http://mrdoob.com/
17369	 */
17370  
17371	function Triangle( a, b, c ) {
17372  
17373		this.a = ( a !== undefined ) ? a : new Vector3();
17374		this.b = ( b !== undefined ) ? b : new Vector3();
17375		this.c = ( c !== undefined ) ? c : new Vector3();
17376  
17377	}
17378  
17379	Object.assign( Triangle, {
17380  
17381		getNormal: function () {
17382  
17383			var v0 = new Vector3();
17384  
17385			return function getNormal( a, b, c, target ) {
17386  
17387				if ( target === undefined ) {
17388  
17389					console.warn( 'THREE.Triangle: .getNormal() target is now required' );
17390					target = new Vector3();
17391  
17392				}
17393  
17394				target.subVectors( c, b );
17395				v0.subVectors( a, b );
17396				target.cross( v0 );
17397  
17398				var targetLengthSq = target.lengthSq();
17399				if ( targetLengthSq > 0 ) {
17400  
17401					return target.multiplyScalar( 1 / Math.sqrt( targetLengthSq ) );
17402  
17403				}
17404  
17405				return target.set( 0, 0, 0 );
17406  
17407			};
17408  
17409		}(),
17410  
17411		// static/instance method to calculate barycentric coordinates
17412		// based on: http://www.blackpawn.com/texts/pointinpoly/default.html
17413		getBarycoord: function () {
17414  
17415			var v0 = new Vector3();
17416			var v1 = new Vector3();
17417			var v2 = new Vector3();
17418  
17419			return function getBarycoord( point, a, b, c, target ) {
17420  
17421				v0.subVectors( c, a );
17422				v1.subVectors( b, a );
17423				v2.subVectors( point, a );
17424  
17425				var dot00 = v0.dot( v0 );
17426				var dot01 = v0.dot( v1 );
17427				var dot02 = v0.dot( v2 );
17428				var dot11 = v1.dot( v1 );
17429				var dot12 = v1.dot( v2 );
17430  
17431				var denom = ( dot00 * dot11 - dot01 * dot01 );
17432  
17433				if ( target === undefined ) {
17434  
17435					console.warn( 'THREE.Triangle: .getBarycoord() target is now required' );
17436					target = new Vector3();
17437  
17438				}
17439  
17440				// collinear or singular triangle
17441				if ( denom === 0 ) {
17442  
17443					// arbitrary location outside of triangle?
17444					// not sure if this is the best idea, maybe should be returning undefined
17445					return target.set( - 2, - 1, - 1 );
17446  
17447				}
17448  
17449				var invDenom = 1 / denom;
17450				var u = ( dot11 * dot02 - dot01 * dot12 ) * invDenom;
17451				var v = ( dot00 * dot12 - dot01 * dot02 ) * invDenom;
17452  
17453				// barycentric coordinates must always sum to 1
17454				return target.set( 1 - u - v, v, u );
17455  
17456			};
17457  
17458		}(),
17459  
17460		containsPoint: function () {
17461  
17462			var v1 = new Vector3();
17463  
17464			return function containsPoint( point, a, b, c ) {
17465  
17466				Triangle.getBarycoord( point, a, b, c, v1 );
17467  
17468				return ( v1.x >= 0 ) && ( v1.y >= 0 ) && ( ( v1.x + v1.y ) <= 1 );
17469  
17470			};
17471  
17472		}()
17473  
17474	} );
17475  
17476	Object.assign( Triangle.prototype, {
17477  
17478		set: function ( a, b, c ) {
17479  
17480			this.a.copy( a );
17481			this.b.copy( b );
17482			this.c.copy( c );
17483  
17484			return this;
17485  
17486		},
17487  
17488		setFromPointsAndIndices: function ( points, i0, i1, i2 ) {
17489  
17490			this.a.copy( points[ i0 ] );
17491			this.b.copy( points[ i1 ] );
17492			this.c.copy( points[ i2 ] );
17493  
17494			return this;
17495  
17496		},
17497  
17498		clone: function () {
17499  
17500			return new this.constructor().copy( this );
17501  
17502		},
17503  
17504		copy: function ( triangle ) {
17505  
17506			this.a.copy( triangle.a );
17507			this.b.copy( triangle.b );
17508			this.c.copy( triangle.c );
17509  
17510			return this;
17511  
17512		},
17513  
17514		getArea: function () {
17515  
17516			var v0 = new Vector3();
17517			var v1 = new Vector3();
17518  
17519			return function getArea() {
17520  
17521				v0.subVectors( this.c, this.b );
17522				v1.subVectors( this.a, this.b );
17523  
17524				return v0.cross( v1 ).length() * 0.5;
17525  
17526			};
17527  
17528		}(),
17529  
17530		getMidpoint: function ( target ) {
17531  
17532			if ( target === undefined ) {
17533  
17534				console.warn( 'THREE.Triangle: .getMidpoint() target is now required' );
17535				target = new Vector3();
17536  
17537			}
17538  
17539			return target.addVectors( this.a, this.b ).add( this.c ).multiplyScalar( 1 / 3 );
17540  
17541		},
17542  
17543		getNormal: function ( target ) {
17544  
17545			return Triangle.getNormal( this.a, this.b, this.c, target );
17546  
17547		},
17548  
17549		getPlane: function ( target ) {
17550  
17551			if ( target === undefined ) {
17552  
17553				console.warn( 'THREE.Triangle: .getPlane() target is now required' );
17554				target = new Vector3();
17555  
17556			}
17557  
17558			return target.setFromCoplanarPoints( this.a, this.b, this.c );
17559  
17560		},
17561  
17562		getBarycoord: function ( point, target ) {
17563  
17564			return Triangle.getBarycoord( point, this.a, this.b, this.c, target );
17565  
17566		},
17567  
17568		containsPoint: function ( point ) {
17569  
17570			return Triangle.containsPoint( point, this.a, this.b, this.c );
17571  
17572		},
17573  
17574		intersectsBox: function ( box ) {
17575  
17576			return box.intersectsTriangle( this );
17577  
17578		},
17579  
17580		closestPointToPoint: function () {
17581  
17582			var plane = new Plane();
17583			var edgeList = [ new Line3(), new Line3(), new Line3() ];
17584			var projectedPoint = new Vector3();
17585			var closestPoint = new Vector3();
17586  
17587			return function closestPointToPoint( point, target ) {
17588  
17589				if ( target === undefined ) {
17590  
17591					console.warn( 'THREE.Triangle: .closestPointToPoint() target is now required' );
17592					target = new Vector3();
17593  
17594				}
17595  
17596				var minDistance = Infinity;
17597  
17598				// project the point onto the plane of the triangle
17599  
17600				plane.setFromCoplanarPoints( this.a, this.b, this.c );
17601				plane.projectPoint( point, projectedPoint );
17602  
17603				// check if the projection lies within the triangle
17604  
17605				if ( this.containsPoint( projectedPoint ) === true ) {
17606  
17607					// if so, this is the closest point
17608  
17609					target.copy( projectedPoint );
17610  
17611				} else {
17612  
17613					// if not, the point falls outside the triangle. the target is the closest point to the triangle's edges or vertices
17614  
17615					edgeList[ 0 ].set( this.a, this.b );
17616					edgeList[ 1 ].set( this.b, this.c );
17617					edgeList[ 2 ].set( this.c, this.a );
17618  
17619					for ( var i = 0; i < edgeList.length; i ++ ) {
17620  
17621						edgeList[ i ].closestPointToPoint( projectedPoint, true, closestPoint );
17622  
17623						var distance = projectedPoint.distanceToSquared( closestPoint );
17624  
17625						if ( distance < minDistance ) {
17626  
17627							minDistance = distance;
17628  
17629							target.copy( closestPoint );
17630  
17631						}
17632  
17633					}
17634  
17635				}
17636  
17637				return target;
17638  
17639			};
17640  
17641		}(),
17642  
17643		equals: function ( triangle ) {
17644  
17645			return triangle.a.equals( this.a ) && triangle.b.equals( this.b ) && triangle.c.equals( this.c );
17646  
17647		}
17648  
17649	} );
17650  
17651	/**
17652	 * @author mrdoob / http://mrdoob.com/
17653	 * @author alteredq / http://alteredqualia.com/
17654	 * @author mikael emtinger / http://gomo.se/
17655	 * @author jonobr1 / http://jonobr1.com/
17656	 */
17657  
17658	function Mesh( geometry, material ) {
17659  
17660		Object3D.call( this );
17661  
17662		this.type = 'Mesh';
17663  
17664		this.geometry = geometry !== undefined ? geometry : new BufferGeometry();
17665		this.material = material !== undefined ? material : new MeshBasicMaterial( { color: Math.random() * 0xffffff } );
17666  
17667		this.drawMode = TrianglesDrawMode;
17668  
17669		this.updateMorphTargets();
17670  
17671	}
17672  
17673	Mesh.prototype = Object.assign( Object.create( Object3D.prototype ), {
17674  
17675		constructor: Mesh,
17676  
17677		isMesh: true,
17678  
17679		setDrawMode: function ( value ) {
17680  
17681			this.drawMode = value;
17682  
17683		},
17684  
vendor: 8,365 bytes, lines 17685-18042
17685		copy: function ( source ) {
17686  
17687			Object3D.prototype.copy.call( this, source );
17688  
17689			this.drawMode = source.drawMode;
17690  
17691			if ( source.morphTargetInfluences !== undefined ) {
17692  
17693				this.morphTargetInfluences = source.morphTargetInfluences.slice();
17694  
17695			}
17696  
17697			if ( source.morphTargetDictionary !== undefined ) {
17698  
17699				this.morphTargetDictionary = Object.assign( {}, source.morphTargetDictionary );
17700  
17701			}
17702  
17703			return this;
17704  
17705		},
17706  
17707		updateMorphTargets: function () {
17708  
17709			var geometry = this.geometry;
17710			var m, ml, name;
17711  
17712			if ( geometry.isBufferGeometry ) {
17713  
17714				var morphAttributes = geometry.morphAttributes;
17715				var keys = Object.keys( morphAttributes );
17716  
17717				if ( keys.length > 0 ) {
17718  
17719					var morphAttribute = morphAttributes[ keys[ 0 ] ];
17720  
17721					if ( morphAttribute !== undefined ) {
17722  
17723						this.morphTargetInfluences = [];
17724						this.morphTargetDictionary = {};
17725  
17726						for ( m = 0, ml = morphAttribute.length; m < ml; m ++ ) {
17727  
17728							name = morphAttribute[ m ].name || String( m );
17729  
17730							this.morphTargetInfluences.push( 0 );
17731							this.morphTargetDictionary[ name ] = m;
17732  
17733						}
17734  
17735					}
17736  
17737				}
17738  
17739			} else {
17740  
17741				var morphTargets = geometry.morphTargets;
17742  
17743				if ( morphTargets !== undefined && morphTargets.length > 0 ) {
17744  
17745					this.morphTargetInfluences = [];
17746					this.morphTargetDictionary = {};
17747  
17748					for ( m = 0, ml = morphTargets.length; m < ml; m ++ ) {
17749  
17750						name = morphTargets[ m ].name || String( m );
17751  
17752						this.morphTargetInfluences.push( 0 );
17753						this.morphTargetDictionary[ name ] = m;
17754  
17755					}
17756  
17757				}
17758  
17759			}
17760  
17761		},
17762  
17763		raycast: ( function () {
17764  
17765			var inverseMatrix = new Matrix4();
17766			var ray = new Ray();
17767			var sphere = new Sphere();
17768  
17769			var vA = new Vector3();
17770			var vB = new Vector3();
17771			var vC = new Vector3();
17772  
17773			var tempA = new Vector3();
17774			var tempB = new Vector3();
17775			var tempC = new Vector3();
17776  
17777			var uvA = new Vector2();
17778			var uvB = new Vector2();
17779			var uvC = new Vector2();
17780  
17781			var barycoord = new Vector3();
17782  
17783			var intersectionPoint = new Vector3();
17784			var intersectionPointWorld = new Vector3();
17785  
17786			function uvIntersection( point, p1, p2, p3, uv1, uv2, uv3 ) {
17787  
17788				Triangle.getBarycoord( point, p1, p2, p3, barycoord );
17789  
17790				uv1.multiplyScalar( barycoord.x );
17791				uv2.multiplyScalar( barycoord.y );
17792				uv3.multiplyScalar( barycoord.z );
17793  
17794				uv1.add( uv2 ).add( uv3 );
17795  
17796				return uv1.clone();
17797  
17798			}
17799  
17800			function checkIntersection( object, material, raycaster, ray, pA, pB, pC, point ) {
17801  
17802				var intersect;
17803  
17804				if ( material.side === BackSide ) {
17805  
17806					intersect = ray.intersectTriangle( pC, pB, pA, true, point );
17807  
17808				} else {
17809  
17810					intersect = ray.intersectTriangle( pA, pB, pC, material.side !== DoubleSide, point );
17811  
17812				}
17813  
17814				if ( intersect === null ) return null;
17815  
17816				intersectionPointWorld.copy( point );
17817				intersectionPointWorld.applyMatrix4( object.matrixWorld );
17818  
17819				var distance = raycaster.ray.origin.distanceTo( intersectionPointWorld );
17820  
17821				if ( distance < raycaster.near || distance > raycaster.far ) return null;
17822  
17823				return {
17824					distance: distance,
17825					point: intersectionPointWorld.clone(),
17826					object: object
17827				};
17828  
17829			}
17830  
17831			function checkBufferGeometryIntersection( object, raycaster, ray, position, uv, a, b, c ) {
17832  
17833				vA.fromBufferAttribute( position, a );
17834				vB.fromBufferAttribute( position, b );
17835				vC.fromBufferAttribute( position, c );
17836  
17837				var intersection = checkIntersection( object, object.material, raycaster, ray, vA, vB, vC, intersectionPoint );
17838  
17839				if ( intersection ) {
17840  
17841					if ( uv ) {
17842  
17843						uvA.fromBufferAttribute( uv, a );
17844						uvB.fromBufferAttribute( uv, b );
17845						uvC.fromBufferAttribute( uv, c );
17846  
17847						intersection.uv = uvIntersection( intersectionPoint, vA, vB, vC, uvA, uvB, uvC );
17848  
17849					}
17850  
17851					var face = new Face3( a, b, c );
17852					Triangle.getNormal( vA, vB, vC, face.normal );
17853  
17854					intersection.face = face;
17855  
17856				}
17857  
17858				return intersection;
17859  
17860			}
17861  
17862			return function raycast( raycaster, intersects ) {
17863  
17864				var geometry = this.geometry;
17865				var material = this.material;
17866				var matrixWorld = this.matrixWorld;
17867  
17868				if ( material === undefined ) return;
17869  
17870				// Checking boundingSphere distance to ray
17871  
17872				if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere();
17873  
17874				sphere.copy( geometry.boundingSphere );
17875				sphere.applyMatrix4( matrixWorld );
17876  
17877				if ( raycaster.ray.intersectsSphere( sphere ) === false ) return;
17878  
17879				//
17880  
17881				inverseMatrix.getInverse( matrixWorld );
17882				ray.copy( raycaster.ray ).applyMatrix4( inverseMatrix );
17883  
17884				// Check boundingBox before continuing
17885  
17886				if ( geometry.boundingBox !== null ) {
17887  
17888					if ( ray.intersectsBox( geometry.boundingBox ) === false ) return;
17889  
17890				}
17891  
17892				var intersection;
17893  
17894				if ( geometry.isBufferGeometry ) {
17895  
17896					var a, b, c;
17897					var index = geometry.index;
17898					var position = geometry.attributes.position;
17899					var uv = geometry.attributes.uv;
17900					var i, l;
17901  
17902					if ( index !== null ) {
17903  
17904						// indexed buffer geometry
17905  
17906						for ( i = 0, l = index.count; i < l; i += 3 ) {
17907  
17908							a = index.getX( i );
17909							b = index.getX( i + 1 );
17910							c = index.getX( i + 2 );
17911  
17912							intersection = checkBufferGeometryIntersection( this, raycaster, ray, position, uv, a, b, c );
17913  
17914							if ( intersection ) {
17915  
17916								intersection.faceIndex = Math.floor( i / 3 ); // triangle number in indexed buffer semantics
17917								intersects.push( intersection );
17918  
17919							}
17920  
17921						}
17922  
17923					} else if ( position !== undefined ) {
17924  
17925						// non-indexed buffer geometry
17926  
17927						for ( i = 0, l = position.count; i < l; i += 3 ) {
17928  
17929							a = i;
17930							b = i + 1;
17931							c = i + 2;
17932  
17933							intersection = checkBufferGeometryIntersection( this, raycaster, ray, position, uv, a, b, c );
17934  
17935							if ( intersection ) {
17936  
17937								intersection.faceIndex = Math.floor( i / 3 ); // triangle number in non-indexed buffer semantics
17938								intersects.push( intersection );
17939  
17940							}
17941  
17942						}
17943  
17944					}
17945  
17946				} else if ( geometry.isGeometry ) {
17947  
17948					var fvA, fvB, fvC;
17949					var isMultiMaterial = Array.isArray( material );
17950  
17951					var vertices = geometry.vertices;
17952					var faces = geometry.faces;
17953					var uvs;
17954  
17955					var faceVertexUvs = geometry.faceVertexUvs[ 0 ];
17956					if ( faceVertexUvs.length > 0 ) uvs = faceVertexUvs;
17957  
17958					for ( var f = 0, fl = faces.length; f < fl; f ++ ) {
17959  
17960						var face = faces[ f ];
17961						var faceMaterial = isMultiMaterial ? material[ face.materialIndex ] : material;
17962  
17963						if ( faceMaterial === undefined ) continue;
17964  
17965						fvA = vertices[ face.a ];
17966						fvB = vertices[ face.b ];
17967						fvC = vertices[ face.c ];
17968  
17969						if ( faceMaterial.morphTargets === true ) {
17970  
17971							var morphTargets = geometry.morphTargets;
17972							var morphInfluences = this.morphTargetInfluences;
17973  
17974							vA.set( 0, 0, 0 );
17975							vB.set( 0, 0, 0 );
17976							vC.set( 0, 0, 0 );
17977  
17978							for ( var t = 0, tl = morphTargets.length; t < tl; t ++ ) {
17979  
17980								var influence = morphInfluences[ t ];
17981  
17982								if ( influence === 0 ) continue;
17983  
17984								var targets = morphTargets[ t ].vertices;
17985  
17986								vA.addScaledVector( tempA.subVectors( targets[ face.a ], fvA ), influence );
17987								vB.addScaledVector( tempB.subVectors( targets[ face.b ], fvB ), influence );
17988								vC.addScaledVector( tempC.subVectors( targets[ face.c ], fvC ), influence );
17989  
17990							}
17991  
17992							vA.add( fvA );
17993							vB.add( fvB );
17994							vC.add( fvC );
17995  
17996							fvA = vA;
17997							fvB = vB;
17998							fvC = vC;
17999  
18000						}
18001  
18002						intersection = checkIntersection( this, faceMaterial, raycaster, ray, fvA, fvB, fvC, intersectionPoint );
18003  
18004						if ( intersection ) {
18005  
18006							if ( uvs && uvs[ f ] ) {
18007  
18008								var uvs_f = uvs[ f ];
18009								uvA.copy( uvs_f[ 0 ] );
18010								uvB.copy( uvs_f[ 1 ] );
18011								uvC.copy( uvs_f[ 2 ] );
18012  
18013								intersection.uv = uvIntersection( intersectionPoint, fvA, fvB, fvC, uvA, uvB, uvC );
18014  
18015							}
18016  
18017							intersection.face = face;
18018							intersection.faceIndex = f;
18019							intersects.push( intersection );
18020  
18021						}
18022  
18023					}
18024  
18025				}
18026  
18027			};
18028  
18029		}() ),
18030  
18031		clone: function () {
18032  
18033			return new this.constructor( this.geometry, this.material ).copy( this );
18034  
18035		}
18036  
18037	} );
18038  
18039	/**
18040	 * @author mrdoob / http://mrdoob.com/
18041	 */
18042  
18043	function WebGLBackground( renderer, state, objects, premultipliedAlpha ) {
18044  
18045		var clearColor = new Color( 0x000000 );
18046		var clearAlpha = 0;
18047  
18048		var planeCamera, planeMesh;
18049		var boxMesh;
18050  
18051		function render( renderList, scene, camera, forceClear ) {
18052  
18053			var background = scene.background;
18054  
18055			if ( background === null ) {
18056  
18057				setClear( clearColor, clearAlpha );
18058  
18059			} else if ( background && background.isColor ) {
18060  
18061				setClear( background, 1 );
18062				forceClear = true;
18063  
18064			}
18065  
18066			if ( renderer.autoClear || forceClear ) {
18067  
18068				renderer.clear( renderer.autoClearColor, renderer.autoClearDepth, renderer.autoClearStencil );
18069  
18070			}
18071  
18072			if ( background && background.isCubeTexture ) {
18073  
18074				if ( boxMesh === undefined ) {
18075  
18076					boxMesh = new Mesh(
18077						new BoxBufferGeometry( 1, 1, 1 ),
18078						new ShaderMaterial( {
18079							uniforms: ShaderLib.cube.uniforms,
18080							vertexShader: ShaderLib.cube.vertexShader,
18081							fragmentShader: ShaderLib.cube.fragmentShader,
18082							side: BackSide,
18083							depthTest: true,
18084							depthWrite: false,
18085							fog: false
18086						} )
18087					);
18088  
18089					boxMesh.geometry.removeAttribute( 'normal' );
18090					boxMesh.geometry.removeAttribute( 'uv' );
18091  
18092					boxMesh.onBeforeRender = function ( renderer, scene, camera ) {
18093  
18094						this.matrixWorld.copyPosition( camera.matrixWorld );
18095  
18096					};
18097  
18098					objects.update( boxMesh );
18099  
18100				}
18101  
18102				boxMesh.material.uniforms.tCube.value = background;
18103  
18104				renderList.push( boxMesh, boxMesh.geometry, boxMesh.material, 0, null );
18105  
18106			} else if ( background && background.isTexture ) {
18107  
18108				if ( planeCamera === undefined ) {
18109  
18110					planeCamera = new OrthographicCamera( - 1, 1, 1, - 1, 0, 1 );
18111  
18112					planeMesh = new Mesh(
18113						new PlaneBufferGeometry( 2, 2 ),
18114						new MeshBasicMaterial( { depthTest: false, depthWrite: false, fog: false } )
18115					);
18116  
18117					objects.update( planeMesh );
18118  
18119				}
18120  
18121				planeMesh.material.map = background;
18122  
18123				// TODO Push this to renderList
18124  
18125				renderer.renderBufferDirect( planeCamera, null, planeMesh.geometry, planeMesh.material, planeMesh, null );
18126  
18127			}
18128  
18129		}
18130  
18131		function setClear( color, alpha ) {
18132  
18133			state.buffers.color.setClear( color.r, color.g, color.b, alpha, premultipliedAlpha );
18134  
18135		}
18136  
18137		return {
18138  
18139			getClearColor: function () {
18140  
18141				return clearColor;
18142  
18143			},
18144			setClearColor: function ( color, alpha ) {
18145  
18146				clearColor.set( color );
18147				clearAlpha = alpha !== undefined ? alpha : 1;
18148				setClear( clearColor, clearAlpha );
18149  
18150			},
18151			getClearAlpha: function () {
18152  
18153				return clearAlpha;
18154  
18155			},
18156			setClearAlpha: function ( alpha ) {
18157  
18158				clearAlpha = alpha;
18159				setClear( clearColor, clearAlpha );
18160  
18161			},
18162			render: render
18163  
18164		};
18165  
18166	}
18167  
18168	/**
18169	 * @author mrdoob / http://mrdoob.com/
18170	 */
18171  
18172	function WebGLBufferRenderer( gl, extensions, info ) {
18173  
18174		var mode;
18175  
18176		function setMode( value ) {
18177  
18178			mode = value;
18179  
18180		}
18181  
18182		function render( start, count ) {
18183  
18184			gl.drawArrays( mode, start, count );
18185  
18186			info.update( count, mode );
18187  
18188		}
18189  
18190		function renderInstances( geometry, start, count ) {
18191  
18192			var extension = extensions.get( 'ANGLE_instanced_arrays' );
18193  
18194			if ( extension === null ) {
18195  
18196				console.error( 'THREE.WebGLBufferRenderer: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.' );
18197				return;
18198  
18199			}
18200  
18201			extension.drawArraysInstancedANGLE( mode, start, count, geometry.maxInstancedCount );
18202  
18203			info.update( count, mode, geometry.maxInstancedCount );
18204  
18205		}
18206  
18207		//
18208  
18209		this.setMode = setMode;
18210		this.render = render;
18211		this.renderInstances = renderInstances;
18212  
18213	}
18214  
18215	/**
18216	 * @author mrdoob / http://mrdoob.com/
18217	 */
18218  
18219	function WebGLCapabilities( gl, extensions, parameters ) {
18220  
18221		var maxAnisotropy;
18222  
18223		function getMaxAnisotropy() {
18224  
18225			if ( maxAnisotropy !== undefined ) return maxAnisotropy;
18226  
18227			var extension = extensions.get( 'EXT_texture_filter_anisotropic' );
18228  
18229			if ( extension !== null ) {
18230  
18231				maxAnisotropy = gl.getParameter( extension.MAX_TEXTURE_MAX_ANISOTROPY_EXT );
18232  
18233			} else {
18234  
18235				maxAnisotropy = 0;
18236  
18237			}
18238  
18239			return maxAnisotropy;
18240  
18241		}
18242  
18243		function getMaxPrecision( precision ) {
18244  
18245			if ( precision === 'highp' ) {
18246  
18247				if ( gl.getShaderPrecisionFormat( gl.VERTEX_SHADER, gl.HIGH_FLOAT ).precision > 0 &&
18248					 gl.getShaderPrecisionFormat( gl.FRAGMENT_SHADER, gl.HIGH_FLOAT ).precision > 0 ) {
18249  
18250					return 'highp';
18251  
18252				}
18253  
18254				precision = 'mediump';
18255  
18256			}
18257  
18258			if ( precision === 'mediump' ) {
18259  
18260				if ( gl.getShaderPrecisionFormat( gl.VERTEX_SHADER, gl.MEDIUM_FLOAT ).precision > 0 &&
18261					 gl.getShaderPrecisionFormat( gl.FRAGMENT_SHADER, gl.MEDIUM_FLOAT ).precision > 0 ) {
18262  
18263					return 'mediump';
18264  
18265				}
18266  
18267			}
18268  
18269			return 'lowp';
18270  
18271		}
18272  
18273		var precision = parameters.precision !== undefined ? parameters.precision : 'highp';
18274		var maxPrecision = getMaxPrecision( precision );
18275  
18276		if ( maxPrecision !== precision ) {
18277  
18278			console.warn( 'THREE.WebGLRenderer:', precision, 'not supported, using', maxPrecision, 'instead.' );
18279			precision = maxPrecision;
18280  
18281		}
18282  
18283		var logarithmicDepthBuffer = parameters.logarithmicDepthBuffer === true;
18284  
18285		var maxTextures = gl.getParameter( gl.MAX_TEXTURE_IMAGE_UNITS );
18286		var maxVertexTextures = gl.getParameter( gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS );
18287		var maxTextureSize = gl.getParameter( gl.MAX_TEXTURE_SIZE );
18288		var maxCubemapSize = gl.getParameter( gl.MAX_CUBE_MAP_TEXTURE_SIZE );
18289  
18290		var maxAttributes = gl.getParameter( gl.MAX_VERTEX_ATTRIBS );
18291		var maxVertexUniforms = gl.getParameter( gl.MAX_VERTEX_UNIFORM_VECTORS );
18292		var maxVaryings = gl.getParameter( gl.MAX_VARYING_VECTORS );
18293		var maxFragmentUniforms = gl.getParameter( gl.MAX_FRAGMENT_UNIFORM_VECTORS );
18294  
18295		var vertexTextures = maxVertexTextures > 0;
18296		var floatFragmentTextures = !! extensions.get( 'OES_texture_float' );
18297		var floatVertexTextures = vertexTextures && floatFragmentTextures;
18298  
18299		return {
18300  
18301			getMaxAnisotropy: getMaxAnisotropy,
18302			getMaxPrecision: getMaxPrecision,
vendor: 29,920 bytes, lines 18303-19826
18303  
18304			precision: precision,
18305			logarithmicDepthBuffer: logarithmicDepthBuffer,
18306  
18307			maxTextures: maxTextures,
18308			maxVertexTextures: maxVertexTextures,
18309			maxTextureSize: maxTextureSize,
18310			maxCubemapSize: maxCubemapSize,
18311  
18312			maxAttributes: maxAttributes,
18313			maxVertexUniforms: maxVertexUniforms,
18314			maxVaryings: maxVaryings,
18315			maxFragmentUniforms: maxFragmentUniforms,
18316  
18317			vertexTextures: vertexTextures,
18318			floatFragmentTextures: floatFragmentTextures,
18319			floatVertexTextures: floatVertexTextures
18320  
18321		};
18322  
18323	}
18324  
18325	/**
18326	 * @author tschw
18327	 */
18328  
18329	function WebGLClipping() {
18330  
18331		var scope = this,
18332  
18333			globalState = null,
18334			numGlobalPlanes = 0,
18335			localClippingEnabled = false,
18336			renderingShadows = false,
18337  
18338			plane = new Plane(),
18339			viewNormalMatrix = new Matrix3(),
18340  
18341			uniform = { value: null, needsUpdate: false };
18342  
18343		this.uniform = uniform;
18344		this.numPlanes = 0;
18345		this.numIntersection = 0;
18346  
18347		this.init = function ( planes, enableLocalClipping, camera ) {
18348  
18349			var enabled =
18350				planes.length !== 0 ||
18351				enableLocalClipping ||
18352				// enable state of previous frame - the clipping code has to
18353				// run another frame in order to reset the state:
18354				numGlobalPlanes !== 0 ||
18355				localClippingEnabled;
18356  
18357			localClippingEnabled = enableLocalClipping;
18358  
18359			globalState = projectPlanes( planes, camera, 0 );
18360			numGlobalPlanes = planes.length;
18361  
18362			return enabled;
18363  
18364		};
18365  
18366		this.beginShadows = function () {
18367  
18368			renderingShadows = true;
18369			projectPlanes( null );
18370  
18371		};
18372  
18373		this.endShadows = function () {
18374  
18375			renderingShadows = false;
18376			resetGlobalState();
18377  
18378		};
18379  
18380		this.setState = function ( planes, clipIntersection, clipShadows, camera, cache, fromCache ) {
18381  
18382			if ( ! localClippingEnabled || planes === null || planes.length === 0 || renderingShadows && ! clipShadows ) {
18383  
18384				// there's no local clipping
18385  
18386				if ( renderingShadows ) {
18387  
18388					// there's no global clipping
18389  
18390					projectPlanes( null );
18391  
18392				} else {
18393  
18394					resetGlobalState();
18395  
18396				}
18397  
18398			} else {
18399  
18400				var nGlobal = renderingShadows ? 0 : numGlobalPlanes,
18401					lGlobal = nGlobal * 4,
18402  
18403					dstArray = cache.clippingState || null;
18404  
18405				uniform.value = dstArray; // ensure unique state
18406  
18407				dstArray = projectPlanes( planes, camera, lGlobal, fromCache );
18408  
18409				for ( var i = 0; i !== lGlobal; ++ i ) {
18410  
18411					dstArray[ i ] = globalState[ i ];
18412  
18413				}
18414  
18415				cache.clippingState = dstArray;
18416				this.numIntersection = clipIntersection ? this.numPlanes : 0;
18417				this.numPlanes += nGlobal;
18418  
18419			}
18420  
18421  
18422		};
18423  
18424		function resetGlobalState() {
18425  
18426			if ( uniform.value !== globalState ) {
18427  
18428				uniform.value = globalState;
18429				uniform.needsUpdate = numGlobalPlanes > 0;
18430  
18431			}
18432  
18433			scope.numPlanes = numGlobalPlanes;
18434			scope.numIntersection = 0;
18435  
18436		}
18437  
18438		function projectPlanes( planes, camera, dstOffset, skipTransform ) {
18439  
18440			var nPlanes = planes !== null ? planes.length : 0,
18441				dstArray = null;
18442  
18443			if ( nPlanes !== 0 ) {
18444  
18445				dstArray = uniform.value;
18446  
18447				if ( skipTransform !== true || dstArray === null ) {
18448  
18449					var flatSize = dstOffset + nPlanes * 4,
18450						viewMatrix = camera.matrixWorldInverse;
18451  
18452					viewNormalMatrix.getNormalMatrix( viewMatrix );
18453  
18454					if ( dstArray === null || dstArray.length < flatSize ) {
18455  
18456						dstArray = new Float32Array( flatSize );
18457  
18458					}
18459  
18460					for ( var i = 0, i4 = dstOffset; i !== nPlanes; ++ i, i4 += 4 ) {
18461  
18462						plane.copy( planes[ i ] ).applyMatrix4( viewMatrix, viewNormalMatrix );
18463  
18464						plane.normal.toArray( dstArray, i4 );
18465						dstArray[ i4 + 3 ] = plane.constant;
18466  
18467					}
18468  
18469				}
18470  
18471				uniform.value = dstArray;
18472				uniform.needsUpdate = true;
18473  
18474			}
18475  
18476			scope.numPlanes = nPlanes;
18477  
18478			return dstArray;
18479  
18480		}
18481  
18482	}
18483  
18484	/**
18485	 * @author mrdoob / http://mrdoob.com/
18486	 */
18487  
18488	function WebGLExtensions( gl ) {
18489  
18490		var extensions = {};
18491  
18492		return {
18493  
18494			get: function ( name ) {
18495  
18496				if ( extensions[ name ] !== undefined ) {
18497  
18498					return extensions[ name ];
18499  
18500				}
18501  
18502				var extension;
18503  
18504				switch ( name ) {
18505  
18506					case 'WEBGL_depth_texture':
18507						extension = gl.getExtension( 'WEBGL_depth_texture' ) || gl.getExtension( 'MOZ_WEBGL_depth_texture' ) || gl.getExtension( 'WEBKIT_WEBGL_depth_texture' );
18508						break;
18509  
18510					case 'EXT_texture_filter_anisotropic':
18511						extension = gl.getExtension( 'EXT_texture_filter_anisotropic' ) || gl.getExtension( 'MOZ_EXT_texture_filter_anisotropic' ) || gl.getExtension( 'WEBKIT_EXT_texture_filter_anisotropic' );
18512						break;
18513  
18514					case 'WEBGL_compressed_texture_s3tc':
18515						extension = gl.getExtension( 'WEBGL_compressed_texture_s3tc' ) || gl.getExtension( 'MOZ_WEBGL_compressed_texture_s3tc' ) || gl.getExtension( 'WEBKIT_WEBGL_compressed_texture_s3tc' );
18516						break;
18517  
18518					case 'WEBGL_compressed_texture_pvrtc':
18519						extension = gl.getExtension( 'WEBGL_compressed_texture_pvrtc' ) || gl.getExtension( 'WEBKIT_WEBGL_compressed_texture_pvrtc' );
18520						break;
18521  
18522					default:
18523						extension = gl.getExtension( name );
18524  
18525				}
18526  
18527				if ( extension === null ) {
18528  
18529					console.warn( 'THREE.WebGLRenderer: ' + name + ' extension not supported.' );
18530  
18531				}
18532  
18533				extensions[ name ] = extension;
18534  
18535				return extension;
18536  
18537			}
18538  
18539		};
18540  
18541	}
18542  
18543	/**
18544	 * @author mrdoob / http://mrdoob.com/
18545	 */
18546  
18547	function WebGLGeometries( gl, attributes, info ) {
18548  
18549		var geometries = {};
18550		var wireframeAttributes = {};
18551  
18552		function onGeometryDispose( event ) {
18553  
18554			var geometry = event.target;
18555			var buffergeometry = geometries[ geometry.id ];
18556  
18557			if ( buffergeometry.index !== null ) {
18558  
18559				attributes.remove( buffergeometry.index );
18560  
18561			}
18562  
18563			for ( var name in buffergeometry.attributes ) {
18564  
18565				attributes.remove( buffergeometry.attributes[ name ] );
18566  
18567			}
18568  
18569			geometry.removeEventListener( 'dispose', onGeometryDispose );
18570  
18571			delete geometries[ geometry.id ];
18572  
18573			// TODO Remove duplicate code
18574  
18575			var attribute = wireframeAttributes[ geometry.id ];
18576  
18577			if ( attribute ) {
18578  
18579				attributes.remove( attribute );
18580				delete wireframeAttributes[ geometry.id ];
18581  
18582			}
18583  
18584			attribute = wireframeAttributes[ buffergeometry.id ];
18585  
18586			if ( attribute ) {
18587  
18588				attributes.remove( attribute );
18589				delete wireframeAttributes[ buffergeometry.id ];
18590  
18591			}
18592  
18593			//
18594  
18595			info.memory.geometries --;
18596  
18597		}
18598  
18599		function get( object, geometry ) {
18600  
18601			var buffergeometry = geometries[ geometry.id ];
18602  
18603			if ( buffergeometry ) return buffergeometry;
18604  
18605			geometry.addEventListener( 'dispose', onGeometryDispose );
18606  
18607			if ( geometry.isBufferGeometry ) {
18608  
18609				buffergeometry = geometry;
18610  
18611			} else if ( geometry.isGeometry ) {
18612  
18613				if ( geometry._bufferGeometry === undefined ) {
18614  
18615					geometry._bufferGeometry = new BufferGeometry().setFromObject( object );
18616  
18617				}
18618  
18619				buffergeometry = geometry._bufferGeometry;
18620  
18621			}
18622  
18623			geometries[ geometry.id ] = buffergeometry;
18624  
18625			info.memory.geometries ++;
18626  
18627			return buffergeometry;
18628  
18629		}
18630  
18631		function update( geometry ) {
18632  
18633			var index = geometry.index;
18634			var geometryAttributes = geometry.attributes;
18635  
18636			if ( index !== null ) {
18637  
18638				attributes.update( index, gl.ELEMENT_ARRAY_BUFFER );
18639  
18640			}
18641  
18642			for ( var name in geometryAttributes ) {
18643  
18644				attributes.update( geometryAttributes[ name ], gl.ARRAY_BUFFER );
18645  
18646			}
18647  
18648			// morph targets
18649  
18650			var morphAttributes = geometry.morphAttributes;
18651  
18652			for ( var name in morphAttributes ) {
18653  
18654				var array = morphAttributes[ name ];
18655  
18656				for ( var i = 0, l = array.length; i < l; i ++ ) {
18657  
18658					attributes.update( array[ i ], gl.ARRAY_BUFFER );
18659  
18660				}
18661  
18662			}
18663  
18664		}
18665  
18666		function getWireframeAttribute( geometry ) {
18667  
18668			var attribute = wireframeAttributes[ geometry.id ];
18669  
18670			if ( attribute ) return attribute;
18671  
18672			var indices = [];
18673  
18674			var geometryIndex = geometry.index;
18675			var geometryAttributes = geometry.attributes;
18676  
18677			// console.time( 'wireframe' );
18678  
18679			if ( geometryIndex !== null ) {
18680  
18681				var array = geometryIndex.array;
18682  
18683				for ( var i = 0, l = array.length; i < l; i += 3 ) {
18684  
18685					var a = array[ i + 0 ];
18686					var b = array[ i + 1 ];
18687					var c = array[ i + 2 ];
18688  
18689					indices.push( a, b, b, c, c, a );
18690  
18691				}
18692  
18693			} else {
18694  
18695				var array = geometryAttributes.position.array;
18696  
18697				for ( var i = 0, l = ( array.length / 3 ) - 1; i < l; i += 3 ) {
18698  
18699					var a = i + 0;
18700					var b = i + 1;
18701					var c = i + 2;
18702  
18703					indices.push( a, b, b, c, c, a );
18704  
18705				}
18706  
18707			}
18708  
18709			// console.timeEnd( 'wireframe' );
18710  
18711			attribute = new ( arrayMax( indices ) > 65535 ? Uint32BufferAttribute : Uint16BufferAttribute )( indices, 1 );
18712  
18713			attributes.update( attribute, gl.ELEMENT_ARRAY_BUFFER );
18714  
18715			wireframeAttributes[ geometry.id ] = attribute;
18716  
18717			return attribute;
18718  
18719		}
18720  
18721		return {
18722  
18723			get: get,
18724			update: update,
18725  
18726			getWireframeAttribute: getWireframeAttribute
18727  
18728		};
18729  
18730	}
18731  
18732	/**
18733	 * @author mrdoob / http://mrdoob.com/
18734	 */
18735  
18736	function WebGLIndexedBufferRenderer( gl, extensions, info ) {
18737  
18738		var mode;
18739  
18740		function setMode( value ) {
18741  
18742			mode = value;
18743  
18744		}
18745  
18746		var type, bytesPerElement;
18747  
18748		function setIndex( value ) {
18749  
18750			type = value.type;
18751			bytesPerElement = value.bytesPerElement;
18752  
18753		}
18754  
18755		function render( start, count ) {
18756  
18757			gl.drawElements( mode, count, type, start * bytesPerElement );
18758  
18759			info.update( count, mode );
18760  
18761		}
18762  
18763		function renderInstances( geometry, start, count ) {
18764  
18765			var extension = extensions.get( 'ANGLE_instanced_arrays' );
18766  
18767			if ( extension === null ) {
18768  
18769				console.error( 'THREE.WebGLIndexedBufferRenderer: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.' );
18770				return;
18771  
18772			}
18773  
18774			extension.drawElementsInstancedANGLE( mode, count, type, start * bytesPerElement, geometry.maxInstancedCount );
18775  
18776			info.update( count, mode, geometry.maxInstancedCount );
18777  
18778		}
18779  
18780		//
18781  
18782		this.setMode = setMode;
18783		this.setIndex = setIndex;
18784		this.render = render;
18785		this.renderInstances = renderInstances;
18786  
18787	}
18788  
18789	/**
18790	 * @author Mugen87 / https://github.com/Mugen87
18791	 */
18792  
18793	function WebGLInfo( gl ) {
18794  
18795		var memory = {
18796			geometries: 0,
18797			textures: 0
18798		};
18799  
18800		var render = {
18801			frame: 0,
18802			calls: 0,
18803			triangles: 0,
18804			points: 0,
18805			lines: 0
18806		};
18807  
18808		function update( count, mode, instanceCount ) {
18809  
18810			instanceCount = instanceCount || 1;
18811  
18812			render.calls ++;
18813  
18814			switch ( mode ) {
18815  
18816				case gl.TRIANGLES:
18817					render.triangles += instanceCount * ( count / 3 );
18818					break;
18819  
18820				case gl.TRIANGLE_STRIP:
18821				case gl.TRIANGLE_FAN:
18822					render.triangles += instanceCount * ( count - 2 );
18823					break;
18824  
18825				case gl.LINES:
18826					render.lines += instanceCount * ( count / 2 );
18827					break;
18828  
18829				case gl.LINE_STRIP:
18830					render.lines += instanceCount * ( count - 1 );
18831					break;
18832  
18833				case gl.LINE_LOOP:
18834					render.lines += instanceCount * count;
18835					break;
18836  
18837				case gl.POINTS:
18838					render.points += instanceCount * count;
18839					break;
18840  
18841				default:
18842					console.error( 'THREE.WebGLInfo: Unknown draw mode:', mode );
18843					break;
18844  
18845			}
18846  
18847		}
18848  
18849		function reset() {
18850  
18851			render.frame ++;
18852			render.calls = 0;
18853			render.triangles = 0;
18854			render.points = 0;
18855			render.lines = 0;
18856  
18857		}
18858  
18859		return {
18860			memory: memory,
18861			render: render,
18862			programs: null,
18863			autoReset: true,
18864			reset: reset,
18865			update: update
18866		};
18867  
18868	}
18869  
18870	/**
18871	 * @author mrdoob / http://mrdoob.com/
18872	 */
18873  
18874	function absNumericalSort( a, b ) {
18875  
18876		return Math.abs( b[ 1 ] ) - Math.abs( a[ 1 ] );
18877  
18878	}
18879  
18880	function WebGLMorphtargets( gl ) {
18881  
18882		var influencesList = {};
18883		var morphInfluences = new Float32Array( 8 );
18884  
18885		function update( object, geometry, material, program ) {
18886  
18887			var objectInfluences = object.morphTargetInfluences;
18888  
18889			var length = objectInfluences.length;
18890  
18891			var influences = influencesList[ geometry.id ];
18892  
18893			if ( influences === undefined ) {
18894  
18895				// initialise list
18896  
18897				influences = [];
18898  
18899				for ( var i = 0; i < length; i ++ ) {
18900  
18901					influences[ i ] = [ i, 0 ];
18902  
18903				}
18904  
18905				influencesList[ geometry.id ] = influences;
18906  
18907			}
18908  
18909			var morphTargets = material.morphTargets && geometry.morphAttributes.position;
18910			var morphNormals = material.morphNormals && geometry.morphAttributes.normal;
18911  
18912			// Remove current morphAttributes
18913  
18914			for ( var i = 0; i < length; i ++ ) {
18915  
18916				var influence = influences[ i ];
18917  
18918				if ( influence[ 1 ] !== 0 ) {
18919  
18920					if ( morphTargets ) geometry.removeAttribute( 'morphTarget' + i );
18921					if ( morphNormals ) geometry.removeAttribute( 'morphNormal' + i );
18922  
18923				}
18924  
18925			}
18926  
18927			// Collect influences
18928  
18929			for ( var i = 0; i < length; i ++ ) {
18930  
18931				var influence = influences[ i ];
18932  
18933				influence[ 0 ] = i;
18934				influence[ 1 ] = objectInfluences[ i ];
18935  
18936			}
18937  
18938			influences.sort( absNumericalSort );
18939  
18940			// Add morphAttributes
18941  
18942			for ( var i = 0; i < 8; i ++ ) {
18943  
18944				var influence = influences[ i ];
18945  
18946				if ( influence ) {
18947  
18948					var index = influence[ 0 ];
18949					var value = influence[ 1 ];
18950  
18951					if ( value ) {
18952  
18953						if ( morphTargets ) geometry.addAttribute( 'morphTarget' + i, morphTargets[ index ] );
18954						if ( morphNormals ) geometry.addAttribute( 'morphNormal' + i, morphNormals[ index ] );
18955  
18956						morphInfluences[ i ] = value;
18957						continue;
18958  
18959					}
18960  
18961				}
18962  
18963				morphInfluences[ i ] = 0;
18964  
18965			}
18966  
18967			program.getUniforms().setValue( gl, 'morphTargetInfluences', morphInfluences );
18968  
18969		}
18970  
18971		return {
18972  
18973			update: update
18974  
18975		};
18976  
18977	}
18978  
18979	/**
18980	 * @author mrdoob / http://mrdoob.com/
18981	 */
18982  
18983	function WebGLObjects( geometries, info ) {
18984  
18985		var updateList = {};
18986  
18987		function update( object ) {
18988  
18989			var frame = info.render.frame;
18990  
18991			var geometry = object.geometry;
18992			var buffergeometry = geometries.get( object, geometry );
18993  
18994			// Update once per frame
18995  
18996			if ( updateList[ buffergeometry.id ] !== frame ) {
18997  
18998				if ( geometry.isGeometry ) {
18999  
19000					buffergeometry.updateFromObject( object );
19001  
19002				}
19003  
19004				geometries.update( buffergeometry );
19005  
19006				updateList[ buffergeometry.id ] = frame;
19007  
19008			}
19009  
19010			return buffergeometry;
19011  
19012		}
19013  
19014		function dispose() {
19015  
19016			updateList = {};
19017  
19018		}
19019  
19020		return {
19021  
19022			update: update,
19023			dispose: dispose
19024  
19025		};
19026  
19027	}
19028  
19029	/**
19030	 * @author mrdoob / http://mrdoob.com/
19031	 */
19032  
19033	function CubeTexture( images, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding ) {
19034  
19035		images = images !== undefined ? images : [];
19036		mapping = mapping !== undefined ? mapping : CubeReflectionMapping;
19037  
19038		Texture.call( this, images, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding );
19039  
19040		this.flipY = false;
19041  
19042	}
19043  
19044	CubeTexture.prototype = Object.create( Texture.prototype );
19045	CubeTexture.prototype.constructor = CubeTexture;
19046  
19047	CubeTexture.prototype.isCubeTexture = true;
19048  
19049	Object.defineProperty( CubeTexture.prototype, 'images', {
19050  
19051		get: function () {
19052  
19053			return this.image;
19054  
19055		},
19056  
19057		set: function ( value ) {
19058  
19059			this.image = value;
19060  
19061		}
19062  
19063	} );
19064  
19065	/**
19066	 * @author tschw
19067	 *
19068	 * Uniforms of a program.
19069	 * Those form a tree structure with a special top-level container for the root,
19070	 * which you get by calling 'new WebGLUniforms( gl, program, renderer )'.
19071	 *
19072	 *
19073	 * Properties of inner nodes including the top-level container:
19074	 *
19075	 * .seq - array of nested uniforms
19076	 * .map - nested uniforms by name
19077	 *
19078	 *
19079	 * Methods of all nodes except the top-level container:
19080	 *
19081	 * .setValue( gl, value, [renderer] )
19082	 *
19083	 * 		uploads a uniform value(s)
19084	 *  	the 'renderer' parameter is needed for sampler uniforms
19085	 *
19086	 *
19087	 * Static methods of the top-level container (renderer factorizations):
19088	 *
19089	 * .upload( gl, seq, values, renderer )
19090	 *
19091	 * 		sets uniforms in 'seq' to 'values[id].value'
19092	 *
19093	 * .seqWithValue( seq, values ) : filteredSeq
19094	 *
19095	 * 		filters 'seq' entries with corresponding entry in values
19096	 *
19097	 *
19098	 * Methods of the top-level container (renderer factorizations):
19099	 *
19100	 * .setValue( gl, name, value )
19101	 *
19102	 * 		sets uniform with  name 'name' to 'value'
19103	 *
19104	 * .set( gl, obj, prop )
19105	 *
19106	 * 		sets uniform from object and property with same name than uniform
19107	 *
19108	 * .setOptional( gl, obj, prop )
19109	 *
19110	 * 		like .set for an optional property of the object
19111	 *
19112	 */
19113  
19114	var emptyTexture = new Texture();
19115	var emptyCubeTexture = new CubeTexture();
19116  
19117	// --- Base for inner nodes (including the root) ---
19118  
19119	function UniformContainer() {
19120  
19121		this.seq = [];
19122		this.map = {};
19123  
19124	}
19125  
19126	// --- Utilities ---
19127  
19128	// Array Caches (provide typed arrays for temporary by size)
19129  
19130	var arrayCacheF32 = [];
19131	var arrayCacheI32 = [];
19132  
19133	// Float32Array caches used for uploading Matrix uniforms
19134  
19135	var mat4array = new Float32Array( 16 );
19136	var mat3array = new Float32Array( 9 );
19137	var mat2array = new Float32Array( 4 );
19138  
19139	// Flattening for arrays of vectors and matrices
19140  
19141	function flatten( array, nBlocks, blockSize ) {
19142  
19143		var firstElem = array[ 0 ];
19144  
19145		if ( firstElem <= 0 || firstElem > 0 ) return array;
19146		// unoptimized: ! isNaN( firstElem )
19147		// see http://jacksondunstan.com/articles/983
19148  
19149		var n = nBlocks * blockSize,
19150			r = arrayCacheF32[ n ];
19151  
19152		if ( r === undefined ) {
19153  
19154			r = new Float32Array( n );
19155			arrayCacheF32[ n ] = r;
19156  
19157		}
19158  
19159		if ( nBlocks !== 0 ) {
19160  
19161			firstElem.toArray( r, 0 );
19162  
19163			for ( var i = 1, offset = 0; i !== nBlocks; ++ i ) {
19164  
19165				offset += blockSize;
19166				array[ i ].toArray( r, offset );
19167  
19168			}
19169  
19170		}
19171  
19172		return r;
19173  
19174	}
19175  
19176	function arraysEqual( a, b ) {
19177  
19178		if ( a.length !== b.length ) return false;
19179  
19180		for ( var i = 0, l = a.length; i < l; i ++ ) {
19181  
19182			if ( a[ i ] !== b[ i ] ) return false;
19183  
19184		}
19185  
19186		return true;
19187  
19188	}
19189  
19190	function copyArray( a, b ) {
19191  
19192		for ( var i = 0, l = b.length; i < l; i ++ ) {
19193  
19194			a[ i ] = b[ i ];
19195  
19196		}
19197  
19198	}
19199  
19200	// Texture unit allocation
19201  
19202	function allocTexUnits( renderer, n ) {
19203  
19204		var r = arrayCacheI32[ n ];
19205  
19206		if ( r === undefined ) {
19207  
19208			r = new Int32Array( n );
19209			arrayCacheI32[ n ] = r;
19210  
19211		}
19212  
19213		for ( var i = 0; i !== n; ++ i )
19214			r[ i ] = renderer.allocTextureUnit();
19215  
19216		return r;
19217  
19218	}
19219  
19220	// --- Setters ---
19221  
19222	// Note: Defining these methods externally, because they come in a bunch
19223	// and this way their names minify.
19224  
19225	// Single scalar
19226  
19227	function setValue1f( gl, v ) {
19228  
19229		var cache = this.cache;
19230  
19231		if ( cache[ 0 ] === v ) return;
19232  
19233		gl.uniform1f( this.addr, v );
19234  
19235		cache[ 0 ] = v;
19236  
19237	}
19238  
19239	function setValue1i( gl, v ) {
19240  
19241		var cache = this.cache;
19242  
19243		if ( cache[ 0 ] === v ) return;
19244  
19245		gl.uniform1i( this.addr, v );
19246  
19247		cache[ 0 ] = v;
19248  
19249	}
19250  
19251	// Single float vector (from flat array or THREE.VectorN)
19252  
19253	function setValue2fv( gl, v ) {
19254  
19255		var cache = this.cache;
19256  
19257		if ( v.x !== undefined ) {
19258  
19259			if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y ) {
19260  
19261				gl.uniform2f( this.addr, v.x, v.y );
19262  
19263				cache[ 0 ] = v.x;
19264				cache[ 1 ] = v.y;
19265  
19266			}
19267  
19268		} else {
19269  
19270			if ( arraysEqual( cache, v ) ) return;
19271  
19272			gl.uniform2fv( this.addr, v );
19273  
19274			copyArray( cache, v );
19275  
19276		}
19277  
19278	}
19279  
19280	function setValue3fv( gl, v ) {
19281  
19282		var cache = this.cache;
19283  
19284		if ( v.x !== undefined ) {
19285  
19286			if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y || cache[ 2 ] !== v.z ) {
19287  
19288				gl.uniform3f( this.addr, v.x, v.y, v.z );
19289  
19290				cache[ 0 ] = v.x;
19291				cache[ 1 ] = v.y;
19292				cache[ 2 ] = v.z;
19293  
19294			}
19295  
19296		} else if ( v.r !== undefined ) {
19297  
19298			if ( cache[ 0 ] !== v.r || cache[ 1 ] !== v.g || cache[ 2 ] !== v.b ) {
19299  
19300				gl.uniform3f( this.addr, v.r, v.g, v.b );
19301  
19302				cache[ 0 ] = v.r;
19303				cache[ 1 ] = v.g;
19304				cache[ 2 ] = v.b;
19305  
19306			}
19307  
19308		} else {
19309  
19310			if ( arraysEqual( cache, v ) ) return;
19311  
19312			gl.uniform3fv( this.addr, v );
19313  
19314			copyArray( cache, v );
19315  
19316		}
19317  
19318	}
19319  
19320	function setValue4fv( gl, v ) {
19321  
19322		var cache = this.cache;
19323  
19324		if ( v.x !== undefined ) {
19325  
19326			if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y || cache[ 2 ] !== v.z || cache[ 3 ] !== v.w ) {
19327  
19328				gl.uniform4f( this.addr, v.x, v.y, v.z, v.w );
19329  
19330				cache[ 0 ] = v.x;
19331				cache[ 1 ] = v.y;
19332				cache[ 2 ] = v.z;
19333				cache[ 3 ] = v.w;
19334  
19335			}
19336  
19337		} else {
19338  
19339			if ( arraysEqual( cache, v ) ) return;
19340  
19341			gl.uniform4fv( this.addr, v );
19342  
19343			copyArray( cache, v );
19344  
19345		}
19346  
19347	}
19348  
19349	// Single matrix (from flat array or MatrixN)
19350  
19351	function setValue2fm( gl, v ) {
19352  
19353		var cache = this.cache;
19354		var elements = v.elements;
19355  
19356		if ( elements === undefined ) {
19357  
19358			if ( arraysEqual( cache, v ) ) return;
19359  
19360			gl.uniformMatrix2fv( this.addr, false, v );
19361  
19362			copyArray( cache, v );
19363  
19364		} else {
19365  
19366			if ( arraysEqual( cache, elements ) ) return;
19367  
19368			mat2array.set( elements );
19369  
19370			gl.uniformMatrix2fv( this.addr, false, mat2array );
19371  
19372			copyArray( cache, elements );
19373  
19374		}
19375  
19376	}
19377  
19378	function setValue3fm( gl, v ) {
19379  
19380		var cache = this.cache;
19381		var elements = v.elements;
19382  
19383		if ( elements === undefined ) {
19384  
19385			if ( arraysEqual( cache, v ) ) return;
19386  
19387			gl.uniformMatrix3fv( this.addr, false, v );
19388  
19389			copyArray( cache, v );
19390  
19391		} else {
19392  
19393			if ( arraysEqual( cache, elements ) ) return;
19394  
19395			mat3array.set( elements );
19396  
19397			gl.uniformMatrix3fv( this.addr, false, mat3array );
19398  
19399			copyArray( cache, elements );
19400  
19401		}
19402  
19403	}
19404  
19405	function setValue4fm( gl, v ) {
19406  
19407		var cache = this.cache;
19408		var elements = v.elements;
19409  
19410		if ( elements === undefined ) {
19411  
19412			if ( arraysEqual( cache, v ) ) return;
19413  
19414			gl.uniformMatrix4fv( this.addr, false, v );
19415  
19416			copyArray( cache, v );
19417  
19418		} else {
19419  
19420			if ( arraysEqual( cache, elements ) ) return;
19421  
19422			mat4array.set( elements );
19423  
19424			gl.uniformMatrix4fv( this.addr, false, mat4array );
19425  
19426			copyArray( cache, elements );
19427  
19428		}
19429  
19430	}
19431  
19432	// Single texture (2D / Cube)
19433  
19434	function setValueT1( gl, v, renderer ) {
19435  
19436		var cache = this.cache;
19437		var unit = renderer.allocTextureUnit();
19438  
19439		if ( cache[ 0 ] !== unit ) {
19440  
19441			gl.uniform1i( this.addr, unit );
19442			cache[ 0 ] = unit;
19443  
19444		}
19445  
19446		renderer.setTexture2D( v || emptyTexture, unit );
19447  
19448	}
19449  
19450	function setValueT6( gl, v, renderer ) {
19451  
19452		var cache = this.cache;
19453		var unit = renderer.allocTextureUnit();
19454  
19455		if ( cache[ 0 ] !== unit ) {
19456  
19457			gl.uniform1i( this.addr, unit );
19458			cache[ 0 ] = unit;
19459  
19460		}
19461  
19462		renderer.setTextureCube( v || emptyCubeTexture, unit );
19463  
19464	}
19465  
19466	// Integer / Boolean vectors or arrays thereof (always flat arrays)
19467  
19468	function setValue2iv( gl, v ) {
19469  
19470		var cache = this.cache;
19471  
19472		if ( arraysEqual( cache, v ) ) return;
19473  
19474		gl.uniform2iv( this.addr, v );
19475  
19476		copyArray( cache, v );
19477  
19478	}
19479  
19480	function setValue3iv( gl, v ) {
19481  
19482		var cache = this.cache;
19483  
19484		if ( arraysEqual( cache, v ) ) return;
19485  
19486		gl.uniform3iv( this.addr, v );
19487  
19488		copyArray( cache, v );
19489  
19490	}
19491  
19492	function setValue4iv( gl, v ) {
19493  
19494		var cache = this.cache;
19495  
19496		if ( arraysEqual( cache, v ) ) return;
19497  
19498		gl.uniform4iv( this.addr, v );
19499  
19500		copyArray( cache, v );
19501  
19502	}
19503  
19504	// Helper to pick the right setter for the singular case
19505  
19506	function getSingularSetter( type ) {
19507  
19508		switch ( type ) {
19509  
19510			case 0x1406: return setValue1f; // FLOAT
19511			case 0x8b50: return setValue2fv; // _VEC2
19512			case 0x8b51: return setValue3fv; // _VEC3
19513			case 0x8b52: return setValue4fv; // _VEC4
19514  
19515			case 0x8b5a: return setValue2fm; // _MAT2
19516			case 0x8b5b: return setValue3fm; // _MAT3
19517			case 0x8b5c: return setValue4fm; // _MAT4
19518  
19519			case 0x8b5e: case 0x8d66: return setValueT1; // SAMPLER_2D, SAMPLER_EXTERNAL_OES
19520			case 0x8b60: return setValueT6; // SAMPLER_CUBE
19521  
19522			case 0x1404: case 0x8b56: return setValue1i; // INT, BOOL
19523			case 0x8b53: case 0x8b57: return setValue2iv; // _VEC2
19524			case 0x8b54: case 0x8b58: return setValue3iv; // _VEC3
19525			case 0x8b55: case 0x8b59: return setValue4iv; // _VEC4
19526  
19527		}
19528  
19529	}
19530  
19531	// Array of scalars
19532  
19533	function setValue1fv( gl, v ) {
19534  
19535		var cache = this.cache;
19536  
19537		if ( arraysEqual( cache, v ) ) return;
19538  
19539		gl.uniform1fv( this.addr, v );
19540  
19541		copyArray( cache, v );
19542  
19543	}
19544	function setValue1iv( gl, v ) {
19545  
19546		var cache = this.cache;
19547  
19548		if ( arraysEqual( cache, v ) ) return;
19549  
19550		gl.uniform1iv( this.addr, v );
19551  
19552		copyArray( cache, v );
19553  
19554	}
19555  
19556	// Array of vectors (flat or from THREE classes)
19557  
19558	function setValueV2a( gl, v ) {
19559  
19560		var cache = this.cache;
19561		var data = flatten( v, this.size, 2 );
19562  
19563		if ( arraysEqual( cache, data ) ) return;
19564  
19565		gl.uniform2fv( this.addr, data );
19566  
19567		this.updateCache( data );
19568  
19569	}
19570  
19571	function setValueV3a( gl, v ) {
19572  
19573		var cache = this.cache;
19574		var data = flatten( v, this.size, 3 );
19575  
19576		if ( arraysEqual( cache, data ) ) return;
19577  
19578		gl.uniform3fv( this.addr, data );
19579  
19580		this.updateCache( data );
19581  
19582	}
19583  
19584	function setValueV4a( gl, v ) {
19585  
19586		var cache = this.cache;
19587		var data = flatten( v, this.size, 4 );
19588  
19589		if ( arraysEqual( cache, data ) ) return;
19590  
19591		gl.uniform4fv( this.addr, data );
19592  
19593		this.updateCache( data );
19594  
19595	}
19596  
19597	// Array of matrices (flat or from THREE clases)
19598  
19599	function setValueM2a( gl, v ) {
19600  
19601		var cache = this.cache;
19602		var data = flatten( v, this.size, 4 );
19603  
19604		if ( arraysEqual( cache, data ) ) return;
19605  
19606		gl.uniformMatrix2fv( this.addr, false, data );
19607  
19608		this.updateCache( data );
19609  
19610	}
19611  
19612	function setValueM3a( gl, v ) {
19613  
19614		var cache = this.cache;
19615		var data = flatten( v, this.size, 9 );
19616  
19617		if ( arraysEqual( cache, data ) ) return;
19618  
19619		gl.uniformMatrix3fv( this.addr, false, data );
19620  
19621		this.updateCache( data );
19622  
19623	}
19624  
19625	function setValueM4a( gl, v ) {
19626  
19627		var cache = this.cache;
19628		var data = flatten( v, this.size, 16 );
19629  
19630		if ( arraysEqual( cache, data ) ) return;
19631  
19632		gl.uniformMatrix4fv( this.addr, false, data );
19633  
19634		this.updateCache( data );
19635  
19636	}
19637  
19638	// Array of textures (2D / Cube)
19639  
19640	function setValueT1a( gl, v, renderer ) {
19641  
19642		var cache = this.cache;
19643		var n = v.length;
19644  
19645		var units = allocTexUnits( renderer, n );
19646  
19647		if ( arraysEqual( cache, units ) === false ) {
19648  
19649			gl.uniform1iv( this.addr, units );
19650			copyArray( cache, units );
19651  
19652		}
19653  
19654		for ( var i = 0; i !== n; ++ i ) {
19655  
19656			renderer.setTexture2D( v[ i ] || emptyTexture, units[ i ] );
19657  
19658		}
19659  
19660	}
19661  
19662	function setValueT6a( gl, v, renderer ) {
19663  
19664		var cache = this.cache;
19665		var n = v.length;
19666  
19667		var units = allocTexUnits( renderer, n );
19668  
19669		if ( arraysEqual( cache, units ) === false ) {
19670  
19671			gl.uniform1iv( this.addr, units );
19672			copyArray( cache, units );
19673  
19674		}
19675  
19676		for ( var i = 0; i !== n; ++ i ) {
19677  
19678			renderer.setTextureCube( v[ i ] || emptyCubeTexture, units[ i ] );
19679  
19680		}
19681  
19682	}
19683  
19684	// Helper to pick the right setter for a pure (bottom-level) array
19685  
19686	function getPureArraySetter( type ) {
19687  
19688		switch ( type ) {
19689  
19690			case 0x1406: return setValue1fv; // FLOAT
19691			case 0x8b50: return setValueV2a; // _VEC2
19692			case 0x8b51: return setValueV3a; // _VEC3
19693			case 0x8b52: return setValueV4a; // _VEC4
19694  
19695			case 0x8b5a: return setValueM2a; // _MAT2
19696			case 0x8b5b: return setValueM3a; // _MAT3
19697			case 0x8b5c: return setValueM4a; // _MAT4
19698  
19699			case 0x8b5e: return setValueT1a; // SAMPLER_2D
19700			case 0x8b60: return setValueT6a; // SAMPLER_CUBE
19701  
19702			case 0x1404: case 0x8b56: return setValue1iv; // INT, BOOL
19703			case 0x8b53: case 0x8b57: return setValue2iv; // _VEC2
19704			case 0x8b54: case 0x8b58: return setValue3iv; // _VEC3
19705			case 0x8b55: case 0x8b59: return setValue4iv; // _VEC4
19706  
19707		}
19708  
19709	}
19710  
19711	// --- Uniform Classes ---
19712  
19713	function SingleUniform( id, activeInfo, addr ) {
19714  
19715		this.id = id;
19716		this.addr = addr;
19717		this.cache = [];
19718		this.setValue = getSingularSetter( activeInfo.type );
19719  
19720		// this.path = activeInfo.name; // DEBUG
19721  
19722	}
19723  
19724	function PureArrayUniform( id, activeInfo, addr ) {
19725  
19726		this.id = id;
19727		this.addr = addr;
19728		this.cache = [];
19729		this.size = activeInfo.size;
19730		this.setValue = getPureArraySetter( activeInfo.type );
19731  
19732		// this.path = activeInfo.name; // DEBUG
19733  
19734	}
19735  
19736	PureArrayUniform.prototype.updateCache = function ( data ) {
19737  
19738		var cache = this.cache;
19739  
19740		if ( data instanceof Float32Array && cache.length !== data.length ) {
19741  
19742			this.cache = new Float32Array( data.length );
19743  
19744		}
19745  
19746		copyArray( cache, data );
19747  
19748	};
19749  
19750	function StructuredUniform( id ) {
19751  
19752		this.id = id;
19753  
19754		UniformContainer.call( this ); // mix-in
19755  
19756	}
19757  
19758	StructuredUniform.prototype.setValue = function ( gl, value ) {
19759  
19760		// Note: Don't need an extra 'renderer' parameter, since samplers
19761		// are not allowed in structured uniforms.
19762  
19763		var seq = this.seq;
19764  
19765		for ( var i = 0, n = seq.length; i !== n; ++ i ) {
19766  
19767			var u = seq[ i ];
19768			u.setValue( gl, value[ u.id ] );
19769  
19770		}
19771  
19772	};
19773  
19774	// --- Top-level ---
19775  
19776	// Parser - builds up the property tree from the path strings
19777  
19778	var RePathPart = /([\w\d_]+)(\])?(\[|\.)?/g;
19779  
19780	// extracts
19781	// 	- the identifier (member name or array index)
19782	//  - followed by an optional right bracket (found when array index)
19783	//  - followed by an optional left bracket or dot (type of subscript)
19784	//
19785	// Note: These portions can be read in a non-overlapping fashion and
19786	// allow straightforward parsing of the hierarchy that WebGL encodes
19787	// in the uniform names.
19788  
19789	function addUniform( container, uniformObject ) {
19790  
19791		container.seq.push( uniformObject );
19792		container.map[ uniformObject.id ] = uniformObject;
19793  
19794	}
19795  
19796	function parseUniform( activeInfo, addr, container ) {
19797  
19798		var path = activeInfo.name,
19799			pathLength = path.length;
19800  
19801		// reset RegExp object, because of the early exit of a previous run
19802		RePathPart.lastIndex = 0;
19803  
19804		while ( true ) {
19805  
19806			var match = RePathPart.exec( path ),
19807				matchEnd = RePathPart.lastIndex,
19808  
19809				id = match[ 1 ],
19810				idIsIndex = match[ 2 ] === ']',
19811				subscript = match[ 3 ];
19812  
19813			if ( idIsIndex ) id = id | 0; // convert to integer
19814  
19815			if ( subscript === undefined || subscript === '[' && matchEnd + 2 === pathLength ) {
19816  
19817				// bare name or "pure" bottom-level array "[0]" suffix
19818  
19819				addUniform( container, subscript === undefined ?
19820					new SingleUniform( id, activeInfo, addr ) :
19821					new PureArrayUniform( id, activeInfo, addr ) );
19822  
19823				break;
19824  
19825			} else {
19826  
vendor: 6,229 bytes, lines 19827-20102
19827				// step into inner node / create it in case it doesn't exist
19828  
19829				var map = container.map, next = map[ id ];
19830  
19831				if ( next === undefined ) {
19832  
19833					next = new StructuredUniform( id );
19834					addUniform( container, next );
19835  
19836				}
19837  
19838				container = next;
19839  
19840			}
19841  
19842		}
19843  
19844	}
19845  
19846	// Root Container
19847  
19848	function WebGLUniforms( gl, program, renderer ) {
19849  
19850		UniformContainer.call( this );
19851  
19852		this.renderer = renderer;
19853  
19854		var n = gl.getProgramParameter( program, gl.ACTIVE_UNIFORMS );
19855  
19856		for ( var i = 0; i < n; ++ i ) {
19857  
19858			var info = gl.getActiveUniform( program, i ),
19859				addr = gl.getUniformLocation( program, info.name );
19860  
19861			parseUniform( info, addr, this );
19862  
19863		}
19864  
19865	}
19866  
19867	WebGLUniforms.prototype.setValue = function ( gl, name, value ) {
19868  
19869		var u = this.map[ name ];
19870  
19871		if ( u !== undefined ) u.setValue( gl, value, this.renderer );
19872  
19873	};
19874  
19875	WebGLUniforms.prototype.setOptional = function ( gl, object, name ) {
19876  
19877		var v = object[ name ];
19878  
19879		if ( v !== undefined ) this.setValue( gl, name, v );
19880  
19881	};
19882  
19883  
19884	// Static interface
19885  
19886	WebGLUniforms.upload = function ( gl, seq, values, renderer ) {
19887  
19888		for ( var i = 0, n = seq.length; i !== n; ++ i ) {
19889  
19890			var u = seq[ i ],
19891				v = values[ u.id ];
19892  
19893			if ( v.needsUpdate !== false ) {
19894  
19895				// note: always updating when .needsUpdate is undefined
19896				u.setValue( gl, v.value, renderer );
19897  
19898			}
19899  
19900		}
19901  
19902	};
19903  
19904	WebGLUniforms.seqWithValue = function ( seq, values ) {
19905  
19906		var r = [];
19907  
19908		for ( var i = 0, n = seq.length; i !== n; ++ i ) {
19909  
19910			var u = seq[ i ];
19911			if ( u.id in values ) r.push( u );
19912  
19913		}
19914  
19915		return r;
19916  
19917	};
19918  
19919	/**
19920	 * @author mrdoob / http://mrdoob.com/
19921	 */
19922  
19923	function addLineNumbers( string ) {
19924  
19925		var lines = string.split( '\n' );
19926  
19927		for ( var i = 0; i < lines.length; i ++ ) {
19928  
19929			lines[ i ] = ( i + 1 ) + ': ' + lines[ i ];
19930  
19931		}
19932  
19933		return lines.join( '\n' );
19934  
19935	}
19936  
19937	function WebGLShader( gl, type, string ) {
19938  
19939		var shader = gl.createShader( type );
19940  
19941		gl.shaderSource( shader, string );
19942		gl.compileShader( shader );
19943  
19944		if ( gl.getShaderParameter( shader, gl.COMPILE_STATUS ) === false ) {
19945  
19946			console.error( 'THREE.WebGLShader: Shader couldn\'t compile.' );
19947  
19948		}
19949  
19950		if ( gl.getShaderInfoLog( shader ) !== '' ) {
19951  
19952			console.warn( 'THREE.WebGLShader: gl.getShaderInfoLog()', type === gl.VERTEX_SHADER ? 'vertex' : 'fragment', gl.getShaderInfoLog( shader ), addLineNumbers( string ) );
19953  
19954		}
19955  
19956		// --enable-privileged-webgl-extension
19957		// console.log( type, gl.getExtension( 'WEBGL_debug_shaders' ).getTranslatedShaderSource( shader ) );
19958  
19959		return shader;
19960  
19961	}
19962  
19963	/**
19964	 * @author mrdoob / http://mrdoob.com/
19965	 */
19966  
19967	var programIdCount = 0;
19968  
19969	function getEncodingComponents( encoding ) {
19970  
19971		switch ( encoding ) {
19972  
19973			case LinearEncoding:
19974				return [ 'Linear', '( value )' ];
19975			case sRGBEncoding:
19976				return [ 'sRGB', '( value )' ];
19977			case RGBEEncoding:
19978				return [ 'RGBE', '( value )' ];
19979			case RGBM7Encoding:
19980				return [ 'RGBM', '( value, 7.0 )' ];
19981			case RGBM16Encoding:
19982				return [ 'RGBM', '( value, 16.0 )' ];
19983			case RGBDEncoding:
19984				return [ 'RGBD', '( value, 256.0 )' ];
19985			case GammaEncoding:
19986				return [ 'Gamma', '( value, float( GAMMA_FACTOR ) )' ];
19987			default:
19988				throw new Error( 'unsupported encoding: ' + encoding );
19989  
19990		}
19991  
19992	}
19993  
19994	function getTexelDecodingFunction( functionName, encoding ) {
19995  
19996		var components = getEncodingComponents( encoding );
19997		return 'vec4 ' + functionName + '( vec4 value ) { return ' + components[ 0 ] + 'ToLinear' + components[ 1 ] + '; }';
19998  
19999	}
20000  
20001	function getTexelEncodingFunction( functionName, encoding ) {
20002  
20003		var components = getEncodingComponents( encoding );
20004		return 'vec4 ' + functionName + '( vec4 value ) { return LinearTo' + components[ 0 ] + components[ 1 ] + '; }';
20005  
20006	}
20007  
20008	function getToneMappingFunction( functionName, toneMapping ) {
20009  
20010		var toneMappingName;
20011  
20012		switch ( toneMapping ) {
20013  
20014			case LinearToneMapping:
20015				toneMappingName = 'Linear';
20016				break;
20017  
20018			case ReinhardToneMapping:
20019				toneMappingName = 'Reinhard';
20020				break;
20021  
20022			case Uncharted2ToneMapping:
20023				toneMappingName = 'Uncharted2';
20024				break;
20025  
20026			case CineonToneMapping:
20027				toneMappingName = 'OptimizedCineon';
20028				break;
20029  
20030			default:
20031				throw new Error( 'unsupported toneMapping: ' + toneMapping );
20032  
20033		}
20034  
20035		return 'vec3 ' + functionName + '( vec3 color ) { return ' + toneMappingName + 'ToneMapping( color ); }';
20036  
20037	}
20038  
20039	function generateExtensions( extensions, parameters, rendererExtensions ) {
20040  
20041		extensions = extensions || {};
20042  
20043		var chunks = [
20044			( extensions.derivatives || parameters.envMapCubeUV || parameters.bumpMap || parameters.normalMap || parameters.flatShading ) ? '#extension GL_OES_standard_derivatives : enable' : '',
20045			( extensions.fragDepth || parameters.logarithmicDepthBuffer ) && rendererExtensions.get( 'EXT_frag_depth' ) ? '#extension GL_EXT_frag_depth : enable' : '',
20046			( extensions.drawBuffers ) && rendererExtensions.get( 'WEBGL_draw_buffers' ) ? '#extension GL_EXT_draw_buffers : require' : '',
20047			( extensions.shaderTextureLOD || parameters.envMap ) && rendererExtensions.get( 'EXT_shader_texture_lod' ) ? '#extension GL_EXT_shader_texture_lod : enable' : ''
20048		];
20049  
20050		return chunks.filter( filterEmptyLine ).join( '\n' );
20051  
20052	}
20053  
20054	function generateDefines( defines ) {
20055  
20056		var chunks = [];
20057  
20058		for ( var name in defines ) {
20059  
20060			var value = defines[ name ];
20061  
20062			if ( value === false ) continue;
20063  
20064			chunks.push( '#define ' + name + ' ' + value );
20065  
20066		}
20067  
20068		return chunks.join( '\n' );
20069  
20070	}
20071  
20072	function fetchAttributeLocations( gl, program ) {
20073  
20074		var attributes = {};
20075  
20076		var n = gl.getProgramParameter( program, gl.ACTIVE_ATTRIBUTES );
20077  
20078		for ( var i = 0; i < n; i ++ ) {
20079  
20080			var info = gl.getActiveAttrib( program, i );
20081			var name = info.name;
20082  
20083			// console.log( 'THREE.WebGLProgram: ACTIVE VERTEX ATTRIBUTE:', name, i );
20084  
20085			attributes[ name ] = gl.getAttribLocation( program, name );
20086  
20087		}
20088  
20089		return attributes;
20090  
20091	}
20092  
20093	function filterEmptyLine( string ) {
20094  
20095		return string !== '';
20096  
20097	}
20098  
20099	function replaceLightNums( string, parameters ) {
20100  
20101		return string
20102			.replace( /NUM_DIR_LIGHTS/g, parameters.numDirLights )
vendor: 12,929 bytes, lines 20103-20513
20103			.replace( /NUM_SPOT_LIGHTS/g, parameters.numSpotLights )
20104			.replace( /NUM_RECT_AREA_LIGHTS/g, parameters.numRectAreaLights )
20105			.replace( /NUM_POINT_LIGHTS/g, parameters.numPointLights )
20106			.replace( /NUM_HEMI_LIGHTS/g, parameters.numHemiLights );
20107  
20108	}
20109  
20110	function replaceClippingPlaneNums( string, parameters ) {
20111  
20112		return string
20113			.replace( /NUM_CLIPPING_PLANES/g, parameters.numClippingPlanes )
20114			.replace( /UNION_CLIPPING_PLANES/g, ( parameters.numClippingPlanes - parameters.numClipIntersection ) );
20115  
20116	}
20117  
20118	function parseIncludes( string ) {
20119  
20120		var pattern = /^[ \t]*#include +<([\w\d.]+)>/gm;
20121  
20122		function replace( match, include ) {
20123  
20124			var replace = ShaderChunk[ include ];
20125  
20126			if ( replace === undefined ) {
20127  
20128				throw new Error( 'Can not resolve #include <' + include + '>' );
20129  
20130			}
20131  
20132			return parseIncludes( replace );
20133  
20134		}
20135  
20136		return string.replace( pattern, replace );
20137  
20138	}
20139  
20140	function unrollLoops( string ) {
20141  
20142		var pattern = /#pragma unroll_loop[\s]+?for \( int i \= (\d+)\; i < (\d+)\; i \+\+ \) \{([\s\S]+?)(?=\})\}/g;
20143  
20144		function replace( match, start, end, snippet ) {
20145  
20146			var unroll = '';
20147  
20148			for ( var i = parseInt( start ); i < parseInt( end ); i ++ ) {
20149  
20150				unroll += snippet.replace( /\[ i \]/g, '[ ' + i + ' ]' );
20151  
20152			}
20153  
20154			return unroll;
20155  
20156		}
20157  
20158		return string.replace( pattern, replace );
20159  
20160	}
20161  
20162	function WebGLProgram( renderer, extensions, code, material, shader, parameters ) {
20163  
20164		var gl = renderer.context;
20165  
20166		var defines = material.defines;
20167  
20168		var vertexShader = shader.vertexShader;
20169		var fragmentShader = shader.fragmentShader;
20170  
20171		var shadowMapTypeDefine = 'SHADOWMAP_TYPE_BASIC';
20172  
20173		if ( parameters.shadowMapType === PCFShadowMap ) {
20174  
20175			shadowMapTypeDefine = 'SHADOWMAP_TYPE_PCF';
20176  
20177		} else if ( parameters.shadowMapType === PCFSoftShadowMap ) {
20178  
20179			shadowMapTypeDefine = 'SHADOWMAP_TYPE_PCF_SOFT';
20180  
20181		}
20182  
20183		var envMapTypeDefine = 'ENVMAP_TYPE_CUBE';
20184		var envMapModeDefine = 'ENVMAP_MODE_REFLECTION';
20185		var envMapBlendingDefine = 'ENVMAP_BLENDING_MULTIPLY';
20186  
20187		if ( parameters.envMap ) {
20188  
20189			switch ( material.envMap.mapping ) {
20190  
20191				case CubeReflectionMapping:
20192				case CubeRefractionMapping:
20193					envMapTypeDefine = 'ENVMAP_TYPE_CUBE';
20194					break;
20195  
20196				case CubeUVReflectionMapping:
20197				case CubeUVRefractionMapping:
20198					envMapTypeDefine = 'ENVMAP_TYPE_CUBE_UV';
20199					break;
20200  
20201				case EquirectangularReflectionMapping:
20202				case EquirectangularRefractionMapping:
20203					envMapTypeDefine = 'ENVMAP_TYPE_EQUIREC';
20204					break;
20205  
20206				case SphericalReflectionMapping:
20207					envMapTypeDefine = 'ENVMAP_TYPE_SPHERE';
20208					break;
20209  
20210			}
20211  
20212			switch ( material.envMap.mapping ) {
20213  
20214				case CubeRefractionMapping:
20215				case EquirectangularRefractionMapping:
20216					envMapModeDefine = 'ENVMAP_MODE_REFRACTION';
20217					break;
20218  
20219			}
20220  
20221			switch ( material.combine ) {
20222  
20223				case MultiplyOperation:
20224					envMapBlendingDefine = 'ENVMAP_BLENDING_MULTIPLY';
20225					break;
20226  
20227				case MixOperation:
20228					envMapBlendingDefine = 'ENVMAP_BLENDING_MIX';
20229					break;
20230  
20231				case AddOperation:
20232					envMapBlendingDefine = 'ENVMAP_BLENDING_ADD';
20233					break;
20234  
20235			}
20236  
20237		}
20238  
20239		var gammaFactorDefine = ( renderer.gammaFactor > 0 ) ? renderer.gammaFactor : 1.0;
20240  
20241		// console.log( 'building new program ' );
20242  
20243		//
20244  
20245		var customExtensions = generateExtensions( material.extensions, parameters, extensions );
20246  
20247		var customDefines = generateDefines( defines );
20248  
20249		//
20250  
20251		var program = gl.createProgram();
20252  
20253		var prefixVertex, prefixFragment;
20254  
20255		if ( material.isRawShaderMaterial ) {
20256  
20257			prefixVertex = [
20258  
20259				customDefines
20260  
20261			].filter( filterEmptyLine ).join( '\n' );
20262  
20263			if ( prefixVertex.length > 0 ) {
20264  
20265				prefixVertex += '\n';
20266  
20267			}
20268  
20269			prefixFragment = [
20270  
20271				customExtensions,
20272				customDefines
20273  
20274			].filter( filterEmptyLine ).join( '\n' );
20275  
20276			if ( prefixFragment.length > 0 ) {
20277  
20278				prefixFragment += '\n';
20279  
20280			}
20281  
20282		} else {
20283  
20284			prefixVertex = [
20285  
20286				'precision ' + parameters.precision + ' float;',
20287				'precision ' + parameters.precision + ' int;',
20288  
20289				'#define SHADER_NAME ' + shader.name,
20290  
20291				customDefines,
20292  
20293				parameters.supportsVertexTextures ? '#define VERTEX_TEXTURES' : '',
20294  
20295				'#define GAMMA_FACTOR ' + gammaFactorDefine,
20296  
20297				'#define MAX_BONES ' + parameters.maxBones,
20298				( parameters.useFog && parameters.fog ) ? '#define USE_FOG' : '',
20299				( parameters.useFog && parameters.fogExp ) ? '#define FOG_EXP2' : '',
20300  
20301				parameters.map ? '#define USE_MAP' : '',
20302				parameters.envMap ? '#define USE_ENVMAP' : '',
20303				parameters.envMap ? '#define ' + envMapModeDefine : '',
20304				parameters.lightMap ? '#define USE_LIGHTMAP' : '',
20305				parameters.aoMap ? '#define USE_AOMAP' : '',
20306				parameters.emissiveMap ? '#define USE_EMISSIVEMAP' : '',
20307				parameters.bumpMap ? '#define USE_BUMPMAP' : '',
20308				parameters.normalMap ? '#define USE_NORMALMAP' : '',
20309				parameters.displacementMap && parameters.supportsVertexTextures ? '#define USE_DISPLACEMENTMAP' : '',
20310				parameters.specularMap ? '#define USE_SPECULARMAP' : '',
20311				parameters.roughnessMap ? '#define USE_ROUGHNESSMAP' : '',
20312				parameters.metalnessMap ? '#define USE_METALNESSMAP' : '',
20313				parameters.alphaMap ? '#define USE_ALPHAMAP' : '',
20314				parameters.vertexColors ? '#define USE_COLOR' : '',
20315  
20316				parameters.flatShading ? '#define FLAT_SHADED' : '',
20317  
20318				parameters.skinning ? '#define USE_SKINNING' : '',
20319				parameters.useVertexTexture ? '#define BONE_TEXTURE' : '',
20320  
20321				parameters.morphTargets ? '#define USE_MORPHTARGETS' : '',
20322				parameters.morphNormals && parameters.flatShading === false ? '#define USE_MORPHNORMALS' : '',
20323				parameters.doubleSided ? '#define DOUBLE_SIDED' : '',
20324				parameters.flipSided ? '#define FLIP_SIDED' : '',
20325  
20326				parameters.shadowMapEnabled ? '#define USE_SHADOWMAP' : '',
20327				parameters.shadowMapEnabled ? '#define ' + shadowMapTypeDefine : '',
20328  
20329				parameters.sizeAttenuation ? '#define USE_SIZEATTENUATION' : '',
20330  
20331				parameters.logarithmicDepthBuffer ? '#define USE_LOGDEPTHBUF' : '',
20332				parameters.logarithmicDepthBuffer && extensions.get( 'EXT_frag_depth' ) ? '#define USE_LOGDEPTHBUF_EXT' : '',
20333  
20334				'uniform mat4 modelMatrix;',
20335				'uniform mat4 modelViewMatrix;',
20336				'uniform mat4 projectionMatrix;',
20337				'uniform mat4 viewMatrix;',
20338				'uniform mat3 normalMatrix;',
20339				'uniform vec3 cameraPosition;',
20340  
20341				'attribute vec3 position;',
20342				'attribute vec3 normal;',
20343				'attribute vec2 uv;',
20344  
20345				'#ifdef USE_COLOR',
20346  
20347				'	attribute vec3 color;',
20348  
20349				'#endif',
20350  
20351				'#ifdef USE_MORPHTARGETS',
20352  
20353				'	attribute vec3 morphTarget0;',
20354				'	attribute vec3 morphTarget1;',
20355				'	attribute vec3 morphTarget2;',
20356				'	attribute vec3 morphTarget3;',
20357  
20358				'	#ifdef USE_MORPHNORMALS',
20359  
20360				'		attribute vec3 morphNormal0;',
20361				'		attribute vec3 morphNormal1;',
20362				'		attribute vec3 morphNormal2;',
20363				'		attribute vec3 morphNormal3;',
20364  
20365				'	#else',
20366  
20367				'		attribute vec3 morphTarget4;',
20368				'		attribute vec3 morphTarget5;',
20369				'		attribute vec3 morphTarget6;',
20370				'		attribute vec3 morphTarget7;',
20371  
20372				'	#endif',
20373  
20374				'#endif',
20375  
20376				'#ifdef USE_SKINNING',
20377  
20378				'	attribute vec4 skinIndex;',
20379				'	attribute vec4 skinWeight;',
20380  
20381				'#endif',
20382  
20383				'\n'
20384  
20385			].filter( filterEmptyLine ).join( '\n' );
20386  
20387			prefixFragment = [
20388  
20389				customExtensions,
20390  
20391				'precision ' + parameters.precision + ' float;',
20392				'precision ' + parameters.precision + ' int;',
20393  
20394				'#define SHADER_NAME ' + shader.name,
20395  
20396				customDefines,
20397  
20398				parameters.alphaTest ? '#define ALPHATEST ' + parameters.alphaTest + ( parameters.alphaTest % 1 ? '' : '.0' ) : '', // add '.0' if integer
20399  
20400				'#define GAMMA_FACTOR ' + gammaFactorDefine,
20401  
20402				( parameters.useFog && parameters.fog ) ? '#define USE_FOG' : '',
20403				( parameters.useFog && parameters.fogExp ) ? '#define FOG_EXP2' : '',
20404  
20405				parameters.map ? '#define USE_MAP' : '',
20406				parameters.envMap ? '#define USE_ENVMAP' : '',
20407				parameters.envMap ? '#define ' + envMapTypeDefine : '',
20408				parameters.envMap ? '#define ' + envMapModeDefine : '',
20409				parameters.envMap ? '#define ' + envMapBlendingDefine : '',
20410				parameters.lightMap ? '#define USE_LIGHTMAP' : '',
20411				parameters.aoMap ? '#define USE_AOMAP' : '',
20412				parameters.emissiveMap ? '#define USE_EMISSIVEMAP' : '',
20413				parameters.bumpMap ? '#define USE_BUMPMAP' : '',
20414				parameters.normalMap ? '#define USE_NORMALMAP' : '',
20415				parameters.specularMap ? '#define USE_SPECULARMAP' : '',
20416				parameters.roughnessMap ? '#define USE_ROUGHNESSMAP' : '',
20417				parameters.metalnessMap ? '#define USE_METALNESSMAP' : '',
20418				parameters.alphaMap ? '#define USE_ALPHAMAP' : '',
20419				parameters.vertexColors ? '#define USE_COLOR' : '',
20420  
20421				parameters.gradientMap ? '#define USE_GRADIENTMAP' : '',
20422  
20423				parameters.flatShading ? '#define FLAT_SHADED' : '',
20424  
20425				parameters.doubleSided ? '#define DOUBLE_SIDED' : '',
20426				parameters.flipSided ? '#define FLIP_SIDED' : '',
20427  
20428				parameters.shadowMapEnabled ? '#define USE_SHADOWMAP' : '',
20429				parameters.shadowMapEnabled ? '#define ' + shadowMapTypeDefine : '',
20430  
20431				parameters.premultipliedAlpha ? '#define PREMULTIPLIED_ALPHA' : '',
20432  
20433				parameters.physicallyCorrectLights ? '#define PHYSICALLY_CORRECT_LIGHTS' : '',
20434  
20435				parameters.logarithmicDepthBuffer ? '#define USE_LOGDEPTHBUF' : '',
20436				parameters.logarithmicDepthBuffer && extensions.get( 'EXT_frag_depth' ) ? '#define USE_LOGDEPTHBUF_EXT' : '',
20437  
20438				parameters.envMap && extensions.get( 'EXT_shader_texture_lod' ) ? '#define TEXTURE_LOD_EXT' : '',
20439  
20440				'uniform mat4 viewMatrix;',
20441				'uniform vec3 cameraPosition;',
20442  
20443				( parameters.toneMapping !== NoToneMapping ) ? '#define TONE_MAPPING' : '',
20444				( parameters.toneMapping !== NoToneMapping ) ? ShaderChunk[ 'tonemapping_pars_fragment' ] : '', // this code is required here because it is used by the toneMapping() function defined below
20445				( parameters.toneMapping !== NoToneMapping ) ? getToneMappingFunction( 'toneMapping', parameters.toneMapping ) : '',
20446  
20447				parameters.dithering ? '#define DITHERING' : '',
20448  
20449				( 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
20450				parameters.mapEncoding ? getTexelDecodingFunction( 'mapTexelToLinear', parameters.mapEncoding ) : '',
20451				parameters.envMapEncoding ? getTexelDecodingFunction( 'envMapTexelToLinear', parameters.envMapEncoding ) : '',
20452				parameters.emissiveMapEncoding ? getTexelDecodingFunction( 'emissiveMapTexelToLinear', parameters.emissiveMapEncoding ) : '',
20453				parameters.outputEncoding ? getTexelEncodingFunction( 'linearToOutputTexel', parameters.outputEncoding ) : '',
20454  
20455				parameters.depthPacking ? '#define DEPTH_PACKING ' + material.depthPacking : '',
20456  
20457				'\n'
20458  
20459			].filter( filterEmptyLine ).join( '\n' );
20460  
20461		}
20462  
20463		vertexShader = parseIncludes( vertexShader );
20464		vertexShader = replaceLightNums( vertexShader, parameters );
20465		vertexShader = replaceClippingPlaneNums( vertexShader, parameters );
20466  
20467		fragmentShader = parseIncludes( fragmentShader );
20468		fragmentShader = replaceLightNums( fragmentShader, parameters );
20469		fragmentShader = replaceClippingPlaneNums( fragmentShader, parameters );
20470  
20471		vertexShader = unrollLoops( vertexShader );
20472		fragmentShader = unrollLoops( fragmentShader );
20473  
20474		var vertexGlsl = prefixVertex + vertexShader;
20475		var fragmentGlsl = prefixFragment + fragmentShader;
20476  
20477		// console.log( '*VERTEX*', vertexGlsl );
20478		// console.log( '*FRAGMENT*', fragmentGlsl );
20479  
20480		var glVertexShader = WebGLShader( gl, gl.VERTEX_SHADER, vertexGlsl );
20481		var glFragmentShader = WebGLShader( gl, gl.FRAGMENT_SHADER, fragmentGlsl );
20482  
20483		gl.attachShader( program, glVertexShader );
20484		gl.attachShader( program, glFragmentShader );
20485  
20486		// Force a particular attribute to index 0.
20487  
20488		if ( material.index0AttributeName !== undefined ) {
20489  
20490			gl.bindAttribLocation( program, 0, material.index0AttributeName );
20491  
20492		} else if ( parameters.morphTargets === true ) {
20493  
20494			// programs with morphTargets displace position out of attribute 0
20495			gl.bindAttribLocation( program, 0, 'position' );
20496  
20497		}
20498  
20499		gl.linkProgram( program );
20500  
20501		var programLog = gl.getProgramInfoLog( program ).trim();
20502		var vertexLog = gl.getShaderInfoLog( glVertexShader ).trim();
20503		var fragmentLog = gl.getShaderInfoLog( glFragmentShader ).trim();
20504  
20505		var runnable = true;
20506		var haveDiagnostics = true;
20507  
20508		// console.log( '**VERTEX**', gl.getExtension( 'WEBGL_debug_shaders' ).getTranslatedShaderSource( glVertexShader ) );
20509		// console.log( '**FRAGMENT**', gl.getExtension( 'WEBGL_debug_shaders' ).getTranslatedShaderSource( glFragmentShader ) );
20510  
20511		if ( gl.getProgramParameter( program, gl.LINK_STATUS ) === false ) {
20512  
20513			runnable = false;
vendor: 4,320 bytes, lines 20514-20699
20514  
20515			console.error( 'THREE.WebGLProgram: shader error: ', gl.getError(), 'gl.VALIDATE_STATUS', gl.getProgramParameter( program, gl.VALIDATE_STATUS ), 'gl.getProgramInfoLog', programLog, vertexLog, fragmentLog );
20516  
20517		} else if ( programLog !== '' ) {
20518  
20519			console.warn( 'THREE.WebGLProgram: gl.getProgramInfoLog()', programLog );
20520  
20521		} else if ( vertexLog === '' || fragmentLog === '' ) {
20522  
20523			haveDiagnostics = false;
20524  
20525		}
20526  
20527		if ( haveDiagnostics ) {
20528  
20529			this.diagnostics = {
20530  
20531				runnable: runnable,
20532				material: material,
20533  
20534				programLog: programLog,
20535  
20536				vertexShader: {
20537  
20538					log: vertexLog,
20539					prefix: prefixVertex
20540  
20541				},
20542  
20543				fragmentShader: {
20544  
20545					log: fragmentLog,
20546					prefix: prefixFragment
20547  
20548				}
20549  
20550			};
20551  
20552		}
20553  
20554		// clean up
20555  
20556		gl.deleteShader( glVertexShader );
20557		gl.deleteShader( glFragmentShader );
20558  
20559		// set up caching for uniform locations
20560  
20561		var cachedUniforms;
20562  
20563		this.getUniforms = function () {
20564  
20565			if ( cachedUniforms === undefined ) {
20566  
20567				cachedUniforms = new WebGLUniforms( gl, program, renderer );
20568  
20569			}
20570  
20571			return cachedUniforms;
20572  
20573		};
20574  
20575		// set up caching for attribute locations
20576  
20577		var cachedAttributes;
20578  
20579		this.getAttributes = function () {
20580  
20581			if ( cachedAttributes === undefined ) {
20582  
20583				cachedAttributes = fetchAttributeLocations( gl, program );
20584  
20585			}
20586  
20587			return cachedAttributes;
20588  
20589		};
20590  
20591		// free resource
20592  
20593		this.destroy = function () {
20594  
20595			gl.deleteProgram( program );
20596			this.program = undefined;
20597  
20598		};
20599  
20600		// DEPRECATED
20601  
20602		Object.defineProperties( this, {
20603  
20604			uniforms: {
20605				get: function () {
20606  
20607					console.warn( 'THREE.WebGLProgram: .uniforms is now .getUniforms().' );
20608					return this.getUniforms();
20609  
20610				}
20611			},
20612  
20613			attributes: {
20614				get: function () {
20615  
20616					console.warn( 'THREE.WebGLProgram: .attributes is now .getAttributes().' );
20617					return this.getAttributes();
20618  
20619				}
20620			}
20621  
20622		} );
20623  
20624  
20625		//
20626  
20627		this.name = shader.name;
20628		this.id = programIdCount ++;
20629		this.code = code;
20630		this.usedTimes = 1;
20631		this.program = program;
20632		this.vertexShader = glVertexShader;
20633		this.fragmentShader = glFragmentShader;
20634  
20635		return this;
20636  
20637	}
20638  
20639	/**
20640	 * @author mrdoob / http://mrdoob.com/
20641	 */
20642  
20643	function WebGLPrograms( renderer, extensions, capabilities ) {
20644  
20645		var programs = [];
20646  
20647		var shaderIDs = {
20648			MeshDepthMaterial: 'depth',
20649			MeshDistanceMaterial: 'distanceRGBA',
20650			MeshNormalMaterial: 'normal',
20651			MeshBasicMaterial: 'basic',
20652			MeshLambertMaterial: 'lambert',
20653			MeshPhongMaterial: 'phong',
20654			MeshToonMaterial: 'phong',
20655			MeshStandardMaterial: 'physical',
20656			MeshPhysicalMaterial: 'physical',
20657			LineBasicMaterial: 'basic',
20658			LineDashedMaterial: 'dashed',
20659			PointsMaterial: 'points',
20660			ShadowMaterial: 'shadow'
20661		};
20662  
20663		var parameterNames = [
20664			"precision", "supportsVertexTextures", "map", "mapEncoding", "envMap", "envMapMode", "envMapEncoding",
20665			"lightMap", "aoMap", "emissiveMap", "emissiveMapEncoding", "bumpMap", "normalMap", "displacementMap", "specularMap",
20666			"roughnessMap", "metalnessMap", "gradientMap",
20667			"alphaMap", "combine", "vertexColors", "fog", "useFog", "fogExp",
20668			"flatShading", "sizeAttenuation", "logarithmicDepthBuffer", "skinning",
20669			"maxBones", "useVertexTexture", "morphTargets", "morphNormals",
20670			"maxMorphTargets", "maxMorphNormals", "premultipliedAlpha",
20671			"numDirLights", "numPointLights", "numSpotLights", "numHemiLights", "numRectAreaLights",
20672			"shadowMapEnabled", "shadowMapType", "toneMapping", 'physicallyCorrectLights',
20673			"alphaTest", "doubleSided", "flipSided", "numClippingPlanes", "numClipIntersection", "depthPacking", "dithering"
20674		];
20675  
20676  
20677		function allocateBones( object ) {
20678  
20679			var skeleton = object.skeleton;
20680			var bones = skeleton.bones;
20681  
20682			if ( capabilities.floatVertexTextures ) {
20683  
20684				return 1024;
20685  
20686			} else {
20687  
20688				// default for when object is not specified
20689				// ( for example when prebuilding shader to be used with multiple objects )
20690				//
20691				//  - leave some extra space for other uniforms
20692				//  - limit here is ANGLE's 254 max uniform vectors
20693				//    (up to 54 should be safe)
20694  
20695				var nVertexUniforms = capabilities.maxVertexUniforms;
20696				var nVertexMatrices = Math.floor( ( nVertexUniforms - 20 ) / 4 );
20697  
20698				var maxBones = Math.min( nVertexMatrices, bones.length );
20699  
20700				if ( maxBones < bones.length ) {
20701  
20702					console.warn( 'THREE.WebGLRenderer: Skeleton has ' + bones.length + ' bones. This GPU supports ' + maxBones + '.' );
20703					return 0;
20704  
20705				}
20706  
20707				return maxBones;
20708  
20709			}
20710  
20711		}
20712  
20713		function getTextureEncodingFromMap( map, gammaOverrideLinear ) {
20714  
20715			var encoding;
20716  
20717			if ( ! map ) {
20718  
20719				encoding = LinearEncoding;
20720  
20721			} else if ( map.isTexture ) {
20722  
20723				encoding = map.encoding;
20724  
20725			} else if ( map.isWebGLRenderTarget ) {
20726  
20727				console.warn( "THREE.WebGLPrograms.getTextureEncodingFromMap: don't use render targets as textures. Use their .texture property instead." );
20728				encoding = map.texture.encoding;
20729  
20730			}
20731  
20732			// add backwards compatibility for WebGLRenderer.gammaInput/gammaOutput parameter, should probably be removed at some point.
20733			if ( encoding === LinearEncoding && gammaOverrideLinear ) {
20734  
20735				encoding = GammaEncoding;
20736  
20737			}
20738  
20739			return encoding;
20740  
20741		}
20742  
20743		this.getParameters = function ( material, lights, shadows, fog, nClipPlanes, nClipIntersection, object ) {
20744  
20745			var shaderID = shaderIDs[ material.type ];
20746  
20747			// heuristics to create shader parameters according to lights in the scene
20748			// (not to blow over maxLights budget)
20749  
20750			var maxBones = object.isSkinnedMesh ? allocateBones( object ) : 0;
20751			var precision = capabilities.precision;
20752  
20753			if ( material.precision !== null ) {
20754  
20755				precision = capabilities.getMaxPrecision( material.precision );
20756  
20757				if ( precision !== material.precision ) {
20758  
20759					console.warn( 'THREE.WebGLProgram.getParameters:', material.precision, 'not supported, using', precision, 'instead.' );
20760  
20761				}
20762  
20763			}
20764  
20765			var currentRenderTarget = renderer.getRenderTarget();
20766  
20767			var parameters = {
20768  
20769				shaderID: shaderID,
20770  
20771				precision: precision,
20772				supportsVertexTextures: capabilities.vertexTextures,
20773				outputEncoding: getTextureEncodingFromMap( ( ! currentRenderTarget ) ? null : currentRenderTarget.texture, renderer.gammaOutput ),
20774				map: !! material.map,
20775				mapEncoding: getTextureEncodingFromMap( material.map, renderer.gammaInput ),
20776				envMap: !! material.envMap,
20777				envMapMode: material.envMap && material.envMap.mapping,
20778				envMapEncoding: getTextureEncodingFromMap( material.envMap, renderer.gammaInput ),
20779				envMapCubeUV: ( !! material.envMap ) && ( ( material.envMap.mapping === CubeUVReflectionMapping ) || ( material.envMap.mapping === CubeUVRefractionMapping ) ),
20780				lightMap: !! material.lightMap,
20781				aoMap: !! material.aoMap,
20782				emissiveMap: !! material.emissiveMap,
20783				emissiveMapEncoding: getTextureEncodingFromMap( material.emissiveMap, renderer.gammaInput ),
20784				bumpMap: !! material.bumpMap,
20785				normalMap: !! material.normalMap,
20786				displacementMap: !! material.displacementMap,
20787				roughnessMap: !! material.roughnessMap,
20788				metalnessMap: !! material.metalnessMap,
20789				specularMap: !! material.specularMap,
20790				alphaMap: !! material.alphaMap,
20791  
20792				gradientMap: !! material.gradientMap,
20793  
20794				combine: material.combine,
20795  
20796				vertexColors: material.vertexColors,
20797  
20798				fog: !! fog,
20799				useFog: material.fog,
20800				fogExp: ( fog && fog.isFogExp2 ),
20801  
20802				flatShading: material.flatShading,
20803  
20804				sizeAttenuation: material.sizeAttenuation,
20805				logarithmicDepthBuffer: capabilities.logarithmicDepthBuffer,
20806  
20807				skinning: material.skinning && maxBones > 0,
20808				maxBones: maxBones,
20809				useVertexTexture: capabilities.floatVertexTextures,
20810  
20811				morphTargets: material.morphTargets,
20812				morphNormals: material.morphNormals,
20813				maxMorphTargets: renderer.maxMorphTargets,
20814				maxMorphNormals: renderer.maxMorphNormals,
20815  
20816				numDirLights: lights.directional.length,
20817				numPointLights: lights.point.length,
20818				numSpotLights: lights.spot.length,
20819				numRectAreaLights: lights.rectArea.length,
20820				numHemiLights: lights.hemi.length,
20821  
20822				numClippingPlanes: nClipPlanes,
20823				numClipIntersection: nClipIntersection,
20824  
20825				dithering: material.dithering,
20826  
20827				shadowMapEnabled: renderer.shadowMap.enabled && object.receiveShadow && shadows.length > 0,
20828				shadowMapType: renderer.shadowMap.type,
20829  
20830				toneMapping: renderer.toneMapping,
20831				physicallyCorrectLights: renderer.physicallyCorrectLights,
20832  
20833				premultipliedAlpha: material.premultipliedAlpha,
20834  
20835				alphaTest: material.alphaTest,
20836				doubleSided: material.side === DoubleSide,
20837				flipSided: material.side === BackSide,
20838  
20839				depthPacking: ( material.depthPacking !== undefined ) ? material.depthPacking : false
20840  
20841			};
20842  
20843			return parameters;
20844  
20845		};
20846  
20847		this.getProgramCode = function ( material, parameters ) {
20848  
20849			var array = [];
20850  
20851			if ( parameters.shaderID ) {
20852  
20853				array.push( parameters.shaderID );
20854  
20855			} else {
20856  
20857				array.push( material.fragmentShader );
20858				array.push( material.vertexShader );
20859  
20860			}
20861  
20862			if ( material.defines !== undefined ) {
20863  
20864				for ( var name in material.defines ) {
20865  
20866					array.push( name );
20867					array.push( material.defines[ name ] );
20868  
20869				}
20870  
20871			}
20872  
20873			for ( var i = 0; i < parameterNames.length; i ++ ) {
20874  
20875				array.push( parameters[ parameterNames[ i ] ] );
20876  
20877			}
20878  
20879			array.push( material.onBeforeCompile.toString() );
20880  
20881			array.push( renderer.gammaOutput );
20882  
20883			return array.join();
20884  
20885		};
20886  
20887		this.acquireProgram = function ( material, shader, parameters, code ) {
20888  
20889			var program;
20890  
20891			// Check if code has been already compiled
20892			for ( var p = 0, pl = programs.length; p < pl; p ++ ) {
20893  
20894				var programInfo = programs[ p ];
20895  
20896				if ( programInfo.code === code ) {
20897  
20898					program = programInfo;
20899					++ program.usedTimes;
20900  
20901					break;
20902  
20903				}
20904  
20905			}
20906  
20907			if ( program === undefined ) {
20908  
20909				program = new WebGLProgram( renderer, extensions, code, material, shader, parameters );
20910				programs.push( program );
20911  
20912			}
20913  
20914			return program;
20915  
20916		};
20917  
20918		this.releaseProgram = function ( program ) {
20919  
20920			if ( -- program.usedTimes === 0 ) {
20921  
20922				// Remove from unordered set
20923				var i = programs.indexOf( program );
20924				programs[ i ] = programs[ programs.length - 1 ];
20925				programs.pop();
20926  
20927				// Free WebGL resources
20928				program.destroy();
20929  
20930			}
20931  
20932		};
20933  
20934		// Exposed for resource monitoring & error feedback via renderer.info:
20935		this.programs = programs;
20936  
20937	}
20938  
20939	/**
20940	 * @author fordacious / fordacious.github.io
20941	 */
20942  
20943	function WebGLProperties() {
20944  
20945		var properties = new WeakMap();
20946  
20947		function get( object ) {
20948  
20949			var map = properties.get( object );
20950  
20951			if ( map === undefined ) {
20952  
20953				map = {};
20954				properties.set( object, map );
20955  
20956			}
20957  
20958			return map;
20959  
20960		}
20961  
20962		function remove( object ) {
20963  
20964			properties.delete( object );
20965  
20966		}
20967  
20968		function update( object, key, value ) {
20969  
20970			properties.get( object )[ key ] = value;
20971  
20972		}
20973  
20974		function dispose() {
20975  
20976			properties = new WeakMap();
20977  
20978		}
20979  
20980		return {
20981			get: get,
20982			remove: remove,
20983			update: update,
20984			dispose: dispose
20985		};
20986  
20987	}
20988  
20989	/**
20990	 * @author mrdoob / http://mrdoob.com/
20991	 */
20992  
20993	function painterSortStable( a, b ) {
20994  
20995		if ( a.renderOrder !== b.renderOrder ) {
20996  
20997			return a.renderOrder - b.renderOrder;
20998  
20999		} else if ( a.program && b.program && a.program !== b.program ) {
21000  
21001			return a.program.id - b.program.id;
21002  
21003		} else if ( a.material.id !== b.material.id ) {
21004  
21005			return a.material.id - b.material.id;
21006  
21007		} else if ( a.z !== b.z ) {
21008  
21009			return a.z - b.z;
21010  
21011		} else {
21012  
21013			return a.id - b.id;
21014  
21015		}
21016  
21017	}
21018  
21019	function reversePainterSortStable( a, b ) {
21020  
21021		if ( a.renderOrder !== b.renderOrder ) {
21022  
21023			return a.renderOrder - b.renderOrder;
21024  
21025		} if ( a.z !== b.z ) {
21026  
21027			return b.z - a.z;
21028  
21029		} else {
21030  
21031			return a.id - b.id;
21032  
21033		}
21034  
21035	}
21036  
21037	function WebGLRenderList() {
21038  
21039		var renderItems = [];
21040		var renderItemsIndex = 0;
21041  
21042		var opaque = [];
21043		var transparent = [];
21044  
21045		function init() {
21046  
21047			renderItemsIndex = 0;
21048  
21049			opaque.length = 0;
21050			transparent.length = 0;
21051  
21052		}
21053  
21054		function push( object, geometry, material, z, group ) {
21055  
21056			var renderItem = renderItems[ renderItemsIndex ];
21057  
21058			if ( renderItem === undefined ) {
21059  
21060				renderItem = {
21061					id: object.id,
21062					object: object,
21063					geometry: geometry,
21064					material: material,
21065					program: material.program,
21066					renderOrder: object.renderOrder,
21067					z: z,
21068					group: group
21069				};
21070  
21071				renderItems[ renderItemsIndex ] = renderItem;
21072  
21073			} else {
21074  
21075				renderItem.id = object.id;
21076				renderItem.object = object;
21077				renderItem.geometry = geometry;
21078				renderItem.material = material;
21079				renderItem.program = material.program;
21080				renderItem.renderOrder = object.renderOrder;
21081				renderItem.z = z;
21082				renderItem.group = group;
21083  
21084			}
21085  
21086			( material.transparent === true ? transparent : opaque ).push( renderItem );
21087  
21088			renderItemsIndex ++;
21089  
21090		}
21091  
21092		function sort() {
21093  
21094			if ( opaque.length > 1 ) opaque.sort( painterSortStable );
21095			if ( transparent.length > 1 ) transparent.sort( reversePainterSortStable );
21096  
21097		}
21098  
21099		return {
21100			opaque: opaque,
21101			transparent: transparent,
21102  
21103			init: init,
21104			push: push,
21105  
21106			sort: sort
21107		};
21108  
21109	}
21110  
21111	function WebGLRenderLists() {
21112  
21113		var lists = {};
21114  
21115		function get( scene, camera ) {
21116  
21117			var hash = scene.id + ',' + camera.id;
21118			var list = lists[ hash ];
21119  
21120			if ( list === undefined ) {
21121  
21122				// console.log( 'THREE.WebGLRenderLists:', hash );
21123  
21124				list = new WebGLRenderList();
21125				lists[ hash ] = list;
21126  
21127			}
21128  
21129			return list;
21130  
21131		}
21132  
21133		function dispose() {
21134  
21135			lists = {};
21136  
21137		}
21138  
21139		return {
21140			get: get,
vendor: 4,154 bytes, lines 21141-21339
21141			dispose: dispose
21142		};
21143  
21144	}
21145  
21146	/**
21147	 * @author mrdoob / http://mrdoob.com/
21148	 */
21149  
21150	function UniformsCache() {
21151  
21152		var lights = {};
21153  
21154		return {
21155  
21156			get: function ( light ) {
21157  
21158				if ( lights[ light.id ] !== undefined ) {
21159  
21160					return lights[ light.id ];
21161  
21162				}
21163  
21164				var uniforms;
21165  
21166				switch ( light.type ) {
21167  
21168					case 'DirectionalLight':
21169						uniforms = {
21170							direction: new Vector3(),
21171							color: new Color(),
21172  
21173							shadow: false,
21174							shadowBias: 0,
21175							shadowRadius: 1,
21176							shadowMapSize: new Vector2()
21177						};
21178						break;
21179  
21180					case 'SpotLight':
21181						uniforms = {
21182							position: new Vector3(),
21183							direction: new Vector3(),
21184							color: new Color(),
21185							distance: 0,
21186							coneCos: 0,
21187							penumbraCos: 0,
21188							decay: 0,
21189  
21190							shadow: false,
21191							shadowBias: 0,
21192							shadowRadius: 1,
21193							shadowMapSize: new Vector2()
21194						};
21195						break;
21196  
21197					case 'PointLight':
21198						uniforms = {
21199							position: new Vector3(),
21200							color: new Color(),
21201							distance: 0,
21202							decay: 0,
21203  
21204							shadow: false,
21205							shadowBias: 0,
21206							shadowRadius: 1,
21207							shadowMapSize: new Vector2(),
21208							shadowCameraNear: 1,
21209							shadowCameraFar: 1000
21210						};
21211						break;
21212  
21213					case 'HemisphereLight':
21214						uniforms = {
21215							direction: new Vector3(),
21216							skyColor: new Color(),
21217							groundColor: new Color()
21218						};
21219						break;
21220  
21221					case 'RectAreaLight':
21222						uniforms = {
21223							color: new Color(),
21224							position: new Vector3(),
21225							halfWidth: new Vector3(),
21226							halfHeight: new Vector3()
21227							// TODO (abelnation): set RectAreaLight shadow uniforms
21228						};
21229						break;
21230  
21231				}
21232  
21233				lights[ light.id ] = uniforms;
21234  
21235				return uniforms;
21236  
21237			}
21238  
21239		};
21240  
21241	}
21242  
21243	var count = 0;
21244  
21245	function WebGLLights() {
21246  
21247		var cache = new UniformsCache();
21248  
21249		var state = {
21250  
21251			id: count ++,
21252  
21253			hash: '',
21254  
21255			ambient: [ 0, 0, 0 ],
21256			directional: [],
21257			directionalShadowMap: [],
21258			directionalShadowMatrix: [],
21259			spot: [],
21260			spotShadowMap: [],
21261			spotShadowMatrix: [],
21262			rectArea: [],
21263			point: [],
21264			pointShadowMap: [],
21265			pointShadowMatrix: [],
21266			hemi: []
21267  
21268		};
21269  
21270		var vector3 = new Vector3();
21271		var matrix4 = new Matrix4();
21272		var matrix42 = new Matrix4();
21273  
21274		function setup( lights, shadows, camera ) {
21275  
21276			var r = 0, g = 0, b = 0;
21277  
21278			var directionalLength = 0;
21279			var pointLength = 0;
21280			var spotLength = 0;
21281			var rectAreaLength = 0;
21282			var hemiLength = 0;
21283  
21284			var viewMatrix = camera.matrixWorldInverse;
21285  
21286			for ( var i = 0, l = lights.length; i < l; i ++ ) {
21287  
21288				var light = lights[ i ];
21289  
21290				var color = light.color;
21291				var intensity = light.intensity;
21292				var distance = light.distance;
21293  
21294				var shadowMap = ( light.shadow && light.shadow.map ) ? light.shadow.map.texture : null;
21295  
21296				if ( light.isAmbientLight ) {
21297  
21298					r += color.r * intensity;
21299					g += color.g * intensity;
21300					b += color.b * intensity;
21301  
21302				} else if ( light.isDirectionalLight ) {
21303  
21304					var uniforms = cache.get( light );
21305  
21306					uniforms.color.copy( light.color ).multiplyScalar( light.intensity );
21307					uniforms.direction.setFromMatrixPosition( light.matrixWorld );
21308					vector3.setFromMatrixPosition( light.target.matrixWorld );
21309					uniforms.direction.sub( vector3 );
21310					uniforms.direction.transformDirection( viewMatrix );
21311  
21312					uniforms.shadow = light.castShadow;
21313  
21314					if ( light.castShadow ) {
21315  
21316						var shadow = light.shadow;
21317  
21318						uniforms.shadowBias = shadow.bias;
21319						uniforms.shadowRadius = shadow.radius;
21320						uniforms.shadowMapSize = shadow.mapSize;
21321  
21322					}
21323  
21324					state.directionalShadowMap[ directionalLength ] = shadowMap;
21325					state.directionalShadowMatrix[ directionalLength ] = light.shadow.matrix;
21326					state.directional[ directionalLength ] = uniforms;
21327  
21328					directionalLength ++;
21329  
21330				} else if ( light.isSpotLight ) {
21331  
21332					var uniforms = cache.get( light );
21333  
21334					uniforms.position.setFromMatrixPosition( light.matrixWorld );
21335					uniforms.position.applyMatrix4( viewMatrix );
21336  
21337					uniforms.color.copy( color ).multiplyScalar( intensity );
21338					uniforms.distance = distance;
21339  
21340					uniforms.direction.setFromMatrixPosition( light.matrixWorld );
21341					vector3.setFromMatrixPosition( light.target.matrixWorld );
21342					uniforms.direction.sub( vector3 );
21343					uniforms.direction.transformDirection( viewMatrix );
21344  
21345					uniforms.coneCos = Math.cos( light.angle );
21346					uniforms.penumbraCos = Math.cos( light.angle * ( 1 - light.penumbra ) );
21347					uniforms.decay = ( light.distance === 0 ) ? 0.0 : light.decay;
21348  
21349					uniforms.shadow = light.castShadow;
21350  
21351					if ( light.castShadow ) {
21352  
21353						var shadow = light.shadow;
21354  
21355						uniforms.shadowBias = shadow.bias;
21356						uniforms.shadowRadius = shadow.radius;
21357						uniforms.shadowMapSize = shadow.mapSize;
21358  
21359					}
21360  
21361					state.spotShadowMap[ spotLength ] = shadowMap;
21362					state.spotShadowMatrix[ spotLength ] = light.shadow.matrix;
21363					state.spot[ spotLength ] = uniforms;
21364  
21365					spotLength ++;
21366  
21367				} else if ( light.isRectAreaLight ) {
21368  
21369					var uniforms = cache.get( light );
21370  
21371					// (a) intensity is the total visible light emitted
21372					//uniforms.color.copy( color ).multiplyScalar( intensity / ( light.width * light.height * Math.PI ) );
21373  
21374					// (b) intensity is the brightness of the light
21375					uniforms.color.copy( color ).multiplyScalar( intensity );
21376  
21377					uniforms.position.setFromMatrixPosition( light.matrixWorld );
21378					uniforms.position.applyMatrix4( viewMatrix );
21379  
21380					// extract local rotation of light to derive width/height half vectors
21381					matrix42.identity();
21382					matrix4.copy( light.matrixWorld );
21383					matrix4.premultiply( viewMatrix );
21384					matrix42.extractRotation( matrix4 );
21385  
21386					uniforms.halfWidth.set( light.width * 0.5, 0.0, 0.0 );
21387					uniforms.halfHeight.set( 0.0, light.height * 0.5, 0.0 );
21388  
21389					uniforms.halfWidth.applyMatrix4( matrix42 );
21390					uniforms.halfHeight.applyMatrix4( matrix42 );
21391  
21392					// TODO (abelnation): RectAreaLight distance?
21393					// uniforms.distance = distance;
21394  
21395					state.rectArea[ rectAreaLength ] = uniforms;
21396  
21397					rectAreaLength ++;
21398  
21399				} else if ( light.isPointLight ) {
21400  
21401					var uniforms = cache.get( light );
21402  
21403					uniforms.position.setFromMatrixPosition( light.matrixWorld );
21404					uniforms.position.applyMatrix4( viewMatrix );
21405  
21406					uniforms.color.copy( light.color ).multiplyScalar( light.intensity );
21407					uniforms.distance = light.distance;
21408					uniforms.decay = ( light.distance === 0 ) ? 0.0 : light.decay;
21409  
21410					uniforms.shadow = light.castShadow;
21411  
21412					if ( light.castShadow ) {
21413  
21414						var shadow = light.shadow;
21415  
21416						uniforms.shadowBias = shadow.bias;
21417						uniforms.shadowRadius = shadow.radius;
21418						uniforms.shadowMapSize = shadow.mapSize;
21419						uniforms.shadowCameraNear = shadow.camera.near;
21420						uniforms.shadowCameraFar = shadow.camera.far;
21421  
21422					}
21423  
21424					state.pointShadowMap[ pointLength ] = shadowMap;
21425					state.pointShadowMatrix[ pointLength ] = light.shadow.matrix;
21426					state.point[ pointLength ] = uniforms;
21427  
21428					pointLength ++;
21429  
21430				} else if ( light.isHemisphereLight ) {
21431  
21432					var uniforms = cache.get( light );
21433  
21434					uniforms.direction.setFromMatrixPosition( light.matrixWorld );
21435					uniforms.direction.transformDirection( viewMatrix );
21436					uniforms.direction.normalize();
21437  
21438					uniforms.skyColor.copy( light.color ).multiplyScalar( intensity );
21439					uniforms.groundColor.copy( light.groundColor ).multiplyScalar( intensity );
21440  
21441					state.hemi[ hemiLength ] = uniforms;
21442  
21443					hemiLength ++;
21444  
21445				}
21446  
21447			}
21448  
21449			state.ambient[ 0 ] = r;
21450			state.ambient[ 1 ] = g;
21451			state.ambient[ 2 ] = b;
21452  
21453			state.directional.length = directionalLength;
21454			state.spot.length = spotLength;
21455			state.rectArea.length = rectAreaLength;
21456			state.point.length = pointLength;
21457			state.hemi.length = hemiLength;
21458  
21459			state.hash = state.id + ',' + directionalLength + ',' + pointLength + ',' + spotLength + ',' + rectAreaLength + ',' + hemiLength + ',' + shadows.length;
21460  
21461		}
21462  
21463		return {
21464			setup: setup,
21465			state: state
21466		};
21467  
21468	}
21469  
21470	/**
21471	 * @author Mugen87 / https://github.com/Mugen87
21472	 */
21473  
21474	function WebGLRenderState() {
21475  
21476		var lights = new WebGLLights();
21477  
21478		var lightsArray = [];
21479		var shadowsArray = [];
21480		var spritesArray = [];
21481  
vendor: 4,489 bytes, lines 21482-21712
21482		function init() {
21483  
21484			lightsArray.length = 0;
21485			shadowsArray.length = 0;
21486			spritesArray.length = 0;
21487  
21488		}
21489  
21490		function pushLight( light ) {
21491  
21492			lightsArray.push( light );
21493  
21494		}
21495  
21496		function pushShadow( shadowLight ) {
21497  
21498			shadowsArray.push( shadowLight );
21499  
21500		}
21501  
21502		function pushSprite( shadowLight ) {
21503  
21504			spritesArray.push( shadowLight );
21505  
21506		}
21507  
21508		function setupLights( camera ) {
21509  
21510			lights.setup( lightsArray, shadowsArray, camera );
21511  
21512		}
21513  
21514		var state = {
21515			lightsArray: lightsArray,
21516			shadowsArray: shadowsArray,
21517			spritesArray: spritesArray,
21518  
21519			lights: lights
21520		};
21521  
21522		return {
21523			init: init,
21524			state: state,
21525			setupLights: setupLights,
21526  
21527			pushLight: pushLight,
21528			pushShadow: pushShadow,
21529			pushSprite: pushSprite
21530		};
21531  
21532	}
21533  
21534	function WebGLRenderStates() {
21535  
21536		var renderStates = {};
21537  
21538		function get( scene, camera ) {
21539  
21540			var hash = scene.id + ',' + camera.id;
21541  
21542			var renderState = renderStates[ hash ];
21543  
21544			if ( renderState === undefined ) {
21545  
21546				renderState = new WebGLRenderState();
21547				renderStates[ hash ] = renderState;
21548  
21549			}
21550  
21551			return renderState;
21552  
21553		}
21554  
21555		function dispose() {
21556  
21557			renderStates = {};
21558  
21559		}
21560  
21561		return {
21562			get: get,
21563			dispose: dispose
21564		};
21565  
21566	}
21567  
21568	/**
21569	 * @author mrdoob / http://mrdoob.com/
21570	 * @author alteredq / http://alteredqualia.com/
21571	 * @author bhouston / https://clara.io
21572	 * @author WestLangley / http://github.com/WestLangley
21573	 *
21574	 * parameters = {
21575	 *
21576	 *  opacity: <float>,
21577	 *
21578	 *  map: new THREE.Texture( <Image> ),
21579	 *
21580	 *  alphaMap: new THREE.Texture( <Image> ),
21581	 *
21582	 *  displacementMap: new THREE.Texture( <Image> ),
21583	 *  displacementScale: <float>,
21584	 *  displacementBias: <float>,
21585	 *
21586	 *  wireframe: <boolean>,
21587	 *  wireframeLinewidth: <float>
21588	 * }
21589	 */
21590  
21591	function MeshDepthMaterial( parameters ) {
21592  
21593		Material.call( this );
21594  
21595		this.type = 'MeshDepthMaterial';
21596  
21597		this.depthPacking = BasicDepthPacking;
21598  
21599		this.skinning = false;
21600		this.morphTargets = false;
21601  
21602		this.map = null;
21603  
21604		this.alphaMap = null;
21605  
21606		this.displacementMap = null;
21607		this.displacementScale = 1;
21608		this.displacementBias = 0;
21609  
21610		this.wireframe = false;
21611		this.wireframeLinewidth = 1;
21612  
21613		this.fog = false;
21614		this.lights = false;
21615  
21616		this.setValues( parameters );
21617  
21618	}
21619  
21620	MeshDepthMaterial.prototype = Object.create( Material.prototype );
21621	MeshDepthMaterial.prototype.constructor = MeshDepthMaterial;
21622  
21623	MeshDepthMaterial.prototype.isMeshDepthMaterial = true;
21624  
21625	MeshDepthMaterial.prototype.copy = function ( source ) {
21626  
21627		Material.prototype.copy.call( this, source );
21628  
21629		this.depthPacking = source.depthPacking;
21630  
21631		this.skinning = source.skinning;
21632		this.morphTargets = source.morphTargets;
21633  
21634		this.map = source.map;
21635  
21636		this.alphaMap = source.alphaMap;
21637  
21638		this.displacementMap = source.displacementMap;
21639		this.displacementScale = source.displacementScale;
21640		this.displacementBias = source.displacementBias;
21641  
21642		this.wireframe = source.wireframe;
21643		this.wireframeLinewidth = source.wireframeLinewidth;
21644  
21645		return this;
21646  
21647	};
21648  
21649	/**
21650	 * @author WestLangley / http://github.com/WestLangley
21651	 *
21652	 * parameters = {
21653	 *
21654	 *  referencePosition: <float>,
21655	 *  nearDistance: <float>,
21656	 *  farDistance: <float>,
21657	 *
21658	 *  skinning: <bool>,
21659	 *  morphTargets: <bool>,
21660	 *
21661	 *  map: new THREE.Texture( <Image> ),
21662	 *
21663	 *  alphaMap: new THREE.Texture( <Image> ),
21664	 *
21665	 *  displacementMap: new THREE.Texture( <Image> ),
21666	 *  displacementScale: <float>,
21667	 *  displacementBias: <float>
21668	 *
21669	 * }
21670	 */
21671  
21672	function MeshDistanceMaterial( parameters ) {
21673  
21674		Material.call( this );
21675  
21676		this.type = 'MeshDistanceMaterial';
21677  
21678		this.referencePosition = new Vector3();
21679		this.nearDistance = 1;
21680		this.farDistance = 1000;
21681  
21682		this.skinning = false;
21683		this.morphTargets = false;
21684  
21685		this.map = null;
21686  
21687		this.alphaMap = null;
21688  
21689		this.displacementMap = null;
21690		this.displacementScale = 1;
21691		this.displacementBias = 0;
21692  
21693		this.fog = false;
21694		this.lights = false;
21695  
21696		this.setValues( parameters );
21697  
21698	}
21699  
21700	MeshDistanceMaterial.prototype = Object.create( Material.prototype );
21701	MeshDistanceMaterial.prototype.constructor = MeshDistanceMaterial;
21702  
21703	MeshDistanceMaterial.prototype.isMeshDistanceMaterial = true;
21704  
21705	MeshDistanceMaterial.prototype.copy = function ( source ) {
21706  
21707		Material.prototype.copy.call( this, source );
21708  
21709		this.referencePosition.copy( source.referencePosition );
21710		this.nearDistance = source.nearDistance;
21711		this.farDistance = source.farDistance;
21712  
21713		this.skinning = source.skinning;
21714		this.morphTargets = source.morphTargets;
21715  
21716		this.map = source.map;
21717  
21718		this.alphaMap = source.alphaMap;
21719  
21720		this.displacementMap = source.displacementMap;
21721		this.displacementScale = source.displacementScale;
21722		this.displacementBias = source.displacementBias;
21723  
21724		return this;
21725  
21726	};
21727  
21728	/**
21729	 * @author alteredq / http://alteredqualia.com/
21730	 * @author mrdoob / http://mrdoob.com/
21731	 */
21732  
21733	function WebGLShadowMap( _renderer, _objects, maxTextureSize ) {
21734  
21735		var _frustum = new Frustum(),
21736			_projScreenMatrix = new Matrix4(),
21737  
21738			_shadowMapSize = new Vector2(),
21739			_maxShadowMapSize = new Vector2( maxTextureSize, maxTextureSize ),
21740  
21741			_lookTarget = new Vector3(),
21742			_lightPositionWorld = new Vector3(),
21743  
21744			_MorphingFlag = 1,
21745			_SkinningFlag = 2,
21746  
21747			_NumberOfMaterialVariants = ( _MorphingFlag | _SkinningFlag ) + 1,
21748  
21749			_depthMaterials = new Array( _NumberOfMaterialVariants ),
21750			_distanceMaterials = new Array( _NumberOfMaterialVariants ),
21751  
21752			_materialCache = {};
21753  
21754		var shadowSide = { 0: BackSide, 1: FrontSide, 2: DoubleSide };
21755  
21756		var cubeDirections = [
21757			new Vector3( 1, 0, 0 ), new Vector3( - 1, 0, 0 ), new Vector3( 0, 0, 1 ),
21758			new Vector3( 0, 0, - 1 ), new Vector3( 0, 1, 0 ), new Vector3( 0, - 1, 0 )
21759		];
21760  
21761		var cubeUps = [
21762			new Vector3( 0, 1, 0 ), new Vector3( 0, 1, 0 ), new Vector3( 0, 1, 0 ),
21763			new Vector3( 0, 1, 0 ), new Vector3( 0, 0, 1 ),	new Vector3( 0, 0, - 1 )
21764		];
21765  
21766		var cube2DViewPorts = [
21767			new Vector4(), new Vector4(), new Vector4(),
21768			new Vector4(), new Vector4(), new Vector4()
21769		];
21770  
21771		// init
21772  
21773		for ( var i = 0; i !== _NumberOfMaterialVariants; ++ i ) {
21774  
21775			var useMorphing = ( i & _MorphingFlag ) !== 0;
21776			var useSkinning = ( i & _SkinningFlag ) !== 0;
21777  
21778			var depthMaterial = new MeshDepthMaterial( {
21779  
21780				depthPacking: RGBADepthPacking,
21781  
21782				morphTargets: useMorphing,
21783				skinning: useSkinning
21784  
21785			} );
21786  
21787			_depthMaterials[ i ] = depthMaterial;
21788  
21789			//
21790  
21791			var distanceMaterial = new MeshDistanceMaterial( {
21792  
21793				morphTargets: useMorphing,
21794				skinning: useSkinning
21795  
21796			} );
21797  
21798			_distanceMaterials[ i ] = distanceMaterial;
21799  
21800		}
21801  
21802		//
21803  
21804		var scope = this;
21805  
21806		this.enabled = false;
21807  
21808		this.autoUpdate = true;
21809		this.needsUpdate = false;
21810  
21811		this.type = PCFShadowMap;
21812  
21813		this.render = function ( lights, scene, camera ) {
21814  
21815			if ( scope.enabled === false ) return;
21816			if ( scope.autoUpdate === false && scope.needsUpdate === false ) return;
21817  
21818			if ( lights.length === 0 ) return;
21819  
21820			// TODO Clean up (needed in case of contextlost)
21821			var _gl = _renderer.context;
21822			var _state = _renderer.state;
21823  
21824			// Set GL state for depth map.
21825			_state.disable( _gl.BLEND );
21826			_state.buffers.color.setClear( 1, 1, 1, 1 );
21827			_state.buffers.depth.setTest( true );
21828			_state.setScissorTest( false );
21829  
21830			// render depth map
21831  
21832			var faceCount;
21833  
21834			for ( var i = 0, il = lights.length; i < il; i ++ ) {
21835  
21836				var light = lights[ i ];
21837				var shadow = light.shadow;
21838				var isPointLight = light && light.isPointLight;
21839  
21840				if ( shadow === undefined ) {
21841  
21842					console.warn( 'THREE.WebGLShadowMap:', light, 'has no shadow.' );
21843					continue;
21844  
21845				}
21846  
21847				var shadowCamera = shadow.camera;
21848  
21849				_shadowMapSize.copy( shadow.mapSize );
21850				_shadowMapSize.min( _maxShadowMapSize );
21851  
21852				if ( isPointLight ) {
21853  
21854					var vpWidth = _shadowMapSize.x;
21855					var vpHeight = _shadowMapSize.y;
21856  
21857					// These viewports map a cube-map onto a 2D texture with the
21858					// following orientation:
21859					//
21860					//  xzXZ
21861					//   y Y
21862					//
21863					// X - Positive x direction
21864					// x - Negative x direction
21865					// Y - Positive y direction
21866					// y - Negative y direction
21867					// Z - Positive z direction
21868					// z - Negative z direction
21869  
21870					// positive X
21871					cube2DViewPorts[ 0 ].set( vpWidth * 2, vpHeight, vpWidth, vpHeight );
21872					// negative X
21873					cube2DViewPorts[ 1 ].set( 0, vpHeight, vpWidth, vpHeight );
21874					// positive Z
21875					cube2DViewPorts[ 2 ].set( vpWidth * 3, vpHeight, vpWidth, vpHeight );
21876					// negative Z
21877					cube2DViewPorts[ 3 ].set( vpWidth, vpHeight, vpWidth, vpHeight );
21878					// positive Y
21879					cube2DViewPorts[ 4 ].set( vpWidth * 3, 0, vpWidth, vpHeight );
21880					// negative Y
21881					cube2DViewPorts[ 5 ].set( vpWidth, 0, vpWidth, vpHeight );
21882  
21883					_shadowMapSize.x *= 4.0;
21884					_shadowMapSize.y *= 2.0;
21885  
21886				}
21887  
21888				if ( shadow.map === null ) {
21889  
21890					var pars = { minFilter: NearestFilter, magFilter: NearestFilter, format: RGBAFormat };
21891  
21892					shadow.map = new WebGLRenderTarget( _shadowMapSize.x, _shadowMapSize.y, pars );
21893					shadow.map.texture.name = light.name + ".shadowMap";
21894  
21895					shadowCamera.updateProjectionMatrix();
21896  
21897				}
21898  
21899				if ( shadow.isSpotLightShadow ) {
21900  
21901					shadow.update( light );
21902  
21903				}
21904  
21905				var shadowMap = shadow.map;
21906				var shadowMatrix = shadow.matrix;
21907  
21908				_lightPositionWorld.setFromMatrixPosition( light.matrixWorld );
21909				shadowCamera.position.copy( _lightPositionWorld );
21910  
21911				if ( isPointLight ) {
21912  
21913					faceCount = 6;
21914  
21915					// for point lights we set the shadow matrix to be a translation-only matrix
21916					// equal to inverse of the light's position
21917  
21918					shadowMatrix.makeTranslation( - _lightPositionWorld.x, - _lightPositionWorld.y, - _lightPositionWorld.z );
21919  
21920				} else {
21921  
21922					faceCount = 1;
21923  
21924					_lookTarget.setFromMatrixPosition( light.target.matrixWorld );
21925					shadowCamera.lookAt( _lookTarget );
21926					shadowCamera.updateMatrixWorld();
21927  
21928					// compute shadow matrix
21929  
21930					shadowMatrix.set(
21931						0.5, 0.0, 0.0, 0.5,
21932						0.0, 0.5, 0.0, 0.5,
21933						0.0, 0.0, 0.5, 0.5,
21934						0.0, 0.0, 0.0, 1.0
21935					);
21936  
21937					shadowMatrix.multiply( shadowCamera.projectionMatrix );
21938					shadowMatrix.multiply( shadowCamera.matrixWorldInverse );
21939  
21940				}
21941  
21942				_renderer.setRenderTarget( shadowMap );
21943				_renderer.clear();
21944  
21945				// render shadow map for each cube face (if omni-directional) or
21946				// run a single pass if not
21947  
21948				for ( var face = 0; face < faceCount; face ++ ) {
21949  
21950					if ( isPointLight ) {
21951  
21952						_lookTarget.copy( shadowCamera.position );
21953						_lookTarget.add( cubeDirections[ face ] );
21954						shadowCamera.up.copy( cubeUps[ face ] );
21955						shadowCamera.lookAt( _lookTarget );
21956						shadowCamera.updateMatrixWorld();
21957  
21958						var vpDimensions = cube2DViewPorts[ face ];
21959						_state.viewport( vpDimensions );
21960  
21961					}
21962  
21963					// update camera matrices and frustum
21964  
21965					_projScreenMatrix.multiplyMatrices( shadowCamera.projectionMatrix, shadowCamera.matrixWorldInverse );
21966					_frustum.setFromMatrix( _projScreenMatrix );
21967  
21968					// set object matrices & frustum culling
21969  
21970					renderObject( scene, camera, shadowCamera, isPointLight );
21971  
21972				}
21973  
21974			}
21975  
21976			scope.needsUpdate = false;
21977  
21978		};
21979  
21980		function getDepthMaterial( object, material, isPointLight, lightPositionWorld, shadowCameraNear, shadowCameraFar ) {
21981  
21982			var geometry = object.geometry;
21983  
21984			var result = null;
21985  
21986			var materialVariants = _depthMaterials;
21987			var customMaterial = object.customDepthMaterial;
21988  
21989			if ( isPointLight ) {
21990  
21991				materialVariants = _distanceMaterials;
21992				customMaterial = object.customDistanceMaterial;
21993  
21994			}
21995  
21996			if ( ! customMaterial ) {
21997  
21998				var useMorphing = false;
21999  
22000				if ( material.morphTargets ) {
22001  
22002					if ( geometry && geometry.isBufferGeometry ) {
22003  
22004						useMorphing = geometry.morphAttributes && geometry.morphAttributes.position && geometry.morphAttributes.position.length > 0;
22005  
22006					} else if ( geometry && geometry.isGeometry ) {
22007  
22008						useMorphing = geometry.morphTargets && geometry.morphTargets.length > 0;
22009  
22010					}
22011  
22012				}
22013  
22014				if ( object.isSkinnedMesh && material.skinning === false ) {
22015  
22016					console.warn( 'THREE.WebGLShadowMap: THREE.SkinnedMesh with material.skinning set to false:', object );
22017  
22018				}
22019  
22020				var useSkinning = object.isSkinnedMesh && material.skinning;
22021  
22022				var variantIndex = 0;
22023  
22024				if ( useMorphing ) variantIndex |= _MorphingFlag;
22025				if ( useSkinning ) variantIndex |= _SkinningFlag;
22026  
22027				result = materialVariants[ variantIndex ];
22028  
22029			} else {
22030  
22031				result = customMaterial;
22032  
22033			}
22034  
22035			if ( _renderer.localClippingEnabled &&
22036					material.clipShadows === true &&
22037					material.clippingPlanes.length !== 0 ) {
22038  
22039				// in this case we need a unique material instance reflecting the
22040				// appropriate state
22041  
22042				var keyA = result.uuid, keyB = material.uuid;
22043  
22044				var materialsForVariant = _materialCache[ keyA ];
22045  
22046				if ( materialsForVariant === undefined ) {
22047  
22048					materialsForVariant = {};
22049					_materialCache[ keyA ] = materialsForVariant;
22050  
22051				}
22052  
22053				var cachedMaterial = materialsForVariant[ keyB ];
22054  
22055				if ( cachedMaterial === undefined ) {
22056  
22057					cachedMaterial = result.clone();
22058					materialsForVariant[ keyB ] = cachedMaterial;
22059  
22060				}
22061  
22062				result = cachedMaterial;
22063  
22064			}
22065  
22066			result.visible = material.visible;
22067			result.wireframe = material.wireframe;
22068  
22069			result.side = ( material.shadowSide != null ) ? material.shadowSide : shadowSide[ material.side ];
22070  
22071			result.clipShadows = material.clipShadows;
22072			result.clippingPlanes = material.clippingPlanes;
22073			result.clipIntersection = material.clipIntersection;
22074  
22075			result.wireframeLinewidth = material.wireframeLinewidth;
22076			result.linewidth = material.linewidth;
22077  
22078			if ( isPointLight && result.isMeshDistanceMaterial ) {
22079  
22080				result.referencePosition.copy( lightPositionWorld );
22081				result.nearDistance = shadowCameraNear;
22082				result.farDistance = shadowCameraFar;
22083  
22084			}
22085  
22086			return result;
22087  
22088		}
22089  
22090		function renderObject( object, camera, shadowCamera, isPointLight ) {
22091  
22092			if ( object.visible === false ) return;
22093  
22094			var visible = object.layers.test( camera.layers );
22095  
22096			if ( visible && ( object.isMesh || object.isLine || object.isPoints ) ) {
22097  
22098				if ( object.castShadow && ( ! object.frustumCulled || _frustum.intersectsObject( object ) ) ) {
22099  
22100					object.modelViewMatrix.multiplyMatrices( shadowCamera.matrixWorldInverse, object.matrixWorld );
22101  
22102					var geometry = _objects.update( object );
22103					var material = object.material;
22104  
22105					if ( Array.isArray( material ) ) {
22106  
22107						var groups = geometry.groups;
22108  
22109						for ( var k = 0, kl = groups.length; k < kl; k ++ ) {
22110  
22111							var group = groups[ k ];
22112							var groupMaterial = material[ group.materialIndex ];
22113  
22114							if ( groupMaterial && groupMaterial.visible ) {
22115  
22116								var depthMaterial = getDepthMaterial( object, groupMaterial, isPointLight, _lightPositionWorld, shadowCamera.near, shadowCamera.far );
22117								_renderer.renderBufferDirect( shadowCamera, null, geometry, depthMaterial, object, group );
22118  
22119							}
22120  
22121						}
22122  
22123					} else if ( material.visible ) {
22124  
22125						var depthMaterial = getDepthMaterial( object, material, isPointLight, _lightPositionWorld, shadowCamera.near, shadowCamera.far );
22126						_renderer.renderBufferDirect( shadowCamera, null, geometry, depthMaterial, object, null );
22127  
22128					}
22129  
22130				}
22131  
22132			}
22133  
22134			var children = object.children;
22135  
22136			for ( var i = 0, l = children.length; i < l; i ++ ) {
22137  
22138				renderObject( children[ i ], camera, shadowCamera, isPointLight );
22139  
22140			}
22141  
22142		}
22143  
22144	}
22145  
22146	/**
22147	 * @author mrdoob / http://mrdoob.com/
22148	 */
22149  
22150	function CanvasTexture( canvas, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ) {
22151  
22152		Texture.call( this, canvas, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy );
22153  
22154		this.needsUpdate = true;
22155  
22156	}
22157  
22158	CanvasTexture.prototype = Object.create( Texture.prototype );
22159	CanvasTexture.prototype.constructor = CanvasTexture;
22160	CanvasTexture.prototype.isCanvasTexture = true;
22161  
22162	/**
22163	 * @author mikael emtinger / http://gomo.se/
22164	 * @author alteredq / http://alteredqualia.com/
22165	 */
22166  
22167	function WebGLSpriteRenderer( renderer, gl, state, textures, capabilities ) {
22168  
22169		var vertexBuffer, elementBuffer;
22170		var program, attributes, uniforms;
22171  
22172		var texture;
22173  
22174		// decompose matrixWorld
22175  
22176		var spritePosition = new Vector3();
22177		var spriteRotation = new Quaternion();
22178		var spriteScale = new Vector3();
22179  
22180		function init() {
22181  
22182			var vertices = new Float32Array( [
22183				- 0.5, - 0.5, 0, 0,
22184				  0.5, - 0.5, 1, 0,
22185				  0.5, 0.5, 1, 1,
22186				- 0.5, 0.5, 0, 1
22187			] );
22188  
22189			var faces = new Uint16Array( [
22190				0, 1, 2,
22191				0, 2, 3
22192			] );
22193  
22194			vertexBuffer = gl.createBuffer();
22195			elementBuffer = gl.createBuffer();
22196  
22197			gl.bindBuffer( gl.ARRAY_BUFFER, vertexBuffer );
22198			gl.bufferData( gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW );
22199  
22200			gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, elementBuffer );
22201			gl.bufferData( gl.ELEMENT_ARRAY_BUFFER, faces, gl.STATIC_DRAW );
22202  
22203			program = createProgram();
22204  
22205			attributes = {
22206				position: gl.getAttribLocation( program, 'position' ),
22207				uv: gl.getAttribLocation( program, 'uv' )
22208			};
22209  
22210			uniforms = {
22211				uvOffset: gl.getUniformLocation( program, 'uvOffset' ),
22212				uvScale: gl.getUniformLocation( program, 'uvScale' ),
22213  
22214				rotation: gl.getUniformLocation( program, 'rotation' ),
22215				center: gl.getUniformLocation( program, 'center' ),
22216				scale: gl.getUniformLocation( program, 'scale' ),
22217  
22218				color: gl.getUniformLocation( program, 'color' ),
22219				map: gl.getUniformLocation( program, 'map' ),
22220				opacity: gl.getUniformLocation( program, 'opacity' ),
22221  
22222				modelViewMatrix: gl.getUniformLocation( program, 'modelViewMatrix' ),
22223				projectionMatrix: gl.getUniformLocation( program, 'projectionMatrix' ),
22224  
22225				fogType: gl.getUniformLocation( program, 'fogType' ),
22226				fogDensity: gl.getUniformLocation( program, 'fogDensity' ),
22227				fogNear: gl.getUniformLocation( program, 'fogNear' ),
22228				fogFar: gl.getUniformLocation( program, 'fogFar' ),
22229				fogColor: gl.getUniformLocation( program, 'fogColor' ),
22230				fogDepth: gl.getUniformLocation( program, 'fogDepth' ),
22231  
22232				alphaTest: gl.getUniformLocation( program, 'alphaTest' )
22233			};
22234  
22235			var canvas = document.createElementNS( 'http://www.w3.org/1999/xhtml', 'canvas' );
22236			canvas.width = 8;
22237			canvas.height = 8;
22238  
22239			var context = canvas.getContext( '2d' );
22240			context.fillStyle = 'white';
22241			context.fillRect( 0, 0, 8, 8 );
22242  
22243			texture = new CanvasTexture( canvas );
22244  
22245		}
22246  
22247		this.render = function ( sprites, scene, camera ) {
22248  
22249			if ( sprites.length === 0 ) return;
22250  
22251			// setup gl
22252  
22253			if ( program === undefined ) {
22254  
22255				init();
22256  
22257			}
22258  
22259			state.useProgram( program );
22260  
22261			state.initAttributes();
22262			state.enableAttribute( attributes.position );
22263			state.enableAttribute( attributes.uv );
22264			state.disableUnusedAttributes();
22265  
22266			state.disable( gl.CULL_FACE );
22267			state.enable( gl.BLEND );
22268  
22269			gl.bindBuffer( gl.ARRAY_BUFFER, vertexBuffer );
22270			gl.vertexAttribPointer( attributes.position, 2, gl.FLOAT, false, 2 * 8, 0 );
22271			gl.vertexAttribPointer( attributes.uv, 2, gl.FLOAT, false, 2 * 8, 8 );
22272  
22273			gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, elementBuffer );
22274  
22275			gl.uniformMatrix4fv( uniforms.projectionMatrix, false, camera.projectionMatrix.elements );
22276  
22277			state.activeTexture( gl.TEXTURE0 );
22278			gl.uniform1i( uniforms.map, 0 );
22279  
22280			var oldFogType = 0;
22281			var sceneFogType = 0;
22282			var fog = scene.fog;
22283  
22284			if ( fog ) {
22285  
22286				gl.uniform3f( uniforms.fogColor, fog.color.r, fog.color.g, fog.color.b );
22287  
22288				if ( fog.isFog ) {
22289  
22290					gl.uniform1f( uniforms.fogNear, fog.near );
22291					gl.uniform1f( uniforms.fogFar, fog.far );
22292  
22293					gl.uniform1i( uniforms.fogType, 1 );
22294					oldFogType = 1;
22295					sceneFogType = 1;
22296  
22297				} else if ( fog.isFogExp2 ) {
22298  
22299					gl.uniform1f( uniforms.fogDensity, fog.density );
22300  
22301					gl.uniform1i( uniforms.fogType, 2 );
22302					oldFogType = 2;
22303					sceneFogType = 2;
22304  
22305				}
22306  
22307			} else {
22308  
22309				gl.uniform1i( uniforms.fogType, 0 );
22310				oldFogType = 0;
22311				sceneFogType = 0;
22312  
22313			}
22314  
22315  
22316			// update positions and sort
22317  
22318			for ( var i = 0, l = sprites.length; i < l; i ++ ) {
22319  
22320				var sprite = sprites[ i ];
22321  
22322				sprite.modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, sprite.matrixWorld );
22323				sprite.z = - sprite.modelViewMatrix.elements[ 14 ];
22324  
22325			}
22326  
22327			sprites.sort( painterSortStable );
22328  
22329			// render all sprites
22330  
22331			var scale = [];
22332			var center = [];
22333  
22334			for ( var i = 0, l = sprites.length; i < l; i ++ ) {
22335  
22336				var sprite = sprites[ i ];
22337				var material = sprite.material;
22338  
22339				if ( material.visible === false ) continue;
22340  
22341				sprite.onBeforeRender( renderer, scene, camera, undefined, material, undefined );
22342  
22343				gl.uniform1f( uniforms.alphaTest, material.alphaTest );
22344				gl.uniformMatrix4fv( uniforms.modelViewMatrix, false, sprite.modelViewMatrix.elements );
22345  
22346				sprite.matrixWorld.decompose( spritePosition, spriteRotation, spriteScale );
22347  
22348				scale[ 0 ] = spriteScale.x;
22349				scale[ 1 ] = spriteScale.y;
22350  
22351				center[ 0 ] = sprite.center.x - 0.5;
22352				center[ 1 ] = sprite.center.y - 0.5;
22353  
22354				var fogType = 0;
22355  
22356				if ( scene.fog && material.fog ) {
22357  
22358					fogType = sceneFogType;
22359  
22360				}
22361  
22362				if ( oldFogType !== fogType ) {
22363  
22364					gl.uniform1i( uniforms.fogType, fogType );
22365					oldFogType = fogType;
22366  
22367				}
22368  
22369				if ( material.map !== null ) {
22370  
22371					gl.uniform2f( uniforms.uvOffset, material.map.offset.x, material.map.offset.y );
22372					gl.uniform2f( uniforms.uvScale, material.map.repeat.x, material.map.repeat.y );
22373  
22374				} else {
22375  
22376					gl.uniform2f( uniforms.uvOffset, 0, 0 );
22377					gl.uniform2f( uniforms.uvScale, 1, 1 );
22378  
22379				}
22380  
22381				gl.uniform1f( uniforms.opacity, material.opacity );
22382				gl.uniform3f( uniforms.color, material.color.r, material.color.g, material.color.b );
22383  
22384				gl.uniform1f( uniforms.rotation, material.rotation );
22385				gl.uniform2fv( uniforms.center, center );
22386				gl.uniform2fv( uniforms.scale, scale );
22387  
22388				state.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst, material.blendEquationAlpha, material.blendSrcAlpha, material.blendDstAlpha, material.premultipliedAlpha );
22389				state.buffers.depth.setTest( material.depthTest );
22390				state.buffers.depth.setMask( material.depthWrite );
22391				state.buffers.color.setMask( material.colorWrite );
22392  
22393				textures.setTexture2D( material.map || texture, 0 );
22394  
22395				gl.drawElements( gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0 );
22396  
22397				sprite.onAfterRender( renderer, scene, camera, undefined, material, undefined );
22398  
22399			}
22400  
22401			// restore gl
22402  
22403			state.enable( gl.CULL_FACE );
22404  
22405			state.reset();
22406  
22407		};
22408  
22409		function createProgram() {
22410  
22411			var program = gl.createProgram();
22412  
22413			var vertexShader = gl.createShader( gl.VERTEX_SHADER );
22414			var fragmentShader = gl.createShader( gl.FRAGMENT_SHADER );
22415  
22416			gl.shaderSource( vertexShader, [
22417  
22418				'precision ' + capabilities.precision + ' float;',
22419  
22420				'#define SHADER_NAME ' + 'SpriteMaterial',
22421  
22422				'uniform mat4 modelViewMatrix;',
22423				'uniform mat4 projectionMatrix;',
22424				'uniform float rotation;',
22425				'uniform vec2 center;',
22426				'uniform vec2 scale;',
22427				'uniform vec2 uvOffset;',
22428				'uniform vec2 uvScale;',
22429  
22430				'attribute vec2 position;',
22431				'attribute vec2 uv;',
22432  
22433				'varying vec2 vUV;',
22434				'varying float fogDepth;',
22435  
22436				'void main() {',
22437  
22438				'	vUV = uvOffset + uv * uvScale;',
22439  
22440				'	vec2 alignedPosition = ( position - center ) * scale;',
22441  
22442				'	vec2 rotatedPosition;',
22443				'	rotatedPosition.x = cos( rotation ) * alignedPosition.x - sin( rotation ) * alignedPosition.y;',
22444				'	rotatedPosition.y = sin( rotation ) * alignedPosition.x + cos( rotation ) * alignedPosition.y;',
22445  
22446				'	vec4 mvPosition;',
22447  
22448				'	mvPosition = modelViewMatrix * vec4( 0.0, 0.0, 0.0, 1.0 );',
22449				'	mvPosition.xy += rotatedPosition;',
22450  
22451				'	gl_Position = projectionMatrix * mvPosition;',
22452  
22453				'	fogDepth = - mvPosition.z;',
22454  
22455				'}'
22456  
22457			].join( '\n' ) );
22458  
22459			gl.shaderSource( fragmentShader, [
22460  
22461				'precision ' + capabilities.precision + ' float;',
22462  
22463				'#define SHADER_NAME ' + 'SpriteMaterial',
22464  
22465				'uniform vec3 color;',
22466				'uniform sampler2D map;',
22467				'uniform float opacity;',
22468  
22469				'uniform int fogType;',
22470				'uniform vec3 fogColor;',
22471				'uniform float fogDensity;',
22472				'uniform float fogNear;',
22473				'uniform float fogFar;',
22474				'uniform float alphaTest;',
22475  
22476				'varying vec2 vUV;',
22477				'varying float fogDepth;',
22478  
22479				'void main() {',
22480  
22481				'	vec4 texture = texture2D( map, vUV );',
22482  
22483				'	gl_FragColor = vec4( color * texture.xyz, texture.a * opacity );',
22484  
22485				'	if ( gl_FragColor.a < alphaTest ) discard;',
22486  
22487				'	if ( fogType > 0 ) {',
22488  
22489				'		float fogFactor = 0.0;',
22490  
22491				'		if ( fogType == 1 ) {',
22492  
22493				'			fogFactor = smoothstep( fogNear, fogFar, fogDepth );',
22494  
22495				'		} else {',
22496  
22497				'			const float LOG2 = 1.442695;',
22498				'			fogFactor = exp2( - fogDensity * fogDensity * fogDepth * fogDepth * LOG2 );',
22499				'			fogFactor = 1.0 - clamp( fogFactor, 0.0, 1.0 );',
22500  
22501				'		}',
22502  
22503				'		gl_FragColor.rgb = mix( gl_FragColor.rgb, fogColor, fogFactor );',
22504  
22505				'	}',
22506  
22507				'}'
22508  
22509			].join( '\n' ) );
22510  
22511			gl.compileShader( vertexShader );
22512			gl.compileShader( fragmentShader );
22513  
22514			gl.attachShader( program, vertexShader );
22515			gl.attachShader( program, fragmentShader );
22516  
22517			gl.linkProgram( program );
22518  
22519			return program;
22520  
vendor: 9,601 bytes, lines 22521-23016
22521		}
22522  
22523		function painterSortStable( a, b ) {
22524  
22525			if ( a.renderOrder !== b.renderOrder ) {
22526  
22527				return a.renderOrder - b.renderOrder;
22528  
22529			} else if ( a.z !== b.z ) {
22530  
22531				return b.z - a.z;
22532  
22533			} else {
22534  
22535				return b.id - a.id;
22536  
22537			}
22538  
22539		}
22540  
22541	}
22542  
22543	/**
22544	 * @author mrdoob / http://mrdoob.com/
22545	 */
22546  
22547	function WebGLState( gl, extensions, utils ) {
22548  
22549		function ColorBuffer() {
22550  
22551			var locked = false;
22552  
22553			var color = new Vector4();
22554			var currentColorMask = null;
22555			var currentColorClear = new Vector4( 0, 0, 0, 0 );
22556  
22557			return {
22558  
22559				setMask: function ( colorMask ) {
22560  
22561					if ( currentColorMask !== colorMask && ! locked ) {
22562  
22563						gl.colorMask( colorMask, colorMask, colorMask, colorMask );
22564						currentColorMask = colorMask;
22565  
22566					}
22567  
22568				},
22569  
22570				setLocked: function ( lock ) {
22571  
22572					locked = lock;
22573  
22574				},
22575  
22576				setClear: function ( r, g, b, a, premultipliedAlpha ) {
22577  
22578					if ( premultipliedAlpha === true ) {
22579  
22580						r *= a; g *= a; b *= a;
22581  
22582					}
22583  
22584					color.set( r, g, b, a );
22585  
22586					if ( currentColorClear.equals( color ) === false ) {
22587  
22588						gl.clearColor( r, g, b, a );
22589						currentColorClear.copy( color );
22590  
22591					}
22592  
22593				},
22594  
22595				reset: function () {
22596  
22597					locked = false;
22598  
22599					currentColorMask = null;
22600					currentColorClear.set( - 1, 0, 0, 0 ); // set to invalid state
22601  
22602				}
22603  
22604			};
22605  
22606		}
22607  
22608		function DepthBuffer() {
22609  
22610			var locked = false;
22611  
22612			var currentDepthMask = null;
22613			var currentDepthFunc = null;
22614			var currentDepthClear = null;
22615  
22616			return {
22617  
22618				setTest: function ( depthTest ) {
22619  
22620					if ( depthTest ) {
22621  
22622						enable( gl.DEPTH_TEST );
22623  
22624					} else {
22625  
22626						disable( gl.DEPTH_TEST );
22627  
22628					}
22629  
22630				},
22631  
22632				setMask: function ( depthMask ) {
22633  
22634					if ( currentDepthMask !== depthMask && ! locked ) {
22635  
22636						gl.depthMask( depthMask );
22637						currentDepthMask = depthMask;
22638  
22639					}
22640  
22641				},
22642  
22643				setFunc: function ( depthFunc ) {
22644  
22645					if ( currentDepthFunc !== depthFunc ) {
22646  
22647						if ( depthFunc ) {
22648  
22649							switch ( depthFunc ) {
22650  
22651								case NeverDepth:
22652  
22653									gl.depthFunc( gl.NEVER );
22654									break;
22655  
22656								case AlwaysDepth:
22657  
22658									gl.depthFunc( gl.ALWAYS );
22659									break;
22660  
22661								case LessDepth:
22662  
22663									gl.depthFunc( gl.LESS );
22664									break;
22665  
22666								case LessEqualDepth:
22667  
22668									gl.depthFunc( gl.LEQUAL );
22669									break;
22670  
22671								case EqualDepth:
22672  
22673									gl.depthFunc( gl.EQUAL );
22674									break;
22675  
22676								case GreaterEqualDepth:
22677  
22678									gl.depthFunc( gl.GEQUAL );
22679									break;
22680  
22681								case GreaterDepth:
22682  
22683									gl.depthFunc( gl.GREATER );
22684									break;
22685  
22686								case NotEqualDepth:
22687  
22688									gl.depthFunc( gl.NOTEQUAL );
22689									break;
22690  
22691								default:
22692  
22693									gl.depthFunc( gl.LEQUAL );
22694  
22695							}
22696  
22697						} else {
22698  
22699							gl.depthFunc( gl.LEQUAL );
22700  
22701						}
22702  
22703						currentDepthFunc = depthFunc;
22704  
22705					}
22706  
22707				},
22708  
22709				setLocked: function ( lock ) {
22710  
22711					locked = lock;
22712  
22713				},
22714  
22715				setClear: function ( depth ) {
22716  
22717					if ( currentDepthClear !== depth ) {
22718  
22719						gl.clearDepth( depth );
22720						currentDepthClear = depth;
22721  
22722					}
22723  
22724				},
22725  
22726				reset: function () {
22727  
22728					locked = false;
22729  
22730					currentDepthMask = null;
22731					currentDepthFunc = null;
22732					currentDepthClear = null;
22733  
22734				}
22735  
22736			};
22737  
22738		}
22739  
22740		function StencilBuffer() {
22741  
22742			var locked = false;
22743  
22744			var currentStencilMask = null;
22745			var currentStencilFunc = null;
22746			var currentStencilRef = null;
22747			var currentStencilFuncMask = null;
22748			var currentStencilFail = null;
22749			var currentStencilZFail = null;
22750			var currentStencilZPass = null;
22751			var currentStencilClear = null;
22752  
22753			return {
22754  
22755				setTest: function ( stencilTest ) {
22756  
22757					if ( stencilTest ) {
22758  
22759						enable( gl.STENCIL_TEST );
22760  
22761					} else {
22762  
22763						disable( gl.STENCIL_TEST );
22764  
22765					}
22766  
22767				},
22768  
22769				setMask: function ( stencilMask ) {
22770  
22771					if ( currentStencilMask !== stencilMask && ! locked ) {
22772  
22773						gl.stencilMask( stencilMask );
22774						currentStencilMask = stencilMask;
22775  
22776					}
22777  
22778				},
22779  
22780				setFunc: function ( stencilFunc, stencilRef, stencilMask ) {
22781  
22782					if ( currentStencilFunc !== stencilFunc ||
22783						 currentStencilRef 	!== stencilRef 	||
22784						 currentStencilFuncMask !== stencilMask ) {
22785  
22786						gl.stencilFunc( stencilFunc, stencilRef, stencilMask );
22787  
22788						currentStencilFunc = stencilFunc;
22789						currentStencilRef = stencilRef;
22790						currentStencilFuncMask = stencilMask;
22791  
22792					}
22793  
22794				},
22795  
22796				setOp: function ( stencilFail, stencilZFail, stencilZPass ) {
22797  
22798					if ( currentStencilFail	 !== stencilFail 	||
22799						 currentStencilZFail !== stencilZFail ||
22800						 currentStencilZPass !== stencilZPass ) {
22801  
22802						gl.stencilOp( stencilFail, stencilZFail, stencilZPass );
22803  
22804						currentStencilFail = stencilFail;
22805						currentStencilZFail = stencilZFail;
22806						currentStencilZPass = stencilZPass;
22807  
22808					}
22809  
22810				},
22811  
22812				setLocked: function ( lock ) {
22813  
22814					locked = lock;
22815  
22816				},
22817  
22818				setClear: function ( stencil ) {
22819  
22820					if ( currentStencilClear !== stencil ) {
22821  
22822						gl.clearStencil( stencil );
22823						currentStencilClear = stencil;
22824  
22825					}
22826  
22827				},
22828  
22829				reset: function () {
22830  
22831					locked = false;
22832  
22833					currentStencilMask = null;
22834					currentStencilFunc = null;
22835					currentStencilRef = null;
22836					currentStencilFuncMask = null;
22837					currentStencilFail = null;
22838					currentStencilZFail = null;
22839					currentStencilZPass = null;
22840					currentStencilClear = null;
22841  
22842				}
22843  
22844			};
22845  
22846		}
22847  
22848		//
22849  
22850		var colorBuffer = new ColorBuffer();
22851		var depthBuffer = new DepthBuffer();
22852		var stencilBuffer = new StencilBuffer();
22853  
22854		var maxVertexAttributes = gl.getParameter( gl.MAX_VERTEX_ATTRIBS );
22855		var newAttributes = new Uint8Array( maxVertexAttributes );
22856		var enabledAttributes = new Uint8Array( maxVertexAttributes );
22857		var attributeDivisors = new Uint8Array( maxVertexAttributes );
22858  
22859		var capabilities = {};
22860  
22861		var compressedTextureFormats = null;
22862  
22863		var currentProgram = null;
22864  
22865		var currentBlending = null;
22866		var currentBlendEquation = null;
22867		var currentBlendSrc = null;
22868		var currentBlendDst = null;
22869		var currentBlendEquationAlpha = null;
22870		var currentBlendSrcAlpha = null;
22871		var currentBlendDstAlpha = null;
22872		var currentPremultipledAlpha = false;
22873  
22874		var currentFlipSided = null;
22875		var currentCullFace = null;
22876  
22877		var currentLineWidth = null;
22878  
22879		var currentPolygonOffsetFactor = null;
22880		var currentPolygonOffsetUnits = null;
22881  
22882		var maxTextures = gl.getParameter( gl.MAX_COMBINED_TEXTURE_IMAGE_UNITS );
22883  
22884		var lineWidthAvailable = false;
22885		var version = 0;
22886		var glVersion = gl.getParameter( gl.VERSION );
22887  
22888		if ( glVersion.indexOf( 'WebGL' ) !== - 1 ) {
22889  
22890			version = parseFloat( /^WebGL\ ([0-9])/.exec( glVersion )[ 1 ] );
22891			lineWidthAvailable = ( version >= 1.0 );
22892  
22893		} else if ( glVersion.indexOf( 'OpenGL ES' ) !== - 1 ) {
22894  
22895			version = parseFloat( /^OpenGL\ ES\ ([0-9])/.exec( glVersion )[ 1 ] );
22896			lineWidthAvailable = ( version >= 2.0 );
22897  
22898		}
22899  
22900		var currentTextureSlot = null;
22901		var currentBoundTextures = {};
22902  
22903		var currentScissor = new Vector4();
22904		var currentViewport = new Vector4();
22905  
22906		function createTexture( type, target, count ) {
22907  
22908			var data = new Uint8Array( 4 ); // 4 is required to match default unpack alignment of 4.
22909			var texture = gl.createTexture();
22910  
22911			gl.bindTexture( type, texture );
22912			gl.texParameteri( type, gl.TEXTURE_MIN_FILTER, gl.NEAREST );
22913			gl.texParameteri( type, gl.TEXTURE_MAG_FILTER, gl.NEAREST );
22914  
22915			for ( var i = 0; i < count; i ++ ) {
22916  
22917				gl.texImage2D( target + i, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, data );
22918  
22919			}
22920  
22921			return texture;
22922  
22923		}
22924  
22925		var emptyTextures = {};
22926		emptyTextures[ gl.TEXTURE_2D ] = createTexture( gl.TEXTURE_2D, gl.TEXTURE_2D, 1 );
22927		emptyTextures[ gl.TEXTURE_CUBE_MAP ] = createTexture( gl.TEXTURE_CUBE_MAP, gl.TEXTURE_CUBE_MAP_POSITIVE_X, 6 );
22928  
22929		// init
22930  
22931		colorBuffer.setClear( 0, 0, 0, 1 );
22932		depthBuffer.setClear( 1 );
22933		stencilBuffer.setClear( 0 );
22934  
22935		enable( gl.DEPTH_TEST );
22936		depthBuffer.setFunc( LessEqualDepth );
22937  
22938		setFlipSided( false );
22939		setCullFace( CullFaceBack );
22940		enable( gl.CULL_FACE );
22941  
22942		enable( gl.BLEND );
22943		setBlending( NormalBlending );
22944  
22945		//
22946  
22947		function initAttributes() {
22948  
22949			for ( var i = 0, l = newAttributes.length; i < l; i ++ ) {
22950  
22951				newAttributes[ i ] = 0;
22952  
22953			}
22954  
22955		}
22956  
22957		function enableAttribute( attribute ) {
22958  
22959			enableAttributeAndDivisor( attribute, 0 );
22960  
22961		}
22962  
22963		function enableAttributeAndDivisor( attribute, meshPerAttribute ) {
22964  
22965			newAttributes[ attribute ] = 1;
22966  
22967			if ( enabledAttributes[ attribute ] === 0 ) {
22968  
22969				gl.enableVertexAttribArray( attribute );
22970				enabledAttributes[ attribute ] = 1;
22971  
22972			}
22973  
22974			if ( attributeDivisors[ attribute ] !== meshPerAttribute ) {
22975  
22976				var extension = extensions.get( 'ANGLE_instanced_arrays' );
22977  
22978				extension.vertexAttribDivisorANGLE( attribute, meshPerAttribute );
22979				attributeDivisors[ attribute ] = meshPerAttribute;
22980  
22981			}
22982  
22983		}
22984  
22985		function disableUnusedAttributes() {
22986  
22987			for ( var i = 0, l = enabledAttributes.length; i !== l; ++ i ) {
22988  
22989				if ( enabledAttributes[ i ] !== newAttributes[ i ] ) {
22990  
22991					gl.disableVertexAttribArray( i );
22992					enabledAttributes[ i ] = 0;
22993  
22994				}
22995  
22996			}
22997  
22998		}
22999  
23000		function enable( id ) {
23001  
23002			if ( capabilities[ id ] !== true ) {
23003  
23004				gl.enable( id );
23005				capabilities[ id ] = true;
23006  
23007			}
23008  
23009		}
23010  
23011		function disable( id ) {
23012  
23013			if ( capabilities[ id ] !== false ) {
23014  
23015				gl.disable( id );
23016				capabilities[ id ] = false;
23017  
23018			}
23019  
23020		}
23021  
23022		function getCompressedTextureFormats() {
23023  
23024			if ( compressedTextureFormats === null ) {
23025  
23026				compressedTextureFormats = [];
23027  
23028				if ( extensions.get( 'WEBGL_compressed_texture_pvrtc' ) ||
23029					 extensions.get( 'WEBGL_compressed_texture_s3tc' ) ||
23030					 extensions.get( 'WEBGL_compressed_texture_etc1' ) ||
23031					 extensions.get( 'WEBGL_compressed_texture_astc' ) ) {
23032  
23033					var formats = gl.getParameter( gl.COMPRESSED_TEXTURE_FORMATS );
23034  
23035					for ( var i = 0; i < formats.length; i ++ ) {
23036  
23037						compressedTextureFormats.push( formats[ i ] );
23038  
23039					}
23040  
23041				}
23042  
23043			}
23044  
23045			return compressedTextureFormats;
23046  
23047		}
23048  
23049		function useProgram( program ) {
23050  
23051			if ( currentProgram !== program ) {
23052  
23053				gl.useProgram( program );
23054  
23055				currentProgram = program;
23056  
23057				return true;
23058  
23059			}
23060  
23061			return false;
23062  
23063		}
23064  
23065		function setBlending( blending, blendEquation, blendSrc, blendDst, blendEquationAlpha, blendSrcAlpha, blendDstAlpha, premultipliedAlpha ) {
23066  
23067			if ( blending !== NoBlending ) {
23068  
23069				enable( gl.BLEND );
23070  
23071			} else {
23072  
23073				disable( gl.BLEND );
23074  
23075			}
23076  
23077			if ( blending !== CustomBlending ) {
23078  
23079				if ( blending !== currentBlending || premultipliedAlpha !== currentPremultipledAlpha ) {
23080  
23081					switch ( blending ) {
23082  
23083						case AdditiveBlending:
23084  
23085							if ( premultipliedAlpha ) {
23086  
23087								gl.blendEquationSeparate( gl.FUNC_ADD, gl.FUNC_ADD );
23088								gl.blendFuncSeparate( gl.ONE, gl.ONE, gl.ONE, gl.ONE );
23089  
23090							} else {
23091  
23092								gl.blendEquation( gl.FUNC_ADD );
23093								gl.blendFunc( gl.SRC_ALPHA, gl.ONE );
23094  
23095							}
23096							break;
23097  
23098						case SubtractiveBlending:
23099  
23100							if ( premultipliedAlpha ) {
23101  
23102								gl.blendEquationSeparate( gl.FUNC_ADD, gl.FUNC_ADD );
23103								gl.blendFuncSeparate( gl.ZERO, gl.ZERO, gl.ONE_MINUS_SRC_COLOR, gl.ONE_MINUS_SRC_ALPHA );
23104  
23105							} else {
23106  
23107								gl.blendEquation( gl.FUNC_ADD );
23108								gl.blendFunc( gl.ZERO, gl.ONE_MINUS_SRC_COLOR );
23109  
23110							}
23111							break;
23112  
23113						case MultiplyBlending:
23114  
23115							if ( premultipliedAlpha ) {
23116  
23117								gl.blendEquationSeparate( gl.FUNC_ADD, gl.FUNC_ADD );
23118								gl.blendFuncSeparate( gl.ZERO, gl.SRC_COLOR, gl.ZERO, gl.SRC_ALPHA );
23119  
23120							} else {
23121  
23122								gl.blendEquation( gl.FUNC_ADD );
23123								gl.blendFunc( gl.ZERO, gl.SRC_COLOR );
23124  
23125							}
23126							break;
23127  
23128						default:
23129  
23130							if ( premultipliedAlpha ) {
23131  
23132								gl.blendEquationSeparate( gl.FUNC_ADD, gl.FUNC_ADD );
23133								gl.blendFuncSeparate( gl.ONE, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA );
23134  
23135							} else {
23136  
23137								gl.blendEquationSeparate( gl.FUNC_ADD, gl.FUNC_ADD );
23138								gl.blendFuncSeparate( gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA );
23139  
23140							}
23141  
23142					}
23143  
23144				}
23145  
23146				currentBlendEquation = null;
23147				currentBlendSrc = null;
23148				currentBlendDst = null;
23149				currentBlendEquationAlpha = null;
23150				currentBlendSrcAlpha = null;
23151				currentBlendDstAlpha = null;
23152  
23153			} else {
23154  
23155				blendEquationAlpha = blendEquationAlpha || blendEquation;
23156				blendSrcAlpha = blendSrcAlpha || blendSrc;
23157				blendDstAlpha = blendDstAlpha || blendDst;
23158  
23159				if ( blendEquation !== currentBlendEquation || blendEquationAlpha !== currentBlendEquationAlpha ) {
23160  
23161					gl.blendEquationSeparate( utils.convert( blendEquation ), utils.convert( blendEquationAlpha ) );
23162  
23163					currentBlendEquation = blendEquation;
23164					currentBlendEquationAlpha = blendEquationAlpha;
23165  
23166				}
23167  
23168				if ( blendSrc !== currentBlendSrc || blendDst !== currentBlendDst || blendSrcAlpha !== currentBlendSrcAlpha || blendDstAlpha !== currentBlendDstAlpha ) {
23169  
23170					gl.blendFuncSeparate( utils.convert( blendSrc ), utils.convert( blendDst ), utils.convert( blendSrcAlpha ), utils.convert( blendDstAlpha ) );
23171  
23172					currentBlendSrc = blendSrc;
23173					currentBlendDst = blendDst;
23174					currentBlendSrcAlpha = blendSrcAlpha;
23175					currentBlendDstAlpha = blendDstAlpha;
23176  
23177				}
23178  
23179			}
23180  
23181			currentBlending = blending;
23182			currentPremultipledAlpha = premultipliedAlpha;
23183  
23184		}
23185  
23186		function setMaterial( material, frontFaceCW ) {
23187  
23188			material.side === DoubleSide
23189				? disable( gl.CULL_FACE )
23190				: enable( gl.CULL_FACE );
23191  
23192			var flipSided = ( material.side === BackSide );
23193			if ( frontFaceCW ) flipSided = ! flipSided;
23194  
23195			setFlipSided( flipSided );
23196  
23197			material.transparent === true
23198				? setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst, material.blendEquationAlpha, material.blendSrcAlpha, material.blendDstAlpha, material.premultipliedAlpha )
23199				: setBlending( NoBlending );
23200  
23201			depthBuffer.setFunc( material.depthFunc );
23202			depthBuffer.setTest( material.depthTest );
23203			depthBuffer.setMask( material.depthWrite );
23204			colorBuffer.setMask( material.colorWrite );
23205  
23206			setPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits );
23207  
23208		}
23209  
23210		//
23211  
23212		function setFlipSided( flipSided ) {
23213  
23214			if ( currentFlipSided !== flipSided ) {
23215  
23216				if ( flipSided ) {
23217  
23218					gl.frontFace( gl.CW );
23219  
23220				} else {
23221  
vendor: 4,155 bytes, lines 23222-23465
23222					gl.frontFace( gl.CCW );
23223  
23224				}
23225  
23226				currentFlipSided = flipSided;
23227  
23228			}
23229  
23230		}
23231  
23232		function setCullFace( cullFace ) {
23233  
23234			if ( cullFace !== CullFaceNone ) {
23235  
23236				enable( gl.CULL_FACE );
23237  
23238				if ( cullFace !== currentCullFace ) {
23239  
23240					if ( cullFace === CullFaceBack ) {
23241  
23242						gl.cullFace( gl.BACK );
23243  
23244					} else if ( cullFace === CullFaceFront ) {
23245  
23246						gl.cullFace( gl.FRONT );
23247  
23248					} else {
23249  
23250						gl.cullFace( gl.FRONT_AND_BACK );
23251  
23252					}
23253  
23254				}
23255  
23256			} else {
23257  
23258				disable( gl.CULL_FACE );
23259  
23260			}
23261  
23262			currentCullFace = cullFace;
23263  
23264		}
23265  
23266		function setLineWidth( width ) {
23267  
23268			if ( width !== currentLineWidth ) {
23269  
23270				if ( lineWidthAvailable ) gl.lineWidth( width );
23271  
23272				currentLineWidth = width;
23273  
23274			}
23275  
23276		}
23277  
23278		function setPolygonOffset( polygonOffset, factor, units ) {
23279  
23280			if ( polygonOffset ) {
23281  
23282				enable( gl.POLYGON_OFFSET_FILL );
23283  
23284				if ( currentPolygonOffsetFactor !== factor || currentPolygonOffsetUnits !== units ) {
23285  
23286					gl.polygonOffset( factor, units );
23287  
23288					currentPolygonOffsetFactor = factor;
23289					currentPolygonOffsetUnits = units;
23290  
23291				}
23292  
23293			} else {
23294  
23295				disable( gl.POLYGON_OFFSET_FILL );
23296  
23297			}
23298  
23299		}
23300  
23301		function setScissorTest( scissorTest ) {
23302  
23303			if ( scissorTest ) {
23304  
23305				enable( gl.SCISSOR_TEST );
23306  
23307			} else {
23308  
23309				disable( gl.SCISSOR_TEST );
23310  
23311			}
23312  
23313		}
23314  
23315		// texture
23316  
23317		function activeTexture( webglSlot ) {
23318  
23319			if ( webglSlot === undefined ) webglSlot = gl.TEXTURE0 + maxTextures - 1;
23320  
23321			if ( currentTextureSlot !== webglSlot ) {
23322  
23323				gl.activeTexture( webglSlot );
23324				currentTextureSlot = webglSlot;
23325  
23326			}
23327  
23328		}
23329  
23330		function bindTexture( webglType, webglTexture ) {
23331  
23332			if ( currentTextureSlot === null ) {
23333  
23334				activeTexture();
23335  
23336			}
23337  
23338			var boundTexture = currentBoundTextures[ currentTextureSlot ];
23339  
23340			if ( boundTexture === undefined ) {
23341  
23342				boundTexture = { type: undefined, texture: undefined };
23343				currentBoundTextures[ currentTextureSlot ] = boundTexture;
23344  
23345			}
23346  
23347			if ( boundTexture.type !== webglType || boundTexture.texture !== webglTexture ) {
23348  
23349				gl.bindTexture( webglType, webglTexture || emptyTextures[ webglType ] );
23350  
23351				boundTexture.type = webglType;
23352				boundTexture.texture = webglTexture;
23353  
23354			}
23355  
23356		}
23357  
23358		function compressedTexImage2D() {
23359  
23360			try {
23361  
23362				gl.compressedTexImage2D.apply( gl, arguments );
23363  
23364			} catch ( error ) {
23365  
23366				console.error( 'THREE.WebGLState:', error );
23367  
23368			}
23369  
23370		}
23371  
23372		function texImage2D() {
23373  
23374			try {
23375  
23376				gl.texImage2D.apply( gl, arguments );
23377  
23378			} catch ( error ) {
23379  
23380				console.error( 'THREE.WebGLState:', error );
23381  
23382			}
23383  
23384		}
23385  
23386		//
23387  
23388		function scissor( scissor ) {
23389  
23390			if ( currentScissor.equals( scissor ) === false ) {
23391  
23392				gl.scissor( scissor.x, scissor.y, scissor.z, scissor.w );
23393				currentScissor.copy( scissor );
23394  
23395			}
23396  
23397		}
23398  
23399		function viewport( viewport ) {
23400  
23401			if ( currentViewport.equals( viewport ) === false ) {
23402  
23403				gl.viewport( viewport.x, viewport.y, viewport.z, viewport.w );
23404				currentViewport.copy( viewport );
23405  
23406			}
23407  
23408		}
23409  
23410		//
23411  
23412		function reset() {
23413  
23414			for ( var i = 0; i < enabledAttributes.length; i ++ ) {
23415  
23416				if ( enabledAttributes[ i ] === 1 ) {
23417  
23418					gl.disableVertexAttribArray( i );
23419					enabledAttributes[ i ] = 0;
23420  
23421				}
23422  
23423			}
23424  
23425			capabilities = {};
23426  
23427			compressedTextureFormats = null;
23428  
23429			currentTextureSlot = null;
23430			currentBoundTextures = {};
23431  
23432			currentProgram = null;
23433  
23434			currentBlending = null;
23435  
23436			currentFlipSided = null;
23437			currentCullFace = null;
23438  
23439			colorBuffer.reset();
23440			depthBuffer.reset();
23441			stencilBuffer.reset();
23442  
23443		}
23444  
23445		return {
23446  
23447			buffers: {
23448				color: colorBuffer,
23449				depth: depthBuffer,
23450				stencil: stencilBuffer
23451			},
23452  
23453			initAttributes: initAttributes,
23454			enableAttribute: enableAttribute,
23455			enableAttributeAndDivisor: enableAttributeAndDivisor,
23456			disableUnusedAttributes: disableUnusedAttributes,
23457			enable: enable,
23458			disable: disable,
23459			getCompressedTextureFormats: getCompressedTextureFormats,
23460  
23461			useProgram: useProgram,
23462  
23463			setBlending: setBlending,
23464			setMaterial: setMaterial,
23465  
23466			setFlipSided: setFlipSided,
23467			setCullFace: setCullFace,
23468  
23469			setLineWidth: setLineWidth,
23470			setPolygonOffset: setPolygonOffset,
23471  
23472			setScissorTest: setScissorTest,
23473  
23474			activeTexture: activeTexture,
23475			bindTexture: bindTexture,
23476			compressedTexImage2D: compressedTexImage2D,
23477			texImage2D: texImage2D,
23478  
23479			scissor: scissor,
23480			viewport: viewport,
23481  
23482			reset: reset
23483  
23484		};
23485  
23486	}
23487  
23488	/**
23489	 * @author mrdoob / http://mrdoob.com/
23490	 */
23491  
23492	function WebGLTextures( _gl, extensions, state, properties, capabilities, utils, info ) {
23493  
23494		var _isWebGL2 = ( typeof WebGL2RenderingContext !== 'undefined' && _gl instanceof WebGL2RenderingContext ); /* global WebGL2RenderingContext */
23495		var _videoTextures = {};
23496		var _canvas;
23497  
23498		//
23499  
23500		function clampToMaxSize( image, maxSize ) {
23501  
23502			if ( image.width > maxSize || image.height > maxSize ) {
23503  
23504				if ( 'data' in image ) {
23505  
23506					console.warn( 'THREE.WebGLRenderer: image in DataTexture is too big (' + image.width + 'x' + image.height + ').' );
23507					return;
23508  
23509				}
23510  
23511				// Warning: Scaling through the canvas will only work with images that use
23512				// premultiplied alpha.
23513  
23514				var scale = maxSize / Math.max( image.width, image.height );
23515  
23516				var canvas = document.createElementNS( 'http://www.w3.org/1999/xhtml', 'canvas' );
23517				canvas.width = Math.floor( image.width * scale );
23518				canvas.height = Math.floor( image.height * scale );
23519  
23520				var context = canvas.getContext( '2d' );
23521				context.drawImage( image, 0, 0, image.width, image.height, 0, 0, canvas.width, canvas.height );
23522  
23523				console.warn( 'THREE.WebGLRenderer: image is too big (' + image.width + 'x' + image.height + '). Resized to ' + canvas.width + 'x' + canvas.height, image );
23524  
23525				return canvas;
23526  
23527			}
23528  
23529			return image;
23530  
23531		}
23532  
23533		function isPowerOfTwo( image ) {
23534  
23535			return _Math.isPowerOfTwo( image.width ) && _Math.isPowerOfTwo( image.height );
23536  
23537		}
23538  
23539		function makePowerOfTwo( image ) {
23540  
23541			if ( image instanceof HTMLImageElement || image instanceof HTMLCanvasElement || image instanceof ImageBitmap ) {
23542  
23543				if ( _canvas === undefined ) _canvas = document.createElementNS( 'http://www.w3.org/1999/xhtml', 'canvas' );
23544  
23545				_canvas.width = _Math.floorPowerOfTwo( image.width );
23546				_canvas.height = _Math.floorPowerOfTwo( image.height );
23547  
23548				var context = _canvas.getContext( '2d' );
23549				context.drawImage( image, 0, 0, _canvas.width, _canvas.height );
23550  
23551				console.warn( 'THREE.WebGLRenderer: image is not power of two (' + image.width + 'x' + image.height + '). Resized to ' + _canvas.width + 'x' + _canvas.height, image );
23552  
23553				return _canvas;
23554  
23555			}
23556  
23557			return image;
23558  
23559		}
23560  
23561		function textureNeedsPowerOfTwo( texture ) {
23562  
23563			return ( texture.wrapS !== ClampToEdgeWrapping || texture.wrapT !== ClampToEdgeWrapping ) ||
23564				( texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter );
23565  
23566		}
23567  
23568		function textureNeedsGenerateMipmaps( texture, isPowerOfTwo ) {
23569  
23570			return texture.generateMipmaps && isPowerOfTwo &&
23571				texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter;
23572  
23573		}
23574  
23575		function generateMipmap( target, texture, width, height ) {
23576  
23577			_gl.generateMipmap( target );
23578  
23579			var textureProperties = properties.get( texture );
23580  
23581			// Note: Math.log( x ) * Math.LOG2E used instead of Math.log2( x ) which is not supported by IE11
23582			textureProperties.__maxMipLevel = Math.log( Math.max( width, height ) ) * Math.LOG2E;
23583  
23584		}
23585  
23586		// Fallback filters for non-power-of-2 textures
23587  
23588		function filterFallback( f ) {
23589  
23590			if ( f === NearestFilter || f === NearestMipMapNearestFilter || f === NearestMipMapLinearFilter ) {
23591  
23592				return _gl.NEAREST;
23593  
23594			}
23595  
23596			return _gl.LINEAR;
23597  
23598		}
23599  
23600		//
23601  
23602		function onTextureDispose( event ) {
23603  
23604			var texture = event.target;
23605  
23606			texture.removeEventListener( 'dispose', onTextureDispose );
23607  
23608			deallocateTexture( texture );
23609  
23610			if ( texture.isVideoTexture ) {
23611  
23612				delete _videoTextures[ texture.id ];
23613  
23614			}
23615  
23616			info.memory.textures --;
23617  
23618		}
23619  
23620		function onRenderTargetDispose( event ) {
23621  
23622			var renderTarget = event.target;
23623  
23624			renderTarget.removeEventListener( 'dispose', onRenderTargetDispose );
23625  
23626			deallocateRenderTarget( renderTarget );
23627  
23628			info.memory.textures --;
23629  
23630		}
23631  
23632		//
23633  
23634		function deallocateTexture( texture ) {
23635  
23636			var textureProperties = properties.get( texture );
23637  
23638			if ( texture.image && textureProperties.__image__webglTextureCube ) {
23639  
23640				// cube texture
23641  
23642				_gl.deleteTexture( textureProperties.__image__webglTextureCube );
23643  
23644			} else {
23645  
vendor: 4,521 bytes, lines 23646-23813
23646				// 2D texture
23647  
23648				if ( textureProperties.__webglInit === undefined ) return;
23649  
23650				_gl.deleteTexture( textureProperties.__webglTexture );
23651  
23652			}
23653  
23654			// remove all webgl properties
23655			properties.remove( texture );
23656  
23657		}
23658  
23659		function deallocateRenderTarget( renderTarget ) {
23660  
23661			var renderTargetProperties = properties.get( renderTarget );
23662			var textureProperties = properties.get( renderTarget.texture );
23663  
23664			if ( ! renderTarget ) return;
23665  
23666			if ( textureProperties.__webglTexture !== undefined ) {
23667  
23668				_gl.deleteTexture( textureProperties.__webglTexture );
23669  
23670			}
23671  
23672			if ( renderTarget.depthTexture ) {
23673  
23674				renderTarget.depthTexture.dispose();
23675  
23676			}
23677  
23678			if ( renderTarget.isWebGLRenderTargetCube ) {
23679  
23680				for ( var i = 0; i < 6; i ++ ) {
23681  
23682					_gl.deleteFramebuffer( renderTargetProperties.__webglFramebuffer[ i ] );
23683					if ( renderTargetProperties.__webglDepthbuffer ) _gl.deleteRenderbuffer( renderTargetProperties.__webglDepthbuffer[ i ] );
23684  
23685				}
23686  
23687			} else {
23688  
23689				_gl.deleteFramebuffer( renderTargetProperties.__webglFramebuffer );
23690				if ( renderTargetProperties.__webglDepthbuffer ) _gl.deleteRenderbuffer( renderTargetProperties.__webglDepthbuffer );
23691  
23692			}
23693  
23694			properties.remove( renderTarget.texture );
23695			properties.remove( renderTarget );
23696  
23697		}
23698  
23699		//
23700  
23701  
23702  
23703		function setTexture2D( texture, slot ) {
23704  
23705			var textureProperties = properties.get( texture );
23706  
23707			if ( texture.isVideoTexture ) updateVideoTexture( texture );
23708  
23709			if ( texture.version > 0 && textureProperties.__version !== texture.version ) {
23710  
23711				var image = texture.image;
23712  
23713				if ( image === undefined ) {
23714  
23715					console.warn( 'THREE.WebGLRenderer: Texture marked for update but image is undefined', texture );
23716  
23717				} else if ( image.complete === false ) {
23718  
23719					console.warn( 'THREE.WebGLRenderer: Texture marked for update but image is incomplete', texture );
23720  
23721				} else {
23722  
23723					uploadTexture( textureProperties, texture, slot );
23724					return;
23725  
23726				}
23727  
23728			}
23729  
23730			state.activeTexture( _gl.TEXTURE0 + slot );
23731			state.bindTexture( _gl.TEXTURE_2D, textureProperties.__webglTexture );
23732  
23733		}
23734  
23735		function setTextureCube( texture, slot ) {
23736  
23737			var textureProperties = properties.get( texture );
23738  
23739			if ( texture.image.length === 6 ) {
23740  
23741				if ( texture.version > 0 && textureProperties.__version !== texture.version ) {
23742  
23743					if ( ! textureProperties.__image__webglTextureCube ) {
23744  
23745						texture.addEventListener( 'dispose', onTextureDispose );
23746  
23747						textureProperties.__image__webglTextureCube = _gl.createTexture();
23748  
23749						info.memory.textures ++;
23750  
23751					}
23752  
23753					state.activeTexture( _gl.TEXTURE0 + slot );
23754					state.bindTexture( _gl.TEXTURE_CUBE_MAP, textureProperties.__image__webglTextureCube );
23755  
23756					_gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, texture.flipY );
23757  
23758					var isCompressed = ( texture && texture.isCompressedTexture );
23759					var isDataTexture = ( texture.image[ 0 ] && texture.image[ 0 ].isDataTexture );
23760  
23761					var cubeImage = [];
23762  
23763					for ( var i = 0; i < 6; i ++ ) {
23764  
23765						if ( ! isCompressed && ! isDataTexture ) {
23766  
23767							cubeImage[ i ] = clampToMaxSize( texture.image[ i ], capabilities.maxCubemapSize );
23768  
23769						} else {
23770  
23771							cubeImage[ i ] = isDataTexture ? texture.image[ i ].image : texture.image[ i ];
23772  
23773						}
23774  
23775					}
23776  
23777					var image = cubeImage[ 0 ],
23778						isPowerOfTwoImage = isPowerOfTwo( image ),
23779						glFormat = utils.convert( texture.format ),
23780						glType = utils.convert( texture.type );
23781  
23782					setTextureParameters( _gl.TEXTURE_CUBE_MAP, texture, isPowerOfTwoImage );
23783  
23784					for ( var i = 0; i < 6; i ++ ) {
23785  
23786						if ( ! isCompressed ) {
23787  
23788							if ( isDataTexture ) {
23789  
23790								state.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glFormat, cubeImage[ i ].width, cubeImage[ i ].height, 0, glFormat, glType, cubeImage[ i ].data );
23791  
23792							} else {
23793  
23794								state.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glFormat, glFormat, glType, cubeImage[ i ] );
23795  
23796							}
23797  
23798						} else {
23799  
23800							var mipmap, mipmaps = cubeImage[ i ].mipmaps;
23801  
23802							for ( var j = 0, jl = mipmaps.length; j < jl; j ++ ) {
23803  
23804								mipmap = mipmaps[ j ];
23805  
23806								if ( texture.format !== RGBAFormat && texture.format !== RGBFormat ) {
23807  
23808									if ( state.getCompressedTextureFormats().indexOf( glFormat ) > - 1 ) {
23809  
23810										state.compressedTexImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glFormat, mipmap.width, mipmap.height, 0, mipmap.data );
23811  
23812									} else {
23813  
23814										console.warn( 'THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .setTextureCube()' );
23815  
23816									}
23817  
23818								} else {
23819  
23820									state.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data );
23821  
23822								}
23823  
23824							}
23825  
23826						}
23827  
23828					}
23829  
23830					if ( ! isCompressed ) {
23831  
23832						textureProperties.__maxMipLevel = 0;
23833  
23834					} else {
23835  
23836						textureProperties.__maxMipLevel = mipmaps.length - 1;
23837  
23838					}
23839  
23840					if ( textureNeedsGenerateMipmaps( texture, isPowerOfTwoImage ) ) {
23841  
23842						// We assume images for cube map have the same size.
23843						generateMipmap( _gl.TEXTURE_CUBE_MAP, texture, image.width, image.height );
23844  
23845					}
23846  
23847					textureProperties.__version = texture.version;
23848  
23849					if ( texture.onUpdate ) texture.onUpdate( texture );
23850  
23851				} else {
23852  
23853					state.activeTexture( _gl.TEXTURE0 + slot );
23854					state.bindTexture( _gl.TEXTURE_CUBE_MAP, textureProperties.__image__webglTextureCube );
23855  
23856				}
23857  
23858			}
23859  
23860		}
23861  
23862		function setTextureCubeDynamic( texture, slot ) {
23863  
23864			state.activeTexture( _gl.TEXTURE0 + slot );
23865			state.bindTexture( _gl.TEXTURE_CUBE_MAP, properties.get( texture ).__webglTexture );
23866  
23867		}
23868  
23869		function setTextureParameters( textureType, texture, isPowerOfTwoImage ) {
23870  
23871			var extension;
23872  
23873			if ( isPowerOfTwoImage ) {
23874  
23875				_gl.texParameteri( textureType, _gl.TEXTURE_WRAP_S, utils.convert( texture.wrapS ) );
23876				_gl.texParameteri( textureType, _gl.TEXTURE_WRAP_T, utils.convert( texture.wrapT ) );
23877  
23878				_gl.texParameteri( textureType, _gl.TEXTURE_MAG_FILTER, utils.convert( texture.magFilter ) );
23879				_gl.texParameteri( textureType, _gl.TEXTURE_MIN_FILTER, utils.convert( texture.minFilter ) );
23880  
23881			} else {
23882  
23883				_gl.texParameteri( textureType, _gl.TEXTURE_WRAP_S, _gl.CLAMP_TO_EDGE );
23884				_gl.texParameteri( textureType, _gl.TEXTURE_WRAP_T, _gl.CLAMP_TO_EDGE );
23885  
23886				if ( texture.wrapS !== ClampToEdgeWrapping || texture.wrapT !== ClampToEdgeWrapping ) {
23887  
23888					console.warn( 'THREE.WebGLRenderer: Texture is not power of two. Texture.wrapS and Texture.wrapT should be set to THREE.ClampToEdgeWrapping.', texture );
23889  
23890				}
23891  
23892				_gl.texParameteri( textureType, _gl.TEXTURE_MAG_FILTER, filterFallback( texture.magFilter ) );
23893				_gl.texParameteri( textureType, _gl.TEXTURE_MIN_FILTER, filterFallback( texture.minFilter ) );
23894  
23895				if ( texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter ) {
23896  
23897					console.warn( 'THREE.WebGLRenderer: Texture is not power of two. Texture.minFilter should be set to THREE.NearestFilter or THREE.LinearFilter.', texture );
23898  
23899				}
23900  
23901			}
23902  
23903			extension = extensions.get( 'EXT_texture_filter_anisotropic' );
23904  
23905			if ( extension ) {
23906  
23907				if ( texture.type === FloatType && extensions.get( 'OES_texture_float_linear' ) === null ) return;
23908				if ( texture.type === HalfFloatType && extensions.get( 'OES_texture_half_float_linear' ) === null ) return;
23909  
23910				if ( texture.anisotropy > 1 || properties.get( texture ).__currentAnisotropy ) {
23911  
23912					_gl.texParameterf( textureType, extension.TEXTURE_MAX_ANISOTROPY_EXT, Math.min( texture.anisotropy, capabilities.getMaxAnisotropy() ) );
23913					properties.get( texture ).__currentAnisotropy = texture.anisotropy;
23914  
23915				}
23916  
23917			}
23918  
23919		}
23920  
23921		function uploadTexture( textureProperties, texture, slot ) {
23922  
23923			if ( textureProperties.__webglInit === undefined ) {
23924  
23925				textureProperties.__webglInit = true;
23926  
23927				texture.addEventListener( 'dispose', onTextureDispose );
23928  
23929				textureProperties.__webglTexture = _gl.createTexture();
23930  
23931				info.memory.textures ++;
23932  
23933			}
23934  
23935			state.activeTexture( _gl.TEXTURE0 + slot );
23936			state.bindTexture( _gl.TEXTURE_2D, textureProperties.__webglTexture );
23937  
23938			_gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, texture.flipY );
23939			_gl.pixelStorei( _gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultiplyAlpha );
23940			_gl.pixelStorei( _gl.UNPACK_ALIGNMENT, texture.unpackAlignment );
23941  
23942			var image = clampToMaxSize( texture.image, capabilities.maxTextureSize );
23943  
23944			if ( textureNeedsPowerOfTwo( texture ) && isPowerOfTwo( image ) === false ) {
23945  
23946				image = makePowerOfTwo( image );
23947  
23948			}
23949  
23950			var isPowerOfTwoImage = isPowerOfTwo( image ),
23951				glFormat = utils.convert( texture.format ),
23952				glType = utils.convert( texture.type );
23953  
23954			setTextureParameters( _gl.TEXTURE_2D, texture, isPowerOfTwoImage );
23955  
23956			var mipmap, mipmaps = texture.mipmaps;
23957  
23958			if ( texture.isDepthTexture ) {
23959  
23960				// populate depth texture with dummy data
23961  
23962				var internalFormat = _gl.DEPTH_COMPONENT;
23963  
23964				if ( texture.type === FloatType ) {
23965  
23966					if ( ! _isWebGL2 ) throw new Error( 'Float Depth Texture only supported in WebGL2.0' );
23967					internalFormat = _gl.DEPTH_COMPONENT32F;
23968  
23969				} else if ( _isWebGL2 ) {
23970  
23971					// WebGL 2.0 requires signed internalformat for glTexImage2D
23972					internalFormat = _gl.DEPTH_COMPONENT16;
23973  
23974				}
23975  
23976				if ( texture.format === DepthFormat && internalFormat === _gl.DEPTH_COMPONENT ) {
23977  
23978					// The error INVALID_OPERATION is generated by texImage2D if format and internalformat are
23979					// DEPTH_COMPONENT and type is not UNSIGNED_SHORT or UNSIGNED_INT
23980					// (https://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/)
23981					if ( texture.type !== UnsignedShortType && texture.type !== UnsignedIntType ) {
23982  
23983						console.warn( 'THREE.WebGLRenderer: Use UnsignedShortType or UnsignedIntType for DepthFormat DepthTexture.' );
23984  
23985						texture.type = UnsignedShortType;
23986						glType = utils.convert( texture.type );
23987  
23988					}
23989  
23990				}
23991  
23992				// Depth stencil textures need the DEPTH_STENCIL internal format
23993				// (https://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/)
23994				if ( texture.format === DepthStencilFormat ) {
23995  
23996					internalFormat = _gl.DEPTH_STENCIL;
23997  
23998					// The error INVALID_OPERATION is generated by texImage2D if format and internalformat are
23999					// DEPTH_STENCIL and type is not UNSIGNED_INT_24_8_WEBGL.
24000					// (https://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/)
24001					if ( texture.type !== UnsignedInt248Type ) {
24002  
24003						console.warn( 'THREE.WebGLRenderer: Use UnsignedInt248Type for DepthStencilFormat DepthTexture.' );
24004  
24005						texture.type = UnsignedInt248Type;
24006						glType = utils.convert( texture.type );
24007  
24008					}
24009  
24010				}
24011  
24012				state.texImage2D( _gl.TEXTURE_2D, 0, internalFormat, image.width, image.height, 0, glFormat, glType, null );
24013  
24014			} else if ( texture.isDataTexture ) {
24015  
24016				// use manually created mipmaps if available
24017				// if there are no manual mipmaps
24018				// set 0 level mipmap and then use GL to generate other mipmap levels
24019  
24020				if ( mipmaps.length > 0 && isPowerOfTwoImage ) {
24021  
24022					for ( var i = 0, il = mipmaps.length; i < il; i ++ ) {
24023  
24024						mipmap = mipmaps[ i ];
24025						state.texImage2D( _gl.TEXTURE_2D, i, glFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data );
24026  
24027					}
24028  
24029					texture.generateMipmaps = false;
24030					textureProperties.__maxMipLevel = mipmaps.length - 1;
24031  
24032				} else {
24033  
24034					state.texImage2D( _gl.TEXTURE_2D, 0, glFormat, image.width, image.height, 0, glFormat, glType, image.data );
24035					textureProperties.__maxMipLevel = 0;
24036  
24037				}
24038  
24039			} else if ( texture.isCompressedTexture ) {
24040  
24041				for ( var i = 0, il = mipmaps.length; i < il; i ++ ) {
24042  
24043					mipmap = mipmaps[ i ];
24044  
24045					if ( texture.format !== RGBAFormat && texture.format !== RGBFormat ) {
24046  
24047						if ( state.getCompressedTextureFormats().indexOf( glFormat ) > - 1 ) {
24048  
24049							state.compressedTexImage2D( _gl.TEXTURE_2D, i, glFormat, mipmap.width, mipmap.height, 0, mipmap.data );
24050  
24051						} else {
24052  
24053							console.warn( 'THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .uploadTexture()' );
24054  
24055						}
24056  
24057					} else {
24058  
24059						state.texImage2D( _gl.TEXTURE_2D, i, glFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data );
24060  
24061					}
24062  
24063				}
24064  
24065				textureProperties.__maxMipLevel = mipmaps.length - 1;
24066  
24067			} else {
24068  
24069				// regular Texture (image, video, canvas)
24070  
24071				// use manually created mipmaps if available
24072				// if there are no manual mipmaps
24073				// set 0 level mipmap and then use GL to generate other mipmap levels
24074  
24075				if ( mipmaps.length > 0 && isPowerOfTwoImage ) {
24076  
24077					for ( var i = 0, il = mipmaps.length; i < il; i ++ ) {
24078  
24079						mipmap = mipmaps[ i ];
24080						state.texImage2D( _gl.TEXTURE_2D, i, glFormat, glFormat, glType, mipmap );
24081  
24082					}
24083  
24084					texture.generateMipmaps = false;
24085					textureProperties.__maxMipLevel = mipmaps.length - 1;
24086  
24087				} else {
24088  
24089					state.texImage2D( _gl.TEXTURE_2D, 0, glFormat, glFormat, glType, image );
24090					textureProperties.__maxMipLevel = 0;
24091  
24092				}
24093  
24094			}
24095  
24096			if ( textureNeedsGenerateMipmaps( texture, isPowerOfTwoImage ) ) {
24097  
24098				generateMipmap( _gl.TEXTURE_2D, texture, image.width, image.height );
24099  
24100			}
24101  
24102			textureProperties.__version = texture.version;
24103  
24104			if ( texture.onUpdate ) texture.onUpdate( texture );
24105  
24106		}
24107  
24108		// Render targets
24109  
24110		// Setup storage for target texture and bind it to correct framebuffer
24111		function setupFrameBufferTexture( framebuffer, renderTarget, attachment, textureTarget ) {
24112  
24113			var glFormat = utils.convert( renderTarget.texture.format );
24114			var glType = utils.convert( renderTarget.texture.type );
24115			state.texImage2D( textureTarget, 0, glFormat, renderTarget.width, renderTarget.height, 0, glFormat, glType, null );
24116			_gl.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );
24117			_gl.framebufferTexture2D( _gl.FRAMEBUFFER, attachment, textureTarget, properties.get( renderTarget.texture ).__webglTexture, 0 );
24118			_gl.bindFramebuffer( _gl.FRAMEBUFFER, null );
24119  
24120		}
24121  
24122		// Setup storage for internal depth/stencil buffers and bind to correct framebuffer
24123		function setupRenderBufferStorage( renderbuffer, renderTarget ) {
24124  
24125			_gl.bindRenderbuffer( _gl.RENDERBUFFER, renderbuffer );
24126  
24127			if ( renderTarget.depthBuffer && ! renderTarget.stencilBuffer ) {
24128  
24129				_gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.DEPTH_COMPONENT16, renderTarget.width, renderTarget.height );
24130				_gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer );
24131  
24132			} else if ( renderTarget.depthBuffer && renderTarget.stencilBuffer ) {
24133  
24134				_gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.DEPTH_STENCIL, renderTarget.width, renderTarget.height );
24135				_gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer );
24136  
24137			} else {
24138  
vendor: 4,660 bytes, lines 24139-24289
24139				// FIXME: We don't support !depth !stencil
24140				_gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.RGBA4, renderTarget.width, renderTarget.height );
24141  
24142			}
24143  
24144			_gl.bindRenderbuffer( _gl.RENDERBUFFER, null );
24145  
24146		}
24147  
24148		// Setup resources for a Depth Texture for a FBO (needs an extension)
24149		function setupDepthTexture( framebuffer, renderTarget ) {
24150  
24151			var isCube = ( renderTarget && renderTarget.isWebGLRenderTargetCube );
24152			if ( isCube ) throw new Error( 'Depth Texture with cube render targets is not supported' );
24153  
24154			_gl.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );
24155  
24156			if ( ! ( renderTarget.depthTexture && renderTarget.depthTexture.isDepthTexture ) ) {
24157  
24158				throw new Error( 'renderTarget.depthTexture must be an instance of THREE.DepthTexture' );
24159  
24160			}
24161  
24162			// upload an empty depth texture with framebuffer size
24163			if ( ! properties.get( renderTarget.depthTexture ).__webglTexture ||
24164					renderTarget.depthTexture.image.width !== renderTarget.width ||
24165					renderTarget.depthTexture.image.height !== renderTarget.height ) {
24166  
24167				renderTarget.depthTexture.image.width = renderTarget.width;
24168				renderTarget.depthTexture.image.height = renderTarget.height;
24169				renderTarget.depthTexture.needsUpdate = true;
24170  
24171			}
24172  
24173			setTexture2D( renderTarget.depthTexture, 0 );
24174  
24175			var webglDepthTexture = properties.get( renderTarget.depthTexture ).__webglTexture;
24176  
24177			if ( renderTarget.depthTexture.format === DepthFormat ) {
24178  
24179				_gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.TEXTURE_2D, webglDepthTexture, 0 );
24180  
24181			} else if ( renderTarget.depthTexture.format === DepthStencilFormat ) {
24182  
24183				_gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.TEXTURE_2D, webglDepthTexture, 0 );
24184  
24185			} else {
24186  
24187				throw new Error( 'Unknown depthTexture format' );
24188  
24189			}
24190  
24191		}
24192  
24193		// Setup GL resources for a non-texture depth buffer
24194		function setupDepthRenderbuffer( renderTarget ) {
24195  
24196			var renderTargetProperties = properties.get( renderTarget );
24197  
24198			var isCube = ( renderTarget.isWebGLRenderTargetCube === true );
24199  
24200			if ( renderTarget.depthTexture ) {
24201  
24202				if ( isCube ) throw new Error( 'target.depthTexture not supported in Cube render targets' );
24203  
24204				setupDepthTexture( renderTargetProperties.__webglFramebuffer, renderTarget );
24205  
24206			} else {
24207  
24208				if ( isCube ) {
24209  
24210					renderTargetProperties.__webglDepthbuffer = [];
24211  
24212					for ( var i = 0; i < 6; i ++ ) {
24213  
24214						_gl.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglFramebuffer[ i ] );
24215						renderTargetProperties.__webglDepthbuffer[ i ] = _gl.createRenderbuffer();
24216						setupRenderBufferStorage( renderTargetProperties.__webglDepthbuffer[ i ], renderTarget );
24217  
24218					}
24219  
24220				} else {
24221  
24222					_gl.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglFramebuffer );
24223					renderTargetProperties.__webglDepthbuffer = _gl.createRenderbuffer();
24224					setupRenderBufferStorage( renderTargetProperties.__webglDepthbuffer, renderTarget );
24225  
24226				}
24227  
24228			}
24229  
24230			_gl.bindFramebuffer( _gl.FRAMEBUFFER, null );
24231  
24232		}
24233  
24234		// Set up GL resources for the render target
24235		function setupRenderTarget( renderTarget ) {
24236  
24237			var renderTargetProperties = properties.get( renderTarget );
24238			var textureProperties = properties.get( renderTarget.texture );
24239  
24240			renderTarget.addEventListener( 'dispose', onRenderTargetDispose );
24241  
24242			textureProperties.__webglTexture = _gl.createTexture();
24243  
24244			info.memory.textures ++;
24245  
24246			var isCube = ( renderTarget.isWebGLRenderTargetCube === true );
24247			var isTargetPowerOfTwo = isPowerOfTwo( renderTarget );
24248  
24249			// Setup framebuffer
24250  
24251			if ( isCube ) {
24252  
24253				renderTargetProperties.__webglFramebuffer = [];
24254  
24255				for ( var i = 0; i < 6; i ++ ) {
24256  
24257					renderTargetProperties.__webglFramebuffer[ i ] = _gl.createFramebuffer();
24258  
24259				}
24260  
24261			} else {
24262  
24263				renderTargetProperties.__webglFramebuffer = _gl.createFramebuffer();
24264  
24265			}
24266  
24267			// Setup color buffer
24268  
24269			if ( isCube ) {
24270  
24271				state.bindTexture( _gl.TEXTURE_CUBE_MAP, textureProperties.__webglTexture );
24272				setTextureParameters( _gl.TEXTURE_CUBE_MAP, renderTarget.texture, isTargetPowerOfTwo );
24273  
24274				for ( var i = 0; i < 6; i ++ ) {
24275  
24276					setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer[ i ], renderTarget, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i );
24277  
24278				}
24279  
24280				if ( textureNeedsGenerateMipmaps( renderTarget.texture, isTargetPowerOfTwo ) ) {
24281  
24282					generateMipmap( _gl.TEXTURE_CUBE_MAP, renderTarget.texture, renderTarget.width, renderTarget.height );
24283  
24284				}
24285  
24286				state.bindTexture( _gl.TEXTURE_CUBE_MAP, null );
24287  
24288			} else {
24289  
24290				state.bindTexture( _gl.TEXTURE_2D, textureProperties.__webglTexture );
24291				setTextureParameters( _gl.TEXTURE_2D, renderTarget.texture, isTargetPowerOfTwo );
24292				setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer, renderTarget, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_2D );
24293  
24294				if ( textureNeedsGenerateMipmaps( renderTarget.texture, isTargetPowerOfTwo ) ) {
24295  
24296					generateMipmap( _gl.TEXTURE_2D, renderTarget.texture, renderTarget.width, renderTarget.height );
24297  
24298				}
24299  
24300				state.bindTexture( _gl.TEXTURE_2D, null );
24301  
24302			}
24303  
24304			// Setup depth and stencil buffers
24305  
24306			if ( renderTarget.depthBuffer ) {
24307  
24308				setupDepthRenderbuffer( renderTarget );
24309  
24310			}
24311  
24312		}
24313  
24314		function updateRenderTargetMipmap( renderTarget ) {
24315  
24316			var texture = renderTarget.texture;
24317			var isTargetPowerOfTwo = isPowerOfTwo( renderTarget );
24318  
24319			if ( textureNeedsGenerateMipmaps( texture, isTargetPowerOfTwo ) ) {
24320  
24321				var target = renderTarget.isWebGLRenderTargetCube ? _gl.TEXTURE_CUBE_MAP : _gl.TEXTURE_2D;
24322				var webglTexture = properties.get( texture ).__webglTexture;
24323  
24324				state.bindTexture( target, webglTexture );
24325				generateMipmap( target, texture, renderTarget.width, renderTarget.height );
24326				state.bindTexture( target, null );
24327  
24328			}
24329  
24330		}
24331  
24332		function updateVideoTexture( texture ) {
24333  
24334			var id = texture.id;
24335			var frame = info.render.frame;
24336  
24337			// Check the last frame we updated the VideoTexture
24338  
24339			if ( _videoTextures[ id ] !== frame ) {
24340  
24341				_videoTextures[ id ] = frame;
24342				texture.update();
24343  
24344			}
24345  
24346		}
24347  
24348		this.setTexture2D = setTexture2D;
24349		this.setTextureCube = setTextureCube;
24350		this.setTextureCubeDynamic = setTextureCubeDynamic;
24351		this.setupRenderTarget = setupRenderTarget;
24352		this.updateRenderTargetMipmap = updateRenderTargetMipmap;
24353  
24354	}
24355  
24356	/**
24357	 * @author thespite / http://www.twitter.com/thespite
24358	 */
24359  
24360	function WebGLUtils( gl, extensions ) {
24361  
24362		function convert( p ) {
24363  
24364			var extension;
24365  
24366			if ( p === RepeatWrapping ) return gl.REPEAT;
24367			if ( p === ClampToEdgeWrapping ) return gl.CLAMP_TO_EDGE;
24368			if ( p === MirroredRepeatWrapping ) return gl.MIRRORED_REPEAT;
24369  
24370			if ( p === NearestFilter ) return gl.NEAREST;
24371			if ( p === NearestMipMapNearestFilter ) return gl.NEAREST_MIPMAP_NEAREST;
24372			if ( p === NearestMipMapLinearFilter ) return gl.NEAREST_MIPMAP_LINEAR;
24373  
24374			if ( p === LinearFilter ) return gl.LINEAR;
24375			if ( p === LinearMipMapNearestFilter ) return gl.LINEAR_MIPMAP_NEAREST;
24376			if ( p === LinearMipMapLinearFilter ) return gl.LINEAR_MIPMAP_LINEAR;
24377  
24378			if ( p === UnsignedByteType ) return gl.UNSIGNED_BYTE;
24379			if ( p === UnsignedShort4444Type ) return gl.UNSIGNED_SHORT_4_4_4_4;
24380			if ( p === UnsignedShort5551Type ) return gl.UNSIGNED_SHORT_5_5_5_1;
24381			if ( p === UnsignedShort565Type ) return gl.UNSIGNED_SHORT_5_6_5;
24382  
24383			if ( p === ByteType ) return gl.BYTE;
24384			if ( p === ShortType ) return gl.SHORT;
24385			if ( p === UnsignedShortType ) return gl.UNSIGNED_SHORT;
24386			if ( p === IntType ) return gl.INT;
24387			if ( p === UnsignedIntType ) return gl.UNSIGNED_INT;
24388			if ( p === FloatType ) return gl.FLOAT;
24389  
24390			if ( p === HalfFloatType ) {
24391  
24392				extension = extensions.get( 'OES_texture_half_float' );
24393  
24394				if ( extension !== null ) return extension.HALF_FLOAT_OES;
24395  
24396			}
24397  
24398			if ( p === AlphaFormat ) return gl.ALPHA;
24399			if ( p === RGBFormat ) return gl.RGB;
24400			if ( p === RGBAFormat ) return gl.RGBA;
24401			if ( p === LuminanceFormat ) return gl.LUMINANCE;
24402			if ( p === LuminanceAlphaFormat ) return gl.LUMINANCE_ALPHA;
24403			if ( p === DepthFormat ) return gl.DEPTH_COMPONENT;
24404			if ( p === DepthStencilFormat ) return gl.DEPTH_STENCIL;
24405  
24406			if ( p === AddEquation ) return gl.FUNC_ADD;
24407			if ( p === SubtractEquation ) return gl.FUNC_SUBTRACT;
24408			if ( p === ReverseSubtractEquation ) return gl.FUNC_REVERSE_SUBTRACT;
24409  
24410			if ( p === ZeroFactor ) return gl.ZERO;
24411			if ( p === OneFactor ) return gl.ONE;
24412			if ( p === SrcColorFactor ) return gl.SRC_COLOR;
24413			if ( p === OneMinusSrcColorFactor ) return gl.ONE_MINUS_SRC_COLOR;
24414			if ( p === SrcAlphaFactor ) return gl.SRC_ALPHA;
24415			if ( p === OneMinusSrcAlphaFactor ) return gl.ONE_MINUS_SRC_ALPHA;
24416			if ( p === DstAlphaFactor ) return gl.DST_ALPHA;
24417			if ( p === OneMinusDstAlphaFactor ) return gl.ONE_MINUS_DST_ALPHA;
24418  
vendor: 9,846 bytes, lines 24419-24801
24419			if ( p === DstColorFactor ) return gl.DST_COLOR;
24420			if ( p === OneMinusDstColorFactor ) return gl.ONE_MINUS_DST_COLOR;
24421			if ( p === SrcAlphaSaturateFactor ) return gl.SRC_ALPHA_SATURATE;
24422  
24423			if ( p === RGB_S3TC_DXT1_Format || p === RGBA_S3TC_DXT1_Format ||
24424				p === RGBA_S3TC_DXT3_Format || p === RGBA_S3TC_DXT5_Format ) {
24425  
24426				extension = extensions.get( 'WEBGL_compressed_texture_s3tc' );
24427  
24428				if ( extension !== null ) {
24429  
24430					if ( p === RGB_S3TC_DXT1_Format ) return extension.COMPRESSED_RGB_S3TC_DXT1_EXT;
24431					if ( p === RGBA_S3TC_DXT1_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT1_EXT;
24432					if ( p === RGBA_S3TC_DXT3_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT3_EXT;
24433					if ( p === RGBA_S3TC_DXT5_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT5_EXT;
24434  
24435				}
24436  
24437			}
24438  
24439			if ( p === RGB_PVRTC_4BPPV1_Format || p === RGB_PVRTC_2BPPV1_Format ||
24440				p === RGBA_PVRTC_4BPPV1_Format || p === RGBA_PVRTC_2BPPV1_Format ) {
24441  
24442				extension = extensions.get( 'WEBGL_compressed_texture_pvrtc' );
24443  
24444				if ( extension !== null ) {
24445  
24446					if ( p === RGB_PVRTC_4BPPV1_Format ) return extension.COMPRESSED_RGB_PVRTC_4BPPV1_IMG;
24447					if ( p === RGB_PVRTC_2BPPV1_Format ) return extension.COMPRESSED_RGB_PVRTC_2BPPV1_IMG;
24448					if ( p === RGBA_PVRTC_4BPPV1_Format ) return extension.COMPRESSED_RGBA_PVRTC_4BPPV1_IMG;
24449					if ( p === RGBA_PVRTC_2BPPV1_Format ) return extension.COMPRESSED_RGBA_PVRTC_2BPPV1_IMG;
24450  
24451				}
24452  
24453			}
24454  
24455			if ( p === RGB_ETC1_Format ) {
24456  
24457				extension = extensions.get( 'WEBGL_compressed_texture_etc1' );
24458  
24459				if ( extension !== null ) return extension.COMPRESSED_RGB_ETC1_WEBGL;
24460  
24461			}
24462  
24463			if ( p === RGBA_ASTC_4x4_Format || p === RGBA_ASTC_5x4_Format || p === RGBA_ASTC_5x5_Format ||
24464				p === RGBA_ASTC_6x5_Format || p === RGBA_ASTC_6x6_Format || p === RGBA_ASTC_8x5_Format ||
24465				p === RGBA_ASTC_8x6_Format || p === RGBA_ASTC_8x8_Format || p === RGBA_ASTC_10x5_Format ||
24466				p === RGBA_ASTC_10x6_Format || p === RGBA_ASTC_10x8_Format || p === RGBA_ASTC_10x10_Format ||
24467				p === RGBA_ASTC_12x10_Format || p === RGBA_ASTC_12x12_Format ) {
24468  
24469				extension = extensions.get( 'WEBGL_compressed_texture_astc' );
24470  
24471				if ( extension !== null ) {
24472  
24473					return p;
24474  
24475				}
24476  
24477			}
24478  
24479			if ( p === MinEquation || p === MaxEquation ) {
24480  
24481				extension = extensions.get( 'EXT_blend_minmax' );
24482  
24483				if ( extension !== null ) {
24484  
24485					if ( p === MinEquation ) return extension.MIN_EXT;
24486					if ( p === MaxEquation ) return extension.MAX_EXT;
24487  
24488				}
24489  
24490			}
24491  
24492			if ( p === UnsignedInt248Type ) {
24493  
24494				extension = extensions.get( 'WEBGL_depth_texture' );
24495  
24496				if ( extension !== null ) return extension.UNSIGNED_INT_24_8_WEBGL;
24497  
24498			}
24499  
24500			return 0;
24501  
24502		}
24503  
24504		return { convert: convert };
24505  
24506	}
24507  
24508	/**
24509	 * @author mrdoob / http://mrdoob.com/
24510	 * @author greggman / http://games.greggman.com/
24511	 * @author zz85 / http://www.lab4games.net/zz85/blog
24512	 * @author tschw
24513	 */
24514  
24515	function PerspectiveCamera( fov, aspect, near, far ) {
24516  
24517		Camera.call( this );
24518  
24519		this.type = 'PerspectiveCamera';
24520  
24521		this.fov = fov !== undefined ? fov : 50;
24522		this.zoom = 1;
24523  
24524		this.near = near !== undefined ? near : 0.1;
24525		this.far = far !== undefined ? far : 2000;
24526		this.focus = 10;
24527  
24528		this.aspect = aspect !== undefined ? aspect : 1;
24529		this.view = null;
24530  
24531		this.filmGauge = 35;	// width of the film (default in millimeters)
24532		this.filmOffset = 0;	// horizontal film offset (same unit as gauge)
24533  
24534		this.updateProjectionMatrix();
24535  
24536	}
24537  
24538	PerspectiveCamera.prototype = Object.assign( Object.create( Camera.prototype ), {
24539  
24540		constructor: PerspectiveCamera,
24541  
24542		isPerspectiveCamera: true,
24543  
24544		copy: function ( source, recursive ) {
24545  
24546			Camera.prototype.copy.call( this, source, recursive );
24547  
24548			this.fov = source.fov;
24549			this.zoom = source.zoom;
24550  
24551			this.near = source.near;
24552			this.far = source.far;
24553			this.focus = source.focus;
24554  
24555			this.aspect = source.aspect;
24556			this.view = source.view === null ? null : Object.assign( {}, source.view );
24557  
24558			this.filmGauge = source.filmGauge;
24559			this.filmOffset = source.filmOffset;
24560  
24561			return this;
24562  
24563		},
24564  
24565		/**
24566		 * Sets the FOV by focal length in respect to the current .filmGauge.
24567		 *
24568		 * The default film gauge is 35, so that the focal length can be specified for
24569		 * a 35mm (full frame) camera.
24570		 *
24571		 * Values for focal length and film gauge must have the same unit.
24572		 */
24573		setFocalLength: function ( focalLength ) {
24574  
24575			// see http://www.bobatkins.com/photography/technical/field_of_view.html
24576			var vExtentSlope = 0.5 * this.getFilmHeight() / focalLength;
24577  
24578			this.fov = _Math.RAD2DEG * 2 * Math.atan( vExtentSlope );
24579			this.updateProjectionMatrix();
24580  
24581		},
24582  
24583		/**
24584		 * Calculates the focal length from the current .fov and .filmGauge.
24585		 */
24586		getFocalLength: function () {
24587  
24588			var vExtentSlope = Math.tan( _Math.DEG2RAD * 0.5 * this.fov );
24589  
24590			return 0.5 * this.getFilmHeight() / vExtentSlope;
24591  
24592		},
24593  
24594		getEffectiveFOV: function () {
24595  
24596			return _Math.RAD2DEG * 2 * Math.atan(
24597				Math.tan( _Math.DEG2RAD * 0.5 * this.fov ) / this.zoom );
24598  
24599		},
24600  
24601		getFilmWidth: function () {
24602  
24603			// film not completely covered in portrait format (aspect < 1)
24604			return this.filmGauge * Math.min( this.aspect, 1 );
24605  
24606		},
24607  
24608		getFilmHeight: function () {
24609  
24610			// film not completely covered in landscape format (aspect > 1)
24611			return this.filmGauge / Math.max( this.aspect, 1 );
24612  
24613		},
24614  
24615		/**
24616		 * Sets an offset in a larger frustum. This is useful for multi-window or
24617		 * multi-monitor/multi-machine setups.
24618		 *
24619		 * For example, if you have 3x2 monitors and each monitor is 1920x1080 and
24620		 * the monitors are in grid like this
24621		 *
24622		 *   +---+---+---+
24623		 *   | A | B | C |
24624		 *   +---+---+---+
24625		 *   | D | E | F |
24626		 *   +---+---+---+
24627		 *
24628		 * then for each monitor you would call it like this
24629		 *
24630		 *   var w = 1920;
24631		 *   var h = 1080;
24632		 *   var fullWidth = w * 3;
24633		 *   var fullHeight = h * 2;
24634		 *
24635		 *   --A--
24636		 *   camera.setOffset( fullWidth, fullHeight, w * 0, h * 0, w, h );
24637		 *   --B--
24638		 *   camera.setOffset( fullWidth, fullHeight, w * 1, h * 0, w, h );
24639		 *   --C--
24640		 *   camera.setOffset( fullWidth, fullHeight, w * 2, h * 0, w, h );
24641		 *   --D--
24642		 *   camera.setOffset( fullWidth, fullHeight, w * 0, h * 1, w, h );
24643		 *   --E--
24644		 *   camera.setOffset( fullWidth, fullHeight, w * 1, h * 1, w, h );
24645		 *   --F--
24646		 *   camera.setOffset( fullWidth, fullHeight, w * 2, h * 1, w, h );
24647		 *
24648		 *   Note there is no reason monitors have to be the same size or in a grid.
24649		 */
24650		setViewOffset: function ( fullWidth, fullHeight, x, y, width, height ) {
24651  
24652			this.aspect = fullWidth / fullHeight;
24653  
24654			if ( this.view === null ) {
24655  
24656				this.view = {
24657					enabled: true,
24658					fullWidth: 1,
24659					fullHeight: 1,
24660					offsetX: 0,
24661					offsetY: 0,
24662					width: 1,
24663					height: 1
24664				};
24665  
24666			}
24667  
24668			this.view.enabled = true;
24669			this.view.fullWidth = fullWidth;
24670			this.view.fullHeight = fullHeight;
24671			this.view.offsetX = x;
24672			this.view.offsetY = y;
24673			this.view.width = width;
24674			this.view.height = height;
24675  
24676			this.updateProjectionMatrix();
24677  
24678		},
24679  
24680		clearViewOffset: function () {
24681  
24682			if ( this.view !== null ) {
24683  
24684				this.view.enabled = false;
24685  
24686			}
24687  
24688			this.updateProjectionMatrix();
24689  
24690		},
24691  
24692		updateProjectionMatrix: function () {
24693  
24694			var near = this.near,
24695				top = near * Math.tan(
24696					_Math.DEG2RAD * 0.5 * this.fov ) / this.zoom,
24697				height = 2 * top,
24698				width = this.aspect * height,
24699				left = - 0.5 * width,
24700				view = this.view;
24701  
24702			if ( this.view !== null && this.view.enabled ) {
24703  
24704				var fullWidth = view.fullWidth,
24705					fullHeight = view.fullHeight;
24706  
24707				left += view.offsetX * width / fullWidth;
24708				top -= view.offsetY * height / fullHeight;
24709				width *= view.width / fullWidth;
24710				height *= view.height / fullHeight;
24711  
24712			}
24713  
24714			var skew = this.filmOffset;
24715			if ( skew !== 0 ) left += near * skew / this.getFilmWidth();
24716  
24717			this.projectionMatrix.makePerspective( left, left + width, top, top - height, near, this.far );
24718  
24719		},
24720  
24721		toJSON: function ( meta ) {
24722  
24723			var data = Object3D.prototype.toJSON.call( this, meta );
24724  
24725			data.object.fov = this.fov;
24726			data.object.zoom = this.zoom;
24727  
24728			data.object.near = this.near;
24729			data.object.far = this.far;
24730			data.object.focus = this.focus;
24731  
24732			data.object.aspect = this.aspect;
24733  
24734			if ( this.view !== null ) data.object.view = Object.assign( {}, this.view );
24735  
24736			data.object.filmGauge = this.filmGauge;
24737			data.object.filmOffset = this.filmOffset;
24738  
24739			return data;
24740  
24741		}
24742  
24743	} );
24744  
24745	/**
24746	 * @author mrdoob / http://mrdoob.com/
24747	 */
24748  
24749	function ArrayCamera( array ) {
24750  
24751		PerspectiveCamera.call( this );
24752  
24753		this.cameras = array || [];
24754  
24755	}
24756  
24757	ArrayCamera.prototype = Object.assign( Object.create( PerspectiveCamera.prototype ), {
24758  
24759		constructor: ArrayCamera,
24760  
24761		isArrayCamera: true
24762  
24763	} );
24764  
24765	/**
24766	 * @author mrdoob / http://mrdoob.com/
24767	 */
24768  
24769	function WebVRManager( renderer ) {
24770  
24771		var scope = this;
24772  
24773		var device = null;
24774		var frameData = null;
24775  
24776		var poseTarget = null;
24777  
24778		var standingMatrix = new Matrix4();
24779		var standingMatrixInverse = new Matrix4();
24780  
24781		if ( typeof window !== 'undefined' && 'VRFrameData' in window ) {
24782  
24783			frameData = new window.VRFrameData();
24784			window.addEventListener( 'vrdisplaypresentchange', onVRDisplayPresentChange, false );
24785  
24786		}
24787  
24788		var matrixWorldInverse = new Matrix4();
24789		var tempQuaternion = new Quaternion();
24790		var tempPosition = new Vector3();
24791  
24792		var cameraL = new PerspectiveCamera();
24793		cameraL.bounds = new Vector4( 0.0, 0.0, 0.5, 1.0 );
24794		cameraL.layers.enable( 1 );
24795  
24796		var cameraR = new PerspectiveCamera();
24797		cameraR.bounds = new Vector4( 0.5, 0.0, 0.5, 1.0 );
24798		cameraR.layers.enable( 2 );
24799  
24800		var cameraVR = new ArrayCamera( [ cameraL, cameraR ] );
24801		cameraVR.layers.enable( 1 );
24802		cameraVR.layers.enable( 2 );
24803  
24804		//
24805  
24806		function isPresenting() {
24807  
24808			return device !== null && device.isPresenting === true;
24809  
24810		}
24811  
24812		var currentSize, currentPixelRatio;
24813  
24814		function onVRDisplayPresentChange() {
24815  
24816			if ( isPresenting() ) {
24817  
24818				var eyeParameters = device.getEyeParameters( 'left' );
24819				var renderWidth = eyeParameters.renderWidth;
24820				var renderHeight = eyeParameters.renderHeight;
24821  
24822				currentPixelRatio = renderer.getPixelRatio();
24823				currentSize = renderer.getSize();
24824  
24825				renderer.setDrawingBufferSize( renderWidth * 2, renderHeight, 1 );
24826  
24827				animation.start();
24828  
24829			} else if ( scope.enabled ) {
24830  
24831				renderer.setDrawingBufferSize( currentSize.width, currentSize.height, currentPixelRatio );
24832  
24833				animation.stop();
24834  
24835			}
24836  
24837		}
24838  
24839		//
24840  
24841		this.enabled = false;
24842		this.userHeight = 1.6;
24843  
24844		this.getDevice = function () {
24845  
24846			return device;
24847  
24848		};
24849  
24850		this.setDevice = function ( value ) {
24851  
24852			if ( value !== undefined ) device = value;
24853  
24854			animation.setContext( value );
24855  
24856		};
24857  
24858		this.setPoseTarget = function ( object ) {
24859  
24860			if ( object !== undefined ) poseTarget = object;
24861  
24862		};
24863  
24864		this.getCamera = function ( camera ) {
24865  
24866			if ( device === null ) return camera;
24867  
24868			device.depthNear = camera.near;
24869			device.depthFar = camera.far;
24870  
24871			device.getFrameData( frameData );
24872  
24873			//
24874  
24875			var stageParameters = device.stageParameters;
24876  
24877			if ( stageParameters ) {
24878  
24879				standingMatrix.fromArray( stageParameters.sittingToStandingTransform );
24880  
24881			} else {
24882  
24883				standingMatrix.makeTranslation( 0, scope.userHeight, 0 );
24884  
24885			}
24886  
24887  
24888			var pose = frameData.pose;
24889			var poseObject = poseTarget !== null ? poseTarget : camera;
24890  
24891			// We want to manipulate poseObject by its position and quaternion components since users may rely on them.
24892			poseObject.matrix.copy( standingMatrix );
24893			poseObject.matrix.decompose( poseObject.position, poseObject.quaternion, poseObject.scale );
24894  
24895			if ( pose.orientation !== null ) {
24896  
24897				tempQuaternion.fromArray( pose.orientation );
24898				poseObject.quaternion.multiply( tempQuaternion );
24899  
24900			}
24901  
24902			if ( pose.position !== null ) {
24903  
24904				tempQuaternion.setFromRotationMatrix( standingMatrix );
24905				tempPosition.fromArray( pose.position );
24906				tempPosition.applyQuaternion( tempQuaternion );
24907				poseObject.position.add( tempPosition );
24908  
24909			}
24910  
24911			poseObject.updateMatrixWorld();
24912  
24913			if ( device.isPresenting === false ) return camera;
24914  
24915			//
24916  
24917			cameraL.near = camera.near;
24918			cameraR.near = camera.near;
24919  
24920			cameraL.far = camera.far;
24921			cameraR.far = camera.far;
24922  
24923			cameraVR.matrixWorld.copy( camera.matrixWorld );
24924			cameraVR.matrixWorldInverse.copy( camera.matrixWorldInverse );
24925  
24926			cameraL.matrixWorldInverse.fromArray( frameData.leftViewMatrix );
24927			cameraR.matrixWorldInverse.fromArray( frameData.rightViewMatrix );
24928  
24929			// TODO (mrdoob) Double check this code
24930  
24931			standingMatrixInverse.getInverse( standingMatrix );
24932  
24933			cameraL.matrixWorldInverse.multiply( standingMatrixInverse );
24934			cameraR.matrixWorldInverse.multiply( standingMatrixInverse );
24935  
24936			var parent = poseObject.parent;
24937  
24938			if ( parent !== null ) {
24939  
24940				matrixWorldInverse.getInverse( parent.matrixWorld );
24941  
24942				cameraL.matrixWorldInverse.multiply( matrixWorldInverse );
24943				cameraR.matrixWorldInverse.multiply( matrixWorldInverse );
24944  
24945			}
24946  
24947			// envMap and Mirror needs camera.matrixWorld
24948  
24949			cameraL.matrixWorld.getInverse( cameraL.matrixWorldInverse );
24950			cameraR.matrixWorld.getInverse( cameraR.matrixWorldInverse );
24951  
24952			cameraL.projectionMatrix.fromArray( frameData.leftProjectionMatrix );
24953			cameraR.projectionMatrix.fromArray( frameData.rightProjectionMatrix );
24954  
24955			// HACK (mrdoob)
24956			// https://github.com/w3c/webvr/issues/203
24957  
24958			cameraVR.projectionMatrix.copy( cameraL.projectionMatrix );
24959  
24960			//
24961  
24962			var layers = device.getLayers();
24963  
24964			if ( layers.length ) {
24965  
24966				var layer = layers[ 0 ];
24967  
24968				if ( layer.leftBounds !== null && layer.leftBounds.length === 4 ) {
24969  
24970					cameraL.bounds.fromArray( layer.leftBounds );
24971  
24972				}
24973  
24974				if ( layer.rightBounds !== null && layer.rightBounds.length === 4 ) {
24975  
24976					cameraR.bounds.fromArray( layer.rightBounds );
24977  
24978				}
24979  
24980			}
24981  
24982			return cameraVR;
24983  
24984		};
24985  
24986		this.getStandingMatrix = function () {
24987  
24988			return standingMatrix;
24989  
24990		};
24991  
24992		this.isPresenting = isPresenting;
24993  
24994		// Animation Loop
24995  
24996		var animation = new WebGLAnimation();
24997  
24998		this.setAnimationLoop = function ( callback ) {
24999  
25000			animation.setAnimationLoop( callback );
25001  
25002		};
25003  
25004		this.submitFrame = function () {
25005  
25006			if ( isPresenting() ) device.submitFrame();
25007  
25008		};
25009  
25010		this.dispose = function () {
25011  
25012			if ( typeof window !== 'undefined' ) {
25013  
25014				window.removeEventListener( 'vrdisplaypresentchange', onVRDisplayPresentChange );
25015  
25016			}
25017  
25018		};
25019  
25020	}
25021  
25022	/**
25023	 * @author mrdoob / http://mrdoob.com/
25024	 */
25025  
25026	function WebXRManager( renderer ) {
25027  
25028		var gl = renderer.context;
25029  
25030		var device = null;
25031		var session = null;
25032  
25033		var frameOfRef = null;
25034  
25035		var pose = null;
25036  
25037		function isPresenting() {
25038  
25039			return session !== null && frameOfRef !== null;
25040  
25041		}
25042  
25043		//
25044  
25045		var cameraL = new PerspectiveCamera();
25046		cameraL.layers.enable( 1 );
25047		cameraL.viewport = new Vector4();
25048  
25049		var cameraR = new PerspectiveCamera();
25050		cameraR.layers.enable( 2 );
25051		cameraR.viewport = new Vector4();
25052  
25053		var cameraVR = new ArrayCamera( [ cameraL, cameraR ] );
25054		cameraVR.layers.enable( 1 );
25055		cameraVR.layers.enable( 2 );
25056  
25057		//
25058  
25059		this.enabled = false;
25060  
25061		this.getDevice = function () {
25062  
25063			return device;
25064  
25065		};
25066  
25067		this.setDevice = function ( value ) {
25068  
25069			if ( value !== undefined ) device = value;
25070  
25071			gl.setCompatibleXRDevice( value );
25072  
25073		};
25074  
25075		//
25076  
25077		this.setSession = function ( value, options ) {
25078  
25079			session = value;
25080  
25081			if ( session !== null ) {
25082  
25083				session.addEventListener( 'end', function () {
25084  
25085					renderer.setFramebuffer( null );
25086					animation.stop();
25087  
25088				} );
25089  
25090				session.baseLayer = new XRWebGLLayer( session, gl );
25091				session.requestFrameOfReference( options.frameOfReferenceType ).then( function ( value ) {
25092  
25093					frameOfRef = value;
25094  
25095					renderer.setFramebuffer( session.baseLayer.framebuffer );
25096  
25097					animation.setContext( session );
25098					animation.start();
25099  
25100				} );
25101  
25102			}
25103  
25104		};
25105  
25106		function updateCamera( camera, parent ) {
25107  
25108			if ( parent === null ) {
25109  
25110				camera.matrixWorld.copy( camera.matrix );
25111  
25112			} else {
25113  
25114				camera.matrixWorld.multiplyMatrices( parent.matrixWorld, camera.matrix );
25115  
25116			}
25117  
25118			camera.matrixWorldInverse.getInverse( camera.matrixWorld );
25119  
25120		}
25121  
25122		this.getCamera = function ( camera ) {
25123  
25124			if ( isPresenting() ) {
25125  
25126				var parent = camera.parent;
25127				var cameras = cameraVR.cameras;
25128  
25129				// apply camera.parent to cameraVR
25130  
25131				updateCamera( cameraVR, parent );
25132  
25133				for ( var i = 0; i < cameras.length; i ++ ) {
25134  
25135					updateCamera( cameras[ i ], parent );
25136  
25137				}
25138  
25139				// update camera and its children
25140  
25141				camera.matrixWorld.copy( cameraVR.matrixWorld );
25142  
25143				var children = camera.children;
25144  
25145				for ( var i = 0, l = children.length; i < l; i ++ ) {
25146  
25147					children[ i ].updateMatrixWorld( true );
25148  
25149				}
25150  
25151				return cameraVR;
25152  
25153			}
25154  
25155			return camera;
25156  
25157		};
25158  
25159		this.isPresenting = isPresenting;
25160  
25161		// Animation Loop
25162  
25163		var onAnimationFrameCallback = null;
25164  
25165		function onAnimationFrame( time, frame ) {
25166  
25167			pose = frame.getDevicePose( frameOfRef );
25168  
25169			var layer = session.baseLayer;
25170			var views = frame.views;
25171  
25172			for ( var i = 0; i < views.length; i ++ ) {
25173  
25174				var view = views[ i ];
25175				var viewport = layer.getViewport( view );
25176				var viewMatrix = pose.getViewMatrix( view );
25177  
25178				var camera = cameraVR.cameras[ i ];
25179				camera.matrix.fromArray( viewMatrix ).getInverse( camera.matrix );
25180				camera.projectionMatrix.fromArray( view.projectionMatrix );
25181				camera.viewport.set( viewport.x, viewport.y, viewport.width, viewport.height );
25182  
25183				if ( i === 0 ) {
25184  
25185					cameraVR.matrix.copy( camera.matrix );
25186  
25187					// HACK (mrdoob)
25188					// https://github.com/w3c/webvr/issues/203
25189  
25190					cameraVR.projectionMatrix.copy( camera.projectionMatrix );
25191  
25192				}
25193  
25194			}
25195  
25196			if ( onAnimationFrameCallback ) onAnimationFrameCallback();
25197  
25198		}
25199  
25200		var animation = new WebGLAnimation();
25201		animation.setAnimationLoop( onAnimationFrame );
25202  
25203		this.setAnimationLoop = function ( callback ) {
25204  
25205			onAnimationFrameCallback = callback;
25206  
25207		};
25208  
25209		// DEPRECATED
25210  
vendor: 11,442 bytes, lines 25211-25704
25211		this.getStandingMatrix = function () {
25212  
25213			console.warn( 'THREE.WebXRManager: getStandingMatrix() is no longer needed.' );
25214			return new THREE.Matrix4();
25215  
25216		};
25217  
25218		this.submitFrame = function () {};
25219  
25220	}
25221  
25222	/**
25223	 * @author supereggbert / http://www.paulbrunt.co.uk/
25224	 * @author mrdoob / http://mrdoob.com/
25225	 * @author alteredq / http://alteredqualia.com/
25226	 * @author szimek / https://github.com/szimek/
25227	 * @author tschw
25228	 */
25229  
25230	function WebGLRenderer( parameters ) {
25231  
25232		console.log( 'THREE.WebGLRenderer', REVISION );
25233  
25234		parameters = parameters || {};
25235  
25236		var _canvas = parameters.canvas !== undefined ? parameters.canvas : document.createElementNS( 'http://www.w3.org/1999/xhtml', 'canvas' ),
25237			_context = parameters.context !== undefined ? parameters.context : null,
25238  
25239			_alpha = parameters.alpha !== undefined ? parameters.alpha : false,
25240			_depth = parameters.depth !== undefined ? parameters.depth : true,
25241			_stencil = parameters.stencil !== undefined ? parameters.stencil : true,
25242			_antialias = parameters.antialias !== undefined ? parameters.antialias : false,
25243			_premultipliedAlpha = parameters.premultipliedAlpha !== undefined ? parameters.premultipliedAlpha : true,
25244			_preserveDrawingBuffer = parameters.preserveDrawingBuffer !== undefined ? parameters.preserveDrawingBuffer : false,
25245			_powerPreference = parameters.powerPreference !== undefined ? parameters.powerPreference : 'default';
25246  
25247		var currentRenderList = null;
25248		var currentRenderState = null;
25249  
25250		// public properties
25251  
25252		this.domElement = _canvas;
25253		this.context = null;
25254  
25255		// clearing
25256  
25257		this.autoClear = true;
25258		this.autoClearColor = true;
25259		this.autoClearDepth = true;
25260		this.autoClearStencil = true;
25261  
25262		// scene graph
25263  
25264		this.sortObjects = true;
25265  
25266		// user-defined clipping
25267  
25268		this.clippingPlanes = [];
25269		this.localClippingEnabled = false;
25270  
25271		// physically based shading
25272  
25273		this.gammaFactor = 2.0;	// for backwards compatibility
25274		this.gammaInput = false;
25275		this.gammaOutput = false;
25276  
25277		// physical lights
25278  
25279		this.physicallyCorrectLights = false;
25280  
25281		// tone mapping
25282  
25283		this.toneMapping = LinearToneMapping;
25284		this.toneMappingExposure = 1.0;
25285		this.toneMappingWhitePoint = 1.0;
25286  
25287		// morphs
25288  
25289		this.maxMorphTargets = 8;
25290		this.maxMorphNormals = 4;
25291  
25292		// internal properties
25293  
25294		var _this = this,
25295  
25296			_isContextLost = false,
25297  
25298			// internal state cache
25299  
25300			_framebuffer = null,
25301  
25302			_currentRenderTarget = null,
25303			_currentFramebuffer = null,
25304			_currentMaterialId = - 1,
25305			_currentGeometryProgram = '',
25306  
25307			_currentCamera = null,
25308			_currentArrayCamera = null,
25309  
25310			_currentViewport = new Vector4(),
25311			_currentScissor = new Vector4(),
25312			_currentScissorTest = null,
25313  
25314			//
25315  
25316			_usedTextureUnits = 0,
25317  
25318			//
25319  
25320			_width = _canvas.width,
25321			_height = _canvas.height,
25322  
25323			_pixelRatio = 1,
25324  
25325			_viewport = new Vector4( 0, 0, _width, _height ),
25326			_scissor = new Vector4( 0, 0, _width, _height ),
25327			_scissorTest = false,
25328  
25329			// frustum
25330  
25331			_frustum = new Frustum(),
25332  
25333			// clipping
25334  
25335			_clipping = new WebGLClipping(),
25336			_clippingEnabled = false,
25337			_localClippingEnabled = false,
25338  
25339			// camera matrices cache
25340  
25341			_projScreenMatrix = new Matrix4(),
25342  
25343			_vector3 = new Vector3();
25344  
25345		function getTargetPixelRatio() {
25346  
25347			return _currentRenderTarget === null ? _pixelRatio : 1;
25348  
25349		}
25350  
25351		// initialize
25352  
25353		var _gl;
25354  
25355		try {
25356  
25357			var contextAttributes = {
25358				alpha: _alpha,
25359				depth: _depth,
25360				stencil: _stencil,
25361				antialias: _antialias,
25362				premultipliedAlpha: _premultipliedAlpha,
25363				preserveDrawingBuffer: _preserveDrawingBuffer,
25364				powerPreference: _powerPreference
25365			};
25366  
25367			// event listeners must be registered before WebGL context is created, see #12753
25368  
25369			_canvas.addEventListener( 'webglcontextlost', onContextLost, false );
25370			_canvas.addEventListener( 'webglcontextrestored', onContextRestore, false );
25371  
25372			_gl = _context || _canvas.getContext( 'webgl', contextAttributes ) || _canvas.getContext( 'experimental-webgl', contextAttributes );
25373  
25374			if ( _gl === null ) {
25375  
25376				if ( _canvas.getContext( 'webgl' ) !== null ) {
25377  
25378					throw new Error( 'Error creating WebGL context with your selected attributes.' );
25379  
25380				} else {
25381  
25382					throw new Error( 'Error creating WebGL context.' );
25383  
25384				}
25385  
25386			}
25387  
25388			// Some experimental-webgl implementations do not have getShaderPrecisionFormat
25389  
25390			if ( _gl.getShaderPrecisionFormat === undefined ) {
25391  
25392				_gl.getShaderPrecisionFormat = function () {
25393  
25394					return { 'rangeMin': 1, 'rangeMax': 1, 'precision': 1 };
25395  
25396				};
25397  
25398			}
25399  
25400		} catch ( error ) {
25401  
25402			console.error( 'THREE.WebGLRenderer: ' + error.message );
25403  
25404		}
25405  
25406		var extensions, capabilities, state, info;
25407		var properties, textures, attributes, geometries, objects;
25408		var programCache, renderLists, renderStates;
25409  
25410		var background, morphtargets, bufferRenderer, indexedBufferRenderer;
25411		var spriteRenderer;
25412  
25413		var utils;
25414  
25415		function initGLContext() {
25416  
25417			extensions = new WebGLExtensions( _gl );
25418			extensions.get( 'WEBGL_depth_texture' );
25419			extensions.get( 'OES_texture_float' );
25420			extensions.get( 'OES_texture_float_linear' );
25421			extensions.get( 'OES_texture_half_float' );
25422			extensions.get( 'OES_texture_half_float_linear' );
25423			extensions.get( 'OES_standard_derivatives' );
25424			extensions.get( 'OES_element_index_uint' );
25425			extensions.get( 'ANGLE_instanced_arrays' );
25426  
25427			utils = new WebGLUtils( _gl, extensions );
25428  
25429			capabilities = new WebGLCapabilities( _gl, extensions, parameters );
25430  
25431			state = new WebGLState( _gl, extensions, utils );
25432			state.scissor( _currentScissor.copy( _scissor ).multiplyScalar( _pixelRatio ) );
25433			state.viewport( _currentViewport.copy( _viewport ).multiplyScalar( _pixelRatio ) );
25434  
25435			info = new WebGLInfo( _gl );
25436			properties = new WebGLProperties();
25437			textures = new WebGLTextures( _gl, extensions, state, properties, capabilities, utils, info );
25438			attributes = new WebGLAttributes( _gl );
25439			geometries = new WebGLGeometries( _gl, attributes, info );
25440			objects = new WebGLObjects( geometries, info );
25441			morphtargets = new WebGLMorphtargets( _gl );
25442			programCache = new WebGLPrograms( _this, extensions, capabilities );
25443			renderLists = new WebGLRenderLists();
25444			renderStates = new WebGLRenderStates();
25445  
25446			background = new WebGLBackground( _this, state, objects, _premultipliedAlpha );
25447  
25448			bufferRenderer = new WebGLBufferRenderer( _gl, extensions, info );
25449			indexedBufferRenderer = new WebGLIndexedBufferRenderer( _gl, extensions, info );
25450  
25451			spriteRenderer = new WebGLSpriteRenderer( _this, _gl, state, textures, capabilities );
25452  
25453			info.programs = programCache.programs;
25454  
25455			_this.context = _gl;
25456			_this.capabilities = capabilities;
25457			_this.extensions = extensions;
25458			_this.properties = properties;
25459			_this.renderLists = renderLists;
25460			_this.state = state;
25461			_this.info = info;
25462  
25463		}
25464  
25465		initGLContext();
25466  
25467		// vr
25468  
25469		var vr = ( 'xr' in navigator ) ? new WebXRManager( _this ) : new WebVRManager( _this );
25470  
25471		this.vr = vr;
25472  
25473		// shadow map
25474  
25475		var shadowMap = new WebGLShadowMap( _this, objects, capabilities.maxTextureSize );
25476  
25477		this.shadowMap = shadowMap;
25478  
25479		// API
25480  
25481		this.getContext = function () {
25482  
25483			return _gl;
25484  
25485		};
25486  
25487		this.getContextAttributes = function () {
25488  
25489			return _gl.getContextAttributes();
25490  
25491		};
25492  
25493		this.forceContextLoss = function () {
25494  
25495			var extension = extensions.get( 'WEBGL_lose_context' );
25496			if ( extension ) extension.loseContext();
25497  
25498		};
25499  
25500		this.forceContextRestore = function () {
25501  
25502			var extension = extensions.get( 'WEBGL_lose_context' );
25503			if ( extension ) extension.restoreContext();
25504  
25505		};
25506  
25507		this.getPixelRatio = function () {
25508  
25509			return _pixelRatio;
25510  
25511		};
25512  
25513		this.setPixelRatio = function ( value ) {
25514  
25515			if ( value === undefined ) return;
25516  
25517			_pixelRatio = value;
25518  
25519			this.setSize( _width, _height, false );
25520  
25521		};
25522  
25523		this.getSize = function () {
25524  
25525			return {
25526				width: _width,
25527				height: _height
25528			};
25529  
25530		};
25531  
25532		this.setSize = function ( width, height, updateStyle ) {
25533  
25534			if ( vr.isPresenting() ) {
25535  
25536				console.warn( 'THREE.WebGLRenderer: Can\'t change size while VR device is presenting.' );
25537				return;
25538  
25539			}
25540  
25541			_width = width;
25542			_height = height;
25543  
25544			_canvas.width = width * _pixelRatio;
25545			_canvas.height = height * _pixelRatio;
25546  
25547			if ( updateStyle !== false ) {
25548  
25549				_canvas.style.width = width + 'px';
25550				_canvas.style.height = height + 'px';
25551  
25552			}
25553  
25554			this.setViewport( 0, 0, width, height );
25555  
25556		};
25557  
25558		this.getDrawingBufferSize = function () {
25559  
25560			return {
25561				width: _width * _pixelRatio,
25562				height: _height * _pixelRatio
25563			};
25564  
25565		};
25566  
25567		this.setDrawingBufferSize = function ( width, height, pixelRatio ) {
25568  
25569			_width = width;
25570			_height = height;
25571  
25572			_pixelRatio = pixelRatio;
25573  
25574			_canvas.width = width * pixelRatio;
25575			_canvas.height = height * pixelRatio;
25576  
25577			this.setViewport( 0, 0, width, height );
25578  
25579		};
25580  
25581		this.getCurrentViewport = function () {
25582  
25583			return _currentViewport;
25584  
25585		};
25586  
25587		this.setViewport = function ( x, y, width, height ) {
25588  
25589			_viewport.set( x, _height - y - height, width, height );
25590			state.viewport( _currentViewport.copy( _viewport ).multiplyScalar( _pixelRatio ) );
25591  
25592		};
25593  
25594		this.setScissor = function ( x, y, width, height ) {
25595  
25596			_scissor.set( x, _height - y - height, width, height );
25597			state.scissor( _currentScissor.copy( _scissor ).multiplyScalar( _pixelRatio ) );
25598  
25599		};
25600  
25601		this.setScissorTest = function ( boolean ) {
25602  
25603			state.setScissorTest( _scissorTest = boolean );
25604  
25605		};
25606  
25607		// Clearing
25608  
25609		this.getClearColor = function () {
25610  
25611			return background.getClearColor();
25612  
25613		};
25614  
25615		this.setClearColor = function () {
25616  
25617			background.setClearColor.apply( background, arguments );
25618  
25619		};
25620  
25621		this.getClearAlpha = function () {
25622  
25623			return background.getClearAlpha();
25624  
25625		};
25626  
25627		this.setClearAlpha = function () {
25628  
25629			background.setClearAlpha.apply( background, arguments );
25630  
25631		};
25632  
25633		this.clear = function ( color, depth, stencil ) {
25634  
25635			var bits = 0;
25636  
25637			if ( color === undefined || color ) bits |= _gl.COLOR_BUFFER_BIT;
25638			if ( depth === undefined || depth ) bits |= _gl.DEPTH_BUFFER_BIT;
25639			if ( stencil === undefined || stencil ) bits |= _gl.STENCIL_BUFFER_BIT;
25640  
25641			_gl.clear( bits );
25642  
25643		};
25644  
25645		this.clearColor = function () {
25646  
25647			this.clear( true, false, false );
25648  
25649		};
25650  
25651		this.clearDepth = function () {
25652  
25653			this.clear( false, true, false );
25654  
25655		};
25656  
25657		this.clearStencil = function () {
25658  
25659			this.clear( false, false, true );
25660  
25661		};
25662  
25663		this.clearTarget = function ( renderTarget, color, depth, stencil ) {
25664  
25665			this.setRenderTarget( renderTarget );
25666			this.clear( color, depth, stencil );
25667  
25668		};
25669  
25670		//
25671  
25672		this.dispose = function () {
25673  
25674			_canvas.removeEventListener( 'webglcontextlost', onContextLost, false );
25675			_canvas.removeEventListener( 'webglcontextrestored', onContextRestore, false );
25676  
25677			renderLists.dispose();
25678			renderStates.dispose();
25679			properties.dispose();
25680			objects.dispose();
25681  
25682			vr.dispose();
25683  
25684			animation.stop();
25685  
25686		};
25687  
25688		// Events
25689  
25690		function onContextLost( event ) {
25691  
25692			event.preventDefault();
25693  
25694			console.log( 'THREE.WebGLRenderer: Context Lost.' );
25695  
25696			_isContextLost = true;
25697  
25698		}
25699  
25700		function onContextRestore( /* event */ ) {
25701  
25702			console.log( 'THREE.WebGLRenderer: Context Restored.' );
25703  
25704			_isContextLost = false;
25705  
25706			initGLContext();
25707  
25708		}
25709  
25710		function onMaterialDispose( event ) {
25711  
25712			var material = event.target;
25713  
25714			material.removeEventListener( 'dispose', onMaterialDispose );
25715  
25716			deallocateMaterial( material );
25717  
25718		}
25719  
25720		// Buffer deallocation
25721  
25722		function deallocateMaterial( material ) {
25723  
25724			releaseMaterialProgramReference( material );
25725  
25726			properties.remove( material );
25727  
25728		}
25729  
25730  
25731		function releaseMaterialProgramReference( material ) {
25732  
25733			var programInfo = properties.get( material ).program;
25734  
25735			material.program = undefined;
25736  
25737			if ( programInfo !== undefined ) {
25738  
25739				programCache.releaseProgram( programInfo );
25740  
25741			}
25742  
25743		}
25744  
25745		// Buffer rendering
25746  
25747		function renderObjectImmediate( object, program, material ) {
25748  
25749			object.render( function ( object ) {
25750  
25751				_this.renderBufferImmediate( object, program, material );
25752  
25753			} );
25754  
25755		}
25756  
25757		this.renderBufferImmediate = function ( object, program, material ) {
25758  
25759			state.initAttributes();
25760  
25761			var buffers = properties.get( object );
25762  
25763			if ( object.hasPositions && ! buffers.position ) buffers.position = _gl.createBuffer();
25764			if ( object.hasNormals && ! buffers.normal ) buffers.normal = _gl.createBuffer();
25765			if ( object.hasUvs && ! buffers.uv ) buffers.uv = _gl.createBuffer();
25766			if ( object.hasColors && ! buffers.color ) buffers.color = _gl.createBuffer();
25767  
25768			var programAttributes = program.getAttributes();
25769  
25770			if ( object.hasPositions ) {
25771  
25772				_gl.bindBuffer( _gl.ARRAY_BUFFER, buffers.position );
25773				_gl.bufferData( _gl.ARRAY_BUFFER, object.positionArray, _gl.DYNAMIC_DRAW );
25774  
25775				state.enableAttribute( programAttributes.position );
25776				_gl.vertexAttribPointer( programAttributes.position, 3, _gl.FLOAT, false, 0, 0 );
25777  
25778			}
25779  
25780			if ( object.hasNormals ) {
25781  
25782				_gl.bindBuffer( _gl.ARRAY_BUFFER, buffers.normal );
25783  
25784				if ( ! material.isMeshPhongMaterial &&
25785					! material.isMeshStandardMaterial &&
25786					! material.isMeshNormalMaterial &&
25787					material.flatShading === true ) {
25788  
25789					for ( var i = 0, l = object.count * 3; i < l; i += 9 ) {
25790  
25791						var array = object.normalArray;
25792  
25793						var nx = ( array[ i + 0 ] + array[ i + 3 ] + array[ i + 6 ] ) / 3;
25794						var ny = ( array[ i + 1 ] + array[ i + 4 ] + array[ i + 7 ] ) / 3;
25795						var nz = ( array[ i + 2 ] + array[ i + 5 ] + array[ i + 8 ] ) / 3;
25796  
25797						array[ i + 0 ] = nx;
25798						array[ i + 1 ] = ny;
25799						array[ i + 2 ] = nz;
25800  
25801						array[ i + 3 ] = nx;
25802						array[ i + 4 ] = ny;
25803						array[ i + 5 ] = nz;
25804  
25805						array[ i + 6 ] = nx;
25806						array[ i + 7 ] = ny;
25807						array[ i + 8 ] = nz;
25808  
25809					}
25810  
25811				}
25812  
25813				_gl.bufferData( _gl.ARRAY_BUFFER, object.normalArray, _gl.DYNAMIC_DRAW );
25814  
25815				state.enableAttribute( programAttributes.normal );
25816  
25817				_gl.vertexAttribPointer( programAttributes.normal, 3, _gl.FLOAT, false, 0, 0 );
25818  
25819			}
25820  
25821			if ( object.hasUvs && material.map ) {
25822  
25823				_gl.bindBuffer( _gl.ARRAY_BUFFER, buffers.uv );
25824				_gl.bufferData( _gl.ARRAY_BUFFER, object.uvArray, _gl.DYNAMIC_DRAW );
25825  
25826				state.enableAttribute( programAttributes.uv );
25827  
25828				_gl.vertexAttribPointer( programAttributes.uv, 2, _gl.FLOAT, false, 0, 0 );
25829  
25830			}
25831  
25832			if ( object.hasColors && material.vertexColors !== NoColors ) {
25833  
25834				_gl.bindBuffer( _gl.ARRAY_BUFFER, buffers.color );
25835				_gl.bufferData( _gl.ARRAY_BUFFER, object.colorArray, _gl.DYNAMIC_DRAW );
25836  
25837				state.enableAttribute( programAttributes.color );
25838  
25839				_gl.vertexAttribPointer( programAttributes.color, 3, _gl.FLOAT, false, 0, 0 );
25840  
25841			}
25842  
25843			state.disableUnusedAttributes();
25844  
25845			_gl.drawArrays( _gl.TRIANGLES, 0, object.count );
25846  
25847			object.count = 0;
25848  
25849		};
25850  
25851		this.renderBufferDirect = function ( camera, fog, geometry, material, object, group ) {
25852  
25853			var frontFaceCW = ( object.isMesh && object.matrixWorld.determinant() < 0 );
25854  
25855			state.setMaterial( material, frontFaceCW );
25856  
25857			var program = setProgram( camera, fog, material, object );
25858			var geometryProgram = geometry.id + '_' + program.id + '_' + ( material.wireframe === true );
25859  
25860			var updateBuffers = false;
25861  
25862			if ( geometryProgram !== _currentGeometryProgram ) {
25863  
25864				_currentGeometryProgram = geometryProgram;
25865				updateBuffers = true;
25866  
25867			}
25868  
25869			if ( object.morphTargetInfluences ) {
25870  
25871				morphtargets.update( object, geometry, material, program );
25872  
25873				updateBuffers = true;
25874  
25875			}
25876  
25877			//
25878  
25879			var index = geometry.index;
25880			var position = geometry.attributes.position;
25881			var rangeFactor = 1;
25882  
25883			if ( material.wireframe === true ) {
25884  
25885				index = geometries.getWireframeAttribute( geometry );
25886				rangeFactor = 2;
25887  
25888			}
25889  
25890			var attribute;
25891			var renderer = bufferRenderer;
25892  
25893			if ( index !== null ) {
25894  
25895				attribute = attributes.get( index );
25896  
25897				renderer = indexedBufferRenderer;
25898				renderer.setIndex( attribute );
25899  
25900			}
25901  
25902			if ( updateBuffers ) {
25903  
25904				setupVertexAttributes( material, program, geometry );
25905  
25906				if ( index !== null ) {
25907  
25908					_gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, attribute.buffer );
25909  
25910				}
25911  
25912			}
25913  
25914			//
25915  
25916			var dataCount = Infinity;
25917  
25918			if ( index !== null ) {
25919  
25920				dataCount = index.count;
25921  
25922			} else if ( position !== undefined ) {
25923  
25924				dataCount = position.count;
25925  
25926			}
25927  
25928			var rangeStart = geometry.drawRange.start * rangeFactor;
25929			var rangeCount = geometry.drawRange.count * rangeFactor;
25930  
25931			var groupStart = group !== null ? group.start * rangeFactor : 0;
25932			var groupCount = group !== null ? group.count * rangeFactor : Infinity;
25933  
25934			var drawStart = Math.max( rangeStart, groupStart );
25935			var drawEnd = Math.min( dataCount, rangeStart + rangeCount, groupStart + groupCount ) - 1;
25936  
25937			var drawCount = Math.max( 0, drawEnd - drawStart + 1 );
25938  
25939			if ( drawCount === 0 ) return;
25940  
25941			//
25942  
25943			if ( object.isMesh ) {
25944  
25945				if ( material.wireframe === true ) {
25946  
25947					state.setLineWidth( material.wireframeLinewidth * getTargetPixelRatio() );
25948					renderer.setMode( _gl.LINES );
25949  
25950				} else {
25951  
vendor: 4,537 bytes, lines 25952-26148
25952					switch ( object.drawMode ) {
25953  
25954						case TrianglesDrawMode:
25955							renderer.setMode( _gl.TRIANGLES );
25956							break;
25957  
25958						case TriangleStripDrawMode:
25959							renderer.setMode( _gl.TRIANGLE_STRIP );
25960							break;
25961  
25962						case TriangleFanDrawMode:
25963							renderer.setMode( _gl.TRIANGLE_FAN );
25964							break;
25965  
25966					}
25967  
25968				}
25969  
25970  
25971			} else if ( object.isLine ) {
25972  
25973				var lineWidth = material.linewidth;
25974  
25975				if ( lineWidth === undefined ) lineWidth = 1; // Not using Line*Material
25976  
25977				state.setLineWidth( lineWidth * getTargetPixelRatio() );
25978  
25979				if ( object.isLineSegments ) {
25980  
25981					renderer.setMode( _gl.LINES );
25982  
25983				} else if ( object.isLineLoop ) {
25984  
25985					renderer.setMode( _gl.LINE_LOOP );
25986  
25987				} else {
25988  
25989					renderer.setMode( _gl.LINE_STRIP );
25990  
25991				}
25992  
25993			} else if ( object.isPoints ) {
25994  
25995				renderer.setMode( _gl.POINTS );
25996  
25997			}
25998  
25999			if ( geometry && geometry.isInstancedBufferGeometry ) {
26000  
26001				if ( geometry.maxInstancedCount > 0 ) {
26002  
26003					renderer.renderInstances( geometry, drawStart, drawCount );
26004  
26005				}
26006  
26007			} else {
26008  
26009				renderer.render( drawStart, drawCount );
26010  
26011			}
26012  
26013		};
26014  
26015		function setupVertexAttributes( material, program, geometry ) {
26016  
26017			if ( geometry && geometry.isInstancedBufferGeometry ) {
26018  
26019				if ( extensions.get( 'ANGLE_instanced_arrays' ) === null ) {
26020  
26021					console.error( 'THREE.WebGLRenderer.setupVertexAttributes: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.' );
26022					return;
26023  
26024				}
26025  
26026			}
26027  
26028			state.initAttributes();
26029  
26030			var geometryAttributes = geometry.attributes;
26031  
26032			var programAttributes = program.getAttributes();
26033  
26034			var materialDefaultAttributeValues = material.defaultAttributeValues;
26035  
26036			for ( var name in programAttributes ) {
26037  
26038				var programAttribute = programAttributes[ name ];
26039  
26040				if ( programAttribute >= 0 ) {
26041  
26042					var geometryAttribute = geometryAttributes[ name ];
26043  
26044					if ( geometryAttribute !== undefined ) {
26045  
26046						var normalized = geometryAttribute.normalized;
26047						var size = geometryAttribute.itemSize;
26048  
26049						var attribute = attributes.get( geometryAttribute );
26050  
26051						// TODO Attribute may not be available on context restore
26052  
26053						if ( attribute === undefined ) continue;
26054  
26055						var buffer = attribute.buffer;
26056						var type = attribute.type;
26057						var bytesPerElement = attribute.bytesPerElement;
26058  
26059						if ( geometryAttribute.isInterleavedBufferAttribute ) {
26060  
26061							var data = geometryAttribute.data;
26062							var stride = data.stride;
26063							var offset = geometryAttribute.offset;
26064  
26065							if ( data && data.isInstancedInterleavedBuffer ) {
26066  
26067								state.enableAttributeAndDivisor( programAttribute, data.meshPerAttribute );
26068  
26069								if ( geometry.maxInstancedCount === undefined ) {
26070  
26071									geometry.maxInstancedCount = data.meshPerAttribute * data.count;
26072  
26073								}
26074  
26075							} else {
26076  
26077								state.enableAttribute( programAttribute );
26078  
26079							}
26080  
26081							_gl.bindBuffer( _gl.ARRAY_BUFFER, buffer );
26082							_gl.vertexAttribPointer( programAttribute, size, type, normalized, stride * bytesPerElement, offset * bytesPerElement );
26083  
26084						} else {
26085  
26086							if ( geometryAttribute.isInstancedBufferAttribute ) {
26087  
26088								state.enableAttributeAndDivisor( programAttribute, geometryAttribute.meshPerAttribute );
26089  
26090								if ( geometry.maxInstancedCount === undefined ) {
26091  
26092									geometry.maxInstancedCount = geometryAttribute.meshPerAttribute * geometryAttribute.count;
26093  
26094								}
26095  
26096							} else {
26097  
26098								state.enableAttribute( programAttribute );
26099  
26100							}
26101  
26102							_gl.bindBuffer( _gl.ARRAY_BUFFER, buffer );
26103							_gl.vertexAttribPointer( programAttribute, size, type, normalized, 0, 0 );
26104  
26105						}
26106  
26107					} else if ( materialDefaultAttributeValues !== undefined ) {
26108  
26109						var value = materialDefaultAttributeValues[ name ];
26110  
26111						if ( value !== undefined ) {
26112  
26113							switch ( value.length ) {
26114  
26115								case 2:
26116									_gl.vertexAttrib2fv( programAttribute, value );
26117									break;
26118  
26119								case 3:
26120									_gl.vertexAttrib3fv( programAttribute, value );
26121									break;
26122  
26123								case 4:
26124									_gl.vertexAttrib4fv( programAttribute, value );
26125									break;
26126  
26127								default:
26128									_gl.vertexAttrib1fv( programAttribute, value );
26129  
26130							}
26131  
26132						}
26133  
26134					}
26135  
26136				}
26137  
26138			}
26139  
26140			state.disableUnusedAttributes();
26141  
26142		}
26143  
26144		// Compile
26145  
26146		this.compile = function ( scene, camera ) {
26147  
26148			currentRenderState = renderStates.get( scene, camera );
26149			currentRenderState.init();
26150  
26151			scene.traverse( function ( object ) {
26152  
26153				if ( object.isLight ) {
26154  
26155					currentRenderState.pushLight( object );
26156  
26157					if ( object.castShadow ) {
26158  
26159						currentRenderState.pushShadow( object );
26160  
26161					}
26162  
26163				}
26164  
26165			} );
26166  
26167			currentRenderState.setupLights( camera );
26168  
26169			scene.traverse( function ( object ) {
26170  
26171				if ( object.material ) {
26172  
26173					if ( Array.isArray( object.material ) ) {
26174  
26175						for ( var i = 0; i < object.material.length; i ++ ) {
26176  
26177							initMaterial( object.material[ i ], scene.fog, object );
26178  
26179						}
26180  
26181					} else {
26182  
26183						initMaterial( object.material, scene.fog, object );
26184  
26185					}
26186  
26187				}
26188  
26189			} );
26190  
26191		};
26192  
26193		// Animation Loop
26194  
26195		var onAnimationFrameCallback = null;
26196  
26197		function onAnimationFrame() {
26198  
26199			if ( vr.isPresenting() ) return;
26200			if ( onAnimationFrameCallback ) onAnimationFrameCallback();
26201  
26202		}
26203  
26204		var animation = new WebGLAnimation();
26205		animation.setAnimationLoop( onAnimationFrame );
26206		animation.setContext( window );
26207  
26208		this.setAnimationLoop = function ( callback ) {
26209  
26210			onAnimationFrameCallback = callback;
26211			vr.setAnimationLoop( callback );
26212  
26213			animation.start();
26214  
26215		};
26216  
26217		// Rendering
26218  
26219		this.render = function ( scene, camera, renderTarget, forceClear ) {
26220  
26221			if ( ! ( camera && camera.isCamera ) ) {
26222  
26223				console.error( 'THREE.WebGLRenderer.render: camera is not an instance of THREE.Camera.' );
26224				return;
26225  
26226			}
26227  
26228			if ( _isContextLost ) return;
26229  
26230			// reset caching for this frame
26231  
26232			_currentGeometryProgram = '';
26233			_currentMaterialId = - 1;
26234			_currentCamera = null;
26235  
26236			// update scene graph
26237  
26238			if ( scene.autoUpdate === true ) scene.updateMatrixWorld();
26239  
26240			// update camera matrices and frustum
26241  
26242			if ( camera.parent === null ) camera.updateMatrixWorld();
26243  
26244			if ( vr.enabled ) {
26245  
26246				camera = vr.getCamera( camera );
26247  
26248			}
26249  
26250			//
26251  
26252			currentRenderState = renderStates.get( scene, camera );
26253			currentRenderState.init();
26254  
26255			scene.onBeforeRender( _this, scene, camera, renderTarget );
26256  
26257			_projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse );
26258			_frustum.setFromMatrix( _projScreenMatrix );
26259  
26260			_localClippingEnabled = this.localClippingEnabled;
26261			_clippingEnabled = _clipping.init( this.clippingPlanes, _localClippingEnabled, camera );
26262  
26263			currentRenderList = renderLists.get( scene, camera );
26264			currentRenderList.init();
26265  
26266			projectObject( scene, camera, _this.sortObjects );
26267  
26268			if ( _this.sortObjects === true ) {
26269  
26270				currentRenderList.sort();
26271  
26272			}
26273  
26274			//
26275  
26276			if ( _clippingEnabled ) _clipping.beginShadows();
26277  
26278			var shadowsArray = currentRenderState.state.shadowsArray;
26279  
26280			shadowMap.render( shadowsArray, scene, camera );
26281  
26282			currentRenderState.setupLights( camera );
26283  
26284			if ( _clippingEnabled ) _clipping.endShadows();
26285  
26286			//
26287  
26288			if ( this.info.autoReset ) this.info.reset();
26289  
26290			if ( renderTarget === undefined ) {
26291  
26292				renderTarget = null;
26293  
26294			}
26295  
26296			this.setRenderTarget( renderTarget );
26297  
26298			//
26299  
26300			background.render( currentRenderList, scene, camera, forceClear );
26301  
26302			// render scene
26303  
26304			var opaqueObjects = currentRenderList.opaque;
26305			var transparentObjects = currentRenderList.transparent;
26306  
26307			if ( scene.overrideMaterial ) {
26308  
26309				var overrideMaterial = scene.overrideMaterial;
26310  
26311				if ( opaqueObjects.length ) renderObjects( opaqueObjects, scene, camera, overrideMaterial );
26312				if ( transparentObjects.length ) renderObjects( transparentObjects, scene, camera, overrideMaterial );
26313  
26314			} else {
26315  
26316				// opaque pass (front-to-back order)
26317  
26318				if ( opaqueObjects.length ) renderObjects( opaqueObjects, scene, camera );
26319  
26320				// transparent pass (back-to-front order)
26321  
26322				if ( transparentObjects.length ) renderObjects( transparentObjects, scene, camera );
26323  
26324			}
26325  
26326			// custom renderers
26327  
26328			var spritesArray = currentRenderState.state.spritesArray;
26329  
26330			spriteRenderer.render( spritesArray, scene, camera );
26331  
26332			// Generate mipmap if we're using any kind of mipmap filtering
26333  
26334			if ( renderTarget ) {
26335  
26336				textures.updateRenderTargetMipmap( renderTarget );
26337  
26338			}
26339  
26340			// Ensure depth buffer writing is enabled so it can be cleared on next render
26341  
26342			state.buffers.depth.setTest( true );
26343			state.buffers.depth.setMask( true );
26344			state.buffers.color.setMask( true );
26345  
26346			state.setPolygonOffset( false );
26347  
26348			scene.onAfterRender( _this, scene, camera );
26349  
26350			if ( vr.enabled ) {
26351  
26352				vr.submitFrame();
26353  
26354			}
26355  
26356			// _gl.finish();
26357  
26358			currentRenderList = null;
26359			currentRenderState = null;
26360  
26361		};
26362  
26363		/*
26364		// TODO Duplicated code (Frustum)
26365  
26366		var _sphere = new Sphere();
26367  
26368		function isObjectViewable( object ) {
26369  
26370			var geometry = object.geometry;
26371  
26372			if ( geometry.boundingSphere === null )
26373				geometry.computeBoundingSphere();
26374  
26375			_sphere.copy( geometry.boundingSphere ).
26376			applyMatrix4( object.matrixWorld );
26377  
26378			return isSphereViewable( _sphere );
26379  
26380		}
26381  
26382		function isSpriteViewable( sprite ) {
26383  
26384			_sphere.center.set( 0, 0, 0 );
26385			_sphere.radius = 0.7071067811865476;
26386			_sphere.applyMatrix4( sprite.matrixWorld );
26387  
26388			return isSphereViewable( _sphere );
26389  
26390		}
26391  
26392		function isSphereViewable( sphere ) {
26393  
26394			if ( ! _frustum.intersectsSphere( sphere ) ) return false;
26395  
26396			var numPlanes = _clipping.numPlanes;
26397  
26398			if ( numPlanes === 0 ) return true;
26399  
26400			var planes = _this.clippingPlanes,
26401  
26402				center = sphere.center,
26403				negRad = - sphere.radius,
26404				i = 0;
26405  
26406			do {
26407  
26408				// out when deeper than radius in the negative halfspace
26409				if ( planes[ i ].distanceToPoint( center ) < negRad ) return false;
26410  
26411			} while ( ++ i !== numPlanes );
26412  
26413			return true;
26414  
26415		}
26416		*/
26417  
26418		function projectObject( object, camera, sortObjects ) {
26419  
26420			if ( object.visible === false ) return;
26421  
26422			var visible = object.layers.test( camera.layers );
26423  
26424			if ( visible ) {
26425  
26426				if ( object.isLight ) {
26427  
26428					currentRenderState.pushLight( object );
26429  
26430					if ( object.castShadow ) {
26431  
26432						currentRenderState.pushShadow( object );
26433  
26434					}
26435  
26436				} else if ( object.isSprite ) {
26437  
26438					if ( ! object.frustumCulled || _frustum.intersectsSprite( object ) ) {
26439  
26440						currentRenderState.pushSprite( object );
26441  
26442					}
26443  
26444				} else if ( object.isImmediateRenderObject ) {
26445  
26446					if ( sortObjects ) {
26447  
26448						_vector3.setFromMatrixPosition( object.matrixWorld )
26449							.applyMatrix4( _projScreenMatrix );
26450  
26451					}
26452  
26453					currentRenderList.push( object, null, object.material, _vector3.z, null );
26454  
26455				} else if ( object.isMesh || object.isLine || object.isPoints ) {
26456  
26457					if ( object.isSkinnedMesh ) {
26458  
26459						object.skeleton.update();
26460  
26461					}
26462  
26463					if ( ! object.frustumCulled || _frustum.intersectsObject( object ) ) {
26464  
26465						if ( sortObjects ) {
26466  
26467							_vector3.setFromMatrixPosition( object.matrixWorld )
26468								.applyMatrix4( _projScreenMatrix );
26469  
26470						}
26471  
26472						var geometry = objects.update( object );
26473						var material = object.material;
26474  
26475						if ( Array.isArray( material ) ) {
26476  
26477							var groups = geometry.groups;
26478  
26479							for ( var i = 0, l = groups.length; i < l; i ++ ) {
26480  
26481								var group = groups[ i ];
26482								var groupMaterial = material[ group.materialIndex ];
26483  
26484								if ( groupMaterial && groupMaterial.visible ) {
26485  
26486									currentRenderList.push( object, geometry, groupMaterial, _vector3.z, group );
26487  
26488								}
26489  
26490							}
26491  
26492						} else if ( material.visible ) {
26493  
26494							currentRenderList.push( object, geometry, material, _vector3.z, null );
26495  
26496						}
26497  
26498					}
26499  
26500				}
26501  
26502			}
26503  
26504			var children = object.children;
26505  
26506			for ( var i = 0, l = children.length; i < l; i ++ ) {
26507  
26508				projectObject( children[ i ], camera, sortObjects );
26509  
26510			}
26511  
26512		}
26513  
26514		function renderObjects( renderList, scene, camera, overrideMaterial ) {
26515  
26516			for ( var i = 0, l = renderList.length; i < l; i ++ ) {
26517  
26518				var renderItem = renderList[ i ];
26519  
26520				var object = renderItem.object;
26521				var geometry = renderItem.geometry;
26522				var material = overrideMaterial === undefined ? renderItem.material : overrideMaterial;
26523				var group = renderItem.group;
26524  
26525				if ( camera.isArrayCamera ) {
26526  
26527					_currentArrayCamera = camera;
26528  
26529					var cameras = camera.cameras;
26530  
26531					for ( var j = 0, jl = cameras.length; j < jl; j ++ ) {
26532  
26533						var camera2 = cameras[ j ];
26534  
26535						if ( object.layers.test( camera2.layers ) ) {
26536  
26537							if ( 'viewport' in camera2 ) { // XR
26538  
26539								state.viewport( _currentViewport.copy( camera2.viewport ) );
26540  
26541							} else {
26542  
26543								var bounds = camera2.bounds;
26544  
26545								var x = bounds.x * _width;
26546								var y = bounds.y * _height;
26547								var width = bounds.z * _width;
26548								var height = bounds.w * _height;
26549  
26550								state.viewport( _currentViewport.set( x, y, width, height ).multiplyScalar( _pixelRatio ) );
26551  
26552							}
26553  
26554							renderObject( object, scene, camera2, geometry, material, group );
26555  
26556						}
26557  
26558					}
26559  
26560				} else {
26561  
26562					_currentArrayCamera = null;
26563  
26564					renderObject( object, scene, camera, geometry, material, group );
26565  
26566				}
26567  
26568			}
26569  
26570		}
26571  
26572		function renderObject( object, scene, camera, geometry, material, group ) {
26573  
26574			object.onBeforeRender( _this, scene, camera, geometry, material, group );
26575			currentRenderState = renderStates.get( scene, _currentArrayCamera || camera );
26576  
26577			object.modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld );
26578			object.normalMatrix.getNormalMatrix( object.modelViewMatrix );
26579  
26580			if ( object.isImmediateRenderObject ) {
26581  
26582				var frontFaceCW = ( object.isMesh && object.matrixWorld.determinant() < 0 );
26583  
26584				state.setMaterial( material, frontFaceCW );
26585  
26586				var program = setProgram( camera, scene.fog, material, object );
26587  
26588				_currentGeometryProgram = '';
26589  
26590				renderObjectImmediate( object, program, material );
26591  
26592			} else {
26593  
26594				_this.renderBufferDirect( camera, scene.fog, geometry, material, object, group );
26595  
26596			}
26597  
26598			object.onAfterRender( _this, scene, camera, geometry, material, group );
26599			currentRenderState = renderStates.get( scene, _currentArrayCamera || camera );
26600  
26601		}
26602  
26603		function initMaterial( material, fog, object ) {
26604  
26605			var materialProperties = properties.get( material );
26606  
26607			var lights = currentRenderState.state.lights;
26608			var shadowsArray = currentRenderState.state.shadowsArray;
26609  
26610			var parameters = programCache.getParameters(
26611				material, lights.state, shadowsArray, fog, _clipping.numPlanes, _clipping.numIntersection, object );
26612  
26613			var code = programCache.getProgramCode( material, parameters );
26614  
26615			var program = materialProperties.program;
26616			var programChange = true;
26617  
26618			if ( program === undefined ) {
26619  
26620				// new material
26621				material.addEventListener( 'dispose', onMaterialDispose );
26622  
26623			} else if ( program.code !== code ) {
26624  
26625				// changed glsl or parameters
26626				releaseMaterialProgramReference( material );
26627  
26628			} else if ( materialProperties.lightsHash !== lights.state.hash ) {
26629  
26630				properties.update( material, 'lightsHash', lights.state.hash );
26631				programChange = false;
26632  
26633			} else if ( parameters.shaderID !== undefined ) {
26634  
26635				// same glsl and uniform list
26636				return;
26637  
26638			} else {
26639  
26640				// only rebuild uniform list
26641				programChange = false;
26642  
26643			}
26644  
26645			if ( programChange ) {
26646  
26647				if ( parameters.shaderID ) {
26648  
26649					var shader = ShaderLib[ parameters.shaderID ];
26650  
26651					materialProperties.shader = {
26652						name: material.type,
26653						uniforms: UniformsUtils.clone( shader.uniforms ),
26654						vertexShader: shader.vertexShader,
26655						fragmentShader: shader.fragmentShader
26656					};
26657  
26658				} else {
26659  
26660					materialProperties.shader = {
26661						name: material.type,
26662						uniforms: material.uniforms,
26663						vertexShader: material.vertexShader,
26664						fragmentShader: material.fragmentShader
26665					};
26666  
26667				}
26668  
26669				material.onBeforeCompile( materialProperties.shader, _this );
26670  
26671				program = programCache.acquireProgram( material, materialProperties.shader, parameters, code );
26672  
26673				materialProperties.program = program;
26674				material.program = program;
26675  
26676			}
26677  
26678			var programAttributes = program.getAttributes();
26679  
26680			if ( material.morphTargets ) {
26681  
26682				material.numSupportedMorphTargets = 0;
26683  
26684				for ( var i = 0; i < _this.maxMorphTargets; i ++ ) {
26685  
26686					if ( programAttributes[ 'morphTarget' + i ] >= 0 ) {
26687  
26688						material.numSupportedMorphTargets ++;
26689  
26690					}
26691  
26692				}
26693  
26694			}
26695  
26696			if ( material.morphNormals ) {
26697  
26698				material.numSupportedMorphNormals = 0;
26699  
26700				for ( var i = 0; i < _this.maxMorphNormals; i ++ ) {
26701  
26702					if ( programAttributes[ 'morphNormal' + i ] >= 0 ) {
26703  
26704						material.numSupportedMorphNormals ++;
26705  
26706					}
26707  
26708				}
26709  
26710			}
26711  
26712			var uniforms = materialProperties.shader.uniforms;
26713  
26714			if ( ! material.isShaderMaterial &&
26715				! material.isRawShaderMaterial ||
26716				material.clipping === true ) {
26717  
26718				materialProperties.numClippingPlanes = _clipping.numPlanes;
26719				materialProperties.numIntersection = _clipping.numIntersection;
26720				uniforms.clippingPlanes = _clipping.uniform;
26721  
26722			}
26723  
26724			materialProperties.fog = fog;
26725  
26726			// store the light setup it was created for
26727  
26728			materialProperties.lightsHash = lights.state.hash;
26729  
26730			if ( material.lights ) {
26731  
26732				// wire up the material to this renderer's lighting state
26733  
26734				uniforms.ambientLightColor.value = lights.state.ambient;
26735				uniforms.directionalLights.value = lights.state.directional;
26736				uniforms.spotLights.value = lights.state.spot;
26737				uniforms.rectAreaLights.value = lights.state.rectArea;
26738				uniforms.pointLights.value = lights.state.point;
26739				uniforms.hemisphereLights.value = lights.state.hemi;
26740  
26741				uniforms.directionalShadowMap.value = lights.state.directionalShadowMap;
26742				uniforms.directionalShadowMatrix.value = lights.state.directionalShadowMatrix;
26743				uniforms.spotShadowMap.value = lights.state.spotShadowMap;
26744				uniforms.spotShadowMatrix.value = lights.state.spotShadowMatrix;
26745				uniforms.pointShadowMap.value = lights.state.pointShadowMap;
26746				uniforms.pointShadowMatrix.value = lights.state.pointShadowMatrix;
26747				// TODO (abelnation): add area lights shadow info to uniforms
26748  
26749			}
26750  
26751			var progUniforms = materialProperties.program.getUniforms(),
26752				uniformsList =
26753					WebGLUniforms.seqWithValue( progUniforms.seq, uniforms );
26754  
26755			materialProperties.uniformsList = uniformsList;
26756  
26757		}
26758  
26759		function setProgram( camera, fog, material, object ) {
26760  
26761			_usedTextureUnits = 0;
26762  
26763			var materialProperties = properties.get( material );
26764			var lights = currentRenderState.state.lights;
26765  
26766			if ( _clippingEnabled ) {
26767  
26768				if ( _localClippingEnabled || camera !== _currentCamera ) {
26769  
26770					var useCache =
26771						camera === _currentCamera &&
26772						material.id === _currentMaterialId;
26773  
26774					// we might want to call this function with some ClippingGroup
26775					// object instead of the material, once it becomes feasible
26776					// (#8465, #8379)
26777					_clipping.setState(
26778						material.clippingPlanes, material.clipIntersection, material.clipShadows,
26779						camera, materialProperties, useCache );
26780  
26781				}
26782  
26783			}
26784  
26785			if ( material.needsUpdate === false ) {
26786  
26787				if ( materialProperties.program === undefined ) {
26788  
26789					material.needsUpdate = true;
26790  
26791				} else if ( material.fog && materialProperties.fog !== fog ) {
26792  
26793					material.needsUpdate = true;
26794  
26795				} else if ( material.lights && materialProperties.lightsHash !== lights.state.hash ) {
26796  
26797					material.needsUpdate = true;
26798  
26799				} else if ( materialProperties.numClippingPlanes !== undefined &&
26800					( materialProperties.numClippingPlanes !== _clipping.numPlanes ||
26801					materialProperties.numIntersection !== _clipping.numIntersection ) ) {
26802  
26803					material.needsUpdate = true;
26804  
26805				}
26806  
26807			}
26808  
26809			if ( material.needsUpdate ) {
26810  
26811				initMaterial( material, fog, object );
26812				material.needsUpdate = false;
26813  
26814			}
26815  
26816			var refreshProgram = false;
26817			var refreshMaterial = false;
26818			var refreshLights = false;
26819  
26820			var program = materialProperties.program,
26821				p_uniforms = program.getUniforms(),
26822				m_uniforms = materialProperties.shader.uniforms;
26823  
26824			if ( state.useProgram( program.program ) ) {
26825  
26826				refreshProgram = true;
26827				refreshMaterial = true;
26828				refreshLights = true;
26829  
26830			}
26831  
26832			if ( material.id !== _currentMaterialId ) {
26833  
26834				_currentMaterialId = material.id;
26835  
26836				refreshMaterial = true;
26837  
26838			}
26839  
26840			if ( refreshProgram || camera !== _currentCamera ) {
26841  
26842				p_uniforms.setValue( _gl, 'projectionMatrix', camera.projectionMatrix );
26843  
26844				if ( capabilities.logarithmicDepthBuffer ) {
26845  
26846					p_uniforms.setValue( _gl, 'logDepthBufFC',
26847						2.0 / ( Math.log( camera.far + 1.0 ) / Math.LN2 ) );
26848  
26849				}
26850  
26851				// Avoid unneeded uniform updates per ArrayCamera's sub-camera
26852  
26853				if ( _currentCamera !== ( _currentArrayCamera || camera ) ) {
26854  
26855					_currentCamera = ( _currentArrayCamera || camera );
26856  
26857					// lighting uniforms depend on the camera so enforce an update
26858					// now, in case this material supports lights - or later, when
26859					// the next material that does gets activated:
26860  
26861					refreshMaterial = true;		// set to true on material change
26862					refreshLights = true;		// remains set until update done
26863  
26864				}
26865  
26866				// load material specific uniforms
26867				// (shader material also gets them for the sake of genericity)
26868  
26869				if ( material.isShaderMaterial ||
26870					material.isMeshPhongMaterial ||
26871					material.isMeshStandardMaterial ||
26872					material.envMap ) {
26873  
26874					var uCamPos = p_uniforms.map.cameraPosition;
26875  
26876					if ( uCamPos !== undefined ) {
26877  
26878						uCamPos.setValue( _gl,
26879							_vector3.setFromMatrixPosition( camera.matrixWorld ) );
26880  
26881					}
26882  
26883				}
26884  
26885				if ( material.isMeshPhongMaterial ||
26886					material.isMeshLambertMaterial ||
26887					material.isMeshBasicMaterial ||
26888					material.isMeshStandardMaterial ||
26889					material.isShaderMaterial ||
26890					material.skinning ) {
26891  
26892					p_uniforms.setValue( _gl, 'viewMatrix', camera.matrixWorldInverse );
26893  
26894				}
26895  
26896			}
26897  
26898			// skinning uniforms must be set even if material didn't change
26899			// auto-setting of texture unit for bone texture must go before other textures
26900			// not sure why, but otherwise weird things happen
26901  
26902			if ( material.skinning ) {
26903  
26904				p_uniforms.setOptional( _gl, object, 'bindMatrix' );
26905				p_uniforms.setOptional( _gl, object, 'bindMatrixInverse' );
26906  
26907				var skeleton = object.skeleton;
26908  
26909				if ( skeleton ) {
26910  
26911					var bones = skeleton.bones;
26912  
26913					if ( capabilities.floatVertexTextures ) {
26914  
26915						if ( skeleton.boneTexture === undefined ) {
26916  
26917							// layout (1 matrix = 4 pixels)
26918							//      RGBA RGBA RGBA RGBA (=> column1, column2, column3, column4)
26919							//  with  8x8  pixel texture max   16 bones * 4 pixels =  (8 * 8)
26920							//       16x16 pixel texture max   64 bones * 4 pixels = (16 * 16)
26921							//       32x32 pixel texture max  256 bones * 4 pixels = (32 * 32)
26922							//       64x64 pixel texture max 1024 bones * 4 pixels = (64 * 64)
26923  
26924  
26925							var size = Math.sqrt( bones.length * 4 ); // 4 pixels needed for 1 matrix
vendor: 4,185 bytes, lines 26926-27079
26926							size = _Math.ceilPowerOfTwo( size );
26927							size = Math.max( size, 4 );
26928  
26929							var boneMatrices = new Float32Array( size * size * 4 ); // 4 floats per RGBA pixel
26930							boneMatrices.set( skeleton.boneMatrices ); // copy current values
26931  
26932							var boneTexture = new DataTexture( boneMatrices, size, size, RGBAFormat, FloatType );
26933							boneTexture.needsUpdate = true;
26934  
26935							skeleton.boneMatrices = boneMatrices;
26936							skeleton.boneTexture = boneTexture;
26937							skeleton.boneTextureSize = size;
26938  
26939						}
26940  
26941						p_uniforms.setValue( _gl, 'boneTexture', skeleton.boneTexture );
26942						p_uniforms.setValue( _gl, 'boneTextureSize', skeleton.boneTextureSize );
26943  
26944					} else {
26945  
26946						p_uniforms.setOptional( _gl, skeleton, 'boneMatrices' );
26947  
26948					}
26949  
26950				}
26951  
26952			}
26953  
26954			if ( refreshMaterial ) {
26955  
26956				p_uniforms.setValue( _gl, 'toneMappingExposure', _this.toneMappingExposure );
26957				p_uniforms.setValue( _gl, 'toneMappingWhitePoint', _this.toneMappingWhitePoint );
26958  
26959				if ( material.lights ) {
26960  
26961					// the current material requires lighting info
26962  
26963					// note: all lighting uniforms are always set correctly
26964					// they simply reference the renderer's state for their
26965					// values
26966					//
26967					// use the current material's .needsUpdate flags to set
26968					// the GL state when required
26969  
26970					markUniformsLightsNeedsUpdate( m_uniforms, refreshLights );
26971  
26972				}
26973  
26974				// refresh uniforms common to several materials
26975  
26976				if ( fog && material.fog ) {
26977  
26978					refreshUniformsFog( m_uniforms, fog );
26979  
26980				}
26981  
26982				if ( material.isMeshBasicMaterial ) {
26983  
26984					refreshUniformsCommon( m_uniforms, material );
26985  
26986				} else if ( material.isMeshLambertMaterial ) {
26987  
26988					refreshUniformsCommon( m_uniforms, material );
26989					refreshUniformsLambert( m_uniforms, material );
26990  
26991				} else if ( material.isMeshPhongMaterial ) {
26992  
26993					refreshUniformsCommon( m_uniforms, material );
26994  
26995					if ( material.isMeshToonMaterial ) {
26996  
26997						refreshUniformsToon( m_uniforms, material );
26998  
26999					} else {
27000  
27001						refreshUniformsPhong( m_uniforms, material );
27002  
27003					}
27004  
27005				} else if ( material.isMeshStandardMaterial ) {
27006  
27007					refreshUniformsCommon( m_uniforms, material );
27008  
27009					if ( material.isMeshPhysicalMaterial ) {
27010  
27011						refreshUniformsPhysical( m_uniforms, material );
27012  
27013					} else {
27014  
27015						refreshUniformsStandard( m_uniforms, material );
27016  
27017					}
27018  
27019				} else if ( material.isMeshDepthMaterial ) {
27020  
27021					refreshUniformsCommon( m_uniforms, material );
27022					refreshUniformsDepth( m_uniforms, material );
27023  
27024				} else if ( material.isMeshDistanceMaterial ) {
27025  
27026					refreshUniformsCommon( m_uniforms, material );
27027					refreshUniformsDistance( m_uniforms, material );
27028  
27029				} else if ( material.isMeshNormalMaterial ) {
27030  
27031					refreshUniformsCommon( m_uniforms, material );
27032					refreshUniformsNormal( m_uniforms, material );
27033  
27034				} else if ( material.isLineBasicMaterial ) {
27035  
27036					refreshUniformsLine( m_uniforms, material );
27037  
27038					if ( material.isLineDashedMaterial ) {
27039  
27040						refreshUniformsDash( m_uniforms, material );
27041  
27042					}
27043  
27044				} else if ( material.isPointsMaterial ) {
27045  
27046					refreshUniformsPoints( m_uniforms, material );
27047  
27048				} else if ( material.isShadowMaterial ) {
27049  
27050					m_uniforms.color.value = material.color;
27051					m_uniforms.opacity.value = material.opacity;
27052  
27053				}
27054  
27055				// RectAreaLight Texture
27056				// TODO (mrdoob): Find a nicer implementation
27057  
27058				if ( m_uniforms.ltc_1 !== undefined ) m_uniforms.ltc_1.value = UniformsLib.LTC_1;
27059				if ( m_uniforms.ltc_2 !== undefined ) m_uniforms.ltc_2.value = UniformsLib.LTC_2;
27060  
27061				WebGLUniforms.upload( _gl, materialProperties.uniformsList, m_uniforms, _this );
27062  
27063			}
27064  
27065			if ( material.isShaderMaterial && material.uniformsNeedUpdate === true ) {
27066  
27067				WebGLUniforms.upload( _gl, materialProperties.uniformsList, m_uniforms, _this );
27068				material.uniformsNeedUpdate = false;
27069  
27070			}
27071  
27072			// common matrices
27073  
27074			p_uniforms.setValue( _gl, 'modelViewMatrix', object.modelViewMatrix );
27075			p_uniforms.setValue( _gl, 'normalMatrix', object.normalMatrix );
27076			p_uniforms.setValue( _gl, 'modelMatrix', object.matrixWorld );
27077  
27078			return program;
27079  
27080		}
27081  
27082		// Uniforms (refresh uniforms objects)
27083  
27084		function refreshUniformsCommon( uniforms, material ) {
27085  
27086			uniforms.opacity.value = material.opacity;
27087  
27088			if ( material.color ) {
27089  
27090				uniforms.diffuse.value = material.color;
27091  
27092			}
27093  
27094			if ( material.emissive ) {
27095  
27096				uniforms.emissive.value.copy( material.emissive ).multiplyScalar( material.emissiveIntensity );
27097  
27098			}
27099  
27100			if ( material.map ) {
27101  
27102				uniforms.map.value = material.map;
27103  
27104			}
27105  
27106			if ( material.alphaMap ) {
27107  
27108				uniforms.alphaMap.value = material.alphaMap;
27109  
27110			}
27111  
27112			if ( material.specularMap ) {
27113  
27114				uniforms.specularMap.value = material.specularMap;
27115  
27116			}
27117  
27118			if ( material.envMap ) {
27119  
27120				uniforms.envMap.value = material.envMap;
27121  
27122				// don't flip CubeTexture envMaps, flip everything else:
27123				//  WebGLRenderTargetCube will be flipped for backwards compatibility
27124				//  WebGLRenderTargetCube.texture will be flipped because it's a Texture and NOT a CubeTexture
27125				// this check must be handled differently, or removed entirely, if WebGLRenderTargetCube uses a CubeTexture in the future
27126				uniforms.flipEnvMap.value = ( ! ( material.envMap && material.envMap.isCubeTexture ) ) ? 1 : - 1;
27127  
27128				uniforms.reflectivity.value = material.reflectivity;
27129				uniforms.refractionRatio.value = material.refractionRatio;
27130  
27131				uniforms.maxMipLevel.value = properties.get( material.envMap ).__maxMipLevel;
27132  
27133			}
27134  
27135			if ( material.lightMap ) {
27136  
27137				uniforms.lightMap.value = material.lightMap;
27138				uniforms.lightMapIntensity.value = material.lightMapIntensity;
27139  
27140			}
27141  
27142			if ( material.aoMap ) {
27143  
27144				uniforms.aoMap.value = material.aoMap;
27145				uniforms.aoMapIntensity.value = material.aoMapIntensity;
27146  
27147			}
27148  
27149			// uv repeat and offset setting priorities
27150			// 1. color map
27151			// 2. specular map
27152			// 3. normal map
27153			// 4. bump map
27154			// 5. alpha map
27155			// 6. emissive map
27156  
27157			var uvScaleMap;
27158  
27159			if ( material.map ) {
27160  
27161				uvScaleMap = material.map;
27162  
27163			} else if ( material.specularMap ) {
27164  
27165				uvScaleMap = material.specularMap;
27166  
27167			} else if ( material.displacementMap ) {
27168  
27169				uvScaleMap = material.displacementMap;
27170  
27171			} else if ( material.normalMap ) {
27172  
27173				uvScaleMap = material.normalMap;
27174  
27175			} else if ( material.bumpMap ) {
27176  
27177				uvScaleMap = material.bumpMap;
27178  
27179			} else if ( material.roughnessMap ) {
27180  
27181				uvScaleMap = material.roughnessMap;
27182  
27183			} else if ( material.metalnessMap ) {
27184  
27185				uvScaleMap = material.metalnessMap;
27186  
27187			} else if ( material.alphaMap ) {
27188  
27189				uvScaleMap = material.alphaMap;
27190  
27191			} else if ( material.emissiveMap ) {
27192  
27193				uvScaleMap = material.emissiveMap;
27194  
27195			}
27196  
27197			if ( uvScaleMap !== undefined ) {
27198  
27199				// backwards compatibility
27200				if ( uvScaleMap.isWebGLRenderTarget ) {
27201  
27202					uvScaleMap = uvScaleMap.texture;
27203  
27204				}
27205  
27206				if ( uvScaleMap.matrixAutoUpdate === true ) {
27207  
27208					uvScaleMap.updateMatrix();
27209  
27210				}
27211  
27212				uniforms.uvTransform.value.copy( uvScaleMap.matrix );
27213  
27214			}
27215  
27216		}
27217  
27218		function refreshUniformsLine( uniforms, material ) {
27219  
27220			uniforms.diffuse.value = material.color;
27221			uniforms.opacity.value = material.opacity;
27222  
27223		}
27224  
27225		function refreshUniformsDash( uniforms, material ) {
27226  
27227			uniforms.dashSize.value = material.dashSize;
27228			uniforms.totalSize.value = material.dashSize + material.gapSize;
27229			uniforms.scale.value = material.scale;
27230  
27231		}
27232  
27233		function refreshUniformsPoints( uniforms, material ) {
27234  
27235			uniforms.diffuse.value = material.color;
27236			uniforms.opacity.value = material.opacity;
27237			uniforms.size.value = material.size * _pixelRatio;
27238			uniforms.scale.value = _height * 0.5;
27239  
27240			uniforms.map.value = material.map;
27241  
27242			if ( material.map !== null ) {
27243  
27244				if ( material.map.matrixAutoUpdate === true ) {
27245  
27246					material.map.updateMatrix();
27247  
27248				}
27249  
27250				uniforms.uvTransform.value.copy( material.map.matrix );
27251  
27252			}
27253  
27254		}
27255  
27256		function refreshUniformsFog( uniforms, fog ) {
27257  
27258			uniforms.fogColor.value = fog.color;
27259  
27260			if ( fog.isFog ) {
27261  
27262				uniforms.fogNear.value = fog.near;
27263				uniforms.fogFar.value = fog.far;
27264  
27265			} else if ( fog.isFogExp2 ) {
27266  
27267				uniforms.fogDensity.value = fog.density;
27268  
27269			}
27270  
27271		}
27272  
27273		function refreshUniformsLambert( uniforms, material ) {
27274  
27275			if ( material.emissiveMap ) {
27276  
27277				uniforms.emissiveMap.value = material.emissiveMap;
27278  
27279			}
27280  
27281		}
27282  
27283		function refreshUniformsPhong( uniforms, material ) {
27284  
27285			uniforms.specular.value = material.specular;
27286			uniforms.shininess.value = Math.max( material.shininess, 1e-4 ); // to prevent pow( 0.0, 0.0 )
27287  
27288			if ( material.emissiveMap ) {
27289  
27290				uniforms.emissiveMap.value = material.emissiveMap;
27291  
27292			}
27293  
27294			if ( material.bumpMap ) {
27295  
27296				uniforms.bumpMap.value = material.bumpMap;
27297				uniforms.bumpScale.value = material.bumpScale;
27298				if ( material.side === BackSide ) uniforms.bumpScale.value *= - 1;
27299  
27300			}
27301  
27302			if ( material.normalMap ) {
27303  
27304				uniforms.normalMap.value = material.normalMap;
27305				uniforms.normalScale.value.copy( material.normalScale );
27306				if ( material.side === BackSide ) uniforms.normalScale.value.negate();
27307  
27308			}
27309  
27310			if ( material.displacementMap ) {
27311  
27312				uniforms.displacementMap.value = material.displacementMap;
27313				uniforms.displacementScale.value = material.displacementScale;
27314				uniforms.displacementBias.value = material.displacementBias;
27315  
27316			}
27317  
27318		}
27319  
27320		function refreshUniformsToon( uniforms, material ) {
27321  
27322			refreshUniformsPhong( uniforms, material );
27323  
27324			if ( material.gradientMap ) {
27325  
27326				uniforms.gradientMap.value = material.gradientMap;
27327  
27328			}
27329  
27330		}
27331  
27332		function refreshUniformsStandard( uniforms, material ) {
27333  
27334			uniforms.roughness.value = material.roughness;
27335			uniforms.metalness.value = material.metalness;
27336  
27337			if ( material.roughnessMap ) {
27338  
27339				uniforms.roughnessMap.value = material.roughnessMap;
27340  
27341			}
27342  
27343			if ( material.metalnessMap ) {
27344  
27345				uniforms.metalnessMap.value = material.metalnessMap;
27346  
27347			}
27348  
27349			if ( material.emissiveMap ) {
27350  
27351				uniforms.emissiveMap.value = material.emissiveMap;
27352  
27353			}
27354  
27355			if ( material.bumpMap ) {
27356  
27357				uniforms.bumpMap.value = material.bumpMap;
27358				uniforms.bumpScale.value = material.bumpScale;
27359				if ( material.side === BackSide ) uniforms.bumpScale.value *= - 1;
27360  
27361			}
27362  
27363			if ( material.normalMap ) {
27364  
27365				uniforms.normalMap.value = material.normalMap;
27366				uniforms.normalScale.value.copy( material.normalScale );
27367				if ( material.side === BackSide ) uniforms.normalScale.value.negate();
27368  
27369			}
27370  
27371			if ( material.displacementMap ) {
27372  
27373				uniforms.displacementMap.value = material.displacementMap;
27374				uniforms.displacementScale.value = material.displacementScale;
27375				uniforms.displacementBias.value = material.displacementBias;
27376  
27377			}
27378  
27379			if ( material.envMap ) {
27380  
27381				//uniforms.envMap.value = material.envMap; // part of uniforms common
27382				uniforms.envMapIntensity.value = material.envMapIntensity;
27383  
27384			}
27385  
27386		}
27387  
27388		function refreshUniformsPhysical( uniforms, material ) {
27389  
27390			uniforms.clearCoat.value = material.clearCoat;
27391			uniforms.clearCoatRoughness.value = material.clearCoatRoughness;
27392  
27393			refreshUniformsStandard( uniforms, material );
27394  
27395		}
27396  
27397		function refreshUniformsDepth( uniforms, material ) {
27398  
27399			if ( material.displacementMap ) {
27400  
27401				uniforms.displacementMap.value = material.displacementMap;
27402				uniforms.displacementScale.value = material.displacementScale;
27403				uniforms.displacementBias.value = material.displacementBias;
27404  
27405			}
27406  
27407		}
27408  
27409		function refreshUniformsDistance( uniforms, material ) {
27410  
27411			if ( material.displacementMap ) {
27412  
27413				uniforms.displacementMap.value = material.displacementMap;
27414				uniforms.displacementScale.value = material.displacementScale;
27415				uniforms.displacementBias.value = material.displacementBias;
27416  
27417			}
27418  
27419			uniforms.referencePosition.value.copy( material.referencePosition );
27420			uniforms.nearDistance.value = material.nearDistance;
27421			uniforms.farDistance.value = material.farDistance;
27422  
27423		}
27424  
27425		function refreshUniformsNormal( uniforms, material ) {
27426  
27427			if ( material.bumpMap ) {
27428  
27429				uniforms.bumpMap.value = material.bumpMap;
27430				uniforms.bumpScale.value = material.bumpScale;
27431				if ( material.side === BackSide ) uniforms.bumpScale.value *= - 1;
27432  
27433			}
27434  
27435			if ( material.normalMap ) {
27436  
27437				uniforms.normalMap.value = material.normalMap;
27438				uniforms.normalScale.value.copy( material.normalScale );
27439				if ( material.side === BackSide ) uniforms.normalScale.value.negate();
27440  
27441			}
27442  
27443			if ( material.displacementMap ) {
27444  
27445				uniforms.displacementMap.value = material.displacementMap;
27446				uniforms.displacementScale.value = material.displacementScale;
27447				uniforms.displacementBias.value = material.displacementBias;
27448  
27449			}
27450  
27451		}
27452  
27453		// If uniforms are marked as clean, they don't need to be loaded to the GPU.
27454  
27455		function markUniformsLightsNeedsUpdate( uniforms, value ) {
27456  
27457			uniforms.ambientLightColor.needsUpdate = value;
27458  
27459			uniforms.directionalLights.needsUpdate = value;
27460			uniforms.pointLights.needsUpdate = value;
27461			uniforms.spotLights.needsUpdate = value;
27462			uniforms.rectAreaLights.needsUpdate = value;
27463			uniforms.hemisphereLights.needsUpdate = value;
27464  
27465		}
27466  
27467		// Textures
27468  
27469		function allocTextureUnit() {
27470  
27471			var textureUnit = _usedTextureUnits;
27472  
27473			if ( textureUnit >= capabilities.maxTextures ) {
27474  
27475				console.warn( 'THREE.WebGLRenderer: Trying to use ' + textureUnit + ' texture units while this GPU supports only ' + capabilities.maxTextures );
27476  
27477			}
27478  
27479			_usedTextureUnits += 1;
27480  
27481			return textureUnit;
27482  
27483		}
27484  
27485		this.allocTextureUnit = allocTextureUnit;
27486  
27487		// this.setTexture2D = setTexture2D;
27488		this.setTexture2D = ( function () {
27489  
27490			var warned = false;
27491  
27492			// backwards compatibility: peel texture.texture
27493			return function setTexture2D( texture, slot ) {
27494  
27495				if ( texture && texture.isWebGLRenderTarget ) {
27496  
27497					if ( ! warned ) {
27498  
27499						console.warn( "THREE.WebGLRenderer.setTexture2D: don't use render targets as textures. Use their .texture property instead." );
27500						warned = true;
27501  
27502					}
27503  
27504					texture = texture.texture;
27505  
27506				}
27507  
27508				textures.setTexture2D( texture, slot );
27509  
27510			};
27511  
27512		}() );
27513  
27514		this.setTexture = ( function () {
27515  
27516			var warned = false;
27517  
27518			return function setTexture( texture, slot ) {
27519  
27520				if ( ! warned ) {
27521  
27522					console.warn( "THREE.WebGLRenderer: .setTexture is deprecated, use setTexture2D instead." );
27523					warned = true;
27524  
27525				}
27526  
27527				textures.setTexture2D( texture, slot );
27528  
27529			};
27530  
27531		}() );
27532  
27533		this.setTextureCube = ( function () {
27534  
27535			var warned = false;
27536  
27537			return function setTextureCube( texture, slot ) {
27538  
27539				// backwards compatibility: peel texture.texture
27540				if ( texture && texture.isWebGLRenderTargetCube ) {
27541  
27542					if ( ! warned ) {
27543  
27544						console.warn( "THREE.WebGLRenderer.setTextureCube: don't use cube render targets as textures. Use their .texture property instead." );
27545						warned = true;
27546  
27547					}
27548  
27549					texture = texture.texture;
27550  
27551				}
27552  
27553				// currently relying on the fact that WebGLRenderTargetCube.texture is a Texture and NOT a CubeTexture
27554				// TODO: unify these code paths
27555				if ( ( texture && texture.isCubeTexture ) ||
27556					( Array.isArray( texture.image ) && texture.image.length === 6 ) ) {
27557  
27558					// CompressedTexture can have Array in image :/
27559  
27560					// this function alone should take care of cube textures
27561					textures.setTextureCube( texture, slot );
27562  
27563				} else {
27564  
27565					// assumed: texture property of THREE.WebGLRenderTargetCube
27566  
27567					textures.setTextureCubeDynamic( texture, slot );
27568  
27569				}
27570  
27571			};
27572  
27573		}() );
27574  
27575		//
27576  
27577		this.setFramebuffer = function ( value ) {
27578  
27579			_framebuffer = value;
27580  
27581		};
27582  
27583		this.getRenderTarget = function () {
27584  
27585			return _currentRenderTarget;
27586  
27587		};
27588  
27589		this.setRenderTarget = function ( renderTarget ) {
27590  
27591			_currentRenderTarget = renderTarget;
27592  
27593			if ( renderTarget && properties.get( renderTarget ).__webglFramebuffer === undefined ) {
27594  
27595				textures.setupRenderTarget( renderTarget );
27596  
27597			}
27598  
27599			var framebuffer = _framebuffer;
27600			var isCube = false;
27601  
27602			if ( renderTarget ) {
27603  
27604				var __webglFramebuffer = properties.get( renderTarget ).__webglFramebuffer;
27605  
27606				if ( renderTarget.isWebGLRenderTargetCube ) {
27607  
27608					framebuffer = __webglFramebuffer[ renderTarget.activeCubeFace ];
27609					isCube = true;
27610  
27611				} else {
27612  
27613					framebuffer = __webglFramebuffer;
27614  
27615				}
27616  
27617				_currentViewport.copy( renderTarget.viewport );
27618				_currentScissor.copy( renderTarget.scissor );
27619				_currentScissorTest = renderTarget.scissorTest;
27620  
27621			} else {
27622  
27623				_currentViewport.copy( _viewport ).multiplyScalar( _pixelRatio );
27624				_currentScissor.copy( _scissor ).multiplyScalar( _pixelRatio );
27625				_currentScissorTest = _scissorTest;
27626  
27627			}
27628  
27629			if ( _currentFramebuffer !== framebuffer ) {
27630  
27631				_gl.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );
27632				_currentFramebuffer = framebuffer;
27633  
27634			}
27635  
27636			state.viewport( _currentViewport );
27637			state.scissor( _currentScissor );
27638			state.setScissorTest( _currentScissorTest );
27639  
27640			if ( isCube ) {
27641  
27642				var textureProperties = properties.get( renderTarget.texture );
27643				_gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_CUBE_MAP_POSITIVE_X + renderTarget.activeCubeFace, textureProperties.__webglTexture, renderTarget.activeMipMapLevel );
27644  
27645			}
27646  
27647		};
27648  
27649		this.readRenderTargetPixels = function ( renderTarget, x, y, width, height, buffer ) {
27650  
27651			if ( ! ( renderTarget && renderTarget.isWebGLRenderTarget ) ) {
27652  
27653				console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.' );
27654				return;
27655  
27656			}
27657  
27658			var framebuffer = properties.get( renderTarget ).__webglFramebuffer;
27659  
27660			if ( framebuffer ) {
27661  
27662				var restore = false;
27663  
27664				if ( framebuffer !== _currentFramebuffer ) {
27665  
27666					_gl.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );
27667  
27668					restore = true;
27669  
27670				}
27671  
27672				try {
27673  
27674					var texture = renderTarget.texture;
27675					var textureFormat = texture.format;
27676					var textureType = texture.type;
27677  
27678					if ( textureFormat !== RGBAFormat && utils.convert( textureFormat ) !== _gl.getParameter( _gl.IMPLEMENTATION_COLOR_READ_FORMAT ) ) {
27679  
27680						console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in RGBA or implementation defined format.' );
27681						return;
27682  
27683					}
27684  
27685					if ( textureType !== UnsignedByteType && utils.convert( textureType ) !== _gl.getParameter( _gl.IMPLEMENTATION_COLOR_READ_TYPE ) && // IE11, Edge and Chrome Mac < 52 (#9513)
27686						! ( textureType === FloatType && ( extensions.get( 'OES_texture_float' ) || extensions.get( 'WEBGL_color_buffer_float' ) ) ) && // Chrome Mac >= 52 and Firefox
27687						! ( textureType === HalfFloatType && extensions.get( 'EXT_color_buffer_half_float' ) ) ) {
27688  
27689						console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in UnsignedByteType or implementation defined type.' );
27690						return;
27691  
27692					}
27693  
27694					if ( _gl.checkFramebufferStatus( _gl.FRAMEBUFFER ) === _gl.FRAMEBUFFER_COMPLETE ) {
27695  
27696						// the following if statement ensures valid read requests (no out-of-bounds pixels, see #8604)
27697  
27698						if ( ( x >= 0 && x <= ( renderTarget.width - width ) ) && ( y >= 0 && y <= ( renderTarget.height - height ) ) ) {
27699  
27700							_gl.readPixels( x, y, width, height, utils.convert( textureFormat ), utils.convert( textureType ), buffer );
27701  
27702						}
27703  
27704					} else {
27705  
27706						console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: readPixels from renderTarget failed. Framebuffer not complete.' );
27707  
27708					}
27709  
27710				} finally {
27711  
27712					if ( restore ) {
27713  
27714						_gl.bindFramebuffer( _gl.FRAMEBUFFER, _currentFramebuffer );
27715  
27716					}
27717  
27718				}
27719  
27720			}
27721  
27722		};
27723  
27724		this.copyFramebufferToTexture = function ( position, texture, level ) {
27725  
27726			var width = texture.image.width;
27727			var height = texture.image.height;
27728			var glFormat = utils.convert( texture.format );
27729  
27730			this.setTexture2D( texture, 0 );
27731  
27732			_gl.copyTexImage2D( _gl.TEXTURE_2D, level || 0, glFormat, position.x, position.y, width, height, 0 );
27733  
27734		};
27735  
27736		this.copyTextureToTexture = function ( position, srcTexture, dstTexture, level ) {
27737  
27738			var width = srcTexture.image.width;
27739			var height = srcTexture.image.height;
27740			var glFormat = utils.convert( dstTexture.format );
27741			var glType = utils.convert( dstTexture.type );
27742  
27743			this.setTexture2D( dstTexture, 0 );
27744  
27745			if ( srcTexture.isDataTexture ) {
27746  
27747				_gl.texSubImage2D( _gl.TEXTURE_2D, level || 0, position.x, position.y, width, height, glFormat, glType, srcTexture.image.data );
27748  
27749			} else {
27750  
27751				_gl.texSubImage2D( _gl.TEXTURE_2D, level || 0, position.x, position.y, glFormat, glType, srcTexture.image );
27752  
27753			}
27754  
27755		};
27756  
27757	}
27758  
27759	/**
27760	 * @author mrdoob / http://mrdoob.com/
27761	 * @author alteredq / http://alteredqualia.com/
27762	 */
27763  
27764	function FogExp2( color, density ) {
27765  
27766		this.name = '';
27767  
27768		this.color = new Color( color );
27769		this.density = ( density !== undefined ) ? density : 0.00025;
27770  
27771	}
27772  
27773	FogExp2.prototype.isFogExp2 = true;
27774  
27775	FogExp2.prototype.clone = function () {
27776  
27777		return new FogExp2( this.color, this.density );
27778  
27779	};
27780  
27781	FogExp2.prototype.toJSON = function ( /* meta */ ) {
27782  
27783		return {
27784			type: 'FogExp2',
27785			color: this.color.getHex(),
27786			density: this.density
27787		};
27788  
27789	};
27790  
27791	/**
27792	 * @author mrdoob / http://mrdoob.com/
27793	 * @author alteredq / http://alteredqualia.com/
27794	 */
27795  
27796	function Fog( color, near, far ) {
27797  
27798		this.name = '';
27799  
27800		this.color = new Color( color );
27801  
27802		this.near = ( near !== undefined ) ? near : 1;
27803		this.far = ( far !== undefined ) ? far : 1000;
27804  
27805	}
27806  
27807	Fog.prototype.isFog = true;
27808  
27809	Fog.prototype.clone = function () {
27810  
27811		return new Fog( this.color, this.near, this.far );
27812  
27813	};
27814  
27815	Fog.prototype.toJSON = function ( /* meta */ ) {
27816  
27817		return {
27818			type: 'Fog',
27819			color: this.color.getHex(),
27820			near: this.near,
27821			far: this.far
27822		};
27823  
27824	};
27825  
27826	/**
27827	 * @author mrdoob / http://mrdoob.com/
27828	 */
27829  
27830	function Scene() {
27831  
27832		Object3D.call( this );
27833  
27834		this.type = 'Scene';
27835  
27836		this.background = null;
27837		this.fog = null;
27838		this.overrideMaterial = null;
27839  
27840		this.autoUpdate = true; // checked by the renderer
27841  
27842	}
27843  
27844	Scene.prototype = Object.assign( Object.create( Object3D.prototype ), {
27845  
27846		constructor: Scene,
27847  
27848		copy: function ( source, recursive ) {
27849  
27850			Object3D.prototype.copy.call( this, source, recursive );
27851  
27852			if ( source.background !== null ) this.background = source.background.clone();
27853			if ( source.fog !== null ) this.fog = source.fog.clone();
27854			if ( source.overrideMaterial !== null ) this.overrideMaterial = source.overrideMaterial.clone();
27855  
27856			this.autoUpdate = source.autoUpdate;
27857			this.matrixAutoUpdate = source.matrixAutoUpdate;
27858  
27859			return this;
27860  
27861		},
27862  
27863		toJSON: function ( meta ) {
27864  
27865			var data = Object3D.prototype.toJSON.call( this, meta );
27866  
27867			if ( this.background !== null ) data.object.background = this.background.toJSON( meta );
27868			if ( this.fog !== null ) data.object.fog = this.fog.toJSON();
27869  
27870			return data;
27871  
27872		}
27873  
27874	} );
27875  
27876	/**
27877	 * @author alteredq / http://alteredqualia.com/
27878	 *
27879	 * parameters = {
27880	 *  color: <hex>,
27881	 *  opacity: <float>,
27882	 *  map: new THREE.Texture( <Image> ),
27883	 *
27884	 *	uvOffset: new THREE.Vector2(),
27885	 *	uvScale: new THREE.Vector2()
27886	 * }
27887	 */
27888  
27889	function SpriteMaterial( parameters ) {
27890  
27891		Material.call( this );
27892  
27893		this.type = 'SpriteMaterial';
27894  
27895		this.color = new Color( 0xffffff );
27896		this.map = null;
27897  
27898		this.rotation = 0;
27899  
27900		this.fog = false;
27901		this.lights = false;
27902  
27903		this.setValues( parameters );
27904  
27905	}
27906  
27907	SpriteMaterial.prototype = Object.create( Material.prototype );
27908	SpriteMaterial.prototype.constructor = SpriteMaterial;
27909	SpriteMaterial.prototype.isSpriteMaterial = true;
27910  
27911	SpriteMaterial.prototype.copy = function ( source ) {
27912  
27913		Material.prototype.copy.call( this, source );
27914  
27915		this.color.copy( source.color );
27916		this.map = source.map;
27917  
27918		this.rotation = source.rotation;
27919  
27920		return this;
27921  
27922	};
27923  
27924	/**
27925	 * @author mikael emtinger / http://gomo.se/
27926	 * @author alteredq / http://alteredqualia.com/
27927	 */
27928  
27929	function Sprite( material ) {
27930  
27931		Object3D.call( this );
27932  
27933		this.type = 'Sprite';
27934  
27935		this.material = ( material !== undefined ) ? material : new SpriteMaterial();
27936  
27937		this.center = new Vector2( 0.5, 0.5 );
27938  
27939	}
27940  
27941	Sprite.prototype = Object.assign( Object.create( Object3D.prototype ), {
27942  
27943		constructor: Sprite,
27944  
27945		isSprite: true,
27946  
27947		raycast: ( function () {
27948  
27949			var intersectPoint = new Vector3();
27950			var worldPosition = new Vector3();
27951			var worldScale = new Vector3();
27952  
27953			return function raycast( raycaster, intersects ) {
27954  
27955				worldPosition.setFromMatrixPosition( this.matrixWorld );
27956				raycaster.ray.closestPointToPoint( worldPosition, intersectPoint );
27957  
27958				worldScale.setFromMatrixScale( this.matrixWorld );
27959				var guessSizeSq = worldScale.x * worldScale.y / 4;
27960  
27961				if ( worldPosition.distanceToSquared( intersectPoint ) > guessSizeSq ) return;
27962  
27963				var distance = raycaster.ray.origin.distanceTo( intersectPoint );
27964  
27965				if ( distance < raycaster.near || distance > raycaster.far ) return;
27966  
27967				intersects.push( {
27968  
27969					distance: distance,
27970					point: intersectPoint.clone(),
27971					face: null,
27972					object: this
27973  
27974				} );
27975  
27976			};
27977  
27978		}() ),
27979  
27980		clone: function () {
27981  
27982			return new this.constructor( this.material ).copy( this );
27983  
27984		},
27985  
vendor: 4,101 bytes, lines 27986-28217
27986		copy: function ( source ) {
27987  
27988			Object3D.prototype.copy.call( this, source );
27989  
27990			if ( source.center !== undefined ) this.center.copy( source.center );
27991  
27992			return this;
27993  
27994		}
27995  
27996  
27997	} );
27998  
27999	/**
28000	 * @author mikael emtinger / http://gomo.se/
28001	 * @author alteredq / http://alteredqualia.com/
28002	 * @author mrdoob / http://mrdoob.com/
28003	 */
28004  
28005	function LOD() {
28006  
28007		Object3D.call( this );
28008  
28009		this.type = 'LOD';
28010  
28011		Object.defineProperties( this, {
28012			levels: {
28013				enumerable: true,
28014				value: []
28015			}
28016		} );
28017  
28018	}
28019  
28020	LOD.prototype = Object.assign( Object.create( Object3D.prototype ), {
28021  
28022		constructor: LOD,
28023  
28024		copy: function ( source ) {
28025  
28026			Object3D.prototype.copy.call( this, source, false );
28027  
28028			var levels = source.levels;
28029  
28030			for ( var i = 0, l = levels.length; i < l; i ++ ) {
28031  
28032				var level = levels[ i ];
28033  
28034				this.addLevel( level.object.clone(), level.distance );
28035  
28036			}
28037  
28038			return this;
28039  
28040		},
28041  
28042		addLevel: function ( object, distance ) {
28043  
28044			if ( distance === undefined ) distance = 0;
28045  
28046			distance = Math.abs( distance );
28047  
28048			var levels = this.levels;
28049  
28050			for ( var l = 0; l < levels.length; l ++ ) {
28051  
28052				if ( distance < levels[ l ].distance ) {
28053  
28054					break;
28055  
28056				}
28057  
28058			}
28059  
28060			levels.splice( l, 0, { distance: distance, object: object } );
28061  
28062			this.add( object );
28063  
28064		},
28065  
28066		getObjectForDistance: function ( distance ) {
28067  
28068			var levels = this.levels;
28069  
28070			for ( var i = 1, l = levels.length; i < l; i ++ ) {
28071  
28072				if ( distance < levels[ i ].distance ) {
28073  
28074					break;
28075  
28076				}
28077  
28078			}
28079  
28080			return levels[ i - 1 ].object;
28081  
28082		},
28083  
28084		raycast: ( function () {
28085  
28086			var matrixPosition = new Vector3();
28087  
28088			return function raycast( raycaster, intersects ) {
28089  
28090				matrixPosition.setFromMatrixPosition( this.matrixWorld );
28091  
28092				var distance = raycaster.ray.origin.distanceTo( matrixPosition );
28093  
28094				this.getObjectForDistance( distance ).raycast( raycaster, intersects );
28095  
28096			};
28097  
28098		}() ),
28099  
28100		update: function () {
28101  
28102			var v1 = new Vector3();
28103			var v2 = new Vector3();
28104  
28105			return function update( camera ) {
28106  
28107				var levels = this.levels;
28108  
28109				if ( levels.length > 1 ) {
28110  
28111					v1.setFromMatrixPosition( camera.matrixWorld );
28112					v2.setFromMatrixPosition( this.matrixWorld );
28113  
28114					var distance = v1.distanceTo( v2 );
28115  
28116					levels[ 0 ].object.visible = true;
28117  
28118					for ( var i = 1, l = levels.length; i < l; i ++ ) {
28119  
28120						if ( distance >= levels[ i ].distance ) {
28121  
28122							levels[ i - 1 ].object.visible = false;
28123							levels[ i ].object.visible = true;
28124  
28125						} else {
28126  
28127							break;
28128  
28129						}
28130  
28131					}
28132  
28133					for ( ; i < l; i ++ ) {
28134  
28135						levels[ i ].object.visible = false;
28136  
28137					}
28138  
28139				}
28140  
28141			};
28142  
28143		}(),
28144  
28145		toJSON: function ( meta ) {
28146  
28147			var data = Object3D.prototype.toJSON.call( this, meta );
28148  
28149			data.object.levels = [];
28150  
28151			var levels = this.levels;
28152  
28153			for ( var i = 0, l = levels.length; i < l; i ++ ) {
28154  
28155				var level = levels[ i ];
28156  
28157				data.object.levels.push( {
28158					object: level.object.uuid,
28159					distance: level.distance
28160				} );
28161  
28162			}
28163  
28164			return data;
28165  
28166		}
28167  
28168	} );
28169  
28170	/**
28171	 * @author mikael emtinger / http://gomo.se/
28172	 * @author alteredq / http://alteredqualia.com/
28173	 * @author michael guerrero / http://realitymeltdown.com
28174	 * @author ikerr / http://verold.com
28175	 */
28176  
28177	function Skeleton( bones, boneInverses ) {
28178  
28179		// copy the bone array
28180  
28181		bones = bones || [];
28182  
28183		this.bones = bones.slice( 0 );
28184		this.boneMatrices = new Float32Array( this.bones.length * 16 );
28185  
28186		// use the supplied bone inverses or calculate the inverses
28187  
28188		if ( boneInverses === undefined ) {
28189  
28190			this.calculateInverses();
28191  
28192		} else {
28193  
28194			if ( this.bones.length === boneInverses.length ) {
28195  
28196				this.boneInverses = boneInverses.slice( 0 );
28197  
28198			} else {
28199  
28200				console.warn( 'THREE.Skeleton boneInverses is the wrong length.' );
28201  
28202				this.boneInverses = [];
28203  
28204				for ( var i = 0, il = this.bones.length; i < il; i ++ ) {
28205  
28206					this.boneInverses.push( new Matrix4() );
28207  
28208				}
28209  
28210			}
28211  
28212		}
28213  
28214	}
28215  
28216	Object.assign( Skeleton.prototype, {
28217  
28218		calculateInverses: function () {
28219  
28220			this.boneInverses = [];
28221  
28222			for ( var i = 0, il = this.bones.length; i < il; i ++ ) {
28223  
28224				var inverse = new Matrix4();
28225  
28226				if ( this.bones[ i ] ) {
28227  
28228					inverse.getInverse( this.bones[ i ].matrixWorld );
28229  
28230				}
28231  
28232				this.boneInverses.push( inverse );
28233  
28234			}
28235  
28236		},
28237  
28238		pose: function () {
28239  
28240			var bone, i, il;
28241  
28242			// recover the bind-time world matrices
28243  
28244			for ( i = 0, il = this.bones.length; i < il; i ++ ) {
28245  
28246				bone = this.bones[ i ];
28247  
28248				if ( bone ) {
28249  
28250					bone.matrixWorld.getInverse( this.boneInverses[ i ] );
28251  
28252				}
28253  
28254			}
28255  
28256			// compute the local matrices, positions, rotations and scales
28257  
28258			for ( i = 0, il = this.bones.length; i < il; i ++ ) {
28259  
28260				bone = this.bones[ i ];
28261  
28262				if ( bone ) {
28263  
28264					if ( bone.parent && bone.parent.isBone ) {
28265  
28266						bone.matrix.getInverse( bone.parent.matrixWorld );
28267						bone.matrix.multiply( bone.matrixWorld );
28268  
28269					} else {
28270  
28271						bone.matrix.copy( bone.matrixWorld );
28272  
28273					}
28274  
28275					bone.matrix.decompose( bone.position, bone.quaternion, bone.scale );
28276  
28277				}
28278  
28279			}
28280  
28281		},
28282  
28283		update: ( function () {
28284  
28285			var offsetMatrix = new Matrix4();
28286			var identityMatrix = new Matrix4();
28287  
28288			return function update() {
28289  
28290				var bones = this.bones;
28291				var boneInverses = this.boneInverses;
28292				var boneMatrices = this.boneMatrices;
28293				var boneTexture = this.boneTexture;
28294  
28295				// flatten bone matrices to array
28296  
28297				for ( var i = 0, il = bones.length; i < il; i ++ ) {
28298  
28299					// compute the offset between the current and the original transform
28300  
28301					var matrix = bones[ i ] ? bones[ i ].matrixWorld : identityMatrix;
28302  
28303					offsetMatrix.multiplyMatrices( matrix, boneInverses[ i ] );
28304					offsetMatrix.toArray( boneMatrices, i * 16 );
28305  
28306				}
28307  
28308				if ( boneTexture !== undefined ) {
28309  
28310					boneTexture.needsUpdate = true;
28311  
28312				}
28313  
28314			};
28315  
28316		} )(),
28317  
28318		clone: function () {
28319  
28320			return new Skeleton( this.bones, this.boneInverses );
28321  
28322		},
28323  
28324		getBoneByName: function ( name ) {
28325  
28326			for ( var i = 0, il = this.bones.length; i < il; i ++ ) {
28327  
28328				var bone = this.bones[ i ];
28329  
28330				if ( bone.name === name ) {
28331  
28332					return bone;
28333  
28334				}
28335  
28336			}
28337  
28338			return undefined;
28339  
28340		}
28341  
28342	} );
28343  
28344	/**
28345	 * @author mikael emtinger / http://gomo.se/
28346	 * @author alteredq / http://alteredqualia.com/
28347	 * @author ikerr / http://verold.com
28348	 */
28349  
28350	function Bone() {
28351  
28352		Object3D.call( this );
28353  
28354		this.type = 'Bone';
28355  
28356	}
28357  
28358	Bone.prototype = Object.assign( Object.create( Object3D.prototype ), {
28359  
28360		constructor: Bone,
28361  
28362		isBone: true
28363  
28364	} );
28365  
28366	/**
28367	 * @author mikael emtinger / http://gomo.se/
28368	 * @author alteredq / http://alteredqualia.com/
28369	 * @author ikerr / http://verold.com
28370	 */
28371  
28372	function SkinnedMesh( geometry, material ) {
28373  
28374		Mesh.call( this, geometry, material );
28375  
28376		this.type = 'SkinnedMesh';
28377  
28378		this.bindMode = 'attached';
28379		this.bindMatrix = new Matrix4();
28380		this.bindMatrixInverse = new Matrix4();
28381  
28382		var bones = this.initBones();
28383		var skeleton = new Skeleton( bones );
28384  
28385		this.bind( skeleton, this.matrixWorld );
28386  
28387		this.normalizeSkinWeights();
28388  
28389	}
28390  
28391	SkinnedMesh.prototype = Object.assign( Object.create( Mesh.prototype ), {
28392  
28393		constructor: SkinnedMesh,
28394  
28395		isSkinnedMesh: true,
28396  
28397		initBones: function () {
28398  
28399			var bones = [], bone, gbone;
28400			var i, il;
28401  
28402			if ( this.geometry && this.geometry.bones !== undefined ) {
28403  
28404				// first, create array of 'Bone' objects from geometry data
28405  
28406				for ( i = 0, il = this.geometry.bones.length; i < il; i ++ ) {
28407  
28408					gbone = this.geometry.bones[ i ];
28409  
28410					// create new 'Bone' object
28411  
28412					bone = new Bone();
28413					bones.push( bone );
28414  
28415					// apply values
28416  
28417					bone.name = gbone.name;
28418					bone.position.fromArray( gbone.pos );
28419					bone.quaternion.fromArray( gbone.rotq );
28420					if ( gbone.scl !== undefined ) bone.scale.fromArray( gbone.scl );
28421  
28422				}
28423  
28424				// second, create bone hierarchy
28425  
28426				for ( i = 0, il = this.geometry.bones.length; i < il; i ++ ) {
28427  
28428					gbone = this.geometry.bones[ i ];
28429  
28430					if ( ( gbone.parent !== - 1 ) && ( gbone.parent !== null ) && ( bones[ gbone.parent ] !== undefined ) ) {
28431  
28432						// subsequent bones in the hierarchy
28433  
28434						bones[ gbone.parent ].add( bones[ i ] );
28435  
28436					} else {
28437  
28438						// topmost bone, immediate child of the skinned mesh
28439  
28440						this.add( bones[ i ] );
28441  
28442					}
28443  
28444				}
28445  
28446			}
28447  
28448			// now the bones are part of the scene graph and children of the skinned mesh.
28449			// let's update the corresponding matrices
28450  
28451			this.updateMatrixWorld( true );
28452  
28453			return bones;
28454  
28455		},
28456  
28457		bind: function ( skeleton, bindMatrix ) {
28458  
28459			this.skeleton = skeleton;
28460  
28461			if ( bindMatrix === undefined ) {
28462  
28463				this.updateMatrixWorld( true );
28464  
28465				this.skeleton.calculateInverses();
28466  
28467				bindMatrix = this.matrixWorld;
28468  
28469			}
28470  
28471			this.bindMatrix.copy( bindMatrix );
28472			this.bindMatrixInverse.getInverse( bindMatrix );
28473  
28474		},
28475  
28476		pose: function () {
28477  
28478			this.skeleton.pose();
28479  
28480		},
28481  
28482		normalizeSkinWeights: function () {
28483  
28484			var scale, i;
28485  
28486			if ( this.geometry && this.geometry.isGeometry ) {
28487  
28488				for ( i = 0; i < this.geometry.skinWeights.length; i ++ ) {
28489  
28490					var sw = this.geometry.skinWeights[ i ];
28491  
28492					scale = 1.0 / sw.manhattanLength();
28493  
28494					if ( scale !== Infinity ) {
28495  
28496						sw.multiplyScalar( scale );
28497  
28498					} else {
28499  
28500						sw.set( 1, 0, 0, 0 );
vendor: 52,515 bytes, lines 28500-30782
28500 // do something reasonable
28501  
28502					}
28503  
28504				}
28505  
28506			} else if ( this.geometry && this.geometry.isBufferGeometry ) {
28507  
28508				var vec = new Vector4();
28509  
28510				var skinWeight = this.geometry.attributes.skinWeight;
28511  
28512				for ( i = 0; i < skinWeight.count; i ++ ) {
28513  
28514					vec.x = skinWeight.getX( i );
28515					vec.y = skinWeight.getY( i );
28516					vec.z = skinWeight.getZ( i );
28517					vec.w = skinWeight.getW( i );
28518  
28519					scale = 1.0 / vec.manhattanLength();
28520  
28521					if ( scale !== Infinity ) {
28522  
28523						vec.multiplyScalar( scale );
28524  
28525					} else {
28526  
28527						vec.set( 1, 0, 0, 0 ); // do something reasonable
28528  
28529					}
28530  
28531					skinWeight.setXYZW( i, vec.x, vec.y, vec.z, vec.w );
28532  
28533				}
28534  
28535			}
28536  
28537		},
28538  
28539		updateMatrixWorld: function ( force ) {
28540  
28541			Mesh.prototype.updateMatrixWorld.call( this, force );
28542  
28543			if ( this.bindMode === 'attached' ) {
28544  
28545				this.bindMatrixInverse.getInverse( this.matrixWorld );
28546  
28547			} else if ( this.bindMode === 'detached' ) {
28548  
28549				this.bindMatrixInverse.getInverse( this.bindMatrix );
28550  
28551			} else {
28552  
28553				console.warn( 'THREE.SkinnedMesh: Unrecognized bindMode: ' + this.bindMode );
28554  
28555			}
28556  
28557		},
28558  
28559		clone: function () {
28560  
28561			return new this.constructor( this.geometry, this.material ).copy( this );
28562  
28563		}
28564  
28565	} );
28566  
28567	/**
28568	 * @author mrdoob / http://mrdoob.com/
28569	 * @author alteredq / http://alteredqualia.com/
28570	 *
28571	 * parameters = {
28572	 *  color: <hex>,
28573	 *  opacity: <float>,
28574	 *
28575	 *  linewidth: <float>,
28576	 *  linecap: "round",
28577	 *  linejoin: "round"
28578	 * }
28579	 */
28580  
28581	function LineBasicMaterial( parameters ) {
28582  
28583		Material.call( this );
28584  
28585		this.type = 'LineBasicMaterial';
28586  
28587		this.color = new Color( 0xffffff );
28588  
28589		this.linewidth = 1;
28590		this.linecap = 'round';
28591		this.linejoin = 'round';
28592  
28593		this.lights = false;
28594  
28595		this.setValues( parameters );
28596  
28597	}
28598  
28599	LineBasicMaterial.prototype = Object.create( Material.prototype );
28600	LineBasicMaterial.prototype.constructor = LineBasicMaterial;
28601  
28602	LineBasicMaterial.prototype.isLineBasicMaterial = true;
28603  
28604	LineBasicMaterial.prototype.copy = function ( source ) {
28605  
28606		Material.prototype.copy.call( this, source );
28607  
28608		this.color.copy( source.color );
28609  
28610		this.linewidth = source.linewidth;
28611		this.linecap = source.linecap;
28612		this.linejoin = source.linejoin;
28613  
28614		return this;
28615  
28616	};
28617  
28618	/**
28619	 * @author mrdoob / http://mrdoob.com/
28620	 */
28621  
28622	function Line( geometry, material, mode ) {
28623  
28624		if ( mode === 1 ) {
28625  
28626			console.warn( 'THREE.Line: parameter THREE.LinePieces no longer supported. Created THREE.LineSegments instead.' );
28627			return new LineSegments( geometry, material );
28628  
28629		}
28630  
28631		Object3D.call( this );
28632  
28633		this.type = 'Line';
28634  
28635		this.geometry = geometry !== undefined ? geometry : new BufferGeometry();
28636		this.material = material !== undefined ? material : new LineBasicMaterial( { color: Math.random() * 0xffffff } );
28637  
28638	}
28639  
28640	Line.prototype = Object.assign( Object.create( Object3D.prototype ), {
28641  
28642		constructor: Line,
28643  
28644		isLine: true,
28645  
28646		computeLineDistances: ( function () {
28647  
28648			var start = new Vector3();
28649			var end = new Vector3();
28650  
28651			return function computeLineDistances() {
28652  
28653				var geometry = this.geometry;
28654  
28655				if ( geometry.isBufferGeometry ) {
28656  
28657					// we assume non-indexed geometry
28658  
28659					if ( geometry.index === null ) {
28660  
28661						var positionAttribute = geometry.attributes.position;
28662						var lineDistances = [ 0 ];
28663  
28664						for ( var i = 1, l = positionAttribute.count; i < l; i ++ ) {
28665  
28666							start.fromBufferAttribute( positionAttribute, i - 1 );
28667							end.fromBufferAttribute( positionAttribute, i );
28668  
28669							lineDistances[ i ] = lineDistances[ i - 1 ];
28670							lineDistances[ i ] += start.distanceTo( end );
28671  
28672						}
28673  
28674						geometry.addAttribute( 'lineDistance', new Float32BufferAttribute( lineDistances, 1 ) );
28675  
28676					} else {
28677  
28678						console.warn( 'THREE.Line.computeLineDistances(): Computation only possible with non-indexed BufferGeometry.' );
28679  
28680					}
28681  
28682				} else if ( geometry.isGeometry ) {
28683  
28684					var vertices = geometry.vertices;
28685					var lineDistances = geometry.lineDistances;
28686  
28687					lineDistances[ 0 ] = 0;
28688  
28689					for ( var i = 1, l = vertices.length; i < l; i ++ ) {
28690  
28691						lineDistances[ i ] = lineDistances[ i - 1 ];
28692						lineDistances[ i ] += vertices[ i - 1 ].distanceTo( vertices[ i ] );
28693  
28694					}
28695  
28696				}
28697  
28698				return this;
28699  
28700			};
28701  
28702		}() ),
28703  
28704		raycast: ( function () {
28705  
28706			var inverseMatrix = new Matrix4();
28707			var ray = new Ray();
28708			var sphere = new Sphere();
28709  
28710			return function raycast( raycaster, intersects ) {
28711  
28712				var precision = raycaster.linePrecision;
28713				var precisionSq = precision * precision;
28714  
28715				var geometry = this.geometry;
28716				var matrixWorld = this.matrixWorld;
28717  
28718				// Checking boundingSphere distance to ray
28719  
28720				if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere();
28721  
28722				sphere.copy( geometry.boundingSphere );
28723				sphere.applyMatrix4( matrixWorld );
28724  
28725				if ( raycaster.ray.intersectsSphere( sphere ) === false ) return;
28726  
28727				//
28728  
28729				inverseMatrix.getInverse( matrixWorld );
28730				ray.copy( raycaster.ray ).applyMatrix4( inverseMatrix );
28731  
28732				var vStart = new Vector3();
28733				var vEnd = new Vector3();
28734				var interSegment = new Vector3();
28735				var interRay = new Vector3();
28736				var step = ( this && this.isLineSegments ) ? 2 : 1;
28737  
28738				if ( geometry.isBufferGeometry ) {
28739  
28740					var index = geometry.index;
28741					var attributes = geometry.attributes;
28742					var positions = attributes.position.array;
28743  
28744					if ( index !== null ) {
28745  
28746						var indices = index.array;
28747  
28748						for ( var i = 0, l = indices.length - 1; i < l; i += step ) {
28749  
28750							var a = indices[ i ];
28751							var b = indices[ i + 1 ];
28752  
28753							vStart.fromArray( positions, a * 3 );
28754							vEnd.fromArray( positions, b * 3 );
28755  
28756							var distSq = ray.distanceSqToSegment( vStart, vEnd, interRay, interSegment );
28757  
28758							if ( distSq > precisionSq ) continue;
28759  
28760							interRay.applyMatrix4( this.matrixWorld ); //Move back to world space for distance calculation
28761  
28762							var distance = raycaster.ray.origin.distanceTo( interRay );
28763  
28764							if ( distance < raycaster.near || distance > raycaster.far ) continue;
28765  
28766							intersects.push( {
28767  
28768								distance: distance,
28769								// What do we want? intersection point on the ray or on the segment??
28770								// point: raycaster.ray.at( distance ),
28771								point: interSegment.clone().applyMatrix4( this.matrixWorld ),
28772								index: i,
28773								face: null,
28774								faceIndex: null,
28775								object: this
28776  
28777							} );
28778  
28779						}
28780  
28781					} else {
28782  
28783						for ( var i = 0, l = positions.length / 3 - 1; i < l; i += step ) {
28784  
28785							vStart.fromArray( positions, 3 * i );
28786							vEnd.fromArray( positions, 3 * i + 3 );
28787  
28788							var distSq = ray.distanceSqToSegment( vStart, vEnd, interRay, interSegment );
28789  
28790							if ( distSq > precisionSq ) continue;
28791  
28792							interRay.applyMatrix4( this.matrixWorld ); //Move back to world space for distance calculation
28793  
28794							var distance = raycaster.ray.origin.distanceTo( interRay );
28795  
28796							if ( distance < raycaster.near || distance > raycaster.far ) continue;
28797  
28798							intersects.push( {
28799  
28800								distance: distance,
28801								// What do we want? intersection point on the ray or on the segment??
28802								// point: raycaster.ray.at( distance ),
28803								point: interSegment.clone().applyMatrix4( this.matrixWorld ),
28804								index: i,
28805								face: null,
28806								faceIndex: null,
28807								object: this
28808  
28809							} );
28810  
28811						}
28812  
28813					}
28814  
28815				} else if ( geometry.isGeometry ) {
28816  
28817					var vertices = geometry.vertices;
28818					var nbVertices = vertices.length;
28819  
28820					for ( var i = 0; i < nbVertices - 1; i += step ) {
28821  
28822						var distSq = ray.distanceSqToSegment( vertices[ i ], vertices[ i + 1 ], interRay, interSegment );
28823  
28824						if ( distSq > precisionSq ) continue;
28825  
28826						interRay.applyMatrix4( this.matrixWorld ); //Move back to world space for distance calculation
28827  
28828						var distance = raycaster.ray.origin.distanceTo( interRay );
28829  
28830						if ( distance < raycaster.near || distance > raycaster.far ) continue;
28831  
28832						intersects.push( {
28833  
28834							distance: distance,
28835							// What do we want? intersection point on the ray or on the segment??
28836							// point: raycaster.ray.at( distance ),
28837							point: interSegment.clone().applyMatrix4( this.matrixWorld ),
28838							index: i,
28839							face: null,
28840							faceIndex: null,
28841							object: this
28842  
28843						} );
28844  
28845					}
28846  
28847				}
28848  
28849			};
28850  
28851		}() ),
28852  
28853		clone: function () {
28854  
28855			return new this.constructor( this.geometry, this.material ).copy( this );
28856  
28857		}
28858  
28859	} );
28860  
28861	/**
28862	 * @author mrdoob / http://mrdoob.com/
28863	 */
28864  
28865	function LineSegments( geometry, material ) {
28866  
28867		Line.call( this, geometry, material );
28868  
28869		this.type = 'LineSegments';
28870  
28871	}
28872  
28873	LineSegments.prototype = Object.assign( Object.create( Line.prototype ), {
28874  
28875		constructor: LineSegments,
28876  
28877		isLineSegments: true,
28878  
28879		computeLineDistances: ( function () {
28880  
28881			var start = new Vector3();
28882			var end = new Vector3();
28883  
28884			return function computeLineDistances() {
28885  
28886				var geometry = this.geometry;
28887  
28888				if ( geometry.isBufferGeometry ) {
28889  
28890					// we assume non-indexed geometry
28891  
28892					if ( geometry.index === null ) {
28893  
28894						var positionAttribute = geometry.attributes.position;
28895						var lineDistances = [];
28896  
28897						for ( var i = 0, l = positionAttribute.count; i < l; i += 2 ) {
28898  
28899							start.fromBufferAttribute( positionAttribute, i );
28900							end.fromBufferAttribute( positionAttribute, i + 1 );
28901  
28902							lineDistances[ i ] = ( i === 0 ) ? 0 : lineDistances[ i - 1 ];
28903							lineDistances[ i + 1 ] = lineDistances[ i ] + start.distanceTo( end );
28904  
28905						}
28906  
28907						geometry.addAttribute( 'lineDistance', new Float32BufferAttribute( lineDistances, 1 ) );
28908  
28909					} else {
28910  
28911						console.warn( 'THREE.LineSegments.computeLineDistances(): Computation only possible with non-indexed BufferGeometry.' );
28912  
28913					}
28914  
28915				} else if ( geometry.isGeometry ) {
28916  
28917					var vertices = geometry.vertices;
28918					var lineDistances = geometry.lineDistances;
28919  
28920					for ( var i = 0, l = vertices.length; i < l; i += 2 ) {
28921  
28922						start.copy( vertices[ i ] );
28923						end.copy( vertices[ i + 1 ] );
28924  
28925						lineDistances[ i ] = ( i === 0 ) ? 0 : lineDistances[ i - 1 ];
28926						lineDistances[ i + 1 ] = lineDistances[ i ] + start.distanceTo( end );
28927  
28928					}
28929  
28930				}
28931  
28932				return this;
28933  
28934			};
28935  
28936		}() )
28937  
28938	} );
28939  
28940	/**
28941	 * @author mgreter / http://github.com/mgreter
28942	 */
28943  
28944	function LineLoop( geometry, material ) {
28945  
28946		Line.call( this, geometry, material );
28947  
28948		this.type = 'LineLoop';
28949  
28950	}
28951  
28952	LineLoop.prototype = Object.assign( Object.create( Line.prototype ), {
28953  
28954		constructor: LineLoop,
28955  
28956		isLineLoop: true,
28957  
28958	} );
28959  
28960	/**
28961	 * @author mrdoob / http://mrdoob.com/
28962	 * @author alteredq / http://alteredqualia.com/
28963	 *
28964	 * parameters = {
28965	 *  color: <hex>,
28966	 *  opacity: <float>,
28967	 *  map: new THREE.Texture( <Image> ),
28968	 *
28969	 *  size: <float>,
28970	 *  sizeAttenuation: <bool>
28971	 *
28972	 *  morphTargets: <bool>
28973	 * }
28974	 */
28975  
28976	function PointsMaterial( parameters ) {
28977  
28978		Material.call( this );
28979  
28980		this.type = 'PointsMaterial';
28981  
28982		this.color = new Color( 0xffffff );
28983  
28984		this.map = null;
28985  
28986		this.size = 1;
28987		this.sizeAttenuation = true;
28988  
28989		this.morphTargets = false;
28990  
28991		this.lights = false;
28992  
28993		this.setValues( parameters );
28994  
28995	}
28996  
28997	PointsMaterial.prototype = Object.create( Material.prototype );
28998	PointsMaterial.prototype.constructor = PointsMaterial;
28999  
29000	PointsMaterial.prototype.isPointsMaterial = true;
29001  
29002	PointsMaterial.prototype.copy = function ( source ) {
29003  
29004		Material.prototype.copy.call( this, source );
29005  
29006		this.color.copy( source.color );
29007  
29008		this.map = source.map;
29009  
29010		this.size = source.size;
29011		this.sizeAttenuation = source.sizeAttenuation;
29012  
29013		this.morphTargets = source.morphTargets;
29014  
29015		return this;
29016  
29017	};
29018  
29019	/**
29020	 * @author alteredq / http://alteredqualia.com/
29021	 */
29022  
29023	function Points( geometry, material ) {
29024  
29025		Object3D.call( this );
29026  
29027		this.type = 'Points';
29028  
29029		this.geometry = geometry !== undefined ? geometry : new BufferGeometry();
29030		this.material = material !== undefined ? material : new PointsMaterial( { color: Math.random() * 0xffffff } );
29031  
29032	}
29033  
29034	Points.prototype = Object.assign( Object.create( Object3D.prototype ), {
29035  
29036		constructor: Points,
29037  
29038		isPoints: true,
29039  
29040		raycast: ( function () {
29041  
29042			var inverseMatrix = new Matrix4();
29043			var ray = new Ray();
29044			var sphere = new Sphere();
29045  
29046			return function raycast( raycaster, intersects ) {
29047  
29048				var object = this;
29049				var geometry = this.geometry;
29050				var matrixWorld = this.matrixWorld;
29051				var threshold = raycaster.params.Points.threshold;
29052  
29053				// Checking boundingSphere distance to ray
29054  
29055				if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere();
29056  
29057				sphere.copy( geometry.boundingSphere );
29058				sphere.applyMatrix4( matrixWorld );
29059				sphere.radius += threshold;
29060  
29061				if ( raycaster.ray.intersectsSphere( sphere ) === false ) return;
29062  
29063				//
29064  
29065				inverseMatrix.getInverse( matrixWorld );
29066				ray.copy( raycaster.ray ).applyMatrix4( inverseMatrix );
29067  
29068				var localThreshold = threshold / ( ( this.scale.x + this.scale.y + this.scale.z ) / 3 );
29069				var localThresholdSq = localThreshold * localThreshold;
29070				var position = new Vector3();
29071				var intersectPoint = new Vector3();
29072  
29073				function testPoint( point, index ) {
29074  
29075					var rayPointDistanceSq = ray.distanceSqToPoint( point );
29076  
29077					if ( rayPointDistanceSq < localThresholdSq ) {
29078  
29079						ray.closestPointToPoint( point, intersectPoint );
29080						intersectPoint.applyMatrix4( matrixWorld );
29081  
29082						var distance = raycaster.ray.origin.distanceTo( intersectPoint );
29083  
29084						if ( distance < raycaster.near || distance > raycaster.far ) return;
29085  
29086						intersects.push( {
29087  
29088							distance: distance,
29089							distanceToRay: Math.sqrt( rayPointDistanceSq ),
29090							point: intersectPoint.clone(),
29091							index: index,
29092							face: null,
29093							object: object
29094  
29095						} );
29096  
29097					}
29098  
29099				}
29100  
29101				if ( geometry.isBufferGeometry ) {
29102  
29103					var index = geometry.index;
29104					var attributes = geometry.attributes;
29105					var positions = attributes.position.array;
29106  
29107					if ( index !== null ) {
29108  
29109						var indices = index.array;
29110  
29111						for ( var i = 0, il = indices.length; i < il; i ++ ) {
29112  
29113							var a = indices[ i ];
29114  
29115							position.fromArray( positions, a * 3 );
29116  
29117							testPoint( position, a );
29118  
29119						}
29120  
29121					} else {
29122  
29123						for ( var i = 0, l = positions.length / 3; i < l; i ++ ) {
29124  
29125							position.fromArray( positions, i * 3 );
29126  
29127							testPoint( position, i );
29128  
29129						}
29130  
29131					}
29132  
29133				} else {
29134  
29135					var vertices = geometry.vertices;
29136  
29137					for ( var i = 0, l = vertices.length; i < l; i ++ ) {
29138  
29139						testPoint( vertices[ i ], i );
29140  
29141					}
29142  
29143				}
29144  
29145			};
29146  
29147		}() ),
29148  
29149		clone: function () {
29150  
29151			return new this.constructor( this.geometry, this.material ).copy( this );
29152  
29153		}
29154  
29155	} );
29156  
29157	/**
29158	 * @author mrdoob / http://mrdoob.com/
29159	 */
29160  
29161	function Group() {
29162  
29163		Object3D.call( this );
29164  
29165		this.type = 'Group';
29166  
29167	}
29168  
29169	Group.prototype = Object.assign( Object.create( Object3D.prototype ), {
29170  
29171		constructor: Group,
29172  
29173		isGroup: true
29174  
29175	} );
29176  
29177	/**
29178	 * @author mrdoob / http://mrdoob.com/
29179	 */
29180  
29181	function VideoTexture( video, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ) {
29182  
29183		Texture.call( this, video, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy );
29184  
29185		this.generateMipmaps = false;
29186  
29187	}
29188  
29189	VideoTexture.prototype = Object.assign( Object.create( Texture.prototype ), {
29190  
29191		constructor: VideoTexture,
29192  
29193		isVideoTexture: true,
29194  
29195		update: function () {
29196  
29197			var video = this.image;
29198  
29199			if ( video.readyState >= video.HAVE_CURRENT_DATA ) {
29200  
29201				this.needsUpdate = true;
29202  
29203			}
29204  
29205		}
29206  
29207	} );
29208  
29209	/**
29210	 * @author alteredq / http://alteredqualia.com/
29211	 */
29212  
29213	function CompressedTexture( mipmaps, width, height, format, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy, encoding ) {
29214  
29215		Texture.call( this, null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding );
29216  
29217		this.image = { width: width, height: height };
29218		this.mipmaps = mipmaps;
29219  
29220		// no flipping for cube textures
29221		// (also flipping doesn't work for compressed textures )
29222  
29223		this.flipY = false;
29224  
29225		// can't generate mipmaps for compressed textures
29226		// mips must be embedded in DDS files
29227  
29228		this.generateMipmaps = false;
29229  
29230	}
29231  
29232	CompressedTexture.prototype = Object.create( Texture.prototype );
29233	CompressedTexture.prototype.constructor = CompressedTexture;
29234  
29235	CompressedTexture.prototype.isCompressedTexture = true;
29236  
29237	/**
29238	 * @author Matt DesLauriers / @mattdesl
29239	 * @author atix / arthursilber.de
29240	 */
29241  
29242	function DepthTexture( width, height, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy, format ) {
29243  
29244		format = format !== undefined ? format : DepthFormat;
29245  
29246		if ( format !== DepthFormat && format !== DepthStencilFormat ) {
29247  
29248			throw new Error( 'DepthTexture format must be either THREE.DepthFormat or THREE.DepthStencilFormat' );
29249  
29250		}
29251  
29252		if ( type === undefined && format === DepthFormat ) type = UnsignedShortType;
29253		if ( type === undefined && format === DepthStencilFormat ) type = UnsignedInt248Type;
29254  
29255		Texture.call( this, null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy );
29256  
29257		this.image = { width: width, height: height };
29258  
29259		this.magFilter = magFilter !== undefined ? magFilter : NearestFilter;
29260		this.minFilter = minFilter !== undefined ? minFilter : NearestFilter;
29261  
29262		this.flipY = false;
29263		this.generateMipmaps	= false;
29264  
29265	}
29266  
29267	DepthTexture.prototype = Object.create( Texture.prototype );
29268	DepthTexture.prototype.constructor = DepthTexture;
29269	DepthTexture.prototype.isDepthTexture = true;
29270  
29271	/**
29272	 * @author mrdoob / http://mrdoob.com/
29273	 * @author Mugen87 / https://github.com/Mugen87
29274	 */
29275  
29276	function WireframeGeometry( geometry ) {
29277  
29278		BufferGeometry.call( this );
29279  
29280		this.type = 'WireframeGeometry';
29281  
29282		// buffer
29283  
29284		var vertices = [];
29285  
29286		// helper variables
29287  
29288		var i, j, l, o, ol;
29289		var edge = [ 0, 0 ], edges = {}, e, edge1, edge2;
29290		var key, keys = [ 'a', 'b', 'c' ];
29291		var vertex;
29292  
29293		// different logic for Geometry and BufferGeometry
29294  
29295		if ( geometry && geometry.isGeometry ) {
29296  
29297			// create a data structure that contains all edges without duplicates
29298  
29299			var faces = geometry.faces;
29300  
29301			for ( i = 0, l = faces.length; i < l; i ++ ) {
29302  
29303				var face = faces[ i ];
29304  
29305				for ( j = 0; j < 3; j ++ ) {
29306  
29307					edge1 = face[ keys[ j ] ];
29308					edge2 = face[ keys[ ( j + 1 ) % 3 ] ];
29309					edge[ 0 ] = Math.min( edge1, edge2 ); // sorting prevents duplicates
29310					edge[ 1 ] = Math.max( edge1, edge2 );
29311  
29312					key = edge[ 0 ] + ',' + edge[ 1 ];
29313  
29314					if ( edges[ key ] === undefined ) {
29315  
29316						edges[ key ] = { index1: edge[ 0 ], index2: edge[ 1 ] };
29317  
29318					}
29319  
29320				}
29321  
29322			}
29323  
29324			// generate vertices
29325  
29326			for ( key in edges ) {
29327  
29328				e = edges[ key ];
29329  
29330				vertex = geometry.vertices[ e.index1 ];
29331				vertices.push( vertex.x, vertex.y, vertex.z );
29332  
29333				vertex = geometry.vertices[ e.index2 ];
29334				vertices.push( vertex.x, vertex.y, vertex.z );
29335  
29336			}
29337  
29338		} else if ( geometry && geometry.isBufferGeometry ) {
29339  
29340			var position, indices, groups;
29341			var group, start, count;
29342			var index1, index2;
29343  
29344			vertex = new Vector3();
29345  
29346			if ( geometry.index !== null ) {
29347  
29348				// indexed BufferGeometry
29349  
29350				position = geometry.attributes.position;
29351				indices = geometry.index;
29352				groups = geometry.groups;
29353  
29354				if ( groups.length === 0 ) {
29355  
29356					groups = [ { start: 0, count: indices.count, materialIndex: 0 } ];
29357  
29358				}
29359  
29360				// create a data structure that contains all eges without duplicates
29361  
29362				for ( o = 0, ol = groups.length; o < ol; ++ o ) {
29363  
29364					group = groups[ o ];
29365  
29366					start = group.start;
29367					count = group.count;
29368  
29369					for ( i = start, l = ( start + count ); i < l; i += 3 ) {
29370  
29371						for ( j = 0; j < 3; j ++ ) {
29372  
29373							edge1 = indices.getX( i + j );
29374							edge2 = indices.getX( i + ( j + 1 ) % 3 );
29375							edge[ 0 ] = Math.min( edge1, edge2 ); // sorting prevents duplicates
29376							edge[ 1 ] = Math.max( edge1, edge2 );
29377  
29378							key = edge[ 0 ] + ',' + edge[ 1 ];
29379  
29380							if ( edges[ key ] === undefined ) {
29381  
29382								edges[ key ] = { index1: edge[ 0 ], index2: edge[ 1 ] };
29383  
29384							}
29385  
29386						}
29387  
29388					}
29389  
29390				}
29391  
29392				// generate vertices
29393  
29394				for ( key in edges ) {
29395  
29396					e = edges[ key ];
29397  
29398					vertex.fromBufferAttribute( position, e.index1 );
29399					vertices.push( vertex.x, vertex.y, vertex.z );
29400  
29401					vertex.fromBufferAttribute( position, e.index2 );
29402					vertices.push( vertex.x, vertex.y, vertex.z );
29403  
29404				}
29405  
29406			} else {
29407  
29408				// non-indexed BufferGeometry
29409  
29410				position = geometry.attributes.position;
29411  
29412				for ( i = 0, l = ( position.count / 3 ); i < l; i ++ ) {
29413  
29414					for ( j = 0; j < 3; j ++ ) {
29415  
29416						// three edges per triangle, an edge is represented as (index1, index2)
29417						// e.g. the first triangle has the following edges: (0,1),(1,2),(2,0)
29418  
29419						index1 = 3 * i + j;
29420						vertex.fromBufferAttribute( position, index1 );
29421						vertices.push( vertex.x, vertex.y, vertex.z );
29422  
29423						index2 = 3 * i + ( ( j + 1 ) % 3 );
29424						vertex.fromBufferAttribute( position, index2 );
29425						vertices.push( vertex.x, vertex.y, vertex.z );
29426  
29427					}
29428  
29429				}
29430  
29431			}
29432  
29433		}
29434  
29435		// build geometry
29436  
29437		this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
29438  
29439	}
29440  
29441	WireframeGeometry.prototype = Object.create( BufferGeometry.prototype );
29442	WireframeGeometry.prototype.constructor = WireframeGeometry;
29443  
29444	/**
29445	 * @author zz85 / https://github.com/zz85
29446	 * @author Mugen87 / https://github.com/Mugen87
29447	 *
29448	 * Parametric Surfaces Geometry
29449	 * based on the brilliant article by @prideout http://prideout.net/blog/?p=44
29450	 */
29451  
29452	// ParametricGeometry
29453  
29454	function ParametricGeometry( func, slices, stacks ) {
29455  
29456		Geometry.call( this );
29457  
29458		this.type = 'ParametricGeometry';
29459  
29460		this.parameters = {
29461			func: func,
29462			slices: slices,
29463			stacks: stacks
29464		};
29465  
29466		this.fromBufferGeometry( new ParametricBufferGeometry( func, slices, stacks ) );
29467		this.mergeVertices();
29468  
29469	}
29470  
29471	ParametricGeometry.prototype = Object.create( Geometry.prototype );
29472	ParametricGeometry.prototype.constructor = ParametricGeometry;
29473  
29474	// ParametricBufferGeometry
29475  
29476	function ParametricBufferGeometry( func, slices, stacks ) {
29477  
29478		BufferGeometry.call( this );
29479  
29480		this.type = 'ParametricBufferGeometry';
29481  
29482		this.parameters = {
29483			func: func,
29484			slices: slices,
29485			stacks: stacks
29486		};
29487  
29488		// buffers
29489  
29490		var indices = [];
29491		var vertices = [];
29492		var normals = [];
29493		var uvs = [];
29494  
29495		var EPS = 0.00001;
29496  
29497		var normal = new Vector3();
29498  
29499		var p0 = new Vector3(), p1 = new Vector3();
29500		var pu = new Vector3(), pv = new Vector3();
29501  
29502		var i, j;
29503  
29504		if ( func.length < 3 ) {
29505  
29506			console.error( 'THREE.ParametricGeometry: Function must now modify a Vector3 as third parameter.' );
29507  
29508		}
29509  
29510		// generate vertices, normals and uvs
29511  
29512		var sliceCount = slices + 1;
29513  
29514		for ( i = 0; i <= stacks; i ++ ) {
29515  
29516			var v = i / stacks;
29517  
29518			for ( j = 0; j <= slices; j ++ ) {
29519  
29520				var u = j / slices;
29521  
29522				// vertex
29523  
29524				func( u, v, p0 );
29525				vertices.push( p0.x, p0.y, p0.z );
29526  
29527				// normal
29528  
29529				// approximate tangent vectors via finite differences
29530  
29531				if ( u - EPS >= 0 ) {
29532  
29533					func( u - EPS, v, p1 );
29534					pu.subVectors( p0, p1 );
29535  
29536				} else {
29537  
29538					func( u + EPS, v, p1 );
29539					pu.subVectors( p1, p0 );
29540  
29541				}
29542  
29543				if ( v - EPS >= 0 ) {
29544  
29545					func( u, v - EPS, p1 );
29546					pv.subVectors( p0, p1 );
29547  
29548				} else {
29549  
29550					func( u, v + EPS, p1 );
29551					pv.subVectors( p1, p0 );
29552  
29553				}
29554  
29555				// cross product of tangent vectors returns surface normal
29556  
29557				normal.crossVectors( pu, pv ).normalize();
29558				normals.push( normal.x, normal.y, normal.z );
29559  
29560				// uv
29561  
29562				uvs.push( u, v );
29563  
29564			}
29565  
29566		}
29567  
29568		// generate indices
29569  
29570		for ( i = 0; i < stacks; i ++ ) {
29571  
29572			for ( j = 0; j < slices; j ++ ) {
29573  
29574				var a = i * sliceCount + j;
29575				var b = i * sliceCount + j + 1;
29576				var c = ( i + 1 ) * sliceCount + j + 1;
29577				var d = ( i + 1 ) * sliceCount + j;
29578  
29579				// faces one and two
29580  
29581				indices.push( a, b, d );
29582				indices.push( b, c, d );
29583  
29584			}
29585  
29586		}
29587  
29588		// build geometry
29589  
29590		this.setIndex( indices );
29591		this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
29592		this.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
29593		this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
29594  
29595	}
29596  
29597	ParametricBufferGeometry.prototype = Object.create( BufferGeometry.prototype );
29598	ParametricBufferGeometry.prototype.constructor = ParametricBufferGeometry;
29599  
29600	/**
29601	 * @author clockworkgeek / https://github.com/clockworkgeek
29602	 * @author timothypratley / https://github.com/timothypratley
29603	 * @author WestLangley / http://github.com/WestLangley
29604	 * @author Mugen87 / https://github.com/Mugen87
29605	 */
29606  
29607	// PolyhedronGeometry
29608  
29609	function PolyhedronGeometry( vertices, indices, radius, detail ) {
29610  
29611		Geometry.call( this );
29612  
29613		this.type = 'PolyhedronGeometry';
29614  
29615		this.parameters = {
29616			vertices: vertices,
29617			indices: indices,
29618			radius: radius,
29619			detail: detail
29620		};
29621  
29622		this.fromBufferGeometry( new PolyhedronBufferGeometry( vertices, indices, radius, detail ) );
29623		this.mergeVertices();
29624  
29625	}
29626  
29627	PolyhedronGeometry.prototype = Object.create( Geometry.prototype );
29628	PolyhedronGeometry.prototype.constructor = PolyhedronGeometry;
29629  
29630	// PolyhedronBufferGeometry
29631  
29632	function PolyhedronBufferGeometry( vertices, indices, radius, detail ) {
29633  
29634		BufferGeometry.call( this );
29635  
29636		this.type = 'PolyhedronBufferGeometry';
29637  
29638		this.parameters = {
29639			vertices: vertices,
29640			indices: indices,
29641			radius: radius,
29642			detail: detail
29643		};
29644  
29645		radius = radius || 1;
29646		detail = detail || 0;
29647  
29648		// default buffer data
29649  
29650		var vertexBuffer = [];
29651		var uvBuffer = [];
29652  
29653		// the subdivision creates the vertex buffer data
29654  
29655		subdivide( detail );
29656  
29657		// all vertices should lie on a conceptual sphere with a given radius
29658  
29659		appplyRadius( radius );
29660  
29661		// finally, create the uv data
29662  
29663		generateUVs();
29664  
29665		// build non-indexed geometry
29666  
29667		this.addAttribute( 'position', new Float32BufferAttribute( vertexBuffer, 3 ) );
29668		this.addAttribute( 'normal', new Float32BufferAttribute( vertexBuffer.slice(), 3 ) );
29669		this.addAttribute( 'uv', new Float32BufferAttribute( uvBuffer, 2 ) );
29670  
29671		if ( detail === 0 ) {
29672  
29673			this.computeVertexNormals(); // flat normals
29674  
29675		} else {
29676  
29677			this.normalizeNormals(); // smooth normals
29678  
29679		}
29680  
29681		// helper functions
29682  
29683		function subdivide( detail ) {
29684  
29685			var a = new Vector3();
29686			var b = new Vector3();
29687			var c = new Vector3();
29688  
29689			// iterate over all faces and apply a subdivison with the given detail value
29690  
29691			for ( var i = 0; i < indices.length; i += 3 ) {
29692  
29693				// get the vertices of the face
29694  
29695				getVertexByIndex( indices[ i + 0 ], a );
29696				getVertexByIndex( indices[ i + 1 ], b );
29697				getVertexByIndex( indices[ i + 2 ], c );
29698  
29699				// perform subdivision
29700  
29701				subdivideFace( a, b, c, detail );
29702  
29703			}
29704  
29705		}
29706  
29707		function subdivideFace( a, b, c, detail ) {
29708  
29709			var cols = Math.pow( 2, detail );
29710  
29711			// we use this multidimensional array as a data structure for creating the subdivision
29712  
29713			var v = [];
29714  
29715			var i, j;
29716  
29717			// construct all of the vertices for this subdivision
29718  
29719			for ( i = 0; i <= cols; i ++ ) {
29720  
29721				v[ i ] = [];
29722  
29723				var aj = a.clone().lerp( c, i / cols );
29724				var bj = b.clone().lerp( c, i / cols );
29725  
29726				var rows = cols - i;
29727  
29728				for ( j = 0; j <= rows; j ++ ) {
29729  
29730					if ( j === 0 && i === cols ) {
29731  
29732						v[ i ][ j ] = aj;
29733  
29734					} else {
29735  
29736						v[ i ][ j ] = aj.clone().lerp( bj, j / rows );
29737  
29738					}
29739  
29740				}
29741  
29742			}
29743  
29744			// construct all of the faces
29745  
29746			for ( i = 0; i < cols; i ++ ) {
29747  
29748				for ( j = 0; j < 2 * ( cols - i ) - 1; j ++ ) {
29749  
29750					var k = Math.floor( j / 2 );
29751  
29752					if ( j % 2 === 0 ) {
29753  
29754						pushVertex( v[ i ][ k + 1 ] );
29755						pushVertex( v[ i + 1 ][ k ] );
29756						pushVertex( v[ i ][ k ] );
29757  
29758					} else {
29759  
29760						pushVertex( v[ i ][ k + 1 ] );
29761						pushVertex( v[ i + 1 ][ k + 1 ] );
29762						pushVertex( v[ i + 1 ][ k ] );
29763  
29764					}
29765  
29766				}
29767  
29768			}
29769  
29770		}
29771  
29772		function appplyRadius( radius ) {
29773  
29774			var vertex = new Vector3();
29775  
29776			// iterate over the entire buffer and apply the radius to each vertex
29777  
29778			for ( var i = 0; i < vertexBuffer.length; i += 3 ) {
29779  
29780				vertex.x = vertexBuffer[ i + 0 ];
29781				vertex.y = vertexBuffer[ i + 1 ];
29782				vertex.z = vertexBuffer[ i + 2 ];
29783  
29784				vertex.normalize().multiplyScalar( radius );
29785  
29786				vertexBuffer[ i + 0 ] = vertex.x;
29787				vertexBuffer[ i + 1 ] = vertex.y;
29788				vertexBuffer[ i + 2 ] = vertex.z;
29789  
29790			}
29791  
29792		}
29793  
29794		function generateUVs() {
29795  
29796			var vertex = new Vector3();
29797  
29798			for ( var i = 0; i < vertexBuffer.length; i += 3 ) {
29799  
29800				vertex.x = vertexBuffer[ i + 0 ];
29801				vertex.y = vertexBuffer[ i + 1 ];
29802				vertex.z = vertexBuffer[ i + 2 ];
29803  
29804				var u = azimuth( vertex ) / 2 / Math.PI + 0.5;
29805				var v = inclination( vertex ) / Math.PI + 0.5;
29806				uvBuffer.push( u, 1 - v );
29807  
29808			}
29809  
29810			correctUVs();
29811  
29812			correctSeam();
29813  
29814		}
29815  
29816		function correctSeam() {
29817  
29818			// handle case when face straddles the seam, see #3269
29819  
29820			for ( var i = 0; i < uvBuffer.length; i += 6 ) {
29821  
29822				// uv data of a single face
29823  
29824				var x0 = uvBuffer[ i + 0 ];
29825				var x1 = uvBuffer[ i + 2 ];
29826				var x2 = uvBuffer[ i + 4 ];
29827  
29828				var max = Math.max( x0, x1, x2 );
29829				var min = Math.min( x0, x1, x2 );
29830  
29831				// 0.9 is somewhat arbitrary
29832  
29833				if ( max > 0.9 && min < 0.1 ) {
29834  
29835					if ( x0 < 0.2 ) uvBuffer[ i + 0 ] += 1;
29836					if ( x1 < 0.2 ) uvBuffer[ i + 2 ] += 1;
29837					if ( x2 < 0.2 ) uvBuffer[ i + 4 ] += 1;
29838  
29839				}
29840  
29841			}
29842  
29843		}
29844  
29845		function pushVertex( vertex ) {
29846  
29847			vertexBuffer.push( vertex.x, vertex.y, vertex.z );
29848  
29849		}
29850  
29851		function getVertexByIndex( index, vertex ) {
29852  
29853			var stride = index * 3;
29854  
29855			vertex.x = vertices[ stride + 0 ];
29856			vertex.y = vertices[ stride + 1 ];
29857			vertex.z = vertices[ stride + 2 ];
29858  
29859		}
29860  
29861		function correctUVs() {
29862  
29863			var a = new Vector3();
29864			var b = new Vector3();
29865			var c = new Vector3();
29866  
29867			var centroid = new Vector3();
29868  
29869			var uvA = new Vector2();
29870			var uvB = new Vector2();
29871			var uvC = new Vector2();
29872  
29873			for ( var i = 0, j = 0; i < vertexBuffer.length; i += 9, j += 6 ) {
29874  
29875				a.set( vertexBuffer[ i + 0 ], vertexBuffer[ i + 1 ], vertexBuffer[ i + 2 ] );
29876				b.set( vertexBuffer[ i + 3 ], vertexBuffer[ i + 4 ], vertexBuffer[ i + 5 ] );
29877				c.set( vertexBuffer[ i + 6 ], vertexBuffer[ i + 7 ], vertexBuffer[ i + 8 ] );
29878  
29879				uvA.set( uvBuffer[ j + 0 ], uvBuffer[ j + 1 ] );
29880				uvB.set( uvBuffer[ j + 2 ], uvBuffer[ j + 3 ] );
29881				uvC.set( uvBuffer[ j + 4 ], uvBuffer[ j + 5 ] );
29882  
29883				centroid.copy( a ).add( b ).add( c ).divideScalar( 3 );
29884  
29885				var azi = azimuth( centroid );
29886  
29887				correctUV( uvA, j + 0, a, azi );
29888				correctUV( uvB, j + 2, b, azi );
29889				correctUV( uvC, j + 4, c, azi );
29890  
29891			}
29892  
29893		}
29894  
29895		function correctUV( uv, stride, vector, azimuth ) {
29896  
29897			if ( ( azimuth < 0 ) && ( uv.x === 1 ) ) {
29898  
29899				uvBuffer[ stride ] = uv.x - 1;
29900  
29901			}
29902  
29903			if ( ( vector.x === 0 ) && ( vector.z === 0 ) ) {
29904  
29905				uvBuffer[ stride ] = azimuth / 2 / Math.PI + 0.5;
29906  
29907			}
29908  
29909		}
29910  
29911		// Angle around the Y axis, counter-clockwise when looking from above.
29912  
29913		function azimuth( vector ) {
29914  
29915			return Math.atan2( vector.z, - vector.x );
29916  
29917		}
29918  
29919  
29920		// Angle above the XZ plane.
29921  
29922		function inclination( vector ) {
29923  
29924			return Math.atan2( - vector.y, Math.sqrt( ( vector.x * vector.x ) + ( vector.z * vector.z ) ) );
29925  
29926		}
29927  
29928	}
29929  
29930	PolyhedronBufferGeometry.prototype = Object.create( BufferGeometry.prototype );
29931	PolyhedronBufferGeometry.prototype.constructor = PolyhedronBufferGeometry;
29932  
29933	/**
29934	 * @author timothypratley / https://github.com/timothypratley
29935	 * @author Mugen87 / https://github.com/Mugen87
29936	 */
29937  
29938	// TetrahedronGeometry
29939  
29940	function TetrahedronGeometry( radius, detail ) {
29941  
29942		Geometry.call( this );
29943  
29944		this.type = 'TetrahedronGeometry';
29945  
29946		this.parameters = {
29947			radius: radius,
29948			detail: detail
29949		};
29950  
29951		this.fromBufferGeometry( new TetrahedronBufferGeometry( radius, detail ) );
29952		this.mergeVertices();
29953  
29954	}
29955  
29956	TetrahedronGeometry.prototype = Object.create( Geometry.prototype );
29957	TetrahedronGeometry.prototype.constructor = TetrahedronGeometry;
29958  
29959	// TetrahedronBufferGeometry
29960  
29961	function TetrahedronBufferGeometry( radius, detail ) {
29962  
29963		var vertices = [
29964			1, 1, 1, 	- 1, - 1, 1, 	- 1, 1, - 1, 	1, - 1, - 1
29965		];
29966  
29967		var indices = [
29968			2, 1, 0, 	0, 3, 2,	1, 3, 0,	2, 3, 1
29969		];
29970  
29971		PolyhedronBufferGeometry.call( this, vertices, indices, radius, detail );
29972  
29973		this.type = 'TetrahedronBufferGeometry';
29974  
29975		this.parameters = {
29976			radius: radius,
29977			detail: detail
29978		};
29979  
29980	}
29981  
29982	TetrahedronBufferGeometry.prototype = Object.create( PolyhedronBufferGeometry.prototype );
29983	TetrahedronBufferGeometry.prototype.constructor = TetrahedronBufferGeometry;
29984  
29985	/**
29986	 * @author timothypratley / https://github.com/timothypratley
29987	 * @author Mugen87 / https://github.com/Mugen87
29988	 */
29989  
29990	// OctahedronGeometry
29991  
29992	function OctahedronGeometry( radius, detail ) {
29993  
29994		Geometry.call( this );
29995  
29996		this.type = 'OctahedronGeometry';
29997  
29998		this.parameters = {
29999			radius: radius,
30000			detail: detail
30001		};
30002  
30003		this.fromBufferGeometry( new OctahedronBufferGeometry( radius, detail ) );
30004		this.mergeVertices();
30005  
30006	}
30007  
30008	OctahedronGeometry.prototype = Object.create( Geometry.prototype );
30009	OctahedronGeometry.prototype.constructor = OctahedronGeometry;
30010  
30011	// OctahedronBufferGeometry
30012  
30013	function OctahedronBufferGeometry( radius, detail ) {
30014  
30015		var vertices = [
30016			1, 0, 0, 	- 1, 0, 0,	0, 1, 0,
30017			0, - 1, 0, 	0, 0, 1,	0, 0, - 1
30018		];
30019  
30020		var indices = [
30021			0, 2, 4,	0, 4, 3,	0, 3, 5,
30022			0, 5, 2,	1, 2, 5,	1, 5, 3,
30023			1, 3, 4,	1, 4, 2
30024		];
30025  
30026		PolyhedronBufferGeometry.call( this, vertices, indices, radius, detail );
30027  
30028		this.type = 'OctahedronBufferGeometry';
30029  
30030		this.parameters = {
30031			radius: radius,
30032			detail: detail
30033		};
30034  
30035	}
30036  
30037	OctahedronBufferGeometry.prototype = Object.create( PolyhedronBufferGeometry.prototype );
30038	OctahedronBufferGeometry.prototype.constructor = OctahedronBufferGeometry;
30039  
30040	/**
30041	 * @author timothypratley / https://github.com/timothypratley
30042	 * @author Mugen87 / https://github.com/Mugen87
30043	 */
30044  
30045	// IcosahedronGeometry
30046  
30047	function IcosahedronGeometry( radius, detail ) {
30048  
30049		Geometry.call( this );
30050  
30051		this.type = 'IcosahedronGeometry';
30052  
30053		this.parameters = {
30054			radius: radius,
30055			detail: detail
30056		};
30057  
30058		this.fromBufferGeometry( new IcosahedronBufferGeometry( radius, detail ) );
30059		this.mergeVertices();
30060  
30061	}
30062  
30063	IcosahedronGeometry.prototype = Object.create( Geometry.prototype );
30064	IcosahedronGeometry.prototype.constructor = IcosahedronGeometry;
30065  
30066	// IcosahedronBufferGeometry
30067  
30068	function IcosahedronBufferGeometry( radius, detail ) {
30069  
30070		var t = ( 1 + Math.sqrt( 5 ) ) / 2;
30071  
30072		var vertices = [
30073			- 1, t, 0, 	1, t, 0, 	- 1, - t, 0, 	1, - t, 0,
30074			 0, - 1, t, 	0, 1, t,	0, - 1, - t, 	0, 1, - t,
30075			 t, 0, - 1, 	t, 0, 1, 	- t, 0, - 1, 	- t, 0, 1
30076		];
30077  
30078		var indices = [
30079			 0, 11, 5, 	0, 5, 1, 	0, 1, 7, 	0, 7, 10, 	0, 10, 11,
30080			 1, 5, 9, 	5, 11, 4,	11, 10, 2,	10, 7, 6,	7, 1, 8,
30081			 3, 9, 4, 	3, 4, 2,	3, 2, 6,	3, 6, 8,	3, 8, 9,
30082			 4, 9, 5, 	2, 4, 11,	6, 2, 10,	8, 6, 7,	9, 8, 1
30083		];
30084  
30085		PolyhedronBufferGeometry.call( this, vertices, indices, radius, detail );
30086  
30087		this.type = 'IcosahedronBufferGeometry';
30088  
30089		this.parameters = {
30090			radius: radius,
30091			detail: detail
30092		};
30093  
30094	}
30095  
30096	IcosahedronBufferGeometry.prototype = Object.create( PolyhedronBufferGeometry.prototype );
30097	IcosahedronBufferGeometry.prototype.constructor = IcosahedronBufferGeometry;
30098  
30099	/**
30100	 * @author Abe Pazos / https://hamoid.com
30101	 * @author Mugen87 / https://github.com/Mugen87
30102	 */
30103  
30104	// DodecahedronGeometry
30105  
30106	function DodecahedronGeometry( radius, detail ) {
30107  
30108		Geometry.call( this );
30109  
30110		this.type = 'DodecahedronGeometry';
30111  
30112		this.parameters = {
30113			radius: radius,
30114			detail: detail
30115		};
30116  
30117		this.fromBufferGeometry( new DodecahedronBufferGeometry( radius, detail ) );
30118		this.mergeVertices();
30119  
30120	}
30121  
30122	DodecahedronGeometry.prototype = Object.create( Geometry.prototype );
30123	DodecahedronGeometry.prototype.constructor = DodecahedronGeometry;
30124  
30125	// DodecahedronBufferGeometry
30126  
30127	function DodecahedronBufferGeometry( radius, detail ) {
30128  
30129		var t = ( 1 + Math.sqrt( 5 ) ) / 2;
30130		var r = 1 / t;
30131  
30132		var vertices = [
30133  
30134			// (±1, ±1, ±1)
30135			- 1, - 1, - 1,	- 1, - 1, 1,
30136			- 1, 1, - 1, - 1, 1, 1,
30137			1, - 1, - 1, 1, - 1, 1,
30138			1, 1, - 1, 1, 1, 1,
30139  
30140			// (0, ±1/φ, ±φ)
30141			 0, - r, - t, 0, - r, t,
30142			 0, r, - t, 0, r, t,
30143  
30144			// (±1/φ, ±φ, 0)
30145			- r, - t, 0, - r, t, 0,
30146			 r, - t, 0, r, t, 0,
30147  
30148			// (±φ, 0, ±1/φ)
30149			- t, 0, - r, t, 0, - r,
30150			- t, 0, r, t, 0, r
30151		];
30152  
30153		var indices = [
30154			3, 11, 7, 	3, 7, 15, 	3, 15, 13,
30155			7, 19, 17, 	7, 17, 6, 	7, 6, 15,
30156			17, 4, 8, 	17, 8, 10, 	17, 10, 6,
30157			8, 0, 16, 	8, 16, 2, 	8, 2, 10,
30158			0, 12, 1, 	0, 1, 18, 	0, 18, 16,
30159			6, 10, 2, 	6, 2, 13, 	6, 13, 15,
30160			2, 16, 18, 	2, 18, 3, 	2, 3, 13,
30161			18, 1, 9, 	18, 9, 11, 	18, 11, 3,
30162			4, 14, 12, 	4, 12, 0, 	4, 0, 8,
30163			11, 9, 5, 	11, 5, 19, 	11, 19, 7,
30164			19, 5, 14, 	19, 14, 4, 	19, 4, 17,
30165			1, 12, 14, 	1, 14, 5, 	1, 5, 9
30166		];
30167  
30168		PolyhedronBufferGeometry.call( this, vertices, indices, radius, detail );
30169  
30170		this.type = 'DodecahedronBufferGeometry';
30171  
30172		this.parameters = {
30173			radius: radius,
30174			detail: detail
30175		};
30176  
30177	}
30178  
30179	DodecahedronBufferGeometry.prototype = Object.create( PolyhedronBufferGeometry.prototype );
30180	DodecahedronBufferGeometry.prototype.constructor = DodecahedronBufferGeometry;
30181  
30182	/**
30183	 * @author oosmoxiecode / https://github.com/oosmoxiecode
30184	 * @author WestLangley / https://github.com/WestLangley
30185	 * @author zz85 / https://github.com/zz85
30186	 * @author miningold / https://github.com/miningold
30187	 * @author jonobr1 / https://github.com/jonobr1
30188	 * @author Mugen87 / https://github.com/Mugen87
30189	 *
30190	 */
30191  
30192	// TubeGeometry
30193  
30194	function TubeGeometry( path, tubularSegments, radius, radialSegments, closed, taper ) {
30195  
30196		Geometry.call( this );
30197  
30198		this.type = 'TubeGeometry';
30199  
30200		this.parameters = {
30201			path: path,
30202			tubularSegments: tubularSegments,
30203			radius: radius,
30204			radialSegments: radialSegments,
30205			closed: closed
30206		};
30207  
30208		if ( taper !== undefined ) console.warn( 'THREE.TubeGeometry: taper has been removed.' );
30209  
30210		var bufferGeometry = new TubeBufferGeometry( path, tubularSegments, radius, radialSegments, closed );
30211  
30212		// expose internals
30213  
30214		this.tangents = bufferGeometry.tangents;
30215		this.normals = bufferGeometry.normals;
30216		this.binormals = bufferGeometry.binormals;
30217  
30218		// create geometry
30219  
30220		this.fromBufferGeometry( bufferGeometry );
30221		this.mergeVertices();
30222  
30223	}
30224  
30225	TubeGeometry.prototype = Object.create( Geometry.prototype );
30226	TubeGeometry.prototype.constructor = TubeGeometry;
30227  
30228	// TubeBufferGeometry
30229  
30230	function TubeBufferGeometry( path, tubularSegments, radius, radialSegments, closed ) {
30231  
30232		BufferGeometry.call( this );
30233  
30234		this.type = 'TubeBufferGeometry';
30235  
30236		this.parameters = {
30237			path: path,
30238			tubularSegments: tubularSegments,
30239			radius: radius,
30240			radialSegments: radialSegments,
30241			closed: closed
30242		};
30243  
30244		tubularSegments = tubularSegments || 64;
30245		radius = radius || 1;
30246		radialSegments = radialSegments || 8;
30247		closed = closed || false;
30248  
30249		var frames = path.computeFrenetFrames( tubularSegments, closed );
30250  
30251		// expose internals
30252  
30253		this.tangents = frames.tangents;
30254		this.normals = frames.normals;
30255		this.binormals = frames.binormals;
30256  
30257		// helper variables
30258  
30259		var vertex = new Vector3();
30260		var normal = new Vector3();
30261		var uv = new Vector2();
30262		var P = new Vector3();
30263  
30264		var i, j;
30265  
30266		// buffer
30267  
30268		var vertices = [];
30269		var normals = [];
30270		var uvs = [];
30271		var indices = [];
30272  
30273		// create buffer data
30274  
30275		generateBufferData();
30276  
30277		// build geometry
30278  
30279		this.setIndex( indices );
30280		this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
30281		this.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
30282		this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
30283  
30284		// functions
30285  
30286		function generateBufferData() {
30287  
30288			for ( i = 0; i < tubularSegments; i ++ ) {
30289  
30290				generateSegment( i );
30291  
30292			}
30293  
30294			// if the geometry is not closed, generate the last row of vertices and normals
30295			// at the regular position on the given path
30296			//
30297			// if the geometry is closed, duplicate the first row of vertices and normals (uvs will differ)
30298  
30299			generateSegment( ( closed === false ) ? tubularSegments : 0 );
30300  
30301			// uvs are generated in a separate function.
30302			// this makes it easy compute correct values for closed geometries
30303  
30304			generateUVs();
30305  
30306			// finally create faces
30307  
30308			generateIndices();
30309  
30310		}
30311  
30312		function generateSegment( i ) {
30313  
30314			// we use getPointAt to sample evenly distributed points from the given path
30315  
30316			P = path.getPointAt( i / tubularSegments, P );
30317  
30318			// retrieve corresponding normal and binormal
30319  
30320			var N = frames.normals[ i ];
30321			var B = frames.binormals[ i ];
30322  
30323			// generate normals and vertices for the current segment
30324  
30325			for ( j = 0; j <= radialSegments; j ++ ) {
30326  
30327				var v = j / radialSegments * Math.PI * 2;
30328  
30329				var sin = Math.sin( v );
30330				var cos = - Math.cos( v );
30331  
30332				// normal
30333  
30334				normal.x = ( cos * N.x + sin * B.x );
30335				normal.y = ( cos * N.y + sin * B.y );
30336				normal.z = ( cos * N.z + sin * B.z );
30337				normal.normalize();
30338  
30339				normals.push( normal.x, normal.y, normal.z );
30340  
30341				// vertex
30342  
30343				vertex.x = P.x + radius * normal.x;
30344				vertex.y = P.y + radius * normal.y;
30345				vertex.z = P.z + radius * normal.z;
30346  
30347				vertices.push( vertex.x, vertex.y, vertex.z );
30348  
30349			}
30350  
30351		}
30352  
30353		function generateIndices() {
30354  
30355			for ( j = 1; j <= tubularSegments; j ++ ) {
30356  
30357				for ( i = 1; i <= radialSegments; i ++ ) {
30358  
30359					var a = ( radialSegments + 1 ) * ( j - 1 ) + ( i - 1 );
30360					var b = ( radialSegments + 1 ) * j + ( i - 1 );
30361					var c = ( radialSegments + 1 ) * j + i;
30362					var d = ( radialSegments + 1 ) * ( j - 1 ) + i;
30363  
30364					// faces
30365  
30366					indices.push( a, b, d );
30367					indices.push( b, c, d );
30368  
30369				}
30370  
30371			}
30372  
30373		}
30374  
30375		function generateUVs() {
30376  
30377			for ( i = 0; i <= tubularSegments; i ++ ) {
30378  
30379				for ( j = 0; j <= radialSegments; j ++ ) {
30380  
30381					uv.x = i / tubularSegments;
30382					uv.y = j / radialSegments;
30383  
30384					uvs.push( uv.x, uv.y );
30385  
30386				}
30387  
30388			}
30389  
30390		}
30391  
30392	}
30393  
30394	TubeBufferGeometry.prototype = Object.create( BufferGeometry.prototype );
30395	TubeBufferGeometry.prototype.constructor = TubeBufferGeometry;
30396  
30397	/**
30398	 * @author oosmoxiecode
30399	 * @author Mugen87 / https://github.com/Mugen87
30400	 *
30401	 * based on http://www.blackpawn.com/texts/pqtorus/
30402	 */
30403  
30404	// TorusKnotGeometry
30405  
30406	function TorusKnotGeometry( radius, tube, tubularSegments, radialSegments, p, q, heightScale ) {
30407  
30408		Geometry.call( this );
30409  
30410		this.type = 'TorusKnotGeometry';
30411  
30412		this.parameters = {
30413			radius: radius,
30414			tube: tube,
30415			tubularSegments: tubularSegments,
30416			radialSegments: radialSegments,
30417			p: p,
30418			q: q
30419		};
30420  
30421		if ( heightScale !== undefined ) console.warn( 'THREE.TorusKnotGeometry: heightScale has been deprecated. Use .scale( x, y, z ) instead.' );
30422  
30423		this.fromBufferGeometry( new TorusKnotBufferGeometry( radius, tube, tubularSegments, radialSegments, p, q ) );
30424		this.mergeVertices();
30425  
30426	}
30427  
30428	TorusKnotGeometry.prototype = Object.create( Geometry.prototype );
30429	TorusKnotGeometry.prototype.constructor = TorusKnotGeometry;
30430  
30431	// TorusKnotBufferGeometry
30432  
30433	function TorusKnotBufferGeometry( radius, tube, tubularSegments, radialSegments, p, q ) {
30434  
30435		BufferGeometry.call( this );
30436  
30437		this.type = 'TorusKnotBufferGeometry';
30438  
30439		this.parameters = {
30440			radius: radius,
30441			tube: tube,
30442			tubularSegments: tubularSegments,
30443			radialSegments: radialSegments,
30444			p: p,
30445			q: q
30446		};
30447  
30448		radius = radius || 1;
30449		tube = tube || 0.4;
30450		tubularSegments = Math.floor( tubularSegments ) || 64;
30451		radialSegments = Math.floor( radialSegments ) || 8;
30452		p = p || 2;
30453		q = q || 3;
30454  
30455		// buffers
30456  
30457		var indices = [];
30458		var vertices = [];
30459		var normals = [];
30460		var uvs = [];
30461  
30462		// helper variables
30463  
30464		var i, j;
30465  
30466		var vertex = new Vector3();
30467		var normal = new Vector3();
30468  
30469		var P1 = new Vector3();
30470		var P2 = new Vector3();
30471  
30472		var B = new Vector3();
30473		var T = new Vector3();
30474		var N = new Vector3();
30475  
30476		// generate vertices, normals and uvs
30477  
30478		for ( i = 0; i <= tubularSegments; ++ i ) {
30479  
30480			// the radian "u" is used to calculate the position on the torus curve of the current tubular segement
30481  
30482			var u = i / tubularSegments * p * Math.PI * 2;
30483  
30484			// now we calculate two points. P1 is our current position on the curve, P2 is a little farther ahead.
30485			// these points are used to create a special "coordinate space", which is necessary to calculate the correct vertex positions
30486  
30487			calculatePositionOnCurve( u, p, q, radius, P1 );
30488			calculatePositionOnCurve( u + 0.01, p, q, radius, P2 );
30489  
30490			// calculate orthonormal basis
30491  
30492			T.subVectors( P2, P1 );
30493			N.addVectors( P2, P1 );
30494			B.crossVectors( T, N );
30495			N.crossVectors( B, T );
30496  
30497			// normalize B, N. T can be ignored, we don't use it
30498  
30499			B.normalize();
30500			N.normalize();
30501  
30502			for ( j = 0; j <= radialSegments; ++ j ) {
30503  
30504				// now calculate the vertices. they are nothing more than an extrusion of the torus curve.
30505				// because we extrude a shape in the xy-plane, there is no need to calculate a z-value.
30506  
30507				var v = j / radialSegments * Math.PI * 2;
30508				var cx = - tube * Math.cos( v );
30509				var cy = tube * Math.sin( v );
30510  
30511				// now calculate the final vertex position.
30512				// first we orient the extrusion with our basis vectos, then we add it to the current position on the curve
30513  
30514				vertex.x = P1.x + ( cx * N.x + cy * B.x );
30515				vertex.y = P1.y + ( cx * N.y + cy * B.y );
30516				vertex.z = P1.z + ( cx * N.z + cy * B.z );
30517  
30518				vertices.push( vertex.x, vertex.y, vertex.z );
30519  
30520				// normal (P1 is always the center/origin of the extrusion, thus we can use it to calculate the normal)
30521  
30522				normal.subVectors( vertex, P1 ).normalize();
30523  
30524				normals.push( normal.x, normal.y, normal.z );
30525  
30526				// uv
30527  
30528				uvs.push( i / tubularSegments );
30529				uvs.push( j / radialSegments );
30530  
30531			}
30532  
30533		}
30534  
30535		// generate indices
30536  
30537		for ( j = 1; j <= tubularSegments; j ++ ) {
30538  
30539			for ( i = 1; i <= radialSegments; i ++ ) {
30540  
30541				// indices
30542  
30543				var a = ( radialSegments + 1 ) * ( j - 1 ) + ( i - 1 );
30544				var b = ( radialSegments + 1 ) * j + ( i - 1 );
30545				var c = ( radialSegments + 1 ) * j + i;
30546				var d = ( radialSegments + 1 ) * ( j - 1 ) + i;
30547  
30548				// faces
30549  
30550				indices.push( a, b, d );
30551				indices.push( b, c, d );
30552  
30553			}
30554  
30555		}
30556  
30557		// build geometry
30558  
30559		this.setIndex( indices );
30560		this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
30561		this.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
30562		this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
30563  
30564		// this function calculates the current position on the torus curve
30565  
30566		function calculatePositionOnCurve( u, p, q, radius, position ) {
30567  
30568			var cu = Math.cos( u );
30569			var su = Math.sin( u );
30570			var quOverP = q / p * u;
30571			var cs = Math.cos( quOverP );
30572  
30573			position.x = radius * ( 2 + cs ) * 0.5 * cu;
30574			position.y = radius * ( 2 + cs ) * su * 0.5;
30575			position.z = radius * Math.sin( quOverP ) * 0.5;
30576  
30577		}
30578  
30579	}
30580  
30581	TorusKnotBufferGeometry.prototype = Object.create( BufferGeometry.prototype );
30582	TorusKnotBufferGeometry.prototype.constructor = TorusKnotBufferGeometry;
30583  
30584	/**
30585	 * @author oosmoxiecode
30586	 * @author mrdoob / http://mrdoob.com/
30587	 * @author Mugen87 / https://github.com/Mugen87
30588	 */
30589  
30590	// TorusGeometry
30591  
30592	function TorusGeometry( radius, tube, radialSegments, tubularSegments, arc ) {
30593  
30594		Geometry.call( this );
30595  
30596		this.type = 'TorusGeometry';
30597  
30598		this.parameters = {
30599			radius: radius,
30600			tube: tube,
30601			radialSegments: radialSegments,
30602			tubularSegments: tubularSegments,
30603			arc: arc
30604		};
30605  
30606		this.fromBufferGeometry( new TorusBufferGeometry( radius, tube, radialSegments, tubularSegments, arc ) );
30607		this.mergeVertices();
30608  
30609	}
30610  
30611	TorusGeometry.prototype = Object.create( Geometry.prototype );
30612	TorusGeometry.prototype.constructor = TorusGeometry;
30613  
30614	// TorusBufferGeometry
30615  
30616	function TorusBufferGeometry( radius, tube, radialSegments, tubularSegments, arc ) {
30617  
30618		BufferGeometry.call( this );
30619  
30620		this.type = 'TorusBufferGeometry';
30621  
30622		this.parameters = {
30623			radius: radius,
30624			tube: tube,
30625			radialSegments: radialSegments,
30626			tubularSegments: tubularSegments,
30627			arc: arc
30628		};
30629  
30630		radius = radius || 1;
30631		tube = tube || 0.4;
30632		radialSegments = Math.floor( radialSegments ) || 8;
30633		tubularSegments = Math.floor( tubularSegments ) || 6;
30634		arc = arc || Math.PI * 2;
30635  
30636		// buffers
30637  
30638		var indices = [];
30639		var vertices = [];
30640		var normals = [];
30641		var uvs = [];
30642  
30643		// helper variables
30644  
30645		var center = new Vector3();
30646		var vertex = new Vector3();
30647		var normal = new Vector3();
30648  
30649		var j, i;
30650  
30651		// generate vertices, normals and uvs
30652  
30653		for ( j = 0; j <= radialSegments; j ++ ) {
30654  
30655			for ( i = 0; i <= tubularSegments; i ++ ) {
30656  
30657				var u = i / tubularSegments * arc;
30658				var v = j / radialSegments * Math.PI * 2;
30659  
30660				// vertex
30661  
30662				vertex.x = ( radius + tube * Math.cos( v ) ) * Math.cos( u );
30663				vertex.y = ( radius + tube * Math.cos( v ) ) * Math.sin( u );
30664				vertex.z = tube * Math.sin( v );
30665  
30666				vertices.push( vertex.x, vertex.y, vertex.z );
30667  
30668				// normal
30669  
30670				center.x = radius * Math.cos( u );
30671				center.y = radius * Math.sin( u );
30672				normal.subVectors( vertex, center ).normalize();
30673  
30674				normals.push( normal.x, normal.y, normal.z );
30675  
30676				// uv
30677  
30678				uvs.push( i / tubularSegments );
30679				uvs.push( j / radialSegments );
30680  
30681			}
30682  
30683		}
30684  
30685		// generate indices
30686  
30687		for ( j = 1; j <= radialSegments; j ++ ) {
30688  
30689			for ( i = 1; i <= tubularSegments; i ++ ) {
30690  
30691				// indices
30692  
30693				var a = ( tubularSegments + 1 ) * j + i - 1;
30694				var b = ( tubularSegments + 1 ) * ( j - 1 ) + i - 1;
30695				var c = ( tubularSegments + 1 ) * ( j - 1 ) + i;
30696				var d = ( tubularSegments + 1 ) * j + i;
30697  
30698				// faces
30699  
30700				indices.push( a, b, d );
30701				indices.push( b, c, d );
30702  
30703			}
30704  
30705		}
30706  
30707		// build geometry
30708  
30709		this.setIndex( indices );
30710		this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
30711		this.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
30712		this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
30713  
30714	}
30715  
30716	TorusBufferGeometry.prototype = Object.create( BufferGeometry.prototype );
30717	TorusBufferGeometry.prototype.constructor = TorusBufferGeometry;
30718  
30719	/**
30720	 * @author Mugen87 / https://github.com/Mugen87
30721	 * Port from https://github.com/mapbox/earcut (v2.1.2)
30722	 */
30723  
30724	var Earcut = {
30725  
30726		triangulate: function ( data, holeIndices, dim ) {
30727  
30728			dim = dim || 2;
30729  
30730			var hasHoles = holeIndices && holeIndices.length,
30731				outerLen = hasHoles ? holeIndices[ 0 ] * dim : data.length,
30732				outerNode = linkedList( data, 0, outerLen, dim, true ),
30733				triangles = [];
30734  
30735			if ( ! outerNode ) return triangles;
30736  
30737			var minX, minY, maxX, maxY, x, y, invSize;
30738  
30739			if ( hasHoles ) outerNode = eliminateHoles( data, holeIndices, outerNode, dim );
30740  
30741			// if the shape is not too simple, we'll use z-order curve hash later; calculate polygon bbox
30742  
30743			if ( data.length > 80 * dim ) {
30744  
30745				minX = maxX = data[ 0 ];
30746				minY = maxY = data[ 1 ];
30747  
30748				for ( var i = dim; i < outerLen; i += dim ) {
30749  
30750					x = data[ i ];
30751					y = data[ i + 1 ];
30752					if ( x < minX ) minX = x;
30753					if ( y < minY ) minY = y;
30754					if ( x > maxX ) maxX = x;
30755					if ( y > maxY ) maxY = y;
30756  
30757				}
30758  
30759				// minX, minY and invSize are later used to transform coords into integers for z-order calculation
30760  
30761				invSize = Math.max( maxX - minX, maxY - minY );
30762				invSize = invSize !== 0 ? 1 / invSize : 0;
30763  
30764			}
30765  
30766			earcutLinked( outerNode, triangles, dim, minX, minY, invSize );
30767  
30768			return triangles;
30769  
30770		}
30771  
30772	};
30773  
30774	// create a circular doubly linked list from polygon points in the specified winding order
30775  
30776	function linkedList( data, start, end, dim, clockwise ) {
30777  
30778		var i, last;
30779  
30780		if ( clockwise === ( signedArea( data, start, end, dim ) > 0 ) ) {
30781  
30782			for ( i = start; i < end;
vendor: 12,853 bytes, lines 30782-31410
30782 i += dim ) last = insertNode( i, data[ i ], data[ i + 1 ], last );
30783  
30784		} else {
30785  
30786			for ( i = end - dim; i >= start; i -= dim ) last = insertNode( i, data[ i ], data[ i + 1 ], last );
30787  
30788		}
30789  
30790		if ( last && equals( last, last.next ) ) {
30791  
30792			removeNode( last );
30793			last = last.next;
30794  
30795		}
30796  
30797		return last;
30798  
30799	}
30800  
30801	// eliminate colinear or duplicate points
30802  
30803	function filterPoints( start, end ) {
30804  
30805		if ( ! start ) return start;
30806		if ( ! end ) end = start;
30807  
30808		var p = start, again;
30809  
30810		do {
30811  
30812			again = false;
30813  
30814			if ( ! p.steiner && ( equals( p, p.next ) || area( p.prev, p, p.next ) === 0 ) ) {
30815  
30816				removeNode( p );
30817				p = end = p.prev;
30818				if ( p === p.next ) break;
30819				again = true;
30820  
30821			} else {
30822  
30823				p = p.next;
30824  
30825			}
30826  
30827		} while ( again || p !== end );
30828  
30829		return end;
30830  
30831	}
30832  
30833	// main ear slicing loop which triangulates a polygon (given as a linked list)
30834  
30835	function earcutLinked( ear, triangles, dim, minX, minY, invSize, pass ) {
30836  
30837		if ( ! ear ) return;
30838  
30839		// interlink polygon nodes in z-order
30840  
30841		if ( ! pass && invSize ) indexCurve( ear, minX, minY, invSize );
30842  
30843		var stop = ear, prev, next;
30844  
30845		// iterate through ears, slicing them one by one
30846  
30847		while ( ear.prev !== ear.next ) {
30848  
30849			prev = ear.prev;
30850			next = ear.next;
30851  
30852			if ( invSize ? isEarHashed( ear, minX, minY, invSize ) : isEar( ear ) ) {
30853  
30854				// cut off the triangle
30855				triangles.push( prev.i / dim );
30856				triangles.push( ear.i / dim );
30857				triangles.push( next.i / dim );
30858  
30859				removeNode( ear );
30860  
30861				// skipping the next vertice leads to less sliver triangles
30862				ear = next.next;
30863				stop = next.next;
30864  
30865				continue;
30866  
30867			}
30868  
30869			ear = next;
30870  
30871			// if we looped through the whole remaining polygon and can't find any more ears
30872  
30873			if ( ear === stop ) {
30874  
30875				// try filtering points and slicing again
30876  
30877				if ( ! pass ) {
30878  
30879					earcutLinked( filterPoints( ear ), triangles, dim, minX, minY, invSize, 1 );
30880  
30881					// if this didn't work, try curing all small self-intersections locally
30882  
30883				} else if ( pass === 1 ) {
30884  
30885					ear = cureLocalIntersections( ear, triangles, dim );
30886					earcutLinked( ear, triangles, dim, minX, minY, invSize, 2 );
30887  
30888				// as a last resort, try splitting the remaining polygon into two
30889  
30890				} else if ( pass === 2 ) {
30891  
30892					splitEarcut( ear, triangles, dim, minX, minY, invSize );
30893  
30894				}
30895  
30896				break;
30897  
30898			}
30899  
30900		}
30901  
30902	}
30903  
30904	// check whether a polygon node forms a valid ear with adjacent nodes
30905  
30906	function isEar( ear ) {
30907  
30908		var a = ear.prev,
30909			b = ear,
30910			c = ear.next;
30911  
30912		if ( area( a, b, c ) >= 0 ) return false; // reflex, can't be an ear
30913  
30914		// now make sure we don't have other points inside the potential ear
30915		var p = ear.next.next;
30916  
30917		while ( p !== ear.prev ) {
30918  
30919			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 ) {
30920  
30921				return false;
30922  
30923			}
30924  
30925			p = p.next;
30926  
30927		}
30928  
30929		return true;
30930  
30931	}
30932  
30933	function isEarHashed( ear, minX, minY, invSize ) {
30934  
30935		var a = ear.prev,
30936			b = ear,
30937			c = ear.next;
30938  
30939		if ( area( a, b, c ) >= 0 ) return false; // reflex, can't be an ear
30940  
30941		// triangle bbox; min & max are calculated like this for speed
30942  
30943		var minTX = a.x < b.x ? ( a.x < c.x ? a.x : c.x ) : ( b.x < c.x ? b.x : c.x ),
30944			minTY = a.y < b.y ? ( a.y < c.y ? a.y : c.y ) : ( b.y < c.y ? b.y : c.y ),
30945			maxTX = a.x > b.x ? ( a.x > c.x ? a.x : c.x ) : ( b.x > c.x ? b.x : c.x ),
30946			maxTY = a.y > b.y ? ( a.y > c.y ? a.y : c.y ) : ( b.y > c.y ? b.y : c.y );
30947  
30948		// z-order range for the current triangle bbox;
30949  
30950		var minZ = zOrder( minTX, minTY, minX, minY, invSize ),
30951			maxZ = zOrder( maxTX, maxTY, minX, minY, invSize );
30952  
30953		// first look for points inside the triangle in increasing z-order
30954  
30955		var p = ear.nextZ;
30956  
30957		while ( p && p.z <= maxZ ) {
30958  
30959			if ( p !== ear.prev && p !== ear.next &&
30960					pointInTriangle( a.x, a.y, b.x, b.y, c.x, c.y, p.x, p.y ) &&
30961					area( p.prev, p, p.next ) >= 0 ) return false;
30962			p = p.nextZ;
30963  
30964		}
30965  
30966		// then look for points in decreasing z-order
30967  
30968		p = ear.prevZ;
30969  
30970		while ( p && p.z >= minZ ) {
30971  
30972			if ( p !== ear.prev && p !== ear.next &&
30973					pointInTriangle( a.x, a.y, b.x, b.y, c.x, c.y, p.x, p.y ) &&
30974					area( p.prev, p, p.next ) >= 0 ) return false;
30975  
30976			p = p.prevZ;
30977  
30978		}
30979  
30980		return true;
30981  
30982	}
30983  
30984	// go through all polygon nodes and cure small local self-intersections
30985  
30986	function cureLocalIntersections( start, triangles, dim ) {
30987  
30988		var p = start;
30989  
30990		do {
30991  
30992			var a = p.prev, b = p.next.next;
30993  
30994			if ( ! equals( a, b ) && intersects( a, p, p.next, b ) && locallyInside( a, b ) && locallyInside( b, a ) ) {
30995  
30996				triangles.push( a.i / dim );
30997				triangles.push( p.i / dim );
30998				triangles.push( b.i / dim );
30999  
31000				// remove two nodes involved
31001  
31002				removeNode( p );
31003				removeNode( p.next );
31004  
31005				p = start = b;
31006  
31007			}
31008  
31009			p = p.next;
31010  
31011		} while ( p !== start );
31012  
31013		return p;
31014  
31015	}
31016  
31017	// try splitting polygon into two and triangulate them independently
31018  
31019	function splitEarcut( start, triangles, dim, minX, minY, invSize ) {
31020  
31021		// look for a valid diagonal that divides the polygon into two
31022  
31023		var a = start;
31024  
31025		do {
31026  
31027			var b = a.next.next;
31028  
31029			while ( b !== a.prev ) {
31030  
31031				if ( a.i !== b.i && isValidDiagonal( a, b ) ) {
31032  
31033					// split the polygon in two by the diagonal
31034  
31035					var c = splitPolygon( a, b );
31036  
31037					// filter colinear points around the cuts
31038  
31039					a = filterPoints( a, a.next );
31040					c = filterPoints( c, c.next );
31041  
31042					// run earcut on each half
31043  
31044					earcutLinked( a, triangles, dim, minX, minY, invSize );
31045					earcutLinked( c, triangles, dim, minX, minY, invSize );
31046					return;
31047  
31048				}
31049  
31050				b = b.next;
31051  
31052			}
31053  
31054			a = a.next;
31055  
31056		} while ( a !== start );
31057  
31058	}
31059  
31060	// link every hole into the outer loop, producing a single-ring polygon without holes
31061  
31062	function eliminateHoles( data, holeIndices, outerNode, dim ) {
31063  
31064		var queue = [], i, len, start, end, list;
31065  
31066		for ( i = 0, len = holeIndices.length; i < len; i ++ ) {
31067  
31068			start = holeIndices[ i ] * dim;
31069			end = i < len - 1 ? holeIndices[ i + 1 ] * dim : data.length;
31070			list = linkedList( data, start, end, dim, false );
31071			if ( list === list.next ) list.steiner = true;
31072			queue.push( getLeftmost( list ) );
31073  
31074		}
31075  
31076		queue.sort( compareX );
31077  
31078		// process holes from left to right
31079  
31080		for ( i = 0; i < queue.length; i ++ ) {
31081  
31082			eliminateHole( queue[ i ], outerNode );
31083			outerNode = filterPoints( outerNode, outerNode.next );
31084  
31085		}
31086  
31087		return outerNode;
31088  
31089	}
31090  
31091	function compareX( a, b ) {
31092  
31093		return a.x - b.x;
31094  
31095	}
31096  
31097	// find a bridge between vertices that connects hole with an outer ring and and link it
31098  
31099	function eliminateHole( hole, outerNode ) {
31100  
31101		outerNode = findHoleBridge( hole, outerNode );
31102  
31103		if ( outerNode ) {
31104  
31105			var b = splitPolygon( outerNode, hole );
31106  
31107			filterPoints( b, b.next );
31108  
31109		}
31110  
31111	}
31112  
31113	// David Eberly's algorithm for finding a bridge between hole and outer polygon
31114  
31115	function findHoleBridge( hole, outerNode ) {
31116  
31117		var p = outerNode,
31118			hx = hole.x,
31119			hy = hole.y,
31120			qx = - Infinity,
31121			m;
31122  
31123		// find a segment intersected by a ray from the hole's leftmost point to the left;
31124		// segment's endpoint with lesser x will be potential connection point
31125  
31126		do {
31127  
31128			if ( hy <= p.y && hy >= p.next.y && p.next.y !== p.y ) {
31129  
31130				var x = p.x + ( hy - p.y ) * ( p.next.x - p.x ) / ( p.next.y - p.y );
31131  
31132				if ( x <= hx && x > qx ) {
31133  
31134					qx = x;
31135  
31136					if ( x === hx ) {
31137  
31138						if ( hy === p.y ) return p;
31139						if ( hy === p.next.y ) return p.next;
31140  
31141					}
31142  
31143					m = p.x < p.next.x ? p : p.next;
31144  
31145				}
31146  
31147			}
31148  
31149			p = p.next;
31150  
31151		} while ( p !== outerNode );
31152  
31153		if ( ! m ) return null;
31154  
31155		if ( hx === qx ) return m.prev; // hole touches outer segment; pick lower endpoint
31156  
31157		// look for points inside the triangle of hole point, segment intersection and endpoint;
31158		// if there are no points found, we have a valid connection;
31159		// otherwise choose the point of the minimum angle with the ray as connection point
31160  
31161		var stop = m,
31162			mx = m.x,
31163			my = m.y,
31164			tanMin = Infinity,
31165			tan;
31166  
31167		p = m.next;
31168  
31169		while ( p !== stop ) {
31170  
31171			if ( hx >= p.x && p.x >= mx && hx !== p.x &&
31172							pointInTriangle( hy < my ? hx : qx, hy, mx, my, hy < my ? qx : hx, hy, p.x, p.y ) ) {
31173  
31174				tan = Math.abs( hy - p.y ) / ( hx - p.x ); // tangential
31175  
31176				if ( ( tan < tanMin || ( tan === tanMin && p.x > m.x ) ) && locallyInside( p, hole ) ) {
31177  
31178					m = p;
31179					tanMin = tan;
31180  
31181				}
31182  
31183			}
31184  
31185			p = p.next;
31186  
31187		}
31188  
31189		return m;
31190  
31191	}
31192  
31193	// interlink polygon nodes in z-order
31194  
31195	function indexCurve( start, minX, minY, invSize ) {
31196  
31197		var p = start;
31198  
31199		do {
31200  
31201			if ( p.z === null ) p.z = zOrder( p.x, p.y, minX, minY, invSize );
31202			p.prevZ = p.prev;
31203			p.nextZ = p.next;
31204			p = p.next;
31205  
31206		} while ( p !== start );
31207  
31208		p.prevZ.nextZ = null;
31209		p.prevZ = null;
31210  
31211		sortLinked( p );
31212  
31213	}
31214  
31215	// Simon Tatham's linked list merge sort algorithm
31216	// http://www.chiark.greenend.org.uk/~sgtatham/algorithms/listsort.html
31217  
31218	function sortLinked( list ) {
31219  
31220		var i, p, q, e, tail, numMerges, pSize, qSize, inSize = 1;
31221  
31222		do {
31223  
31224			p = list;
31225			list = null;
31226			tail = null;
31227			numMerges = 0;
31228  
31229			while ( p ) {
31230  
31231				numMerges ++;
31232				q = p;
31233				pSize = 0;
31234  
31235				for ( i = 0; i < inSize; i ++ ) {
31236  
31237					pSize ++;
31238					q = q.nextZ;
31239					if ( ! q ) break;
31240  
31241				}
31242  
31243				qSize = inSize;
31244  
31245				while ( pSize > 0 || ( qSize > 0 && q ) ) {
31246  
31247					if ( pSize !== 0 && ( qSize === 0 || ! q || p.z <= q.z ) ) {
31248  
31249						e = p;
31250						p = p.nextZ;
31251						pSize --;
31252  
31253					} else {
31254  
31255						e = q;
31256						q = q.nextZ;
31257						qSize --;
31258  
31259					}
31260  
31261					if ( tail ) tail.nextZ = e;
31262					else list = e;
31263  
31264					e.prevZ = tail;
31265					tail = e;
31266  
31267				}
31268  
31269				p = q;
31270  
31271			}
31272  
31273			tail.nextZ = null;
31274			inSize *= 2;
31275  
31276		} while ( numMerges > 1 );
31277  
31278		return list;
31279  
31280	}
31281  
31282	// z-order of a point given coords and inverse of the longer side of data bbox
31283  
31284	function zOrder( x, y, minX, minY, invSize ) {
31285  
31286		// coords are transformed into non-negative 15-bit integer range
31287  
31288		x = 32767 * ( x - minX ) * invSize;
31289		y = 32767 * ( y - minY ) * invSize;
31290  
31291		x = ( x | ( x << 8 ) ) & 0x00FF00FF;
31292		x = ( x | ( x << 4 ) ) & 0x0F0F0F0F;
31293		x = ( x | ( x << 2 ) ) & 0x33333333;
31294		x = ( x | ( x << 1 ) ) & 0x55555555;
31295  
31296		y = ( y | ( y << 8 ) ) & 0x00FF00FF;
31297		y = ( y | ( y << 4 ) ) & 0x0F0F0F0F;
31298		y = ( y | ( y << 2 ) ) & 0x33333333;
31299		y = ( y | ( y << 1 ) ) & 0x55555555;
31300  
31301		return x | ( y << 1 );
31302  
31303	}
31304  
31305	// find the leftmost node of a polygon ring
31306  
31307	function getLeftmost( start ) {
31308  
31309		var p = start, leftmost = start;
31310  
31311		do {
31312  
31313			if ( p.x < leftmost.x ) leftmost = p;
31314			p = p.next;
31315  
31316		} while ( p !== start );
31317  
31318		return leftmost;
31319  
31320	}
31321  
31322	// check if a point lies within a convex triangle
31323  
31324	function pointInTriangle( ax, ay, bx, by, cx, cy, px, py ) {
31325  
31326		return ( cx - px ) * ( ay - py ) - ( ax - px ) * ( cy - py ) >= 0 &&
31327		 ( ax - px ) * ( by - py ) - ( bx - px ) * ( ay - py ) >= 0 &&
31328		 ( bx - px ) * ( cy - py ) - ( cx - px ) * ( by - py ) >= 0;
31329  
31330	}
31331  
31332	// check if a diagonal between two polygon nodes is valid (lies in polygon interior)
31333  
31334	function isValidDiagonal( a, b ) {
31335  
31336		return a.next.i !== b.i && a.prev.i !== b.i && ! intersectsPolygon( a, b ) &&
31337			locallyInside( a, b ) && locallyInside( b, a ) && middleInside( a, b );
31338  
31339	}
31340  
31341	// signed area of a triangle
31342  
31343	function area( p, q, r ) {
31344  
31345		return ( q.y - p.y ) * ( r.x - q.x ) - ( q.x - p.x ) * ( r.y - q.y );
31346  
31347	}
31348  
31349	// check if two points are equal
31350  
31351	function equals( p1, p2 ) {
31352  
31353		return p1.x === p2.x && p1.y === p2.y;
31354  
31355	}
31356  
31357	// check if two segments intersect
31358  
31359	function intersects( p1, q1, p2, q2 ) {
31360  
31361		if ( ( equals( p1, q1 ) && equals( p2, q2 ) ) ||
31362				( equals( p1, q2 ) && equals( p2, q1 ) ) ) return true;
31363  
31364		return area( p1, q1, p2 ) > 0 !== area( p1, q1, q2 ) > 0 &&
31365					 area( p2, q2, p1 ) > 0 !== area( p2, q2, q1 ) > 0;
31366  
31367	}
31368  
31369	// check if a polygon diagonal intersects any polygon segments
31370  
31371	function intersectsPolygon( a, b ) {
31372  
31373		var p = a;
31374  
31375		do {
31376  
31377			if ( p.i !== a.i && p.next.i !== a.i && p.i !== b.i && p.next.i !== b.i &&
31378							intersects( p, p.next, a, b ) ) {
31379  
31380				return true;
31381  
31382			}
31383  
31384			p = p.next;
31385  
31386		} while ( p !== a );
31387  
31388		return false;
31389  
31390	}
31391  
31392	// check if a polygon diagonal is locally inside the polygon
31393  
31394	function locallyInside( a, b ) {
31395  
31396		return area( a.prev, a, a.next ) < 0 ?
31397			area( a, b, a.next ) >= 0 && area( a, a.prev, b ) >= 0 :
31398			area( a, b, a.prev ) < 0 || area( a, a.next, b ) < 0;
31399  
31400	}
31401  
31402	// check if the middle point of a polygon diagonal is inside the polygon
31403  
31404	function middleInside( a, b ) {
31405  
31406		var p = a,
31407			inside = false,
31408			px = ( a.x + b.x ) / 2,
31409			py = ( a.y + b.y ) / 2;
31410  
vendor: 56,222 bytes, lines 31411-33904
31411		do {
31412  
31413			if ( ( ( p.y > py ) !== ( p.next.y > py ) ) && p.next.y !== p.y &&
31414							( px < ( p.next.x - p.x ) * ( py - p.y ) / ( p.next.y - p.y ) + p.x ) ) {
31415  
31416				inside = ! inside;
31417  
31418			}
31419  
31420			p = p.next;
31421  
31422		} while ( p !== a );
31423  
31424		return inside;
31425  
31426	}
31427  
31428	// link two polygon vertices with a bridge; if the vertices belong to the same ring, it splits polygon into two;
31429	// if one belongs to the outer ring and another to a hole, it merges it into a single ring
31430  
31431	function splitPolygon( a, b ) {
31432  
31433		var a2 = new Node( a.i, a.x, a.y ),
31434			b2 = new Node( b.i, b.x, b.y ),
31435			an = a.next,
31436			bp = b.prev;
31437  
31438		a.next = b;
31439		b.prev = a;
31440  
31441		a2.next = an;
31442		an.prev = a2;
31443  
31444		b2.next = a2;
31445		a2.prev = b2;
31446  
31447		bp.next = b2;
31448		b2.prev = bp;
31449  
31450		return b2;
31451  
31452	}
31453  
31454	// create a node and optionally link it with previous one (in a circular doubly linked list)
31455  
31456	function insertNode( i, x, y, last ) {
31457  
31458		var p = new Node( i, x, y );
31459  
31460		if ( ! last ) {
31461  
31462			p.prev = p;
31463			p.next = p;
31464  
31465		} else {
31466  
31467			p.next = last.next;
31468			p.prev = last;
31469			last.next.prev = p;
31470			last.next = p;
31471  
31472		}
31473  
31474		return p;
31475  
31476	}
31477  
31478	function removeNode( p ) {
31479  
31480		p.next.prev = p.prev;
31481		p.prev.next = p.next;
31482  
31483		if ( p.prevZ ) p.prevZ.nextZ = p.nextZ;
31484		if ( p.nextZ ) p.nextZ.prevZ = p.prevZ;
31485  
31486	}
31487  
31488	function Node( i, x, y ) {
31489  
31490		// vertice index in coordinates array
31491		this.i = i;
31492  
31493		// vertex coordinates
31494		this.x = x;
31495		this.y = y;
31496  
31497		// previous and next vertice nodes in a polygon ring
31498		this.prev = null;
31499		this.next = null;
31500  
31501		// z-order curve value
31502		this.z = null;
31503  
31504		// previous and next nodes in z-order
31505		this.prevZ = null;
31506		this.nextZ = null;
31507  
31508		// indicates whether this is a steiner point
31509		this.steiner = false;
31510  
31511	}
31512  
31513	function signedArea( data, start, end, dim ) {
31514  
31515		var sum = 0;
31516  
31517		for ( var i = start, j = end - dim; i < end; i += dim ) {
31518  
31519			sum += ( data[ j ] - data[ i ] ) * ( data[ i + 1 ] + data[ j + 1 ] );
31520			j = i;
31521  
31522		}
31523  
31524		return sum;
31525  
31526	}
31527  
31528	/**
31529	 * @author zz85 / http://www.lab4games.net/zz85/blog
31530	 */
31531  
31532	var ShapeUtils = {
31533  
31534		// calculate area of the contour polygon
31535  
31536		area: function ( contour ) {
31537  
31538			var n = contour.length;
31539			var a = 0.0;
31540  
31541			for ( var p = n - 1, q = 0; q < n; p = q ++ ) {
31542  
31543				a += contour[ p ].x * contour[ q ].y - contour[ q ].x * contour[ p ].y;
31544  
31545			}
31546  
31547			return a * 0.5;
31548  
31549		},
31550  
31551		isClockWise: function ( pts ) {
31552  
31553			return ShapeUtils.area( pts ) < 0;
31554  
31555		},
31556  
31557		triangulateShape: function ( contour, holes ) {
31558  
31559			var vertices = []; // flat array of vertices like [ x0,y0, x1,y1, x2,y2, ... ]
31560			var holeIndices = []; // array of hole indices
31561			var faces = []; // final array of vertex indices like [ [ a,b,d ], [ b,c,d ] ]
31562  
31563			removeDupEndPts( contour );
31564			addContour( vertices, contour );
31565  
31566			//
31567  
31568			var holeIndex = contour.length;
31569  
31570			holes.forEach( removeDupEndPts );
31571  
31572			for ( var i = 0; i < holes.length; i ++ ) {
31573  
31574				holeIndices.push( holeIndex );
31575				holeIndex += holes[ i ].length;
31576				addContour( vertices, holes[ i ] );
31577  
31578			}
31579  
31580			//
31581  
31582			var triangles = Earcut.triangulate( vertices, holeIndices );
31583  
31584			//
31585  
31586			for ( var i = 0; i < triangles.length; i += 3 ) {
31587  
31588				faces.push( triangles.slice( i, i + 3 ) );
31589  
31590			}
31591  
31592			return faces;
31593  
31594		}
31595  
31596	};
31597  
31598	function removeDupEndPts( points ) {
31599  
31600		var l = points.length;
31601  
31602		if ( l > 2 && points[ l - 1 ].equals( points[ 0 ] ) ) {
31603  
31604			points.pop();
31605  
31606		}
31607  
31608	}
31609  
31610	function addContour( vertices, contour ) {
31611  
31612		for ( var i = 0; i < contour.length; i ++ ) {
31613  
31614			vertices.push( contour[ i ].x );
31615			vertices.push( contour[ i ].y );
31616  
31617		}
31618  
31619	}
31620  
31621	/**
31622	 * @author zz85 / http://www.lab4games.net/zz85/blog
31623	 *
31624	 * Creates extruded geometry from a path shape.
31625	 *
31626	 * parameters = {
31627	 *
31628	 *  curveSegments: <int>, // number of points on the curves
31629	 *  steps: <int>, // number of points for z-side extrusions / used for subdividing segments of extrude spline too
31630	 *  depth: <float>, // Depth to extrude the shape
31631	 *
31632	 *  bevelEnabled: <bool>, // turn on bevel
31633	 *  bevelThickness: <float>, // how deep into the original shape bevel goes
31634	 *  bevelSize: <float>, // how far from shape outline is bevel
31635	 *  bevelSegments: <int>, // number of bevel layers
31636	 *
31637	 *  extrudePath: <THREE.Curve> // curve to extrude shape along
31638	 *
31639	 *  UVGenerator: <Object> // object that provides UV generator functions
31640	 *
31641	 * }
31642	 */
31643  
31644	// ExtrudeGeometry
31645  
31646	function ExtrudeGeometry( shapes, options ) {
31647  
31648		Geometry.call( this );
31649  
31650		this.type = 'ExtrudeGeometry';
31651  
31652		this.parameters = {
31653			shapes: shapes,
31654			options: options
31655		};
31656  
31657		this.fromBufferGeometry( new ExtrudeBufferGeometry( shapes, options ) );
31658		this.mergeVertices();
31659  
31660	}
31661  
31662	ExtrudeGeometry.prototype = Object.create( Geometry.prototype );
31663	ExtrudeGeometry.prototype.constructor = ExtrudeGeometry;
31664  
31665	ExtrudeGeometry.prototype.toJSON = function () {
31666  
31667		var data = Geometry.prototype.toJSON.call( this );
31668  
31669		var shapes = this.parameters.shapes;
31670		var options = this.parameters.options;
31671  
31672		return toJSON( shapes, options, data );
31673  
31674	};
31675  
31676	// ExtrudeBufferGeometry
31677  
31678	function ExtrudeBufferGeometry( shapes, options ) {
31679  
31680		BufferGeometry.call( this );
31681  
31682		this.type = 'ExtrudeBufferGeometry';
31683  
31684		this.parameters = {
31685			shapes: shapes,
31686			options: options
31687		};
31688  
31689		shapes = Array.isArray( shapes ) ? shapes : [ shapes ];
31690  
31691		var scope = this;
31692  
31693		var verticesArray = [];
31694		var uvArray = [];
31695  
31696		for ( var i = 0, l = shapes.length; i < l; i ++ ) {
31697  
31698			var shape = shapes[ i ];
31699			addShape( shape );
31700  
31701		}
31702  
31703		// build geometry
31704  
31705		this.addAttribute( 'position', new Float32BufferAttribute( verticesArray, 3 ) );
31706		this.addAttribute( 'uv', new Float32BufferAttribute( uvArray, 2 ) );
31707  
31708		this.computeVertexNormals();
31709  
31710		// functions
31711  
31712		function addShape( shape ) {
31713  
31714			var placeholder = [];
31715  
31716			// options
31717  
31718			var curveSegments = options.curveSegments !== undefined ? options.curveSegments : 12;
31719			var steps = options.steps !== undefined ? options.steps : 1;
31720			var depth = options.depth !== undefined ? options.depth : 100;
31721  
31722			var bevelEnabled = options.bevelEnabled !== undefined ? options.bevelEnabled : true;
31723			var bevelThickness = options.bevelThickness !== undefined ? options.bevelThickness : 6;
31724			var bevelSize = options.bevelSize !== undefined ? options.bevelSize : bevelThickness - 2;
31725			var bevelSegments = options.bevelSegments !== undefined ? options.bevelSegments : 3;
31726  
31727			var extrudePath = options.extrudePath;
31728  
31729			var uvgen = options.UVGenerator !== undefined ? options.UVGenerator : WorldUVGenerator;
31730  
31731			// deprecated options
31732  
31733			if ( options.amount !== undefined ) {
31734  
31735				console.warn( 'THREE.ExtrudeBufferGeometry: amount has been renamed to depth.' );
31736				depth = options.amount;
31737  
31738			}
31739  
31740			//
31741  
31742			var extrudePts, extrudeByPath = false;
31743			var splineTube, binormal, normal, position2;
31744  
31745			if ( extrudePath ) {
31746  
31747				extrudePts = extrudePath.getSpacedPoints( steps );
31748  
31749				extrudeByPath = true;
31750				bevelEnabled = false; // bevels not supported for path extrusion
31751  
31752				// SETUP TNB variables
31753  
31754				// TODO1 - have a .isClosed in spline?
31755  
31756				splineTube = extrudePath.computeFrenetFrames( steps, false );
31757  
31758				// console.log(splineTube, 'splineTube', splineTube.normals.length, 'steps', steps, 'extrudePts', extrudePts.length);
31759  
31760				binormal = new Vector3();
31761				normal = new Vector3();
31762				position2 = new Vector3();
31763  
31764			}
31765  
31766			// Safeguards if bevels are not enabled
31767  
31768			if ( ! bevelEnabled ) {
31769  
31770				bevelSegments = 0;
31771				bevelThickness = 0;
31772				bevelSize = 0;
31773  
31774			}
31775  
31776			// Variables initialization
31777  
31778			var ahole, h, hl; // looping of holes
31779  
31780			var shapePoints = shape.extractPoints( curveSegments );
31781  
31782			var vertices = shapePoints.shape;
31783			var holes = shapePoints.holes;
31784  
31785			var reverse = ! ShapeUtils.isClockWise( vertices );
31786  
31787			if ( reverse ) {
31788  
31789				vertices = vertices.reverse();
31790  
31791				// Maybe we should also check if holes are in the opposite direction, just to be safe ...
31792  
31793				for ( h = 0, hl = holes.length; h < hl; h ++ ) {
31794  
31795					ahole = holes[ h ];
31796  
31797					if ( ShapeUtils.isClockWise( ahole ) ) {
31798  
31799						holes[ h ] = ahole.reverse();
31800  
31801					}
31802  
31803				}
31804  
31805			}
31806  
31807  
31808			var faces = ShapeUtils.triangulateShape( vertices, holes );
31809  
31810			/* Vertices */
31811  
31812			var contour = vertices; // vertices has all points but contour has only points of circumference
31813  
31814			for ( h = 0, hl = holes.length; h < hl; h ++ ) {
31815  
31816				ahole = holes[ h ];
31817  
31818				vertices = vertices.concat( ahole );
31819  
31820			}
31821  
31822  
31823			function scalePt2( pt, vec, size ) {
31824  
31825				if ( ! vec ) console.error( "THREE.ExtrudeGeometry: vec does not exist" );
31826  
31827				return vec.clone().multiplyScalar( size ).add( pt );
31828  
31829			}
31830  
31831			var b, bs, t, z,
31832				vert, vlen = vertices.length,
31833				face, flen = faces.length;
31834  
31835  
31836			// Find directions for point movement
31837  
31838  
31839			function getBevelVec( inPt, inPrev, inNext ) {
31840  
31841				// computes for inPt the corresponding point inPt' on a new contour
31842				//   shifted by 1 unit (length of normalized vector) to the left
31843				// if we walk along contour clockwise, this new contour is outside the old one
31844				//
31845				// inPt' is the intersection of the two lines parallel to the two
31846				//  adjacent edges of inPt at a distance of 1 unit on the left side.
31847  
31848				var v_trans_x, v_trans_y, shrink_by; // resulting translation vector for inPt
31849  
31850				// good reading for geometry algorithms (here: line-line intersection)
31851				// http://geomalgorithms.com/a05-_intersect-1.html
31852  
31853				var v_prev_x = inPt.x - inPrev.x,
31854					v_prev_y = inPt.y - inPrev.y;
31855				var v_next_x = inNext.x - inPt.x,
31856					v_next_y = inNext.y - inPt.y;
31857  
31858				var v_prev_lensq = ( v_prev_x * v_prev_x + v_prev_y * v_prev_y );
31859  
31860				// check for collinear edges
31861				var collinear0 = ( v_prev_x * v_next_y - v_prev_y * v_next_x );
31862  
31863				if ( Math.abs( collinear0 ) > Number.EPSILON ) {
31864  
31865					// not collinear
31866  
31867					// length of vectors for normalizing
31868  
31869					var v_prev_len = Math.sqrt( v_prev_lensq );
31870					var v_next_len = Math.sqrt( v_next_x * v_next_x + v_next_y * v_next_y );
31871  
31872					// shift adjacent points by unit vectors to the left
31873  
31874					var ptPrevShift_x = ( inPrev.x - v_prev_y / v_prev_len );
31875					var ptPrevShift_y = ( inPrev.y + v_prev_x / v_prev_len );
31876  
31877					var ptNextShift_x = ( inNext.x - v_next_y / v_next_len );
31878					var ptNextShift_y = ( inNext.y + v_next_x / v_next_len );
31879  
31880					// scaling factor for v_prev to intersection point
31881  
31882					var sf = ( ( ptNextShift_x - ptPrevShift_x ) * v_next_y -
31883							( ptNextShift_y - ptPrevShift_y ) * v_next_x ) /
31884						( v_prev_x * v_next_y - v_prev_y * v_next_x );
31885  
31886					// vector from inPt to intersection point
31887  
31888					v_trans_x = ( ptPrevShift_x + v_prev_x * sf - inPt.x );
31889					v_trans_y = ( ptPrevShift_y + v_prev_y * sf - inPt.y );
31890  
31891					// Don't normalize!, otherwise sharp corners become ugly
31892					//  but prevent crazy spikes
31893					var v_trans_lensq = ( v_trans_x * v_trans_x + v_trans_y * v_trans_y );
31894					if ( v_trans_lensq <= 2 ) {
31895  
31896						return new Vector2( v_trans_x, v_trans_y );
31897  
31898					} else {
31899  
31900						shrink_by = Math.sqrt( v_trans_lensq / 2 );
31901  
31902					}
31903  
31904				} else {
31905  
31906					// handle special case of collinear edges
31907  
31908					var direction_eq = false; // assumes: opposite
31909					if ( v_prev_x > Number.EPSILON ) {
31910  
31911						if ( v_next_x > Number.EPSILON ) {
31912  
31913							direction_eq = true;
31914  
31915						}
31916  
31917					} else {
31918  
31919						if ( v_prev_x < - Number.EPSILON ) {
31920  
31921							if ( v_next_x < - Number.EPSILON ) {
31922  
31923								direction_eq = true;
31924  
31925							}
31926  
31927						} else {
31928  
31929							if ( Math.sign( v_prev_y ) === Math.sign( v_next_y ) ) {
31930  
31931								direction_eq = true;
31932  
31933							}
31934  
31935						}
31936  
31937					}
31938  
31939					if ( direction_eq ) {
31940  
31941						// console.log("Warning: lines are a straight sequence");
31942						v_trans_x = - v_prev_y;
31943						v_trans_y = v_prev_x;
31944						shrink_by = Math.sqrt( v_prev_lensq );
31945  
31946					} else {
31947  
31948						// console.log("Warning: lines are a straight spike");
31949						v_trans_x = v_prev_x;
31950						v_trans_y = v_prev_y;
31951						shrink_by = Math.sqrt( v_prev_lensq / 2 );
31952  
31953					}
31954  
31955				}
31956  
31957				return new Vector2( v_trans_x / shrink_by, v_trans_y / shrink_by );
31958  
31959			}
31960  
31961  
31962			var contourMovements = [];
31963  
31964			for ( var i = 0, il = contour.length, j = il - 1, k = i + 1; i < il; i ++, j ++, k ++ ) {
31965  
31966				if ( j === il ) j = 0;
31967				if ( k === il ) k = 0;
31968  
31969				//  (j)---(i)---(k)
31970				// console.log('i,j,k', i, j , k)
31971  
31972				contourMovements[ i ] = getBevelVec( contour[ i ], contour[ j ], contour[ k ] );
31973  
31974			}
31975  
31976			var holesMovements = [],
31977				oneHoleMovements, verticesMovements = contourMovements.concat();
31978  
31979			for ( h = 0, hl = holes.length; h < hl; h ++ ) {
31980  
31981				ahole = holes[ h ];
31982  
31983				oneHoleMovements = [];
31984  
31985				for ( i = 0, il = ahole.length, j = il - 1, k = i + 1; i < il; i ++, j ++, k ++ ) {
31986  
31987					if ( j === il ) j = 0;
31988					if ( k === il ) k = 0;
31989  
31990					//  (j)---(i)---(k)
31991					oneHoleMovements[ i ] = getBevelVec( ahole[ i ], ahole[ j ], ahole[ k ] );
31992  
31993				}
31994  
31995				holesMovements.push( oneHoleMovements );
31996				verticesMovements = verticesMovements.concat( oneHoleMovements );
31997  
31998			}
31999  
32000  
32001			// Loop bevelSegments, 1 for the front, 1 for the back
32002  
32003			for ( b = 0; b < bevelSegments; b ++ ) {
32004  
32005				//for ( b = bevelSegments; b > 0; b -- ) {
32006  
32007				t = b / bevelSegments;
32008				z = bevelThickness * Math.cos( t * Math.PI / 2 );
32009				bs = bevelSize * Math.sin( t * Math.PI / 2 );
32010  
32011				// contract shape
32012  
32013				for ( i = 0, il = contour.length; i < il; i ++ ) {
32014  
32015					vert = scalePt2( contour[ i ], contourMovements[ i ], bs );
32016  
32017					v( vert.x, vert.y, - z );
32018  
32019				}
32020  
32021				// expand holes
32022  
32023				for ( h = 0, hl = holes.length; h < hl; h ++ ) {
32024  
32025					ahole = holes[ h ];
32026					oneHoleMovements = holesMovements[ h ];
32027  
32028					for ( i = 0, il = ahole.length; i < il; i ++ ) {
32029  
32030						vert = scalePt2( ahole[ i ], oneHoleMovements[ i ], bs );
32031  
32032						v( vert.x, vert.y, - z );
32033  
32034					}
32035  
32036				}
32037  
32038			}
32039  
32040			bs = bevelSize;
32041  
32042			// Back facing vertices
32043  
32044			for ( i = 0; i < vlen; i ++ ) {
32045  
32046				vert = bevelEnabled ? scalePt2( vertices[ i ], verticesMovements[ i ], bs ) : vertices[ i ];
32047  
32048				if ( ! extrudeByPath ) {
32049  
32050					v( vert.x, vert.y, 0 );
32051  
32052				} else {
32053  
32054					// v( vert.x, vert.y + extrudePts[ 0 ].y, extrudePts[ 0 ].x );
32055  
32056					normal.copy( splineTube.normals[ 0 ] ).multiplyScalar( vert.x );
32057					binormal.copy( splineTube.binormals[ 0 ] ).multiplyScalar( vert.y );
32058  
32059					position2.copy( extrudePts[ 0 ] ).add( normal ).add( binormal );
32060  
32061					v( position2.x, position2.y, position2.z );
32062  
32063				}
32064  
32065			}
32066  
32067			// Add stepped vertices...
32068			// Including front facing vertices
32069  
32070			var s;
32071  
32072			for ( s = 1; s <= steps; s ++ ) {
32073  
32074				for ( i = 0; i < vlen; i ++ ) {
32075  
32076					vert = bevelEnabled ? scalePt2( vertices[ i ], verticesMovements[ i ], bs ) : vertices[ i ];
32077  
32078					if ( ! extrudeByPath ) {
32079  
32080						v( vert.x, vert.y, depth / steps * s );
32081  
32082					} else {
32083  
32084						// v( vert.x, vert.y + extrudePts[ s - 1 ].y, extrudePts[ s - 1 ].x );
32085  
32086						normal.copy( splineTube.normals[ s ] ).multiplyScalar( vert.x );
32087						binormal.copy( splineTube.binormals[ s ] ).multiplyScalar( vert.y );
32088  
32089						position2.copy( extrudePts[ s ] ).add( normal ).add( binormal );
32090  
32091						v( position2.x, position2.y, position2.z );
32092  
32093					}
32094  
32095				}
32096  
32097			}
32098  
32099  
32100			// Add bevel segments planes
32101  
32102			//for ( b = 1; b <= bevelSegments; b ++ ) {
32103			for ( b = bevelSegments - 1; b >= 0; b -- ) {
32104  
32105				t = b / bevelSegments;
32106				z = bevelThickness * Math.cos( t * Math.PI / 2 );
32107				bs = bevelSize * Math.sin( t * Math.PI / 2 );
32108  
32109				// contract shape
32110  
32111				for ( i = 0, il = contour.length; i < il; i ++ ) {
32112  
32113					vert = scalePt2( contour[ i ], contourMovements[ i ], bs );
32114					v( vert.x, vert.y, depth + z );
32115  
32116				}
32117  
32118				// expand holes
32119  
32120				for ( h = 0, hl = holes.length; h < hl; h ++ ) {
32121  
32122					ahole = holes[ h ];
32123					oneHoleMovements = holesMovements[ h ];
32124  
32125					for ( i = 0, il = ahole.length; i < il; i ++ ) {
32126  
32127						vert = scalePt2( ahole[ i ], oneHoleMovements[ i ], bs );
32128  
32129						if ( ! extrudeByPath ) {
32130  
32131							v( vert.x, vert.y, depth + z );
32132  
32133						} else {
32134  
32135							v( vert.x, vert.y + extrudePts[ steps - 1 ].y, extrudePts[ steps - 1 ].x + z );
32136  
32137						}
32138  
32139					}
32140  
32141				}
32142  
32143			}
32144  
32145			/* Faces */
32146  
32147			// Top and bottom faces
32148  
32149			buildLidFaces();
32150  
32151			// Sides faces
32152  
32153			buildSideFaces();
32154  
32155  
32156			/////  Internal functions
32157  
32158			function buildLidFaces() {
32159  
32160				var start = verticesArray.length / 3;
32161  
32162				if ( bevelEnabled ) {
32163  
32164					var layer = 0; // steps + 1
32165					var offset = vlen * layer;
32166  
32167					// Bottom faces
32168  
32169					for ( i = 0; i < flen; i ++ ) {
32170  
32171						face = faces[ i ];
32172						f3( face[ 2 ] + offset, face[ 1 ] + offset, face[ 0 ] + offset );
32173  
32174					}
32175  
32176					layer = steps + bevelSegments * 2;
32177					offset = vlen * layer;
32178  
32179					// Top faces
32180  
32181					for ( i = 0; i < flen; i ++ ) {
32182  
32183						face = faces[ i ];
32184						f3( face[ 0 ] + offset, face[ 1 ] + offset, face[ 2 ] + offset );
32185  
32186					}
32187  
32188				} else {
32189  
32190					// Bottom faces
32191  
32192					for ( i = 0; i < flen; i ++ ) {
32193  
32194						face = faces[ i ];
32195						f3( face[ 2 ], face[ 1 ], face[ 0 ] );
32196  
32197					}
32198  
32199					// Top faces
32200  
32201					for ( i = 0; i < flen; i ++ ) {
32202  
32203						face = faces[ i ];
32204						f3( face[ 0 ] + vlen * steps, face[ 1 ] + vlen * steps, face[ 2 ] + vlen * steps );
32205  
32206					}
32207  
32208				}
32209  
32210				scope.addGroup( start, verticesArray.length / 3 - start, 0 );
32211  
32212			}
32213  
32214			// Create faces for the z-sides of the shape
32215  
32216			function buildSideFaces() {
32217  
32218				var start = verticesArray.length / 3;
32219				var layeroffset = 0;
32220				sidewalls( contour, layeroffset );
32221				layeroffset += contour.length;
32222  
32223				for ( h = 0, hl = holes.length; h < hl; h ++ ) {
32224  
32225					ahole = holes[ h ];
32226					sidewalls( ahole, layeroffset );
32227  
32228					//, true
32229					layeroffset += ahole.length;
32230  
32231				}
32232  
32233  
32234				scope.addGroup( start, verticesArray.length / 3 - start, 1 );
32235  
32236  
32237			}
32238  
32239			function sidewalls( contour, layeroffset ) {
32240  
32241				var j, k;
32242				i = contour.length;
32243  
32244				while ( -- i >= 0 ) {
32245  
32246					j = i;
32247					k = i - 1;
32248					if ( k < 0 ) k = contour.length - 1;
32249  
32250					//console.log('b', i,j, i-1, k,vertices.length);
32251  
32252					var s = 0,
32253						sl = steps + bevelSegments * 2;
32254  
32255					for ( s = 0; s < sl; s ++ ) {
32256  
32257						var slen1 = vlen * s;
32258						var slen2 = vlen * ( s + 1 );
32259  
32260						var a = layeroffset + j + slen1,
32261							b = layeroffset + k + slen1,
32262							c = layeroffset + k + slen2,
32263							d = layeroffset + j + slen2;
32264  
32265						f4( a, b, c, d );
32266  
32267					}
32268  
32269				}
32270  
32271			}
32272  
32273			function v( x, y, z ) {
32274  
32275				placeholder.push( x );
32276				placeholder.push( y );
32277				placeholder.push( z );
32278  
32279			}
32280  
32281  
32282			function f3( a, b, c ) {
32283  
32284				addVertex( a );
32285				addVertex( b );
32286				addVertex( c );
32287  
32288				var nextIndex = verticesArray.length / 3;
32289				var uvs = uvgen.generateTopUV( scope, verticesArray, nextIndex - 3, nextIndex - 2, nextIndex - 1 );
32290  
32291				addUV( uvs[ 0 ] );
32292				addUV( uvs[ 1 ] );
32293				addUV( uvs[ 2 ] );
32294  
32295			}
32296  
32297			function f4( a, b, c, d ) {
32298  
32299				addVertex( a );
32300				addVertex( b );
32301				addVertex( d );
32302  
32303				addVertex( b );
32304				addVertex( c );
32305				addVertex( d );
32306  
32307  
32308				var nextIndex = verticesArray.length / 3;
32309				var uvs = uvgen.generateSideWallUV( scope, verticesArray, nextIndex - 6, nextIndex - 3, nextIndex - 2, nextIndex - 1 );
32310  
32311				addUV( uvs[ 0 ] );
32312				addUV( uvs[ 1 ] );
32313				addUV( uvs[ 3 ] );
32314  
32315				addUV( uvs[ 1 ] );
32316				addUV( uvs[ 2 ] );
32317				addUV( uvs[ 3 ] );
32318  
32319			}
32320  
32321			function addVertex( index ) {
32322  
32323				verticesArray.push( placeholder[ index * 3 + 0 ] );
32324				verticesArray.push( placeholder[ index * 3 + 1 ] );
32325				verticesArray.push( placeholder[ index * 3 + 2 ] );
32326  
32327			}
32328  
32329  
32330			function addUV( vector2 ) {
32331  
32332				uvArray.push( vector2.x );
32333				uvArray.push( vector2.y );
32334  
32335			}
32336  
32337		}
32338  
32339	}
32340  
32341	ExtrudeBufferGeometry.prototype = Object.create( BufferGeometry.prototype );
32342	ExtrudeBufferGeometry.prototype.constructor = ExtrudeBufferGeometry;
32343  
32344	ExtrudeBufferGeometry.prototype.toJSON = function () {
32345  
32346		var data = BufferGeometry.prototype.toJSON.call( this );
32347  
32348		var shapes = this.parameters.shapes;
32349		var options = this.parameters.options;
32350  
32351		return toJSON( shapes, options, data );
32352  
32353	};
32354  
32355	//
32356  
32357	var WorldUVGenerator = {
32358  
32359		generateTopUV: function ( geometry, vertices, indexA, indexB, indexC ) {
32360  
32361			var a_x = vertices[ indexA * 3 ];
32362			var a_y = vertices[ indexA * 3 + 1 ];
32363			var b_x = vertices[ indexB * 3 ];
32364			var b_y = vertices[ indexB * 3 + 1 ];
32365			var c_x = vertices[ indexC * 3 ];
32366			var c_y = vertices[ indexC * 3 + 1 ];
32367  
32368			return [
32369				new Vector2( a_x, a_y ),
32370				new Vector2( b_x, b_y ),
32371				new Vector2( c_x, c_y )
32372			];
32373  
32374		},
32375  
32376		generateSideWallUV: function ( geometry, vertices, indexA, indexB, indexC, indexD ) {
32377  
32378			var a_x = vertices[ indexA * 3 ];
32379			var a_y = vertices[ indexA * 3 + 1 ];
32380			var a_z = vertices[ indexA * 3 + 2 ];
32381			var b_x = vertices[ indexB * 3 ];
32382			var b_y = vertices[ indexB * 3 + 1 ];
32383			var b_z = vertices[ indexB * 3 + 2 ];
32384			var c_x = vertices[ indexC * 3 ];
32385			var c_y = vertices[ indexC * 3 + 1 ];
32386			var c_z = vertices[ indexC * 3 + 2 ];
32387			var d_x = vertices[ indexD * 3 ];
32388			var d_y = vertices[ indexD * 3 + 1 ];
32389			var d_z = vertices[ indexD * 3 + 2 ];
32390  
32391			if ( Math.abs( a_y - b_y ) < 0.01 ) {
32392  
32393				return [
32394					new Vector2( a_x, 1 - a_z ),
32395					new Vector2( b_x, 1 - b_z ),
32396					new Vector2( c_x, 1 - c_z ),
32397					new Vector2( d_x, 1 - d_z )
32398				];
32399  
32400			} else {
32401  
32402				return [
32403					new Vector2( a_y, 1 - a_z ),
32404					new Vector2( b_y, 1 - b_z ),
32405					new Vector2( c_y, 1 - c_z ),
32406					new Vector2( d_y, 1 - d_z )
32407				];
32408  
32409			}
32410  
32411		}
32412	};
32413  
32414	function toJSON( shapes, options, data ) {
32415  
32416		//
32417  
32418		data.shapes = [];
32419  
32420		if ( Array.isArray( shapes ) ) {
32421  
32422			for ( var i = 0, l = shapes.length; i < l; i ++ ) {
32423  
32424				var shape = shapes[ i ];
32425  
32426				data.shapes.push( shape.uuid );
32427  
32428			}
32429  
32430		} else {
32431  
32432			data.shapes.push( shapes.uuid );
32433  
32434		}
32435  
32436		//
32437  
32438		if ( options.extrudePath !== undefined ) data.options.extrudePath = options.extrudePath.toJSON();
32439  
32440		return data;
32441  
32442	}
32443  
32444	/**
32445	 * @author zz85 / http://www.lab4games.net/zz85/blog
32446	 * @author alteredq / http://alteredqualia.com/
32447	 *
32448	 * Text = 3D Text
32449	 *
32450	 * parameters = {
32451	 *  font: <THREE.Font>, // font
32452	 *
32453	 *  size: <float>, // size of the text
32454	 *  height: <float>, // thickness to extrude text
32455	 *  curveSegments: <int>, // number of points on the curves
32456	 *
32457	 *  bevelEnabled: <bool>, // turn on bevel
32458	 *  bevelThickness: <float>, // how deep into text bevel goes
32459	 *  bevelSize: <float> // how far from text outline is bevel
32460	 * }
32461	 */
32462  
32463	// TextGeometry
32464  
32465	function TextGeometry( text, parameters ) {
32466  
32467		Geometry.call( this );
32468  
32469		this.type = 'TextGeometry';
32470  
32471		this.parameters = {
32472			text: text,
32473			parameters: parameters
32474		};
32475  
32476		this.fromBufferGeometry( new TextBufferGeometry( text, parameters ) );
32477		this.mergeVertices();
32478  
32479	}
32480  
32481	TextGeometry.prototype = Object.create( Geometry.prototype );
32482	TextGeometry.prototype.constructor = TextGeometry;
32483  
32484	// TextBufferGeometry
32485  
32486	function TextBufferGeometry( text, parameters ) {
32487  
32488		parameters = parameters || {};
32489  
32490		var font = parameters.font;
32491  
32492		if ( ! ( font && font.isFont ) ) {
32493  
32494			console.error( 'THREE.TextGeometry: font parameter is not an instance of THREE.Font.' );
32495			return new Geometry();
32496  
32497		}
32498  
32499		var shapes = font.generateShapes( text, parameters.size, parameters.curveSegments );
32500  
32501		// translate parameters to ExtrudeGeometry API
32502  
32503		parameters.depth = parameters.height !== undefined ? parameters.height : 50;
32504  
32505		// defaults
32506  
32507		if ( parameters.bevelThickness === undefined ) parameters.bevelThickness = 10;
32508		if ( parameters.bevelSize === undefined ) parameters.bevelSize = 8;
32509		if ( parameters.bevelEnabled === undefined ) parameters.bevelEnabled = false;
32510  
32511		ExtrudeBufferGeometry.call( this, shapes, parameters );
32512  
32513		this.type = 'TextBufferGeometry';
32514  
32515	}
32516  
32517	TextBufferGeometry.prototype = Object.create( ExtrudeBufferGeometry.prototype );
32518	TextBufferGeometry.prototype.constructor = TextBufferGeometry;
32519  
32520	/**
32521	 * @author mrdoob / http://mrdoob.com/
32522	 * @author benaadams / https://twitter.com/ben_a_adams
32523	 * @author Mugen87 / https://github.com/Mugen87
32524	 */
32525  
32526	// SphereGeometry
32527  
32528	function SphereGeometry( radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength ) {
32529  
32530		Geometry.call( this );
32531  
32532		this.type = 'SphereGeometry';
32533  
32534		this.parameters = {
32535			radius: radius,
32536			widthSegments: widthSegments,
32537			heightSegments: heightSegments,
32538			phiStart: phiStart,
32539			phiLength: phiLength,
32540			thetaStart: thetaStart,
32541			thetaLength: thetaLength
32542		};
32543  
32544		this.fromBufferGeometry( new SphereBufferGeometry( radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength ) );
32545		this.mergeVertices();
32546  
32547	}
32548  
32549	SphereGeometry.prototype = Object.create( Geometry.prototype );
32550	SphereGeometry.prototype.constructor = SphereGeometry;
32551  
32552	// SphereBufferGeometry
32553  
32554	function SphereBufferGeometry( radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength ) {
32555  
32556		BufferGeometry.call( this );
32557  
32558		this.type = 'SphereBufferGeometry';
32559  
32560		this.parameters = {
32561			radius: radius,
32562			widthSegments: widthSegments,
32563			heightSegments: heightSegments,
32564			phiStart: phiStart,
32565			phiLength: phiLength,
32566			thetaStart: thetaStart,
32567			thetaLength: thetaLength
32568		};
32569  
32570		radius = radius || 1;
32571  
32572		widthSegments = Math.max( 3, Math.floor( widthSegments ) || 8 );
32573		heightSegments = Math.max( 2, Math.floor( heightSegments ) || 6 );
32574  
32575		phiStart = phiStart !== undefined ? phiStart : 0;
32576		phiLength = phiLength !== undefined ? phiLength : Math.PI * 2;
32577  
32578		thetaStart = thetaStart !== undefined ? thetaStart : 0;
32579		thetaLength = thetaLength !== undefined ? thetaLength : Math.PI;
32580  
32581		var thetaEnd = thetaStart + thetaLength;
32582  
32583		var ix, iy;
32584  
32585		var index = 0;
32586		var grid = [];
32587  
32588		var vertex = new Vector3();
32589		var normal = new Vector3();
32590  
32591		// buffers
32592  
32593		var indices = [];
32594		var vertices = [];
32595		var normals = [];
32596		var uvs = [];
32597  
32598		// generate vertices, normals and uvs
32599  
32600		for ( iy = 0; iy <= heightSegments; iy ++ ) {
32601  
32602			var verticesRow = [];
32603  
32604			var v = iy / heightSegments;
32605  
32606			for ( ix = 0; ix <= widthSegments; ix ++ ) {
32607  
32608				var u = ix / widthSegments;
32609  
32610				// vertex
32611  
32612				vertex.x = - radius * Math.cos( phiStart + u * phiLength ) * Math.sin( thetaStart + v * thetaLength );
32613				vertex.y = radius * Math.cos( thetaStart + v * thetaLength );
32614				vertex.z = radius * Math.sin( phiStart + u * phiLength ) * Math.sin( thetaStart + v * thetaLength );
32615  
32616				vertices.push( vertex.x, vertex.y, vertex.z );
32617  
32618				// normal
32619  
32620				normal.set( vertex.x, vertex.y, vertex.z ).normalize();
32621				normals.push( normal.x, normal.y, normal.z );
32622  
32623				// uv
32624  
32625				uvs.push( u, 1 - v );
32626  
32627				verticesRow.push( index ++ );
32628  
32629			}
32630  
32631			grid.push( verticesRow );
32632  
32633		}
32634  
32635		// indices
32636  
32637		for ( iy = 0; iy < heightSegments; iy ++ ) {
32638  
32639			for ( ix = 0; ix < widthSegments; ix ++ ) {
32640  
32641				var a = grid[ iy ][ ix + 1 ];
32642				var b = grid[ iy ][ ix ];
32643				var c = grid[ iy + 1 ][ ix ];
32644				var d = grid[ iy + 1 ][ ix + 1 ];
32645  
32646				if ( iy !== 0 || thetaStart > 0 ) indices.push( a, b, d );
32647				if ( iy !== heightSegments - 1 || thetaEnd < Math.PI ) indices.push( b, c, d );
32648  
32649			}
32650  
32651		}
32652  
32653		// build geometry
32654  
32655		this.setIndex( indices );
32656		this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
32657		this.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
32658		this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
32659  
32660	}
32661  
32662	SphereBufferGeometry.prototype = Object.create( BufferGeometry.prototype );
32663	SphereBufferGeometry.prototype.constructor = SphereBufferGeometry;
32664  
32665	/**
32666	 * @author Kaleb Murphy
32667	 * @author Mugen87 / https://github.com/Mugen87
32668	 */
32669  
32670	// RingGeometry
32671  
32672	function RingGeometry( innerRadius, outerRadius, thetaSegments, phiSegments, thetaStart, thetaLength ) {
32673  
32674		Geometry.call( this );
32675  
32676		this.type = 'RingGeometry';
32677  
32678		this.parameters = {
32679			innerRadius: innerRadius,
32680			outerRadius: outerRadius,
32681			thetaSegments: thetaSegments,
32682			phiSegments: phiSegments,
32683			thetaStart: thetaStart,
32684			thetaLength: thetaLength
32685		};
32686  
32687		this.fromBufferGeometry( new RingBufferGeometry( innerRadius, outerRadius, thetaSegments, phiSegments, thetaStart, thetaLength ) );
32688		this.mergeVertices();
32689  
32690	}
32691  
32692	RingGeometry.prototype = Object.create( Geometry.prototype );
32693	RingGeometry.prototype.constructor = RingGeometry;
32694  
32695	// RingBufferGeometry
32696  
32697	function RingBufferGeometry( innerRadius, outerRadius, thetaSegments, phiSegments, thetaStart, thetaLength ) {
32698  
32699		BufferGeometry.call( this );
32700  
32701		this.type = 'RingBufferGeometry';
32702  
32703		this.parameters = {
32704			innerRadius: innerRadius,
32705			outerRadius: outerRadius,
32706			thetaSegments: thetaSegments,
32707			phiSegments: phiSegments,
32708			thetaStart: thetaStart,
32709			thetaLength: thetaLength
32710		};
32711  
32712		innerRadius = innerRadius || 0.5;
32713		outerRadius = outerRadius || 1;
32714  
32715		thetaStart = thetaStart !== undefined ? thetaStart : 0;
32716		thetaLength = thetaLength !== undefined ? thetaLength : Math.PI * 2;
32717  
32718		thetaSegments = thetaSegments !== undefined ? Math.max( 3, thetaSegments ) : 8;
32719		phiSegments = phiSegments !== undefined ? Math.max( 1, phiSegments ) : 1;
32720  
32721		// buffers
32722  
32723		var indices = [];
32724		var vertices = [];
32725		var normals = [];
32726		var uvs = [];
32727  
32728		// some helper variables
32729  
32730		var segment;
32731		var radius = innerRadius;
32732		var radiusStep = ( ( outerRadius - innerRadius ) / phiSegments );
32733		var vertex = new Vector3();
32734		var uv = new Vector2();
32735		var j, i;
32736  
32737		// generate vertices, normals and uvs
32738  
32739		for ( j = 0; j <= phiSegments; j ++ ) {
32740  
32741			for ( i = 0; i <= thetaSegments; i ++ ) {
32742  
32743				// values are generate from the inside of the ring to the outside
32744  
32745				segment = thetaStart + i / thetaSegments * thetaLength;
32746  
32747				// vertex
32748  
32749				vertex.x = radius * Math.cos( segment );
32750				vertex.y = radius * Math.sin( segment );
32751  
32752				vertices.push( vertex.x, vertex.y, vertex.z );
32753  
32754				// normal
32755  
32756				normals.push( 0, 0, 1 );
32757  
32758				// uv
32759  
32760				uv.x = ( vertex.x / outerRadius + 1 ) / 2;
32761				uv.y = ( vertex.y / outerRadius + 1 ) / 2;
32762  
32763				uvs.push( uv.x, uv.y );
32764  
32765			}
32766  
32767			// increase the radius for next row of vertices
32768  
32769			radius += radiusStep;
32770  
32771		}
32772  
32773		// indices
32774  
32775		for ( j = 0; j < phiSegments; j ++ ) {
32776  
32777			var thetaSegmentLevel = j * ( thetaSegments + 1 );
32778  
32779			for ( i = 0; i < thetaSegments; i ++ ) {
32780  
32781				segment = i + thetaSegmentLevel;
32782  
32783				var a = segment;
32784				var b = segment + thetaSegments + 1;
32785				var c = segment + thetaSegments + 2;
32786				var d = segment + 1;
32787  
32788				// faces
32789  
32790				indices.push( a, b, d );
32791				indices.push( b, c, d );
32792  
32793			}
32794  
32795		}
32796  
32797		// build geometry
32798  
32799		this.setIndex( indices );
32800		this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
32801		this.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
32802		this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
32803  
32804	}
32805  
32806	RingBufferGeometry.prototype = Object.create( BufferGeometry.prototype );
32807	RingBufferGeometry.prototype.constructor = RingBufferGeometry;
32808  
32809	/**
32810	 * @author astrodud / http://astrodud.isgreat.org/
32811	 * @author zz85 / https://github.com/zz85
32812	 * @author bhouston / http://clara.io
32813	 * @author Mugen87 / https://github.com/Mugen87
32814	 */
32815  
32816	// LatheGeometry
32817  
32818	function LatheGeometry( points, segments, phiStart, phiLength ) {
32819  
32820		Geometry.call( this );
32821  
32822		this.type = 'LatheGeometry';
32823  
32824		this.parameters = {
32825			points: points,
32826			segments: segments,
32827			phiStart: phiStart,
32828			phiLength: phiLength
32829		};
32830  
32831		this.fromBufferGeometry( new LatheBufferGeometry( points, segments, phiStart, phiLength ) );
32832		this.mergeVertices();
32833  
32834	}
32835  
32836	LatheGeometry.prototype = Object.create( Geometry.prototype );
32837	LatheGeometry.prototype.constructor = LatheGeometry;
32838  
32839	// LatheBufferGeometry
32840  
32841	function LatheBufferGeometry( points, segments, phiStart, phiLength ) {
32842  
32843		BufferGeometry.call( this );
32844  
32845		this.type = 'LatheBufferGeometry';
32846  
32847		this.parameters = {
32848			points: points,
32849			segments: segments,
32850			phiStart: phiStart,
32851			phiLength: phiLength
32852		};
32853  
32854		segments = Math.floor( segments ) || 12;
32855		phiStart = phiStart || 0;
32856		phiLength = phiLength || Math.PI * 2;
32857  
32858		// clamp phiLength so it's in range of [ 0, 2PI ]
32859  
32860		phiLength = _Math.clamp( phiLength, 0, Math.PI * 2 );
32861  
32862  
32863		// buffers
32864  
32865		var indices = [];
32866		var vertices = [];
32867		var uvs = [];
32868  
32869		// helper variables
32870  
32871		var base;
32872		var inverseSegments = 1.0 / segments;
32873		var vertex = new Vector3();
32874		var uv = new Vector2();
32875		var i, j;
32876  
32877		// generate vertices and uvs
32878  
32879		for ( i = 0; i <= segments; i ++ ) {
32880  
32881			var phi = phiStart + i * inverseSegments * phiLength;
32882  
32883			var sin = Math.sin( phi );
32884			var cos = Math.cos( phi );
32885  
32886			for ( j = 0; j <= ( points.length - 1 ); j ++ ) {
32887  
32888				// vertex
32889  
32890				vertex.x = points[ j ].x * sin;
32891				vertex.y = points[ j ].y;
32892				vertex.z = points[ j ].x * cos;
32893  
32894				vertices.push( vertex.x, vertex.y, vertex.z );
32895  
32896				// uv
32897  
32898				uv.x = i / segments;
32899				uv.y = j / ( points.length - 1 );
32900  
32901				uvs.push( uv.x, uv.y );
32902  
32903  
32904			}
32905  
32906		}
32907  
32908		// indices
32909  
32910		for ( i = 0; i < segments; i ++ ) {
32911  
32912			for ( j = 0; j < ( points.length - 1 ); j ++ ) {
32913  
32914				base = j + i * points.length;
32915  
32916				var a = base;
32917				var b = base + points.length;
32918				var c = base + points.length + 1;
32919				var d = base + 1;
32920  
32921				// faces
32922  
32923				indices.push( a, b, d );
32924				indices.push( b, c, d );
32925  
32926			}
32927  
32928		}
32929  
32930		// build geometry
32931  
32932		this.setIndex( indices );
32933		this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
32934		this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
32935  
32936		// generate normals
32937  
32938		this.computeVertexNormals();
32939  
32940		// if the geometry is closed, we need to average the normals along the seam.
32941		// because the corresponding vertices are identical (but still have different UVs).
32942  
32943		if ( phiLength === Math.PI * 2 ) {
32944  
32945			var normals = this.attributes.normal.array;
32946			var n1 = new Vector3();
32947			var n2 = new Vector3();
32948			var n = new Vector3();
32949  
32950			// this is the buffer offset for the last line of vertices
32951  
32952			base = segments * points.length * 3;
32953  
32954			for ( i = 0, j = 0; i < points.length; i ++, j += 3 ) {
32955  
32956				// select the normal of the vertex in the first line
32957  
32958				n1.x = normals[ j + 0 ];
32959				n1.y = normals[ j + 1 ];
32960				n1.z = normals[ j + 2 ];
32961  
32962				// select the normal of the vertex in the last line
32963  
32964				n2.x = normals[ base + j + 0 ];
32965				n2.y = normals[ base + j + 1 ];
32966				n2.z = normals[ base + j + 2 ];
32967  
32968				// average normals
32969  
32970				n.addVectors( n1, n2 ).normalize();
32971  
32972				// assign the new values to both normals
32973  
32974				normals[ j + 0 ] = normals[ base + j + 0 ] = n.x;
32975				normals[ j + 1 ] = normals[ base + j + 1 ] = n.y;
32976				normals[ j + 2 ] = normals[ base + j + 2 ] = n.z;
32977  
32978			}
32979  
32980		}
32981  
32982	}
32983  
32984	LatheBufferGeometry.prototype = Object.create( BufferGeometry.prototype );
32985	LatheBufferGeometry.prototype.constructor = LatheBufferGeometry;
32986  
32987	/**
32988	 * @author jonobr1 / http://jonobr1.com
32989	 * @author Mugen87 / https://github.com/Mugen87
32990	 */
32991  
32992	// ShapeGeometry
32993  
32994	function ShapeGeometry( shapes, curveSegments ) {
32995  
32996		Geometry.call( this );
32997  
32998		this.type = 'ShapeGeometry';
32999  
33000		if ( typeof curveSegments === 'object' ) {
33001  
33002			console.warn( 'THREE.ShapeGeometry: Options parameter has been removed.' );
33003  
33004			curveSegments = curveSegments.curveSegments;
33005  
33006		}
33007  
33008		this.parameters = {
33009			shapes: shapes,
33010			curveSegments: curveSegments
33011		};
33012  
33013		this.fromBufferGeometry( new ShapeBufferGeometry( shapes, curveSegments ) );
33014		this.mergeVertices();
33015  
33016	}
33017  
33018	ShapeGeometry.prototype = Object.create( Geometry.prototype );
33019	ShapeGeometry.prototype.constructor = ShapeGeometry;
33020  
33021	ShapeGeometry.prototype.toJSON = function () {
33022  
33023		var data = Geometry.prototype.toJSON.call( this );
33024  
33025		var shapes = this.parameters.shapes;
33026  
33027		return toJSON$1( shapes, data );
33028  
33029	};
33030  
33031	// ShapeBufferGeometry
33032  
33033	function ShapeBufferGeometry( shapes, curveSegments ) {
33034  
33035		BufferGeometry.call( this );
33036  
33037		this.type = 'ShapeBufferGeometry';
33038  
33039		this.parameters = {
33040			shapes: shapes,
33041			curveSegments: curveSegments
33042		};
33043  
33044		curveSegments = curveSegments || 12;
33045  
33046		// buffers
33047  
33048		var indices = [];
33049		var vertices = [];
33050		var normals = [];
33051		var uvs = [];
33052  
33053		// helper variables
33054  
33055		var groupStart = 0;
33056		var groupCount = 0;
33057  
33058		// allow single and array values for "shapes" parameter
33059  
33060		if ( Array.isArray( shapes ) === false ) {
33061  
33062			addShape( shapes );
33063  
33064		} else {
33065  
33066			for ( var i = 0; i < shapes.length; i ++ ) {
33067  
33068				addShape( shapes[ i ] );
33069  
33070				this.addGroup( groupStart, groupCount, i ); // enables MultiMaterial support
33071  
33072				groupStart += groupCount;
33073				groupCount = 0;
33074  
33075			}
33076  
33077		}
33078  
33079		// build geometry
33080  
33081		this.setIndex( indices );
33082		this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
33083		this.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
33084		this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
33085  
33086  
33087		// helper functions
33088  
33089		function addShape( shape ) {
33090  
33091			var i, l, shapeHole;
33092  
33093			var indexOffset = vertices.length / 3;
33094			var points = shape.extractPoints( curveSegments );
33095  
33096			var shapeVertices = points.shape;
33097			var shapeHoles = points.holes;
33098  
33099			// check direction of vertices
33100  
33101			if ( ShapeUtils.isClockWise( shapeVertices ) === false ) {
33102  
33103				shapeVertices = shapeVertices.reverse();
33104  
33105				// also check if holes are in the opposite direction
33106  
33107				for ( i = 0, l = shapeHoles.length; i < l; i ++ ) {
33108  
33109					shapeHole = shapeHoles[ i ];
33110  
33111					if ( ShapeUtils.isClockWise( shapeHole ) === true ) {
33112  
33113						shapeHoles[ i ] = shapeHole.reverse();
33114  
33115					}
33116  
33117				}
33118  
33119			}
33120  
33121			var faces = ShapeUtils.triangulateShape( shapeVertices, shapeHoles );
33122  
33123			// join vertices of inner and outer paths to a single array
33124  
33125			for ( i = 0, l = shapeHoles.length; i < l; i ++ ) {
33126  
33127				shapeHole = shapeHoles[ i ];
33128				shapeVertices = shapeVertices.concat( shapeHole );
33129  
33130			}
33131  
33132			// vertices, normals, uvs
33133  
33134			for ( i = 0, l = shapeVertices.length; i < l; i ++ ) {
33135  
33136				var vertex = shapeVertices[ i ];
33137  
33138				vertices.push( vertex.x, vertex.y, 0 );
33139				normals.push( 0, 0, 1 );
33140				uvs.push( vertex.x, vertex.y ); // world uvs
33141  
33142			}
33143  
33144			// incides
33145  
33146			for ( i = 0, l = faces.length; i < l; i ++ ) {
33147  
33148				var face = faces[ i ];
33149  
33150				var a = face[ 0 ] + indexOffset;
33151				var b = face[ 1 ] + indexOffset;
33152				var c = face[ 2 ] + indexOffset;
33153  
33154				indices.push( a, b, c );
33155				groupCount += 3;
33156  
33157			}
33158  
33159		}
33160  
33161	}
33162  
33163	ShapeBufferGeometry.prototype = Object.create( BufferGeometry.prototype );
33164	ShapeBufferGeometry.prototype.constructor = ShapeBufferGeometry;
33165  
33166	ShapeBufferGeometry.prototype.toJSON = function () {
33167  
33168		var data = BufferGeometry.prototype.toJSON.call( this );
33169  
33170		var shapes = this.parameters.shapes;
33171  
33172		return toJSON$1( shapes, data );
33173  
33174	};
33175  
33176	//
33177  
33178	function toJSON$1( shapes, data ) {
33179  
33180		data.shapes = [];
33181  
33182		if ( Array.isArray( shapes ) ) {
33183  
33184			for ( var i = 0, l = shapes.length; i < l; i ++ ) {
33185  
33186				var shape = shapes[ i ];
33187  
33188				data.shapes.push( shape.uuid );
33189  
33190			}
33191  
33192		} else {
33193  
33194			data.shapes.push( shapes.uuid );
33195  
33196		}
33197  
33198		return data;
33199  
33200	}
33201  
33202	/**
33203	 * @author WestLangley / http://github.com/WestLangley
33204	 * @author Mugen87 / https://github.com/Mugen87
33205	 */
33206  
33207	function EdgesGeometry( geometry, thresholdAngle ) {
33208  
33209		BufferGeometry.call( this );
33210  
33211		this.type = 'EdgesGeometry';
33212  
33213		this.parameters = {
33214			thresholdAngle: thresholdAngle
33215		};
33216  
33217		thresholdAngle = ( thresholdAngle !== undefined ) ? thresholdAngle : 1;
33218  
33219		// buffer
33220  
33221		var vertices = [];
33222  
33223		// helper variables
33224  
33225		var thresholdDot = Math.cos( _Math.DEG2RAD * thresholdAngle );
33226		var edge = [ 0, 0 ], edges = {}, edge1, edge2;
33227		var key, keys = [ 'a', 'b', 'c' ];
33228  
33229		// prepare source geometry
33230  
33231		var geometry2;
33232  
33233		if ( geometry.isBufferGeometry ) {
33234  
33235			geometry2 = new Geometry();
33236			geometry2.fromBufferGeometry( geometry );
33237  
33238		} else {
33239  
33240			geometry2 = geometry.clone();
33241  
33242		}
33243  
33244		geometry2.mergeVertices();
33245		geometry2.computeFaceNormals();
33246  
33247		var sourceVertices = geometry2.vertices;
33248		var faces = geometry2.faces;
33249  
33250		// now create a data structure where each entry represents an edge with its adjoining faces
33251  
33252		for ( var i = 0, l = faces.length; i < l; i ++ ) {
33253  
33254			var face = faces[ i ];
33255  
33256			for ( var j = 0; j < 3; j ++ ) {
33257  
33258				edge1 = face[ keys[ j ] ];
33259				edge2 = face[ keys[ ( j + 1 ) % 3 ] ];
33260				edge[ 0 ] = Math.min( edge1, edge2 );
33261				edge[ 1 ] = Math.max( edge1, edge2 );
33262  
33263				key = edge[ 0 ] + ',' + edge[ 1 ];
33264  
33265				if ( edges[ key ] === undefined ) {
33266  
33267					edges[ key ] = { index1: edge[ 0 ], index2: edge[ 1 ], face1: i, face2: undefined };
33268  
33269				} else {
33270  
33271					edges[ key ].face2 = i;
33272  
33273				}
33274  
33275			}
33276  
33277		}
33278  
33279		// generate vertices
33280  
33281		for ( key in edges ) {
33282  
33283			var e = edges[ key ];
33284  
33285			// an edge is only rendered if the angle (in degrees) between the face normals of the adjoining faces exceeds this value. default = 1 degree.
33286  
33287			if ( e.face2 === undefined || faces[ e.face1 ].normal.dot( faces[ e.face2 ].normal ) <= thresholdDot ) {
33288  
33289				var vertex = sourceVertices[ e.index1 ];
33290				vertices.push( vertex.x, vertex.y, vertex.z );
33291  
33292				vertex = sourceVertices[ e.index2 ];
33293				vertices.push( vertex.x, vertex.y, vertex.z );
33294  
33295			}
33296  
33297		}
33298  
33299		// build geometry
33300  
33301		this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
33302  
33303	}
33304  
33305	EdgesGeometry.prototype = Object.create( BufferGeometry.prototype );
33306	EdgesGeometry.prototype.constructor = EdgesGeometry;
33307  
33308	/**
33309	 * @author mrdoob / http://mrdoob.com/
33310	 * @author Mugen87 / https://github.com/Mugen87
33311	 */
33312  
33313	// CylinderGeometry
33314  
33315	function CylinderGeometry( radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ) {
33316  
33317		Geometry.call( this );
33318  
33319		this.type = 'CylinderGeometry';
33320  
33321		this.parameters = {
33322			radiusTop: radiusTop,
33323			radiusBottom: radiusBottom,
33324			height: height,
33325			radialSegments: radialSegments,
33326			heightSegments: heightSegments,
33327			openEnded: openEnded,
33328			thetaStart: thetaStart,
33329			thetaLength: thetaLength
33330		};
33331  
33332		this.fromBufferGeometry( new CylinderBufferGeometry( radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ) );
33333		this.mergeVertices();
33334  
33335	}
33336  
33337	CylinderGeometry.prototype = Object.create( Geometry.prototype );
33338	CylinderGeometry.prototype.constructor = CylinderGeometry;
33339  
33340	// CylinderBufferGeometry
33341  
33342	function CylinderBufferGeometry( radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ) {
33343  
33344		BufferGeometry.call( this );
33345  
33346		this.type = 'CylinderBufferGeometry';
33347  
33348		this.parameters = {
33349			radiusTop: radiusTop,
33350			radiusBottom: radiusBottom,
33351			height: height,
33352			radialSegments: radialSegments,
33353			heightSegments: heightSegments,
33354			openEnded: openEnded,
33355			thetaStart: thetaStart,
33356			thetaLength: thetaLength
33357		};
33358  
33359		var scope = this;
33360  
33361		radiusTop = radiusTop !== undefined ? radiusTop : 1;
33362		radiusBottom = radiusBottom !== undefined ? radiusBottom : 1;
33363		height = height || 1;
33364  
33365		radialSegments = Math.floor( radialSegments ) || 8;
33366		heightSegments = Math.floor( heightSegments ) || 1;
33367  
33368		openEnded = openEnded !== undefined ? openEnded : false;
33369		thetaStart = thetaStart !== undefined ? thetaStart : 0.0;
33370		thetaLength = thetaLength !== undefined ? thetaLength : Math.PI * 2;
33371  
33372		// buffers
33373  
33374		var indices = [];
33375		var vertices = [];
33376		var normals = [];
33377		var uvs = [];
33378  
33379		// helper variables
33380  
33381		var index = 0;
33382		var indexArray = [];
33383		var halfHeight = height / 2;
33384		var groupStart = 0;
33385  
33386		// generate geometry
33387  
33388		generateTorso();
33389  
33390		if ( openEnded === false ) {
33391  
33392			if ( radiusTop > 0 ) generateCap( true );
33393			if ( radiusBottom > 0 ) generateCap( false );
33394  
33395		}
33396  
33397		// build geometry
33398  
33399		this.setIndex( indices );
33400		this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
33401		this.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
33402		this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
33403  
33404		function generateTorso() {
33405  
33406			var x, y;
33407			var normal = new Vector3();
33408			var vertex = new Vector3();
33409  
33410			var groupCount = 0;
33411  
33412			// this will be used to calculate the normal
33413			var slope = ( radiusBottom - radiusTop ) / height;
33414  
33415			// generate vertices, normals and uvs
33416  
33417			for ( y = 0; y <= heightSegments; y ++ ) {
33418  
33419				var indexRow = [];
33420  
33421				var v = y / heightSegments;
33422  
33423				// calculate the radius of the current row
33424  
33425				var radius = v * ( radiusBottom - radiusTop ) + radiusTop;
33426  
33427				for ( x = 0; x <= radialSegments; x ++ ) {
33428  
33429					var u = x / radialSegments;
33430  
33431					var theta = u * thetaLength + thetaStart;
33432  
33433					var sinTheta = Math.sin( theta );
33434					var cosTheta = Math.cos( theta );
33435  
33436					// vertex
33437  
33438					vertex.x = radius * sinTheta;
33439					vertex.y = - v * height + halfHeight;
33440					vertex.z = radius * cosTheta;
33441					vertices.push( vertex.x, vertex.y, vertex.z );
33442  
33443					// normal
33444  
33445					normal.set( sinTheta, slope, cosTheta ).normalize();
33446					normals.push( normal.x, normal.y, normal.z );
33447  
33448					// uv
33449  
33450					uvs.push( u, 1 - v );
33451  
33452					// save index of vertex in respective row
33453  
33454					indexRow.push( index ++ );
33455  
33456				}
33457  
33458				// now save vertices of the row in our index array
33459  
33460				indexArray.push( indexRow );
33461  
33462			}
33463  
33464			// generate indices
33465  
33466			for ( x = 0; x < radialSegments; x ++ ) {
33467  
33468				for ( y = 0; y < heightSegments; y ++ ) {
33469  
33470					// we use the index array to access the correct indices
33471  
33472					var a = indexArray[ y ][ x ];
33473					var b = indexArray[ y + 1 ][ x ];
33474					var c = indexArray[ y + 1 ][ x + 1 ];
33475					var d = indexArray[ y ][ x + 1 ];
33476  
33477					// faces
33478  
33479					indices.push( a, b, d );
33480					indices.push( b, c, d );
33481  
33482					// update group counter
33483  
33484					groupCount += 6;
33485  
33486				}
33487  
33488			}
33489  
33490			// add a group to the geometry. this will ensure multi material support
33491  
33492			scope.addGroup( groupStart, groupCount, 0 );
33493  
33494			// calculate new start value for groups
33495  
33496			groupStart += groupCount;
33497  
33498		}
33499  
33500		function generateCap( top ) {
33501  
33502			var x, centerIndexStart, centerIndexEnd;
33503  
33504			var uv = new Vector2();
33505			var vertex = new Vector3();
33506  
33507			var groupCount = 0;
33508  
33509			var radius = ( top === true ) ? radiusTop : radiusBottom;
33510			var sign = ( top === true ) ? 1 : - 1;
33511  
33512			// save the index of the first center vertex
33513			centerIndexStart = index;
33514  
33515			// first we generate the center vertex data of the cap.
33516			// because the geometry needs one set of uvs per face,
33517			// we must generate a center vertex per face/segment
33518  
33519			for ( x = 1; x <= radialSegments; x ++ ) {
33520  
33521				// vertex
33522  
33523				vertices.push( 0, halfHeight * sign, 0 );
33524  
33525				// normal
33526  
33527				normals.push( 0, sign, 0 );
33528  
33529				// uv
33530  
33531				uvs.push( 0.5, 0.5 );
33532  
33533				// increase index
33534  
33535				index ++;
33536  
33537			}
33538  
33539			// save the index of the last center vertex
33540  
33541			centerIndexEnd = index;
33542  
33543			// now we generate the surrounding vertices, normals and uvs
33544  
33545			for ( x = 0; x <= radialSegments; x ++ ) {
33546  
33547				var u = x / radialSegments;
33548				var theta = u * thetaLength + thetaStart;
33549  
33550				var cosTheta = Math.cos( theta );
33551				var sinTheta = Math.sin( theta );
33552  
33553				// vertex
33554  
33555				vertex.x = radius * sinTheta;
33556				vertex.y = halfHeight * sign;
33557				vertex.z = radius * cosTheta;
33558				vertices.push( vertex.x, vertex.y, vertex.z );
33559  
33560				// normal
33561  
33562				normals.push( 0, sign, 0 );
33563  
33564				// uv
33565  
33566				uv.x = ( cosTheta * 0.5 ) + 0.5;
33567				uv.y = ( sinTheta * 0.5 * sign ) + 0.5;
33568				uvs.push( uv.x, uv.y );
33569  
33570				// increase index
33571  
33572				index ++;
33573  
33574			}
33575  
33576			// generate indices
33577  
33578			for ( x = 0; x < radialSegments; x ++ ) {
33579  
33580				var c = centerIndexStart + x;
33581				var i = centerIndexEnd + x;
33582  
33583				if ( top === true ) {
33584  
33585					// face top
33586  
33587					indices.push( i, i + 1, c );
33588  
33589				} else {
33590  
33591					// face bottom
33592  
33593					indices.push( i + 1, i, c );
33594  
33595				}
33596  
33597				groupCount += 3;
33598  
33599			}
33600  
33601			// add a group to the geometry. this will ensure multi material support
33602  
33603			scope.addGroup( groupStart, groupCount, top === true ? 1 : 2 );
33604  
33605			// calculate new start value for groups
33606  
33607			groupStart += groupCount;
33608  
33609		}
33610  
33611	}
33612  
33613	CylinderBufferGeometry.prototype = Object.create( BufferGeometry.prototype );
33614	CylinderBufferGeometry.prototype.constructor = CylinderBufferGeometry;
33615  
33616	/**
33617	 * @author abelnation / http://github.com/abelnation
33618	 */
33619  
33620	// ConeGeometry
33621  
33622	function ConeGeometry( radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ) {
33623  
33624		CylinderGeometry.call( this, 0, radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength );
33625  
33626		this.type = 'ConeGeometry';
33627  
33628		this.parameters = {
33629			radius: radius,
33630			height: height,
33631			radialSegments: radialSegments,
33632			heightSegments: heightSegments,
33633			openEnded: openEnded,
33634			thetaStart: thetaStart,
33635			thetaLength: thetaLength
33636		};
33637  
33638	}
33639  
33640	ConeGeometry.prototype = Object.create( CylinderGeometry.prototype );
33641	ConeGeometry.prototype.constructor = ConeGeometry;
33642  
33643	// ConeBufferGeometry
33644  
33645	function ConeBufferGeometry( radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ) {
33646  
33647		CylinderBufferGeometry.call( this, 0, radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength );
33648  
33649		this.type = 'ConeBufferGeometry';
33650  
33651		this.parameters = {
33652			radius: radius,
33653			height: height,
33654			radialSegments: radialSegments,
33655			heightSegments: heightSegments,
33656			openEnded: openEnded,
33657			thetaStart: thetaStart,
33658			thetaLength: thetaLength
33659		};
33660  
33661	}
33662  
33663	ConeBufferGeometry.prototype = Object.create( CylinderBufferGeometry.prototype );
33664	ConeBufferGeometry.prototype.constructor = ConeBufferGeometry;
33665  
33666	/**
33667	 * @author benaadams / https://twitter.com/ben_a_adams
33668	 * @author Mugen87 / https://github.com/Mugen87
33669	 * @author hughes
33670	 */
33671  
33672	// CircleGeometry
33673  
33674	function CircleGeometry( radius, segments, thetaStart, thetaLength ) {
33675  
33676		Geometry.call( this );
33677  
33678		this.type = 'CircleGeometry';
33679  
33680		this.parameters = {
33681			radius: radius,
33682			segments: segments,
33683			thetaStart: thetaStart,
33684			thetaLength: thetaLength
33685		};
33686  
33687		this.fromBufferGeometry( new CircleBufferGeometry( radius, segments, thetaStart, thetaLength ) );
33688		this.mergeVertices();
33689  
33690	}
33691  
33692	CircleGeometry.prototype = Object.create( Geometry.prototype );
33693	CircleGeometry.prototype.constructor = CircleGeometry;
33694  
33695	// CircleBufferGeometry
33696  
33697	function CircleBufferGeometry( radius, segments, thetaStart, thetaLength ) {
33698  
33699		BufferGeometry.call( this );
33700  
33701		this.type = 'CircleBufferGeometry';
33702  
33703		this.parameters = {
33704			radius: radius,
33705			segments: segments,
33706			thetaStart: thetaStart,
33707			thetaLength: thetaLength
33708		};
33709  
33710		radius = radius || 1;
33711		segments = segments !== undefined ? Math.max( 3, segments ) : 8;
33712  
33713		thetaStart = thetaStart !== undefined ? thetaStart : 0;
33714		thetaLength = thetaLength !== undefined ? thetaLength : Math.PI * 2;
33715  
33716		// buffers
33717  
33718		var indices = [];
33719		var vertices = [];
33720		var normals = [];
33721		var uvs = [];
33722  
33723		// helper variables
33724  
33725		var i, s;
33726		var vertex = new Vector3();
33727		var uv = new Vector2();
33728  
33729		// center point
33730  
33731		vertices.push( 0, 0, 0 );
33732		normals.push( 0, 0, 1 );
33733		uvs.push( 0.5, 0.5 );
33734  
33735		for ( s = 0, i = 3; s <= segments; s ++, i += 3 ) {
33736  
33737			var segment = thetaStart + s / segments * thetaLength;
33738  
33739			// vertex
33740  
33741			vertex.x = radius * Math.cos( segment );
33742			vertex.y = radius * Math.sin( segment );
33743  
33744			vertices.push( vertex.x, vertex.y, vertex.z );
33745  
33746			// normal
33747  
33748			normals.push( 0, 0, 1 );
33749  
33750			// uvs
33751  
33752			uv.x = ( vertices[ i ] / radius + 1 ) / 2;
33753			uv.y = ( vertices[ i + 1 ] / radius + 1 ) / 2;
33754  
33755			uvs.push( uv.x, uv.y );
33756  
33757		}
33758  
33759		// indices
33760  
33761		for ( i = 1; i <= segments; i ++ ) {
33762  
33763			indices.push( i, i + 1, 0 );
33764  
33765		}
33766  
33767		// build geometry
33768  
33769		this.setIndex( indices );
33770		this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
33771		this.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
33772		this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
33773  
33774	}
33775  
33776	CircleBufferGeometry.prototype = Object.create( BufferGeometry.prototype );
33777	CircleBufferGeometry.prototype.constructor = CircleBufferGeometry;
33778  
33779  
33780  
33781	var Geometries = /*#__PURE__*/Object.freeze({
33782		WireframeGeometry: WireframeGeometry,
33783		ParametricGeometry: ParametricGeometry,
33784		ParametricBufferGeometry: ParametricBufferGeometry,
33785		TetrahedronGeometry: TetrahedronGeometry,
33786		TetrahedronBufferGeometry: TetrahedronBufferGeometry,
33787		OctahedronGeometry: OctahedronGeometry,
33788		OctahedronBufferGeometry: OctahedronBufferGeometry,
33789		IcosahedronGeometry: IcosahedronGeometry,
33790		IcosahedronBufferGeometry: IcosahedronBufferGeometry,
33791		DodecahedronGeometry: DodecahedronGeometry,
33792		DodecahedronBufferGeometry: DodecahedronBufferGeometry,
33793		PolyhedronGeometry: PolyhedronGeometry,
33794		PolyhedronBufferGeometry: PolyhedronBufferGeometry,
33795		TubeGeometry: TubeGeometry,
33796		TubeBufferGeometry: TubeBufferGeometry,
33797		TorusKnotGeometry: TorusKnotGeometry,
33798		TorusKnotBufferGeometry: TorusKnotBufferGeometry,
33799		TorusGeometry: TorusGeometry,
33800		TorusBufferGeometry: TorusBufferGeometry,
33801		TextGeometry: TextGeometry,
33802		TextBufferGeometry: TextBufferGeometry,
33803		SphereGeometry: SphereGeometry,
33804		SphereBufferGeometry: SphereBufferGeometry,
33805		RingGeometry: RingGeometry,
33806		RingBufferGeometry: RingBufferGeometry,
33807		PlaneGeometry: PlaneGeometry,
33808		PlaneBufferGeometry: PlaneBufferGeometry,
33809		LatheGeometry: LatheGeometry,
33810		LatheBufferGeometry: LatheBufferGeometry,
33811		ShapeGeometry: ShapeGeometry,
33812		ShapeBufferGeometry: ShapeBufferGeometry,
33813		ExtrudeGeometry: ExtrudeGeometry,
33814		ExtrudeBufferGeometry: ExtrudeBufferGeometry,
33815		EdgesGeometry: EdgesGeometry,
33816		ConeGeometry: ConeGeometry,
33817		ConeBufferGeometry: ConeBufferGeometry,
33818		CylinderGeometry: CylinderGeometry,
33819		CylinderBufferGeometry: CylinderBufferGeometry,
33820		CircleGeometry: CircleGeometry,
33821		CircleBufferGeometry: CircleBufferGeometry,
33822		BoxGeometry: BoxGeometry,
33823		BoxBufferGeometry: BoxBufferGeometry
33824	});
33825  
33826	/**
33827	 * @author mrdoob / http://mrdoob.com/
33828	 *
33829	 * parameters = {
33830	 *  color: <THREE.Color>
33831	 * }
33832	 */
33833  
33834	function ShadowMaterial( parameters ) {
33835  
33836		Material.call( this );
33837  
33838		this.type = 'ShadowMaterial';
33839  
33840		this.color = new Color( 0x000000 );
33841		this.transparent = true;
33842  
33843		this.setValues( parameters );
33844  
33845	}
33846  
33847	ShadowMaterial.prototype = Object.create( Material.prototype );
33848	ShadowMaterial.prototype.constructor = ShadowMaterial;
33849  
33850	ShadowMaterial.prototype.isShadowMaterial = true;
33851  
33852	ShadowMaterial.prototype.copy = function ( source ) {
33853  
33854		Material.prototype.copy.call( this, source );
33855  
33856		this.color.copy( source.color );
33857  
33858		return this;
33859  
33860	};
33861  
33862	/**
33863	 * @author mrdoob / http://mrdoob.com/
33864	 */
33865  
33866	function RawShaderMaterial( parameters ) {
33867  
33868		ShaderMaterial.call( this, parameters );
33869  
33870		this.type = 'RawShaderMaterial';
33871  
33872	}
33873  
33874	RawShaderMaterial.prototype = Object.create( ShaderMaterial.prototype );
33875	RawShaderMaterial.prototype.constructor = RawShaderMaterial;
33876  
33877	RawShaderMaterial.prototype.isRawShaderMaterial = true;
33878  
33879	/**
33880	 * @author WestLangley / http://github.com/WestLangley
33881	 *
33882	 * parameters = {
33883	 *  color: <hex>,
33884	 *  roughness: <float>,
33885	 *  metalness: <float>,
33886	 *  opacity: <float>,
33887	 *
33888	 *  map: new THREE.Texture( <Image> ),
33889	 *
33890	 *  lightMap: new THREE.Texture( <Image> ),
33891	 *  lightMapIntensity: <float>
33892	 *
33893	 *  aoMap: new THREE.Texture( <Image> ),
33894	 *  aoMapIntensity: <float>
33895	 *
33896	 *  emissive: <hex>,
33897	 *  emissiveIntensity: <float>
33898	 *  emissiveMap: new THREE.Texture( <Image> ),
33899	 *
33900	 *  bumpMap: new THREE.Texture( <Image> ),
33901	 *  bumpScale: <float>,
33902	 *
33903	 *  normalMap: new THREE.Texture( <Image> ),
33904	 *  normalScale: <Vector2>,
33905	 *
33906	 *  displacementMap: new THREE.Texture( <Image> ),
33907	 *  displacementScale: <float>,
33908	 *  displacementBias: <float>,
33909	 *
33910	 *  roughnessMap: new THREE.Texture( <Image> ),
33911	 *
33912	 *  metalnessMap: new THREE.Texture( <Image> ),
33913	 *
33914	 *  alphaMap: new THREE.Texture( <Image> ),
33915	 *
33916	 *  envMap: new THREE.CubeTexture( [posx, negx, posy, negy, posz, negz] ),
33917	 *  envMapIntensity: <float>
33918	 *
33919	 *  refractionRatio: <float>,
33920	 *
33921	 *  wireframe: <boolean>,
33922	 *  wireframeLinewidth: <float>,
33923	 *
33924	 *  skinning: <bool>,
33925	 *  morphTargets: <bool>,
33926	 *  morphNormals: <bool>
33927	 * }
33928	 */
33929  
33930	function MeshStandardMaterial( parameters ) {
33931  
33932		Material.call( this );
33933  
33934		this.defines = { 'STANDARD': '' };
33935  
33936		this.type = 'MeshStandardMaterial';
33937  
33938		this.color = new Color( 0xffffff ); // diffuse
33939		this.roughness = 0.5;
33940		this.metalness = 0.5;
33941  
33942		this.map = null;
33943  
33944		this.lightMap = null;
33945		this.lightMapIntensity = 1.0;
33946  
33947		this.aoMap = null;
33948		this.aoMapIntensity = 1.0;
33949  
33950		this.emissive = new Color( 0x000000 );
33951		this.emissiveIntensity = 1.0;
33952		this.emissiveMap = null;
33953  
33954		this.bumpMap = null;
33955		this.bumpScale = 1;
33956  
33957		this.normalMap = null;
33958		this.normalScale = new Vector2( 1, 1 );
33959  
33960		this.displacementMap = null;
33961		this.displacementScale = 1;
33962		this.displacementBias = 0;
33963  
33964		this.roughnessMap = null;
33965  
33966		this.metalnessMap = null;
33967  
33968		this.alphaMap = null;
33969  
33970		this.envMap = null;
33971		this.envMapIntensity = 1.0;
33972  
33973		this.refractionRatio = 0.98;
33974  
33975		this.wireframe = false;
33976		this.wireframeLinewidth = 1;
33977		this.wireframeLinecap = 'round';
33978		this.wireframeLinejoin = 'round';
33979  
33980		this.skinning = false;
33981		this.morphTargets = false;
33982		this.morphNormals = false;
33983  
33984		this.setValues( parameters );
33985  
33986	}
33987  
33988	MeshStandardMaterial.prototype = Object.create( Material.prototype );
33989	MeshStandardMaterial.prototype.constructor = MeshStandardMaterial;
33990  
33991	MeshStandardMaterial.prototype.isMeshStandardMaterial = true;
33992  
33993	MeshStandardMaterial.prototype.copy = function ( source ) {
33994  
33995		Material.prototype.copy.call( this, source );
33996  
33997		this.defines = { 'STANDARD': '' };
33998  
33999		this.color.copy( source.color );
34000		this.roughness = source.roughness;
34001		this.metalness = source.metalness;
34002  
34003		this.map = source.map;
34004  
34005		this.lightMap = source.lightMap;
34006		this.lightMapIntensity = source.lightMapIntensity;
34007  
34008		this.aoMap = source.aoMap;
34009		this.aoMapIntensity = source.aoMapIntensity;
34010  
34011		this.emissive.copy( source.emissive );
34012		this.emissiveMap = source.emissiveMap;
34013		this.emissiveIntensity = source.emissiveIntensity;
34014  
34015		this.bumpMap = source.bumpMap;
34016		this.bumpScale = source.bumpScale;
34017  
34018		this.normalMap = source.normalMap;
34019		this.normalScale.copy( source.normalScale );
34020  
34021		this.displacementMap = source.displacementMap;
34022		this.displacementScale = source.displacementScale;
34023		this.displacementBias = source.displacementBias;
34024  
34025		this.roughnessMap = source.roughnessMap;
34026  
34027		this.metalnessMap = source.metalnessMap;
34028  
34029		this.alphaMap = source.alphaMap;
34030  
34031		this.envMap = source.envMap;
34032		this.envMapIntensity = source.envMapIntensity;
34033  
34034		this.refractionRatio = source.refractionRatio;
34035  
34036		this.wireframe = source.wireframe;
34037		this.wireframeLinewidth = source.wireframeLinewidth;
34038		this.wireframeLinecap = source.wireframeLinecap;
34039		this.wireframeLinejoin = source.wireframeLinejoin;
34040  
34041		this.skinning = source.skinning;
34042		this.morphTargets = source.morphTargets;
34043		this.morphNormals = source.morphNormals;
34044  
34045		return this;
34046  
34047	};
34048  
34049	/**
34050	 * @author WestLangley / http://github.com/WestLangley
34051	 *
34052	 * parameters = {
34053	 *  reflectivity: <float>
34054	 * }
34055	 */
34056  
34057	function MeshPhysicalMaterial( parameters ) {
34058  
34059		MeshStandardMaterial.call( this );
34060  
34061		this.defines = { 'PHYSICAL': '' };
34062  
34063		this.type = 'MeshPhysicalMaterial';
34064  
34065		this.reflectivity = 0.5; // maps to F0 = 0.04
34066  
34067		this.clearCoat = 0.0;
34068		this.clearCoatRoughness = 0.0;
34069  
34070		this.setValues( parameters );
34071  
34072	}
34073  
34074	MeshPhysicalMaterial.prototype = Object.create( MeshStandardMaterial.prototype );
34075	MeshPhysicalMaterial.prototype.constructor = MeshPhysicalMaterial;
34076  
34077	MeshPhysicalMaterial.prototype.isMeshPhysicalMaterial = true;
34078  
34079	MeshPhysicalMaterial.prototype.copy = function ( source ) {
34080  
34081		MeshStandardMaterial.prototype.copy.call( this, source );
34082  
34083		this.defines = { 'PHYSICAL': '' };
34084  
34085		this.reflectivity = source.reflectivity;
34086  
34087		this.clearCoat = source.clearCoat;
34088		this.clearCoatRoughness = source.clearCoatRoughness;
34089  
34090		return this;
34091  
34092	};
34093  
34094	/**
34095	 * @author mrdoob / http://mrdoob.com/
34096	 * @author alteredq / http://alteredqualia.com/
34097	 *
34098	 * parameters = {
34099	 *  color: <hex>,
34100	 *  specular: <hex>,
34101	 *  shininess: <float>,
34102	 *  opacity: <float>,
34103	 *
34104	 *  map: new THREE.Texture( <Image> ),
34105	 *
34106	 *  lightMap: new THREE.Texture( <Image> ),
34107	 *  lightMapIntensity: <float>
34108	 *
34109	 *  aoMap: new THREE.Texture( <Image> ),
34110	 *  aoMapIntensity: <float>
34111	 *
34112	 *  emissive: <hex>,
34113	 *  emissiveIntensity: <float>
34114	 *  emissiveMap: new THREE.Texture( <Image> ),
34115	 *
34116	 *  bumpMap: new THREE.Texture( <Image> ),
34117	 *  bumpScale: <float>,
34118	 *
34119	 *  normalMap: new THREE.Texture( <Image> ),
34120	 *  normalScale: <Vector2>,
34121	 *
34122	 *  displacementMap: new THREE.Texture( <Image> ),
34123	 *  displacementScale: <float>,
34124	 *  displacementBias: <float>,
34125	 *
34126	 *  specularMap: new THREE.Texture( <Image> ),
34127	 *
34128	 *  alphaMap: new THREE.Texture( <Image> ),
34129	 *
34130	 *  envMap: new THREE.CubeTexture( [posx, negx, posy, negy, posz, negz] ),
34131	 *  combine: THREE.Multiply,
34132	 *  reflectivity: <float>,
34133	 *  refractionRatio: <float>,
34134	 *
34135	 *  wireframe: <boolean>,
34136	 *  wireframeLinewidth: <float>,
34137	 *
34138	 *  skinning: <bool>,
34139	 *  morphTargets: <bool>,
34140	 *  morphNormals: <bool>
34141	 * }
34142	 */
34143  
34144	function MeshPhongMaterial( parameters ) {
34145  
34146		Material.call( this );
34147  
34148		this.type = 'MeshPhongMaterial';
34149  
34150		this.color = new Color( 0xffffff ); // diffuse
34151		this.specular = new Color( 0x111111 );
34152		this.shininess = 30;
34153  
34154		this.map = null;
34155  
34156		this.lightMap = null;
34157		this.lightMapIntensity = 1.0;
34158  
34159		this.aoMap = null;
34160		this.aoMapIntensity = 1.0;
34161  
34162		this.emissive = new Color( 0x000000 );
34163		this.emissiveIntensity = 1.0;
34164		this.emissiveMap = null;
34165  
34166		this.bumpMap = null;
34167		this.bumpScale = 1;
34168  
34169		this.normalMap = null;
34170		this.normalScale = new Vector2( 1, 1 );
34171  
34172		this.displacementMap = null;
34173		this.displacementScale = 1;
34174		this.displacementBias = 0;
34175  
34176		this.specularMap = null;
34177  
34178		this.alphaMap = null;
34179  
34180		this.envMap = null;
34181		this.combine = MultiplyOperation;
34182		this.reflectivity = 1;
34183		this.refractionRatio = 0.98;
34184  
34185		this.wireframe = false;
34186		this.wireframeLinewidth = 1;
34187		this.wireframeLinecap = 'round';
34188		this.wireframeLinejoin = 'round';
34189  
34190		this.skinning = false;
34191		this.morphTargets = false;
34192		this.morphNormals = false;
34193  
34194		this.setValues( parameters );
34195  
34196	}
34197  
34198	MeshPhongMaterial.prototype = Object.create( Material.prototype );
34199	MeshPhongMaterial.prototype.constructor = MeshPhongMaterial;
34200  
34201	MeshPhongMaterial.prototype.isMeshPhongMaterial = true;
34202  
34203	MeshPhongMaterial.prototype.copy = function ( source ) {
34204  
34205		Material.prototype.copy.call( this, source );
34206  
34207		this.color.copy( source.color );
34208		this.specular.copy( source.specular );
34209		this.shininess = source.shininess;
34210  
34211		this.map = source.map;
34212  
34213		this.lightMap = source.lightMap;
34214		this.lightMapIntensity = source.lightMapIntensity;
34215  
34216		this.aoMap = source.aoMap;
34217		this.aoMapIntensity = source.aoMapIntensity;
34218  
34219		this.emissive.copy( source.emissive );
34220		this.emissiveMap = source.emissiveMap;
34221		this.emissiveIntensity = source.emissiveIntensity;
34222  
34223		this.bumpMap = source.bumpMap;
34224		this.bumpScale = source.bumpScale;
34225  
34226		this.normalMap = source.normalMap;
34227		this.normalScale.copy( source.normalScale );
34228  
34229		this.displacementMap = source.displacementMap;
34230		this.displacementScale = source.displacementScale;
34231		this.displacementBias = source.displacementBias;
34232  
34233		this.specularMap = source.specularMap;
34234  
34235		this.alphaMap = source.alphaMap;
34236  
34237		this.envMap = source.envMap;
34238		this.combine = source.combine;
34239		this.reflectivity = source.reflectivity;
34240		this.refractionRatio = source.refractionRatio;
34241  
34242		this.wireframe = source.wireframe;
34243		this.wireframeLinewidth = source.wireframeLinewidth;
34244		this.wireframeLinecap = source.wireframeLinecap;
34245		this.wireframeLinejoin = source.wireframeLinejoin;
34246  
34247		this.skinning = source.skinning;
34248		this.morphTargets = source.morphTargets;
34249		this.morphNormals = source.morphNormals;
34250  
34251		return this;
34252  
34253	};
34254  
34255	/**
34256	 * @author takahirox / http://github.com/takahirox
34257	 *
34258	 * parameters = {
34259	 *  gradientMap: new THREE.Texture( <Image> )
34260	 * }
34261	 */
34262  
34263	function MeshToonMaterial( parameters ) {
34264  
34265		MeshPhongMaterial.call( this );
34266  
34267		this.defines = { 'TOON': '' };
34268  
34269		this.type = 'MeshToonMaterial';
34270  
34271		this.gradientMap = null;
34272  
34273		this.setValues( parameters );
34274  
34275	}
34276  
34277	MeshToonMaterial.prototype = Object.create( MeshPhongMaterial.prototype );
34278	MeshToonMaterial.prototype.constructor = MeshToonMaterial;
34279  
34280	MeshToonMaterial.prototype.isMeshToonMaterial = true;
34281  
34282	MeshToonMaterial.prototype.copy = function ( source ) {
34283  
34284		MeshPhongMaterial.prototype.copy.call( this, source );
34285  
34286		this.gradientMap = source.gradientMap;
34287  
34288		return this;
34289  
34290	};
34291  
34292	/**
34293	 * @author mrdoob / http://mrdoob.com/
34294	 * @author WestLangley / http://github.com/WestLangley
34295	 *
34296	 * parameters = {
34297	 *  opacity: <float>,
34298	 *
34299	 *  bumpMap: new THREE.Texture( <Image> ),
34300	 *  bumpScale: <float>,
34301	 *
34302	 *  normalMap: new THREE.Texture( <Image> ),
34303	 *  normalScale: <Vector2>,
34304	 *
34305	 *  displacementMap: new THREE.Texture( <Image> ),
34306	 *  displacementScale: <float>,
34307	 *  displacementBias: <float>,
34308	 *
34309	 *  wireframe: <boolean>,
34310	 *  wireframeLinewidth: <float>
34311	 *
34312	 *  skinning: <bool>,
34313	 *  morphTargets: <bool>,
34314	 *  morphNormals: <bool>
34315	 * }
34316	 */
34317  
34318	function MeshNormalMaterial( parameters ) {
34319  
34320		Material.call( this );
34321  
34322		this.type = 'MeshNormalMaterial';
34323  
34324		this.bumpMap = null;
34325		this.bumpScale = 1;
34326  
34327		this.normalMap = null;
34328		this.normalScale = new Vector2( 1, 1 );
34329  
34330		this.displacementMap = null;
34331		this.displacementScale = 1;
34332		this.displacementBias = 0;
34333  
34334		this.wireframe = false;
34335		this.wireframeLinewidth = 1;
34336  
34337		this.fog = false;
34338		this.lights = false;
34339  
34340		this.skinning = false;
34341		this.morphTargets = false;
34342		this.morphNormals = false;
34343  
34344		this.setValues( parameters );
34345  
34346	}
34347  
34348	MeshNormalMaterial.prototype = Object.create( Material.prototype );
34349	MeshNormalMaterial.prototype.constructor = MeshNormalMaterial;
34350  
34351	MeshNormalMaterial.prototype.isMeshNormalMaterial = true;
34352  
34353	MeshNormalMaterial.prototype.copy = function ( source ) {
34354  
34355		Material.prototype.copy.call( this, source );
34356  
34357		this.bumpMap = source.bumpMap;
34358		this.bumpScale = source.bumpScale;
34359  
34360		this.normalMap = source.normalMap;
34361		this.normalScale.copy( source.normalScale );
34362  
34363		this.displacementMap = source.displacementMap;
34364		this.displacementScale = source.displacementScale;
34365		this.displacementBias = source.displacementBias;
34366  
34367		this.wireframe = source.wireframe;
34368		this.wireframeLinewidth = source.wireframeLinewidth;
34369  
34370		this.skinning = source.skinning;
34371		this.morphTargets = source.morphTargets;
34372		this.morphNormals = source.morphNormals;
34373  
34374		return this;
34375  
34376	};
34377  
34378	/**
34379	 * @author mrdoob / http://mrdoob.com/
34380	 * @author alteredq / http://alteredqualia.com/
34381	 *
34382	 * parameters = {
34383	 *  color: <hex>,
34384	 *  opacity: <float>,
34385	 *
34386	 *  map: new THREE.Texture( <Image> ),
34387	 *
34388	 *  lightMap: new THREE.Texture( <Image> ),
34389	 *  lightMapIntensity: <float>
34390	 *
34391	 *  aoMap: new THREE.Texture( <Image> ),
34392	 *  aoMapIntensity: <float>
34393	 *
34394	 *  emissive: <hex>,
34395	 *  emissiveIntensity: <float>
34396	 *  emissiveMap: new THREE.Texture( <Image> ),
34397	 *
34398	 *  specularMap: new THREE.Texture( <Image> ),
34399	 *
34400	 *  alphaMap: new THREE.Texture( <Image> ),
34401	 *
34402	 *  envMap: new THREE.CubeTexture( [posx, negx, posy, negy, posz, negz] ),
34403	 *  combine: THREE.Multiply,
34404	 *  reflectivity: <float>,
34405	 *  refractionRatio: <float>,
34406	 *
34407	 *  wireframe: <boolean>,
34408	 *  wireframeLinewidth: <float>,
34409	 *
34410	 *  skinning: <bool>,
34411	 *  morphTargets: <bool>,
34412	 *  morphNormals: <bool>
34413	 * }
34414	 */
34415  
34416	function MeshLambertMaterial( parameters ) {
34417  
34418		Material.call( this );
34419  
34420		this.type = 'MeshLambertMaterial';
34421  
34422		this.color = new Color( 0xffffff ); // diffuse
34423  
34424		this.map = null;
34425  
34426		this.lightMap = null;
34427		this.lightMapIntensity = 1.0;
34428  
34429		this.aoMap = null;
34430		this.aoMapIntensity = 1.0;
34431  
34432		this.emissive = new Color( 0x000000 );
34433		this.emissiveIntensity = 1.0;
34434		this.emissiveMap = null;
34435  
34436		this.specularMap = null;
34437  
34438		this.alphaMap = null;
34439  
34440		this.envMap = null;
34441		this.combine = MultiplyOperation;
34442		this.reflectivity = 1;
34443		this.refractionRatio = 0.98;
34444  
34445		this.wireframe = false;
34446		this.wireframeLinewidth = 1;
34447		this.wireframeLinecap = 'round';
34448		this.wireframeLinejoin = 'round';
34449  
34450		this.skinning = false;
34451		this.morphTargets = false;
34452		this.morphNormals = false;
34453  
34454		this.setValues( parameters );
34455  
34456	}
34457  
34458	MeshLambertMaterial.prototype = Object.create( Material.prototype );
34459	MeshLambertMaterial.prototype.constructor = MeshLambertMaterial;
34460  
34461	MeshLambertMaterial.prototype.isMeshLambertMaterial = true;
34462  
34463	MeshLambertMaterial.prototype.copy = function ( source ) {
34464  
34465		Material.prototype.copy.call( this, source );
34466  
34467		this.color.copy( source.color );
34468  
34469		this.map = source.map;
34470  
34471		this.lightMap = source.lightMap;
34472		this.lightMapIntensity = source.lightMapIntensity;
34473  
34474		this.aoMap = source.aoMap;
34475		this.aoMapIntensity = source.aoMapIntensity;
34476  
34477		this.emissive.copy( source.emissive );
34478		this.emissiveMap = source.emissiveMap;
34479		this.emissiveIntensity = source.emissiveIntensity;
34480  
34481		this.specularMap = source.specularMap;
34482  
34483		this.alphaMap = source.alphaMap;
34484  
34485		this.envMap = source.envMap;
34486		this.combine = source.combine;
34487		this.reflectivity = source.reflectivity;
34488		this.refractionRatio = source.refractionRatio;
34489  
34490		this.wireframe = source.wireframe;
34491		this.wireframeLinewidth = source.wireframeLinewidth;
34492		this.wireframeLinecap = source.wireframeLinecap;
34493		this.wireframeLinejoin = source.wireframeLinejoin;
34494  
34495		this.skinning = source.skinning;
34496		this.morphTargets = source.morphTargets;
34497		this.morphNormals = source.morphNormals;
34498  
34499		return this;
34500  
34501	};
34502  
34503	/**
34504	 * @author alteredq / http://alteredqualia.com/
34505	 *
34506	 * parameters = {
34507	 *  color: <hex>,
34508	 *  opacity: <float>,
34509	 *
34510	 *  linewidth: <float>,
34511	 *
34512	 *  scale: <float>,
34513	 *  dashSize: <float>,
34514	 *  gapSize: <float>
34515	 * }
34516	 */
34517  
34518	function LineDashedMaterial( parameters ) {
34519  
34520		LineBasicMaterial.call( this );
34521  
34522		this.type = 'LineDashedMaterial';
34523  
34524		this.scale = 1;
34525		this.dashSize = 3;
34526		this.gapSize = 1;
34527  
34528		this.setValues( parameters );
34529  
34530	}
34531  
34532	LineDashedMaterial.prototype = Object.create( LineBasicMaterial.prototype );
34533	LineDashedMaterial.prototype.constructor = LineDashedMaterial;
34534  
34535	LineDashedMaterial.prototype.isLineDashedMaterial = true;
34536  
34537	LineDashedMaterial.prototype.copy = function ( source ) {
34538  
34539		LineBasicMaterial.prototype.copy.call( this, source );
34540  
34541		this.scale = source.scale;
34542		this.dashSize = source.dashSize;
34543		this.gapSize = source.gapSize;
34544  
34545		return this;
34546  
34547	};
34548  
34549  
34550  
34551	var Materials = /*#__PURE__*/Object.freeze({
34552		ShadowMaterial: ShadowMaterial,
34553		SpriteMaterial: SpriteMaterial,
34554		RawShaderMaterial: RawShaderMaterial,
34555		ShaderMaterial: ShaderMaterial,
34556		PointsMaterial: PointsMaterial,
34557		MeshPhysicalMaterial: MeshPhysicalMaterial,
34558		MeshStandardMaterial: MeshStandardMaterial,
34559		MeshPhongMaterial: MeshPhongMaterial,
34560		MeshToonMaterial: MeshToonMaterial,
34561		MeshNormalMaterial: MeshNormalMaterial,
34562		MeshLambertMaterial: MeshLambertMaterial,
34563		MeshDepthMaterial: MeshDepthMaterial,
34564		MeshDistanceMaterial: MeshDistanceMaterial,
34565		MeshBasicMaterial: MeshBasicMaterial,
34566		LineDashedMaterial: LineDashedMaterial,
34567		LineBasicMaterial: LineBasicMaterial,
34568		Material: Material
34569	});
34570  
34571	/**
34572	 * @author mrdoob / http://mrdoob.com/
34573	 */
34574  
34575	var Cache = {
34576  
34577		enabled: false,
34578  
34579		files: {},
34580  
34581		add: function ( key, file ) {
34582  
34583			if ( this.enabled === false ) return;
34584  
vendor: 10,683 bytes, lines 34585-35154
34585			// console.log( 'THREE.Cache', 'Adding key:', key );
34586  
34587			this.files[ key ] = file;
34588  
34589		},
34590  
34591		get: function ( key ) {
34592  
34593			if ( this.enabled === false ) return;
34594  
34595			// console.log( 'THREE.Cache', 'Checking key:', key );
34596  
34597			return this.files[ key ];
34598  
34599		},
34600  
34601		remove: function ( key ) {
34602  
34603			delete this.files[ key ];
34604  
34605		},
34606  
34607		clear: function () {
34608  
34609			this.files = {};
34610  
34611		}
34612  
34613	};
34614  
34615	/**
34616	 * @author mrdoob / http://mrdoob.com/
34617	 */
34618  
34619	function LoadingManager( onLoad, onProgress, onError ) {
34620  
34621		var scope = this;
34622  
34623		var isLoading = false;
34624		var itemsLoaded = 0;
34625		var itemsTotal = 0;
34626		var urlModifier = undefined;
34627  
34628		this.onStart = undefined;
34629		this.onLoad = onLoad;
34630		this.onProgress = onProgress;
34631		this.onError = onError;
34632  
34633		this.itemStart = function ( url ) {
34634  
34635			itemsTotal ++;
34636  
34637			if ( isLoading === false ) {
34638  
34639				if ( scope.onStart !== undefined ) {
34640  
34641					scope.onStart( url, itemsLoaded, itemsTotal );
34642  
34643				}
34644  
34645			}
34646  
34647			isLoading = true;
34648  
34649		};
34650  
34651		this.itemEnd = function ( url ) {
34652  
34653			itemsLoaded ++;
34654  
34655			if ( scope.onProgress !== undefined ) {
34656  
34657				scope.onProgress( url, itemsLoaded, itemsTotal );
34658  
34659			}
34660  
34661			if ( itemsLoaded === itemsTotal ) {
34662  
34663				isLoading = false;
34664  
34665				if ( scope.onLoad !== undefined ) {
34666  
34667					scope.onLoad();
34668  
34669				}
34670  
34671			}
34672  
34673		};
34674  
34675		this.itemError = function ( url ) {
34676  
34677			if ( scope.onError !== undefined ) {
34678  
34679				scope.onError( url );
34680  
34681			}
34682  
34683		};
34684  
34685		this.resolveURL = function ( url ) {
34686  
34687			if ( urlModifier ) {
34688  
34689				return urlModifier( url );
34690  
34691			}
34692  
34693			return url;
34694  
34695		};
34696  
34697		this.setURLModifier = function ( transform ) {
34698  
34699			urlModifier = transform;
34700			return this;
34701  
34702		};
34703  
34704	}
34705  
34706	var DefaultLoadingManager = new LoadingManager();
34707  
34708	/**
34709	 * @author mrdoob / http://mrdoob.com/
34710	 */
34711  
34712	var loading = {};
34713  
34714	function FileLoader( manager ) {
34715  
34716		this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager;
34717  
34718	}
34719  
34720	Object.assign( FileLoader.prototype, {
34721  
34722		load: function ( url, onLoad, onProgress, onError ) {
34723  
34724			if ( url === undefined ) url = '';
34725  
34726			if ( this.path !== undefined ) url = this.path + url;
34727  
34728			url = this.manager.resolveURL( url );
34729  
34730			var scope = this;
34731  
34732			var cached = Cache.get( url );
34733  
34734			if ( cached !== undefined ) {
34735  
34736				scope.manager.itemStart( url );
34737  
34738				setTimeout( function () {
34739  
34740					if ( onLoad ) onLoad( cached );
34741  
34742					scope.manager.itemEnd( url );
34743  
34744				}, 0 );
34745  
34746				return cached;
34747  
34748			}
34749  
34750			// Check if request is duplicate
34751  
34752			if ( loading[ url ] !== undefined ) {
34753  
34754				loading[ url ].push( {
34755  
34756					onLoad: onLoad,
34757					onProgress: onProgress,
34758					onError: onError
34759  
34760				} );
34761  
34762				return;
34763  
34764			}
34765  
34766			// Check for data: URI
34767			var dataUriRegex = /^data:(.*?)(;base64)?,(.*)$/;
34768			var dataUriRegexResult = url.match( dataUriRegex );
34769  
34770			// Safari can not handle Data URIs through XMLHttpRequest so process manually
34771			if ( dataUriRegexResult ) {
34772  
34773				var mimeType = dataUriRegexResult[ 1 ];
34774				var isBase64 = !! dataUriRegexResult[ 2 ];
34775				var data = dataUriRegexResult[ 3 ];
34776  
34777				data = window.decodeURIComponent( data );
34778  
34779				if ( isBase64 ) data = window.atob( data );
34780  
34781				try {
34782  
34783					var response;
34784					var responseType = ( this.responseType || '' ).toLowerCase();
34785  
34786					switch ( responseType ) {
34787  
34788						case 'arraybuffer':
34789						case 'blob':
34790  
34791							var view = new Uint8Array( data.length );
34792  
34793							for ( var i = 0; i < data.length; i ++ ) {
34794  
34795								view[ i ] = data.charCodeAt( i );
34796  
34797							}
34798  
34799							if ( responseType === 'blob' ) {
34800  
34801								response = new Blob( [ view.buffer ], { type: mimeType } );
34802  
34803							} else {
34804  
34805								response = view.buffer;
34806  
34807							}
34808  
34809							break;
34810  
34811						case 'document':
34812  
34813							var parser = new DOMParser();
34814							response = parser.parseFromString( data, mimeType );
34815  
34816							break;
34817  
34818						case 'json':
34819  
34820							response = JSON.parse( data );
34821  
34822							break;
34823  
34824						default: // 'text' or other
34825  
34826							response = data;
34827  
34828							break;
34829  
34830					}
34831  
34832					// Wait for next browser tick like standard XMLHttpRequest event dispatching does
34833					window.setTimeout( function () {
34834  
34835						if ( onLoad ) onLoad( response );
34836  
34837						scope.manager.itemEnd( url );
34838  
34839					}, 0 );
34840  
34841				} catch ( error ) {
34842  
34843					// Wait for next browser tick like standard XMLHttpRequest event dispatching does
34844					window.setTimeout( function () {
34845  
34846						if ( onError ) onError( error );
34847  
34848						scope.manager.itemEnd( url );
34849						scope.manager.itemError( url );
34850  
34851					}, 0 );
34852  
34853				}
34854  
34855			} else {
34856  
34857				// Initialise array for duplicate requests
34858  
34859				loading[ url ] = [];
34860  
34861				loading[ url ].push( {
34862  
34863					onLoad: onLoad,
34864					onProgress: onProgress,
34865					onError: onError
34866  
34867				} );
34868  
34869				var request = new XMLHttpRequest();
34870  
34871				request.open( 'GET', url, true );
34872  
34873				request.addEventListener( 'load', function ( event ) {
34874  
34875					var response = this.response;
34876  
34877					Cache.add( url, response );
34878  
34879					var callbacks = loading[ url ];
34880  
34881					delete loading[ url ];
34882  
34883					if ( this.status === 200 || this.status === 0 ) {
34884  
34885						// Some browsers return HTTP Status 0 when using non-http protocol
34886						// e.g. 'file://' or 'data://'. Handle as success.
34887  
34888						if ( this.status === 0 ) console.warn( 'THREE.FileLoader: HTTP Status 0 received.' );
34889  
34890						for ( var i = 0, il = callbacks.length; i < il; i ++ ) {
34891  
34892							var callback = callbacks[ i ];
34893							if ( callback.onLoad ) callback.onLoad( response );
34894  
34895						}
34896  
34897						scope.manager.itemEnd( url );
34898  
34899					} else {
34900  
34901						for ( var i = 0, il = callbacks.length; i < il; i ++ ) {
34902  
34903							var callback = callbacks[ i ];
34904							if ( callback.onError ) callback.onError( event );
34905  
34906						}
34907  
34908						scope.manager.itemEnd( url );
34909						scope.manager.itemError( url );
34910  
34911					}
34912  
34913				}, false );
34914  
34915				request.addEventListener( 'progress', function ( event ) {
34916  
34917					var callbacks = loading[ url ];
34918  
34919					for ( var i = 0, il = callbacks.length; i < il; i ++ ) {
34920  
34921						var callback = callbacks[ i ];
34922						if ( callback.onProgress ) callback.onProgress( event );
34923  
34924					}
34925  
34926				}, false );
34927  
34928				request.addEventListener( 'error', function ( event ) {
34929  
34930					var callbacks = loading[ url ];
34931  
34932					delete loading[ url ];
34933  
34934					for ( var i = 0, il = callbacks.length; i < il; i ++ ) {
34935  
34936						var callback = callbacks[ i ];
34937						if ( callback.onError ) callback.onError( event );
34938  
34939					}
34940  
34941					scope.manager.itemEnd( url );
34942					scope.manager.itemError( url );
34943  
34944				}, false );
34945  
34946				if ( this.responseType !== undefined ) request.responseType = this.responseType;
34947				if ( this.withCredentials !== undefined ) request.withCredentials = this.withCredentials;
34948  
34949				if ( request.overrideMimeType ) request.overrideMimeType( this.mimeType !== undefined ? this.mimeType : 'text/plain' );
34950  
34951				for ( var header in this.requestHeader ) {
34952  
34953					request.setRequestHeader( header, this.requestHeader[ header ] );
34954  
34955				}
34956  
34957				request.send( null );
34958  
34959			}
34960  
34961			scope.manager.itemStart( url );
34962  
34963			return request;
34964  
34965		},
34966  
34967		setPath: function ( value ) {
34968  
34969			this.path = value;
34970			return this;
34971  
34972		},
34973  
34974		setResponseType: function ( value ) {
34975  
34976			this.responseType = value;
34977			return this;
34978  
34979		},
34980  
34981		setWithCredentials: function ( value ) {
34982  
34983			this.withCredentials = value;
34984			return this;
34985  
34986		},
34987  
34988		setMimeType: function ( value ) {
34989  
34990			this.mimeType = value;
34991			return this;
34992  
34993		},
34994  
34995		setRequestHeader: function ( value ) {
34996  
34997			this.requestHeader = value;
34998			return this;
34999  
35000		}
35001  
35002	} );
35003  
35004	/**
35005	 * @author mrdoob / http://mrdoob.com/
35006	 *
35007	 * Abstract Base class to block based textures loader (dds, pvr, ...)
35008	 */
35009  
35010	function CompressedTextureLoader( manager ) {
35011  
35012		this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager;
35013  
35014		// override in sub classes
35015		this._parser = null;
35016  
35017	}
35018  
35019	Object.assign( CompressedTextureLoader.prototype, {
35020  
35021		load: function ( url, onLoad, onProgress, onError ) {
35022  
35023			var scope = this;
35024  
35025			var images = [];
35026  
35027			var texture = new CompressedTexture();
35028			texture.image = images;
35029  
35030			var loader = new FileLoader( this.manager );
35031			loader.setPath( this.path );
35032			loader.setResponseType( 'arraybuffer' );
35033  
35034			function loadTexture( i ) {
35035  
35036				loader.load( url[ i ], function ( buffer ) {
35037  
35038					var texDatas = scope._parser( buffer, true );
35039  
35040					images[ i ] = {
35041						width: texDatas.width,
35042						height: texDatas.height,
35043						format: texDatas.format,
35044						mipmaps: texDatas.mipmaps
35045					};
35046  
35047					loaded += 1;
35048  
35049					if ( loaded === 6 ) {
35050  
35051						if ( texDatas.mipmapCount === 1 )
35052							texture.minFilter = LinearFilter;
35053  
35054						texture.format = texDatas.format;
35055						texture.needsUpdate = true;
35056  
35057						if ( onLoad ) onLoad( texture );
35058  
35059					}
35060  
35061				}, onProgress, onError );
35062  
35063			}
35064  
35065			if ( Array.isArray( url ) ) {
35066  
35067				var loaded = 0;
35068  
35069				for ( var i = 0, il = url.length; i < il; ++ i ) {
35070  
35071					loadTexture( i );
35072  
35073				}
35074  
35075			} else {
35076  
35077				// compressed cubemap texture stored in a single DDS file
35078  
35079				loader.load( url, function ( buffer ) {
35080  
35081					var texDatas = scope._parser( buffer, true );
35082  
35083					if ( texDatas.isCubemap ) {
35084  
35085						var faces = texDatas.mipmaps.length / texDatas.mipmapCount;
35086  
35087						for ( var f = 0; f < faces; f ++ ) {
35088  
35089							images[ f ] = { mipmaps: [] };
35090  
35091							for ( var i = 0; i < texDatas.mipmapCount; i ++ ) {
35092  
35093								images[ f ].mipmaps.push( texDatas.mipmaps[ f * texDatas.mipmapCount + i ] );
35094								images[ f ].format = texDatas.format;
35095								images[ f ].width = texDatas.width;
35096								images[ f ].height = texDatas.height;
35097  
35098							}
35099  
35100						}
35101  
35102					} else {
35103  
35104						texture.image.width = texDatas.width;
35105						texture.image.height = texDatas.height;
35106						texture.mipmaps = texDatas.mipmaps;
35107  
35108					}
35109  
35110					if ( texDatas.mipmapCount === 1 ) {
35111  
35112						texture.minFilter = LinearFilter;
35113  
35114					}
35115  
35116					texture.format = texDatas.format;
35117					texture.needsUpdate = true;
35118  
35119					if ( onLoad ) onLoad( texture );
35120  
35121				}, onProgress, onError );
35122  
35123			}
35124  
35125			return texture;
35126  
35127		},
35128  
35129		setPath: function ( value ) {
35130  
35131			this.path = value;
35132			return this;
35133  
35134		}
35135  
35136	} );
35137  
35138	/**
35139	 * @author Nikos M. / https://github.com/foo123/
35140	 *
35141	 * Abstract Base class to load generic binary textures formats (rgbe, hdr, ...)
35142	 */
35143  
35144	function DataTextureLoader( manager ) {
35145  
35146		this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager;
35147  
35148		// override in sub classes
35149		this._parser = null;
35150  
35151	}
35152  
35153	Object.assign( DataTextureLoader.prototype, {
35154  
35155		load: function ( url, onLoad, onProgress, onError ) {
35156  
35157			var scope = this;
35158  
35159			var texture = new DataTexture();
35160  
35161			var loader = new FileLoader( this.manager );
35162			loader.setResponseType( 'arraybuffer' );
35163  
35164			loader.load( url, function ( buffer ) {
35165  
35166				var texData = scope._parser( buffer );
35167  
35168				if ( ! texData ) return;
35169  
35170				if ( undefined !== texData.image ) {
35171  
35172					texture.image = texData.image;
35173  
35174				} else if ( undefined !== texData.data ) {
35175  
35176					texture.image.width = texData.width;
35177					texture.image.height = texData.height;
35178					texture.image.data = texData.data;
35179  
35180				}
35181  
35182				texture.wrapS = undefined !== texData.wrapS ? texData.wrapS : ClampToEdgeWrapping;
35183				texture.wrapT = undefined !== texData.wrapT ? texData.wrapT : ClampToEdgeWrapping;
35184  
35185				texture.magFilter = undefined !== texData.magFilter ? texData.magFilter : LinearFilter;
35186				texture.minFilter = undefined !== texData.minFilter ? texData.minFilter : LinearMipMapLinearFilter;
35187  
35188				texture.anisotropy = undefined !== texData.anisotropy ? texData.anisotropy : 1;
35189  
35190				if ( undefined !== texData.format ) {
35191  
35192					texture.format = texData.format;
35193  
35194				}
35195				if ( undefined !== texData.type ) {
35196  
35197					texture.type = texData.type;
35198  
35199				}
35200  
35201				if ( undefined !== texData.mipmaps ) {
35202  
35203					texture.mipmaps = texData.mipmaps;
35204  
35205				}
35206  
35207				if ( 1 === texData.mipmapCount ) {
35208  
35209					texture.minFilter = LinearFilter;
35210  
35211				}
35212  
35213				texture.needsUpdate = true;
35214  
35215				if ( onLoad ) onLoad( texture, texData );
35216  
35217			}, onProgress, onError );
35218  
35219  
35220			return texture;
35221  
35222		}
35223  
35224	} );
35225  
35226	/**
35227	 * @author mrdoob / http://mrdoob.com/
35228	 */
35229  
35230  
35231	function ImageLoader( manager ) {
35232  
35233		this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager;
35234  
35235	}
35236  
35237	Object.assign( ImageLoader.prototype, {
35238  
vendor: 100,403 bytes, lines 35239-39931
35239		crossOrigin: 'Anonymous',
35240  
35241		load: function ( url, onLoad, onProgress, onError ) {
35242  
35243			if ( url === undefined ) url = '';
35244  
35245			if ( this.path !== undefined ) url = this.path + url;
35246  
35247			url = this.manager.resolveURL( url );
35248  
35249			var scope = this;
35250  
35251			var cached = Cache.get( url );
35252  
35253			if ( cached !== undefined ) {
35254  
35255				scope.manager.itemStart( url );
35256  
35257				setTimeout( function () {
35258  
35259					if ( onLoad ) onLoad( cached );
35260  
35261					scope.manager.itemEnd( url );
35262  
35263				}, 0 );
35264  
35265				return cached;
35266  
35267			}
35268  
35269			var image = document.createElementNS( 'http://www.w3.org/1999/xhtml', 'img' );
35270  
35271			function onImageLoad() {
35272  
35273				image.removeEventListener( 'load', onImageLoad, false );
35274				image.removeEventListener( 'error', onImageError, false );
35275  
35276				Cache.add( url, this );
35277  
35278				if ( onLoad ) onLoad( this );
35279  
35280				scope.manager.itemEnd( url );
35281  
35282			}
35283  
35284			function onImageError( event ) {
35285  
35286				image.removeEventListener( 'load', onImageLoad, false );
35287				image.removeEventListener( 'error', onImageError, false );
35288  
35289				if ( onError ) onError( event );
35290  
35291				scope.manager.itemEnd( url );
35292				scope.manager.itemError( url );
35293  
35294			}
35295  
35296			image.addEventListener( 'load', onImageLoad, false );
35297			image.addEventListener( 'error', onImageError, false );
35298  
35299			if ( url.substr( 0, 5 ) !== 'data:' ) {
35300  
35301				if ( this.crossOrigin !== undefined ) image.crossOrigin = this.crossOrigin;
35302  
35303			}
35304  
35305			scope.manager.itemStart( url );
35306  
35307			image.src = url;
35308  
35309			return image;
35310  
35311		},
35312  
35313		setCrossOrigin: function ( value ) {
35314  
35315			this.crossOrigin = value;
35316			return this;
35317  
35318		},
35319  
35320		setPath: function ( value ) {
35321  
35322			this.path = value;
35323			return this;
35324  
35325		}
35326  
35327	} );
35328  
35329	/**
35330	 * @author mrdoob / http://mrdoob.com/
35331	 */
35332  
35333  
35334	function CubeTextureLoader( manager ) {
35335  
35336		this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager;
35337  
35338	}
35339  
35340	Object.assign( CubeTextureLoader.prototype, {
35341  
35342		crossOrigin: 'Anonymous',
35343  
35344		load: function ( urls, onLoad, onProgress, onError ) {
35345  
35346			var texture = new CubeTexture();
35347  
35348			var loader = new ImageLoader( this.manager );
35349			loader.setCrossOrigin( this.crossOrigin );
35350			loader.setPath( this.path );
35351  
35352			var loaded = 0;
35353  
35354			function loadTexture( i ) {
35355  
35356				loader.load( urls[ i ], function ( image ) {
35357  
35358					texture.images[ i ] = image;
35359  
35360					loaded ++;
35361  
35362					if ( loaded === 6 ) {
35363  
35364						texture.needsUpdate = true;
35365  
35366						if ( onLoad ) onLoad( texture );
35367  
35368					}
35369  
35370				}, undefined, onError );
35371  
35372			}
35373  
35374			for ( var i = 0; i < urls.length; ++ i ) {
35375  
35376				loadTexture( i );
35377  
35378			}
35379  
35380			return texture;
35381  
35382		},
35383  
35384		setCrossOrigin: function ( value ) {
35385  
35386			this.crossOrigin = value;
35387			return this;
35388  
35389		},
35390  
35391		setPath: function ( value ) {
35392  
35393			this.path = value;
35394			return this;
35395  
35396		}
35397  
35398	} );
35399  
35400	/**
35401	 * @author mrdoob / http://mrdoob.com/
35402	 */
35403  
35404  
35405	function TextureLoader( manager ) {
35406  
35407		this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager;
35408  
35409	}
35410  
35411	Object.assign( TextureLoader.prototype, {
35412  
35413		crossOrigin: 'Anonymous',
35414  
35415		load: function ( url, onLoad, onProgress, onError ) {
35416  
35417			var texture = new Texture();
35418  
35419			var loader = new ImageLoader( this.manager );
35420			loader.setCrossOrigin( this.crossOrigin );
35421			loader.setPath( this.path );
35422  
35423			loader.load( url, function ( image ) {
35424  
35425				texture.image = image;
35426  
35427				// JPEGs can't have an alpha channel, so memory can be saved by storing them as RGB.
35428				var isJPEG = url.search( /\.(jpg|jpeg)$/ ) > 0 || url.search( /^data\:image\/jpeg/ ) === 0;
35429  
35430				texture.format = isJPEG ? RGBFormat : RGBAFormat;
35431				texture.needsUpdate = true;
35432  
35433				if ( onLoad !== undefined ) {
35434  
35435					onLoad( texture );
35436  
35437				}
35438  
35439			}, onProgress, onError );
35440  
35441			return texture;
35442  
35443		},
35444  
35445		setCrossOrigin: function ( value ) {
35446  
35447			this.crossOrigin = value;
35448			return this;
35449  
35450		},
35451  
35452		setPath: function ( value ) {
35453  
35454			this.path = value;
35455			return this;
35456  
35457		}
35458  
35459	} );
35460  
35461	/**
35462	 * @author zz85 / http://www.lab4games.net/zz85/blog
35463	 * Extensible curve object
35464	 *
35465	 * Some common of curve methods:
35466	 * .getPoint( t, optionalTarget ), .getTangent( t )
35467	 * .getPointAt( u, optionalTarget ), .getTangentAt( u )
35468	 * .getPoints(), .getSpacedPoints()
35469	 * .getLength()
35470	 * .updateArcLengths()
35471	 *
35472	 * This following curves inherit from THREE.Curve:
35473	 *
35474	 * -- 2D curves --
35475	 * THREE.ArcCurve
35476	 * THREE.CubicBezierCurve
35477	 * THREE.EllipseCurve
35478	 * THREE.LineCurve
35479	 * THREE.QuadraticBezierCurve
35480	 * THREE.SplineCurve
35481	 *
35482	 * -- 3D curves --
35483	 * THREE.CatmullRomCurve3
35484	 * THREE.CubicBezierCurve3
35485	 * THREE.LineCurve3
35486	 * THREE.QuadraticBezierCurve3
35487	 *
35488	 * A series of curves can be represented as a THREE.CurvePath.
35489	 *
35490	 **/
35491  
35492	/**************************************************************
35493	 *	Abstract Curve base class
35494	 **************************************************************/
35495  
35496	function Curve() {
35497  
35498		this.type = 'Curve';
35499  
35500		this.arcLengthDivisions = 200;
35501  
35502	}
35503  
35504	Object.assign( Curve.prototype, {
35505  
35506		// Virtual base class method to overwrite and implement in subclasses
35507		//	- t [0 .. 1]
35508  
35509		getPoint: function ( /* t, optionalTarget */ ) {
35510  
35511			console.warn( 'THREE.Curve: .getPoint() not implemented.' );
35512			return null;
35513  
35514		},
35515  
35516		// Get point at relative position in curve according to arc length
35517		// - u [0 .. 1]
35518  
35519		getPointAt: function ( u, optionalTarget ) {
35520  
35521			var t = this.getUtoTmapping( u );
35522			return this.getPoint( t, optionalTarget );
35523  
35524		},
35525  
35526		// Get sequence of points using getPoint( t )
35527  
35528		getPoints: function ( divisions ) {
35529  
35530			if ( divisions === undefined ) divisions = 5;
35531  
35532			var points = [];
35533  
35534			for ( var d = 0; d <= divisions; d ++ ) {
35535  
35536				points.push( this.getPoint( d / divisions ) );
35537  
35538			}
35539  
35540			return points;
35541  
35542		},
35543  
35544		// Get sequence of points using getPointAt( u )
35545  
35546		getSpacedPoints: function ( divisions ) {
35547  
35548			if ( divisions === undefined ) divisions = 5;
35549  
35550			var points = [];
35551  
35552			for ( var d = 0; d <= divisions; d ++ ) {
35553  
35554				points.push( this.getPointAt( d / divisions ) );
35555  
35556			}
35557  
35558			return points;
35559  
35560		},
35561  
35562		// Get total curve arc length
35563  
35564		getLength: function () {
35565  
35566			var lengths = this.getLengths();
35567			return lengths[ lengths.length - 1 ];
35568  
35569		},
35570  
35571		// Get list of cumulative segment lengths
35572  
35573		getLengths: function ( divisions ) {
35574  
35575			if ( divisions === undefined ) divisions = this.arcLengthDivisions;
35576  
35577			if ( this.cacheArcLengths &&
35578				( this.cacheArcLengths.length === divisions + 1 ) &&
35579				! this.needsUpdate ) {
35580  
35581				return this.cacheArcLengths;
35582  
35583			}
35584  
35585			this.needsUpdate = false;
35586  
35587			var cache = [];
35588			var current, last = this.getPoint( 0 );
35589			var p, sum = 0;
35590  
35591			cache.push( 0 );
35592  
35593			for ( p = 1; p <= divisions; p ++ ) {
35594  
35595				current = this.getPoint( p / divisions );
35596				sum += current.distanceTo( last );
35597				cache.push( sum );
35598				last = current;
35599  
35600			}
35601  
35602			this.cacheArcLengths = cache;
35603  
35604			return cache; // { sums: cache, sum: sum }; Sum is in the last element.
35605  
35606		},
35607  
35608		updateArcLengths: function () {
35609  
35610			this.needsUpdate = true;
35611			this.getLengths();
35612  
35613		},
35614  
35615		// Given u ( 0 .. 1 ), get a t to find p. This gives you points which are equidistant
35616  
35617		getUtoTmapping: function ( u, distance ) {
35618  
35619			var arcLengths = this.getLengths();
35620  
35621			var i = 0, il = arcLengths.length;
35622  
35623			var targetArcLength; // The targeted u distance value to get
35624  
35625			if ( distance ) {
35626  
35627				targetArcLength = distance;
35628  
35629			} else {
35630  
35631				targetArcLength = u * arcLengths[ il - 1 ];
35632  
35633			}
35634  
35635			// binary search for the index with largest value smaller than target u distance
35636  
35637			var low = 0, high = il - 1, comparison;
35638  
35639			while ( low <= high ) {
35640  
35641				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
35642  
35643				comparison = arcLengths[ i ] - targetArcLength;
35644  
35645				if ( comparison < 0 ) {
35646  
35647					low = i + 1;
35648  
35649				} else if ( comparison > 0 ) {
35650  
35651					high = i - 1;
35652  
35653				} else {
35654  
35655					high = i;
35656					break;
35657  
35658					// DONE
35659  
35660				}
35661  
35662			}
35663  
35664			i = high;
35665  
35666			if ( arcLengths[ i ] === targetArcLength ) {
35667  
35668				return i / ( il - 1 );
35669  
35670			}
35671  
35672			// we could get finer grain at lengths, or use simple interpolation between two points
35673  
35674			var lengthBefore = arcLengths[ i ];
35675			var lengthAfter = arcLengths[ i + 1 ];
35676  
35677			var segmentLength = lengthAfter - lengthBefore;
35678  
35679			// determine where we are between the 'before' and 'after' points
35680  
35681			var segmentFraction = ( targetArcLength - lengthBefore ) / segmentLength;
35682  
35683			// add that fractional amount to t
35684  
35685			var t = ( i + segmentFraction ) / ( il - 1 );
35686  
35687			return t;
35688  
35689		},
35690  
35691		// Returns a unit vector tangent at t
35692		// In case any sub curve does not implement its tangent derivation,
35693		// 2 points a small delta apart will be used to find its gradient
35694		// which seems to give a reasonable approximation
35695  
35696		getTangent: function ( t ) {
35697  
35698			var delta = 0.0001;
35699			var t1 = t - delta;
35700			var t2 = t + delta;
35701  
35702			// Capping in case of danger
35703  
35704			if ( t1 < 0 ) t1 = 0;
35705			if ( t2 > 1 ) t2 = 1;
35706  
35707			var pt1 = this.getPoint( t1 );
35708			var pt2 = this.getPoint( t2 );
35709  
35710			var vec = pt2.clone().sub( pt1 );
35711			return vec.normalize();
35712  
35713		},
35714  
35715		getTangentAt: function ( u ) {
35716  
35717			var t = this.getUtoTmapping( u );
35718			return this.getTangent( t );
35719  
35720		},
35721  
35722		computeFrenetFrames: function ( segments, closed ) {
35723  
35724			// see http://www.cs.indiana.edu/pub/techreports/TR425.pdf
35725  
35726			var normal = new Vector3();
35727  
35728			var tangents = [];
35729			var normals = [];
35730			var binormals = [];
35731  
35732			var vec = new Vector3();
35733			var mat = new Matrix4();
35734  
35735			var i, u, theta;
35736  
35737			// compute the tangent vectors for each segment on the curve
35738  
35739			for ( i = 0; i <= segments; i ++ ) {
35740  
35741				u = i / segments;
35742  
35743				tangents[ i ] = this.getTangentAt( u );
35744				tangents[ i ].normalize();
35745  
35746			}
35747  
35748			// select an initial normal vector perpendicular to the first tangent vector,
35749			// and in the direction of the minimum tangent xyz component
35750  
35751			normals[ 0 ] = new Vector3();
35752			binormals[ 0 ] = new Vector3();
35753			var min = Number.MAX_VALUE;
35754			var tx = Math.abs( tangents[ 0 ].x );
35755			var ty = Math.abs( tangents[ 0 ].y );
35756			var tz = Math.abs( tangents[ 0 ].z );
35757  
35758			if ( tx <= min ) {
35759  
35760				min = tx;
35761				normal.set( 1, 0, 0 );
35762  
35763			}
35764  
35765			if ( ty <= min ) {
35766  
35767				min = ty;
35768				normal.set( 0, 1, 0 );
35769  
35770			}
35771  
35772			if ( tz <= min ) {
35773  
35774				normal.set( 0, 0, 1 );
35775  
35776			}
35777  
35778			vec.crossVectors( tangents[ 0 ], normal ).normalize();
35779  
35780			normals[ 0 ].crossVectors( tangents[ 0 ], vec );
35781			binormals[ 0 ].crossVectors( tangents[ 0 ], normals[ 0 ] );
35782  
35783  
35784			// compute the slowly-varying normal and binormal vectors for each segment on the curve
35785  
35786			for ( i = 1; i <= segments; i ++ ) {
35787  
35788				normals[ i ] = normals[ i - 1 ].clone();
35789  
35790				binormals[ i ] = binormals[ i - 1 ].clone();
35791  
35792				vec.crossVectors( tangents[ i - 1 ], tangents[ i ] );
35793  
35794				if ( vec.length() > Number.EPSILON ) {
35795  
35796					vec.normalize();
35797  
35798					theta = Math.acos( _Math.clamp( tangents[ i - 1 ].dot( tangents[ i ] ), - 1, 1 ) ); // clamp for floating pt errors
35799  
35800					normals[ i ].applyMatrix4( mat.makeRotationAxis( vec, theta ) );
35801  
35802				}
35803  
35804				binormals[ i ].crossVectors( tangents[ i ], normals[ i ] );
35805  
35806			}
35807  
35808			// if the curve is closed, postprocess the vectors so the first and last normal vectors are the same
35809  
35810			if ( closed === true ) {
35811  
35812				theta = Math.acos( _Math.clamp( normals[ 0 ].dot( normals[ segments ] ), - 1, 1 ) );
35813				theta /= segments;
35814  
35815				if ( tangents[ 0 ].dot( vec.crossVectors( normals[ 0 ], normals[ segments ] ) ) > 0 ) {
35816  
35817					theta = - theta;
35818  
35819				}
35820  
35821				for ( i = 1; i <= segments; i ++ ) {
35822  
35823					// twist a little...
35824					normals[ i ].applyMatrix4( mat.makeRotationAxis( tangents[ i ], theta * i ) );
35825					binormals[ i ].crossVectors( tangents[ i ], normals[ i ] );
35826  
35827				}
35828  
35829			}
35830  
35831			return {
35832				tangents: tangents,
35833				normals: normals,
35834				binormals: binormals
35835			};
35836  
35837		},
35838  
35839		clone: function () {
35840  
35841			return new this.constructor().copy( this );
35842  
35843		},
35844  
35845		copy: function ( source ) {
35846  
35847			this.arcLengthDivisions = source.arcLengthDivisions;
35848  
35849			return this;
35850  
35851		},
35852  
35853		toJSON: function () {
35854  
35855			var data = {
35856				metadata: {
35857					version: 4.5,
35858					type: 'Curve',
35859					generator: 'Curve.toJSON'
35860				}
35861			};
35862  
35863			data.arcLengthDivisions = this.arcLengthDivisions;
35864			data.type = this.type;
35865  
35866			return data;
35867  
35868		},
35869  
35870		fromJSON: function ( json ) {
35871  
35872			this.arcLengthDivisions = json.arcLengthDivisions;
35873  
35874			return this;
35875  
35876		}
35877  
35878	} );
35879  
35880	function EllipseCurve( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ) {
35881  
35882		Curve.call( this );
35883  
35884		this.type = 'EllipseCurve';
35885  
35886		this.aX = aX || 0;
35887		this.aY = aY || 0;
35888  
35889		this.xRadius = xRadius || 1;
35890		this.yRadius = yRadius || 1;
35891  
35892		this.aStartAngle = aStartAngle || 0;
35893		this.aEndAngle = aEndAngle || 2 * Math.PI;
35894  
35895		this.aClockwise = aClockwise || false;
35896  
35897		this.aRotation = aRotation || 0;
35898  
35899	}
35900  
35901	EllipseCurve.prototype = Object.create( Curve.prototype );
35902	EllipseCurve.prototype.constructor = EllipseCurve;
35903  
35904	EllipseCurve.prototype.isEllipseCurve = true;
35905  
35906	EllipseCurve.prototype.getPoint = function ( t, optionalTarget ) {
35907  
35908		var point = optionalTarget || new Vector2();
35909  
35910		var twoPi = Math.PI * 2;
35911		var deltaAngle = this.aEndAngle - this.aStartAngle;
35912		var samePoints = Math.abs( deltaAngle ) < Number.EPSILON;
35913  
35914		// ensures that deltaAngle is 0 .. 2 PI
35915		while ( deltaAngle < 0 ) deltaAngle += twoPi;
35916		while ( deltaAngle > twoPi ) deltaAngle -= twoPi;
35917  
35918		if ( deltaAngle < Number.EPSILON ) {
35919  
35920			if ( samePoints ) {
35921  
35922				deltaAngle = 0;
35923  
35924			} else {
35925  
35926				deltaAngle = twoPi;
35927  
35928			}
35929  
35930		}
35931  
35932		if ( this.aClockwise === true && ! samePoints ) {
35933  
35934			if ( deltaAngle === twoPi ) {
35935  
35936				deltaAngle = - twoPi;
35937  
35938			} else {
35939  
35940				deltaAngle = deltaAngle - twoPi;
35941  
35942			}
35943  
35944		}
35945  
35946		var angle = this.aStartAngle + t * deltaAngle;
35947		var x = this.aX + this.xRadius * Math.cos( angle );
35948		var y = this.aY + this.yRadius * Math.sin( angle );
35949  
35950		if ( this.aRotation !== 0 ) {
35951  
35952			var cos = Math.cos( this.aRotation );
35953			var sin = Math.sin( this.aRotation );
35954  
35955			var tx = x - this.aX;
35956			var ty = y - this.aY;
35957  
35958			// Rotate the point about the center of the ellipse.
35959			x = tx * cos - ty * sin + this.aX;
35960			y = tx * sin + ty * cos + this.aY;
35961  
35962		}
35963  
35964		return point.set( x, y );
35965  
35966	};
35967  
35968	EllipseCurve.prototype.copy = function ( source ) {
35969  
35970		Curve.prototype.copy.call( this, source );
35971  
35972		this.aX = source.aX;
35973		this.aY = source.aY;
35974  
35975		this.xRadius = source.xRadius;
35976		this.yRadius = source.yRadius;
35977  
35978		this.aStartAngle = source.aStartAngle;
35979		this.aEndAngle = source.aEndAngle;
35980  
35981		this.aClockwise = source.aClockwise;
35982  
35983		this.aRotation = source.aRotation;
35984  
35985		return this;
35986  
35987	};
35988  
35989  
35990	EllipseCurve.prototype.toJSON = function () {
35991  
35992		var data = Curve.prototype.toJSON.call( this );
35993  
35994		data.aX = this.aX;
35995		data.aY = this.aY;
35996  
35997		data.xRadius = this.xRadius;
35998		data.yRadius = this.yRadius;
35999  
36000		data.aStartAngle = this.aStartAngle;
36001		data.aEndAngle = this.aEndAngle;
36002  
36003		data.aClockwise = this.aClockwise;
36004  
36005		data.aRotation = this.aRotation;
36006  
36007		return data;
36008  
36009	};
36010  
36011	EllipseCurve.prototype.fromJSON = function ( json ) {
36012  
36013		Curve.prototype.fromJSON.call( this, json );
36014  
36015		this.aX = json.aX;
36016		this.aY = json.aY;
36017  
36018		this.xRadius = json.xRadius;
36019		this.yRadius = json.yRadius;
36020  
36021		this.aStartAngle = json.aStartAngle;
36022		this.aEndAngle = json.aEndAngle;
36023  
36024		this.aClockwise = json.aClockwise;
36025  
36026		this.aRotation = json.aRotation;
36027  
36028		return this;
36029  
36030	};
36031  
36032	function ArcCurve( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) {
36033  
36034		EllipseCurve.call( this, aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise );
36035  
36036		this.type = 'ArcCurve';
36037  
36038	}
36039  
36040	ArcCurve.prototype = Object.create( EllipseCurve.prototype );
36041	ArcCurve.prototype.constructor = ArcCurve;
36042  
36043	ArcCurve.prototype.isArcCurve = true;
36044  
36045	/**
36046	 * @author zz85 https://github.com/zz85
36047	 *
36048	 * Centripetal CatmullRom Curve - which is useful for avoiding
36049	 * cusps and self-intersections in non-uniform catmull rom curves.
36050	 * http://www.cemyuksel.com/research/catmullrom_param/catmullrom.pdf
36051	 *
36052	 * curve.type accepts centripetal(default), chordal and catmullrom
36053	 * curve.tension is used for catmullrom which defaults to 0.5
36054	 */
36055  
36056  
36057	/*
36058	Based on an optimized c++ solution in
36059	 - http://stackoverflow.com/questions/9489736/catmull-rom-curve-with-no-cusps-and-no-self-intersections/
36060	 - http://ideone.com/NoEbVM
36061  
36062	This CubicPoly class could be used for reusing some variables and calculations,
36063	but for three.js curve use, it could be possible inlined and flatten into a single function call
36064	which can be placed in CurveUtils.
36065	*/
36066  
36067	function CubicPoly() {
36068  
36069		var c0 = 0, c1 = 0, c2 = 0, c3 = 0;
36070  
36071		/*
36072		 * Compute coefficients for a cubic polynomial
36073		 *   p(s) = c0 + c1*s + c2*s^2 + c3*s^3
36074		 * such that
36075		 *   p(0) = x0, p(1) = x1
36076		 *  and
36077		 *   p'(0) = t0, p'(1) = t1.
36078		 */
36079		function init( x0, x1, t0, t1 ) {
36080  
36081			c0 = x0;
36082			c1 = t0;
36083			c2 = - 3 * x0 + 3 * x1 - 2 * t0 - t1;
36084			c3 = 2 * x0 - 2 * x1 + t0 + t1;
36085  
36086		}
36087  
36088		return {
36089  
36090			initCatmullRom: function ( x0, x1, x2, x3, tension ) {
36091  
36092				init( x1, x2, tension * ( x2 - x0 ), tension * ( x3 - x1 ) );
36093  
36094			},
36095  
36096			initNonuniformCatmullRom: function ( x0, x1, x2, x3, dt0, dt1, dt2 ) {
36097  
36098				// compute tangents when parameterized in [t1,t2]
36099				var t1 = ( x1 - x0 ) / dt0 - ( x2 - x0 ) / ( dt0 + dt1 ) + ( x2 - x1 ) / dt1;
36100				var t2 = ( x2 - x1 ) / dt1 - ( x3 - x1 ) / ( dt1 + dt2 ) + ( x3 - x2 ) / dt2;
36101  
36102				// rescale tangents for parametrization in [0,1]
36103				t1 *= dt1;
36104				t2 *= dt1;
36105  
36106				init( x1, x2, t1, t2 );
36107  
36108			},
36109  
36110			calc: function ( t ) {
36111  
36112				var t2 = t * t;
36113				var t3 = t2 * t;
36114				return c0 + c1 * t + c2 * t2 + c3 * t3;
36115  
36116			}
36117  
36118		};
36119  
36120	}
36121  
36122	//
36123  
36124	var tmp = new Vector3();
36125	var px = new CubicPoly(), py = new CubicPoly(), pz = new CubicPoly();
36126  
36127	function CatmullRomCurve3( points, closed, curveType, tension ) {
36128  
36129		Curve.call( this );
36130  
36131		this.type = 'CatmullRomCurve3';
36132  
36133		this.points = points || [];
36134		this.closed = closed || false;
36135		this.curveType = curveType || 'centripetal';
36136		this.tension = tension || 0.5;
36137  
36138	}
36139  
36140	CatmullRomCurve3.prototype = Object.create( Curve.prototype );
36141	CatmullRomCurve3.prototype.constructor = CatmullRomCurve3;
36142  
36143	CatmullRomCurve3.prototype.isCatmullRomCurve3 = true;
36144  
36145	CatmullRomCurve3.prototype.getPoint = function ( t, optionalTarget ) {
36146  
36147		var point = optionalTarget || new Vector3();
36148  
36149		var points = this.points;
36150		var l = points.length;
36151  
36152		var p = ( l - ( this.closed ? 0 : 1 ) ) * t;
36153		var intPoint = Math.floor( p );
36154		var weight = p - intPoint;
36155  
36156		if ( this.closed ) {
36157  
36158			intPoint += intPoint > 0 ? 0 : ( Math.floor( Math.abs( intPoint ) / l ) + 1 ) * l;
36159  
36160		} else if ( weight === 0 && intPoint === l - 1 ) {
36161  
36162			intPoint = l - 2;
36163			weight = 1;
36164  
36165		}
36166  
36167		var p0, p1, p2, p3; // 4 points
36168  
36169		if ( this.closed || intPoint > 0 ) {
36170  
36171			p0 = points[ ( intPoint - 1 ) % l ];
36172  
36173		} else {
36174  
36175			// extrapolate first point
36176			tmp.subVectors( points[ 0 ], points[ 1 ] ).add( points[ 0 ] );
36177			p0 = tmp;
36178  
36179		}
36180  
36181		p1 = points[ intPoint % l ];
36182		p2 = points[ ( intPoint + 1 ) % l ];
36183  
36184		if ( this.closed || intPoint + 2 < l ) {
36185  
36186			p3 = points[ ( intPoint + 2 ) % l ];
36187  
36188		} else {
36189  
36190			// extrapolate last point
36191			tmp.subVectors( points[ l - 1 ], points[ l - 2 ] ).add( points[ l - 1 ] );
36192			p3 = tmp;
36193  
36194		}
36195  
36196		if ( this.curveType === 'centripetal' || this.curveType === 'chordal' ) {
36197  
36198			// init Centripetal / Chordal Catmull-Rom
36199			var pow = this.curveType === 'chordal' ? 0.5 : 0.25;
36200			var dt0 = Math.pow( p0.distanceToSquared( p1 ), pow );
36201			var dt1 = Math.pow( p1.distanceToSquared( p2 ), pow );
36202			var dt2 = Math.pow( p2.distanceToSquared( p3 ), pow );
36203  
36204			// safety check for repeated points
36205			if ( dt1 < 1e-4 ) dt1 = 1.0;
36206			if ( dt0 < 1e-4 ) dt0 = dt1;
36207			if ( dt2 < 1e-4 ) dt2 = dt1;
36208  
36209			px.initNonuniformCatmullRom( p0.x, p1.x, p2.x, p3.x, dt0, dt1, dt2 );
36210			py.initNonuniformCatmullRom( p0.y, p1.y, p2.y, p3.y, dt0, dt1, dt2 );
36211			pz.initNonuniformCatmullRom( p0.z, p1.z, p2.z, p3.z, dt0, dt1, dt2 );
36212  
36213		} else if ( this.curveType === 'catmullrom' ) {
36214  
36215			px.initCatmullRom( p0.x, p1.x, p2.x, p3.x, this.tension );
36216			py.initCatmullRom( p0.y, p1.y, p2.y, p3.y, this.tension );
36217			pz.initCatmullRom( p0.z, p1.z, p2.z, p3.z, this.tension );
36218  
36219		}
36220  
36221		point.set(
36222			px.calc( weight ),
36223			py.calc( weight ),
36224			pz.calc( weight )
36225		);
36226  
36227		return point;
36228  
36229	};
36230  
36231	CatmullRomCurve3.prototype.copy = function ( source ) {
36232  
36233		Curve.prototype.copy.call( this, source );
36234  
36235		this.points = [];
36236  
36237		for ( var i = 0, l = source.points.length; i < l; i ++ ) {
36238  
36239			var point = source.points[ i ];
36240  
36241			this.points.push( point.clone() );
36242  
36243		}
36244  
36245		this.closed = source.closed;
36246		this.curveType = source.curveType;
36247		this.tension = source.tension;
36248  
36249		return this;
36250  
36251	};
36252  
36253	CatmullRomCurve3.prototype.toJSON = function () {
36254  
36255		var data = Curve.prototype.toJSON.call( this );
36256  
36257		data.points = [];
36258  
36259		for ( var i = 0, l = this.points.length; i < l; i ++ ) {
36260  
36261			var point = this.points[ i ];
36262			data.points.push( point.toArray() );
36263  
36264		}
36265  
36266		data.closed = this.closed;
36267		data.curveType = this.curveType;
36268		data.tension = this.tension;
36269  
36270		return data;
36271  
36272	};
36273  
36274	CatmullRomCurve3.prototype.fromJSON = function ( json ) {
36275  
36276		Curve.prototype.fromJSON.call( this, json );
36277  
36278		this.points = [];
36279  
36280		for ( var i = 0, l = json.points.length; i < l; i ++ ) {
36281  
36282			var point = json.points[ i ];
36283			this.points.push( new Vector3().fromArray( point ) );
36284  
36285		}
36286  
36287		this.closed = json.closed;
36288		this.curveType = json.curveType;
36289		this.tension = json.tension;
36290  
36291		return this;
36292  
36293	};
36294  
36295	/**
36296	 * @author zz85 / http://www.lab4games.net/zz85/blog
36297	 *
36298	 * Bezier Curves formulas obtained from
36299	 * http://en.wikipedia.org/wiki/Bézier_curve
36300	 */
36301  
36302	function CatmullRom( t, p0, p1, p2, p3 ) {
36303  
36304		var v0 = ( p2 - p0 ) * 0.5;
36305		var v1 = ( p3 - p1 ) * 0.5;
36306		var t2 = t * t;
36307		var t3 = t * t2;
36308		return ( 2 * p1 - 2 * p2 + v0 + v1 ) * t3 + ( - 3 * p1 + 3 * p2 - 2 * v0 - v1 ) * t2 + v0 * t + p1;
36309  
36310	}
36311  
36312	//
36313  
36314	function QuadraticBezierP0( t, p ) {
36315  
36316		var k = 1 - t;
36317		return k * k * p;
36318  
36319	}
36320  
36321	function QuadraticBezierP1( t, p ) {
36322  
36323		return 2 * ( 1 - t ) * t * p;
36324  
36325	}
36326  
36327	function QuadraticBezierP2( t, p ) {
36328  
36329		return t * t * p;
36330  
36331	}
36332  
36333	function QuadraticBezier( t, p0, p1, p2 ) {
36334  
36335		return QuadraticBezierP0( t, p0 ) + QuadraticBezierP1( t, p1 ) +
36336			QuadraticBezierP2( t, p2 );
36337  
36338	}
36339  
36340	//
36341  
36342	function CubicBezierP0( t, p ) {
36343  
36344		var k = 1 - t;
36345		return k * k * k * p;
36346  
36347	}
36348  
36349	function CubicBezierP1( t, p ) {
36350  
36351		var k = 1 - t;
36352		return 3 * k * k * t * p;
36353  
36354	}
36355  
36356	function CubicBezierP2( t, p ) {
36357  
36358		return 3 * ( 1 - t ) * t * t * p;
36359  
36360	}
36361  
36362	function CubicBezierP3( t, p ) {
36363  
36364		return t * t * t * p;
36365  
36366	}
36367  
36368	function CubicBezier( t, p0, p1, p2, p3 ) {
36369  
36370		return CubicBezierP0( t, p0 ) + CubicBezierP1( t, p1 ) + CubicBezierP2( t, p2 ) +
36371			CubicBezierP3( t, p3 );
36372  
36373	}
36374  
36375	function CubicBezierCurve( v0, v1, v2, v3 ) {
36376  
36377		Curve.call( this );
36378  
36379		this.type = 'CubicBezierCurve';
36380  
36381		this.v0 = v0 || new Vector2();
36382		this.v1 = v1 || new Vector2();
36383		this.v2 = v2 || new Vector2();
36384		this.v3 = v3 || new Vector2();
36385  
36386	}
36387  
36388	CubicBezierCurve.prototype = Object.create( Curve.prototype );
36389	CubicBezierCurve.prototype.constructor = CubicBezierCurve;
36390  
36391	CubicBezierCurve.prototype.isCubicBezierCurve = true;
36392  
36393	CubicBezierCurve.prototype.getPoint = function ( t, optionalTarget ) {
36394  
36395		var point = optionalTarget || new Vector2();
36396  
36397		var v0 = this.v0, v1 = this.v1, v2 = this.v2, v3 = this.v3;
36398  
36399		point.set(
36400			CubicBezier( t, v0.x, v1.x, v2.x, v3.x ),
36401			CubicBezier( t, v0.y, v1.y, v2.y, v3.y )
36402		);
36403  
36404		return point;
36405  
36406	};
36407  
36408	CubicBezierCurve.prototype.copy = function ( source ) {
36409  
36410		Curve.prototype.copy.call( this, source );
36411  
36412		this.v0.copy( source.v0 );
36413		this.v1.copy( source.v1 );
36414		this.v2.copy( source.v2 );
36415		this.v3.copy( source.v3 );
36416  
36417		return this;
36418  
36419	};
36420  
36421	CubicBezierCurve.prototype.toJSON = function () {
36422  
36423		var data = Curve.prototype.toJSON.call( this );
36424  
36425		data.v0 = this.v0.toArray();
36426		data.v1 = this.v1.toArray();
36427		data.v2 = this.v2.toArray();
36428		data.v3 = this.v3.toArray();
36429  
36430		return data;
36431  
36432	};
36433  
36434	CubicBezierCurve.prototype.fromJSON = function ( json ) {
36435  
36436		Curve.prototype.fromJSON.call( this, json );
36437  
36438		this.v0.fromArray( json.v0 );
36439		this.v1.fromArray( json.v1 );
36440		this.v2.fromArray( json.v2 );
36441		this.v3.fromArray( json.v3 );
36442  
36443		return this;
36444  
36445	};
36446  
36447	function CubicBezierCurve3( v0, v1, v2, v3 ) {
36448  
36449		Curve.call( this );
36450  
36451		this.type = 'CubicBezierCurve3';
36452  
36453		this.v0 = v0 || new Vector3();
36454		this.v1 = v1 || new Vector3();
36455		this.v2 = v2 || new Vector3();
36456		this.v3 = v3 || new Vector3();
36457  
36458	}
36459  
36460	CubicBezierCurve3.prototype = Object.create( Curve.prototype );
36461	CubicBezierCurve3.prototype.constructor = CubicBezierCurve3;
36462  
36463	CubicBezierCurve3.prototype.isCubicBezierCurve3 = true;
36464  
36465	CubicBezierCurve3.prototype.getPoint = function ( t, optionalTarget ) {
36466  
36467		var point = optionalTarget || new Vector3();
36468  
36469		var v0 = this.v0, v1 = this.v1, v2 = this.v2, v3 = this.v3;
36470  
36471		point.set(
36472			CubicBezier( t, v0.x, v1.x, v2.x, v3.x ),
36473			CubicBezier( t, v0.y, v1.y, v2.y, v3.y ),
36474			CubicBezier( t, v0.z, v1.z, v2.z, v3.z )
36475		);
36476  
36477		return point;
36478  
36479	};
36480  
36481	CubicBezierCurve3.prototype.copy = function ( source ) {
36482  
36483		Curve.prototype.copy.call( this, source );
36484  
36485		this.v0.copy( source.v0 );
36486		this.v1.copy( source.v1 );
36487		this.v2.copy( source.v2 );
36488		this.v3.copy( source.v3 );
36489  
36490		return this;
36491  
36492	};
36493  
36494	CubicBezierCurve3.prototype.toJSON = function () {
36495  
36496		var data = Curve.prototype.toJSON.call( this );
36497  
36498		data.v0 = this.v0.toArray();
36499		data.v1 = this.v1.toArray();
36500		data.v2 = this.v2.toArray();
36501		data.v3 = this.v3.toArray();
36502  
36503		return data;
36504  
36505	};
36506  
36507	CubicBezierCurve3.prototype.fromJSON = function ( json ) {
36508  
36509		Curve.prototype.fromJSON.call( this, json );
36510  
36511		this.v0.fromArray( json.v0 );
36512		this.v1.fromArray( json.v1 );
36513		this.v2.fromArray( json.v2 );
36514		this.v3.fromArray( json.v3 );
36515  
36516		return this;
36517  
36518	};
36519  
36520	function LineCurve( v1, v2 ) {
36521  
36522		Curve.call( this );
36523  
36524		this.type = 'LineCurve';
36525  
36526		this.v1 = v1 || new Vector2();
36527		this.v2 = v2 || new Vector2();
36528  
36529	}
36530  
36531	LineCurve.prototype = Object.create( Curve.prototype );
36532	LineCurve.prototype.constructor = LineCurve;
36533  
36534	LineCurve.prototype.isLineCurve = true;
36535  
36536	LineCurve.prototype.getPoint = function ( t, optionalTarget ) {
36537  
36538		var point = optionalTarget || new Vector2();
36539  
36540		if ( t === 1 ) {
36541  
36542			point.copy( this.v2 );
36543  
36544		} else {
36545  
36546			point.copy( this.v2 ).sub( this.v1 );
36547			point.multiplyScalar( t ).add( this.v1 );
36548  
36549		}
36550  
36551		return point;
36552  
36553	};
36554  
36555	// Line curve is linear, so we can overwrite default getPointAt
36556  
36557	LineCurve.prototype.getPointAt = function ( u, optionalTarget ) {
36558  
36559		return this.getPoint( u, optionalTarget );
36560  
36561	};
36562  
36563	LineCurve.prototype.getTangent = function ( /* t */ ) {
36564  
36565		var tangent = this.v2.clone().sub( this.v1 );
36566  
36567		return tangent.normalize();
36568  
36569	};
36570  
36571	LineCurve.prototype.copy = function ( source ) {
36572  
36573		Curve.prototype.copy.call( this, source );
36574  
36575		this.v1.copy( source.v1 );
36576		this.v2.copy( source.v2 );
36577  
36578		return this;
36579  
36580	};
36581  
36582	LineCurve.prototype.toJSON = function () {
36583  
36584		var data = Curve.prototype.toJSON.call( this );
36585  
36586		data.v1 = this.v1.toArray();
36587		data.v2 = this.v2.toArray();
36588  
36589		return data;
36590  
36591	};
36592  
36593	LineCurve.prototype.fromJSON = function ( json ) {
36594  
36595		Curve.prototype.fromJSON.call( this, json );
36596  
36597		this.v1.fromArray( json.v1 );
36598		this.v2.fromArray( json.v2 );
36599  
36600		return this;
36601  
36602	};
36603  
36604	function LineCurve3( v1, v2 ) {
36605  
36606		Curve.call( this );
36607  
36608		this.type = 'LineCurve3';
36609  
36610		this.v1 = v1 || new Vector3();
36611		this.v2 = v2 || new Vector3();
36612  
36613	}
36614  
36615	LineCurve3.prototype = Object.create( Curve.prototype );
36616	LineCurve3.prototype.constructor = LineCurve3;
36617  
36618	LineCurve3.prototype.isLineCurve3 = true;
36619  
36620	LineCurve3.prototype.getPoint = function ( t, optionalTarget ) {
36621  
36622		var point = optionalTarget || new Vector3();
36623  
36624		if ( t === 1 ) {
36625  
36626			point.copy( this.v2 );
36627  
36628		} else {
36629  
36630			point.copy( this.v2 ).sub( this.v1 );
36631			point.multiplyScalar( t ).add( this.v1 );
36632  
36633		}
36634  
36635		return point;
36636  
36637	};
36638  
36639	// Line curve is linear, so we can overwrite default getPointAt
36640  
36641	LineCurve3.prototype.getPointAt = function ( u, optionalTarget ) {
36642  
36643		return this.getPoint( u, optionalTarget );
36644  
36645	};
36646  
36647	LineCurve3.prototype.copy = function ( source ) {
36648  
36649		Curve.prototype.copy.call( this, source );
36650  
36651		this.v1.copy( source.v1 );
36652		this.v2.copy( source.v2 );
36653  
36654		return this;
36655  
36656	};
36657  
36658	LineCurve3.prototype.toJSON = function () {
36659  
36660		var data = Curve.prototype.toJSON.call( this );
36661  
36662		data.v1 = this.v1.toArray();
36663		data.v2 = this.v2.toArray();
36664  
36665		return data;
36666  
36667	};
36668  
36669	LineCurve3.prototype.fromJSON = function ( json ) {
36670  
36671		Curve.prototype.fromJSON.call( this, json );
36672  
36673		this.v1.fromArray( json.v1 );
36674		this.v2.fromArray( json.v2 );
36675  
36676		return this;
36677  
36678	};
36679  
36680	function QuadraticBezierCurve( v0, v1, v2 ) {
36681  
36682		Curve.call( this );
36683  
36684		this.type = 'QuadraticBezierCurve';
36685  
36686		this.v0 = v0 || new Vector2();
36687		this.v1 = v1 || new Vector2();
36688		this.v2 = v2 || new Vector2();
36689  
36690	}
36691  
36692	QuadraticBezierCurve.prototype = Object.create( Curve.prototype );
36693	QuadraticBezierCurve.prototype.constructor = QuadraticBezierCurve;
36694  
36695	QuadraticBezierCurve.prototype.isQuadraticBezierCurve = true;
36696  
36697	QuadraticBezierCurve.prototype.getPoint = function ( t, optionalTarget ) {
36698  
36699		var point = optionalTarget || new Vector2();
36700  
36701		var v0 = this.v0, v1 = this.v1, v2 = this.v2;
36702  
36703		point.set(
36704			QuadraticBezier( t, v0.x, v1.x, v2.x ),
36705			QuadraticBezier( t, v0.y, v1.y, v2.y )
36706		);
36707  
36708		return point;
36709  
36710	};
36711  
36712	QuadraticBezierCurve.prototype.copy = function ( source ) {
36713  
36714		Curve.prototype.copy.call( this, source );
36715  
36716		this.v0.copy( source.v0 );
36717		this.v1.copy( source.v1 );
36718		this.v2.copy( source.v2 );
36719  
36720		return this;
36721  
36722	};
36723  
36724	QuadraticBezierCurve.prototype.toJSON = function () {
36725  
36726		var data = Curve.prototype.toJSON.call( this );
36727  
36728		data.v0 = this.v0.toArray();
36729		data.v1 = this.v1.toArray();
36730		data.v2 = this.v2.toArray();
36731  
36732		return data;
36733  
36734	};
36735  
36736	QuadraticBezierCurve.prototype.fromJSON = function ( json ) {
36737  
36738		Curve.prototype.fromJSON.call( this, json );
36739  
36740		this.v0.fromArray( json.v0 );
36741		this.v1.fromArray( json.v1 );
36742		this.v2.fromArray( json.v2 );
36743  
36744		return this;
36745  
36746	};
36747  
36748	function QuadraticBezierCurve3( v0, v1, v2 ) {
36749  
36750		Curve.call( this );
36751  
36752		this.type = 'QuadraticBezierCurve3';
36753  
36754		this.v0 = v0 || new Vector3();
36755		this.v1 = v1 || new Vector3();
36756		this.v2 = v2 || new Vector3();
36757  
36758	}
36759  
36760	QuadraticBezierCurve3.prototype = Object.create( Curve.prototype );
36761	QuadraticBezierCurve3.prototype.constructor = QuadraticBezierCurve3;
36762  
36763	QuadraticBezierCurve3.prototype.isQuadraticBezierCurve3 = true;
36764  
36765	QuadraticBezierCurve3.prototype.getPoint = function ( t, optionalTarget ) {
36766  
36767		var point = optionalTarget || new Vector3();
36768  
36769		var v0 = this.v0, v1 = this.v1, v2 = this.v2;
36770  
36771		point.set(
36772			QuadraticBezier( t, v0.x, v1.x, v2.x ),
36773			QuadraticBezier( t, v0.y, v1.y, v2.y ),
36774			QuadraticBezier( t, v0.z, v1.z, v2.z )
36775		);
36776  
36777		return point;
36778  
36779	};
36780  
36781	QuadraticBezierCurve3.prototype.copy = function ( source ) {
36782  
36783		Curve.prototype.copy.call( this, source );
36784  
36785		this.v0.copy( source.v0 );
36786		this.v1.copy( source.v1 );
36787		this.v2.copy( source.v2 );
36788  
36789		return this;
36790  
36791	};
36792  
36793	QuadraticBezierCurve3.prototype.toJSON = function () {
36794  
36795		var data = Curve.prototype.toJSON.call( this );
36796  
36797		data.v0 = this.v0.toArray();
36798		data.v1 = this.v1.toArray();
36799		data.v2 = this.v2.toArray();
36800  
36801		return data;
36802  
36803	};
36804  
36805	QuadraticBezierCurve3.prototype.fromJSON = function ( json ) {
36806  
36807		Curve.prototype.fromJSON.call( this, json );
36808  
36809		this.v0.fromArray( json.v0 );
36810		this.v1.fromArray( json.v1 );
36811		this.v2.fromArray( json.v2 );
36812  
36813		return this;
36814  
36815	};
36816  
36817	function SplineCurve( points /* array of Vector2 */ ) {
36818  
36819		Curve.call( this );
36820  
36821		this.type = 'SplineCurve';
36822  
36823		this.points = points || [];
36824  
36825	}
36826  
36827	SplineCurve.prototype = Object.create( Curve.prototype );
36828	SplineCurve.prototype.constructor = SplineCurve;
36829  
36830	SplineCurve.prototype.isSplineCurve = true;
36831  
36832	SplineCurve.prototype.getPoint = function ( t, optionalTarget ) {
36833  
36834		var point = optionalTarget || new Vector2();
36835  
36836		var points = this.points;
36837		var p = ( points.length - 1 ) * t;
36838  
36839		var intPoint = Math.floor( p );
36840		var weight = p - intPoint;
36841  
36842		var p0 = points[ intPoint === 0 ? intPoint : intPoint - 1 ];
36843		var p1 = points[ intPoint ];
36844		var p2 = points[ intPoint > points.length - 2 ? points.length - 1 : intPoint + 1 ];
36845		var p3 = points[ intPoint > points.length - 3 ? points.length - 1 : intPoint + 2 ];
36846  
36847		point.set(
36848			CatmullRom( weight, p0.x, p1.x, p2.x, p3.x ),
36849			CatmullRom( weight, p0.y, p1.y, p2.y, p3.y )
36850		);
36851  
36852		return point;
36853  
36854	};
36855  
36856	SplineCurve.prototype.copy = function ( source ) {
36857  
36858		Curve.prototype.copy.call( this, source );
36859  
36860		this.points = [];
36861  
36862		for ( var i = 0, l = source.points.length; i < l; i ++ ) {
36863  
36864			var point = source.points[ i ];
36865  
36866			this.points.push( point.clone() );
36867  
36868		}
36869  
36870		return this;
36871  
36872	};
36873  
36874	SplineCurve.prototype.toJSON = function () {
36875  
36876		var data = Curve.prototype.toJSON.call( this );
36877  
36878		data.points = [];
36879  
36880		for ( var i = 0, l = this.points.length; i < l; i ++ ) {
36881  
36882			var point = this.points[ i ];
36883			data.points.push( point.toArray() );
36884  
36885		}
36886  
36887		return data;
36888  
36889	};
36890  
36891	SplineCurve.prototype.fromJSON = function ( json ) {
36892  
36893		Curve.prototype.fromJSON.call( this, json );
36894  
36895		this.points = [];
36896  
36897		for ( var i = 0, l = json.points.length; i < l; i ++ ) {
36898  
36899			var point = json.points[ i ];
36900			this.points.push( new Vector2().fromArray( point ) );
36901  
36902		}
36903  
36904		return this;
36905  
36906	};
36907  
36908  
36909  
36910	var Curves = /*#__PURE__*/Object.freeze({
36911		ArcCurve: ArcCurve,
36912		CatmullRomCurve3: CatmullRomCurve3,
36913		CubicBezierCurve: CubicBezierCurve,
36914		CubicBezierCurve3: CubicBezierCurve3,
36915		EllipseCurve: EllipseCurve,
36916		LineCurve: LineCurve,
36917		LineCurve3: LineCurve3,
36918		QuadraticBezierCurve: QuadraticBezierCurve,
36919		QuadraticBezierCurve3: QuadraticBezierCurve3,
36920		SplineCurve: SplineCurve
36921	});
36922  
36923	/**
36924	 * @author zz85 / http://www.lab4games.net/zz85/blog
36925	 *
36926	 **/
36927  
36928	/**************************************************************
36929	 *	Curved Path - a curve path is simply a array of connected
36930	 *  curves, but retains the api of a curve
36931	 **************************************************************/
36932  
36933	function CurvePath() {
36934  
36935		Curve.call( this );
36936  
36937		this.type = 'CurvePath';
36938  
36939		this.curves = [];
36940		this.autoClose = false; // Automatically closes the path
36941  
36942	}
36943  
36944	CurvePath.prototype = Object.assign( Object.create( Curve.prototype ), {
36945  
36946		constructor: CurvePath,
36947  
36948		add: function ( curve ) {
36949  
36950			this.curves.push( curve );
36951  
36952		},
36953  
36954		closePath: function () {
36955  
36956			// Add a line curve if start and end of lines are not connected
36957			var startPoint = this.curves[ 0 ].getPoint( 0 );
36958			var endPoint = this.curves[ this.curves.length - 1 ].getPoint( 1 );
36959  
36960			if ( ! startPoint.equals( endPoint ) ) {
36961  
36962				this.curves.push( new LineCurve( endPoint, startPoint ) );
36963  
36964			}
36965  
36966		},
36967  
36968		// To get accurate point with reference to
36969		// entire path distance at time t,
36970		// following has to be done:
36971  
36972		// 1. Length of each sub path have to be known
36973		// 2. Locate and identify type of curve
36974		// 3. Get t for the curve
36975		// 4. Return curve.getPointAt(t')
36976  
36977		getPoint: function ( t ) {
36978  
36979			var d = t * this.getLength();
36980			var curveLengths = this.getCurveLengths();
36981			var i = 0;
36982  
36983			// To think about boundaries points.
36984  
36985			while ( i < curveLengths.length ) {
36986  
36987				if ( curveLengths[ i ] >= d ) {
36988  
36989					var diff = curveLengths[ i ] - d;
36990					var curve = this.curves[ i ];
36991  
36992					var segmentLength = curve.getLength();
36993					var u = segmentLength === 0 ? 0 : 1 - diff / segmentLength;
36994  
36995					return curve.getPointAt( u );
36996  
36997				}
36998  
36999				i ++;
37000  
37001			}
37002  
37003			return null;
37004  
37005			// loop where sum != 0, sum > d , sum+1 <d
37006  
37007		},
37008  
37009		// We cannot use the default THREE.Curve getPoint() with getLength() because in
37010		// THREE.Curve, getLength() depends on getPoint() but in THREE.CurvePath
37011		// getPoint() depends on getLength
37012  
37013		getLength: function () {
37014  
37015			var lens = this.getCurveLengths();
37016			return lens[ lens.length - 1 ];
37017  
37018		},
37019  
37020		// cacheLengths must be recalculated.
37021		updateArcLengths: function () {
37022  
37023			this.needsUpdate = true;
37024			this.cacheLengths = null;
37025			this.getCurveLengths();
37026  
37027		},
37028  
37029		// Compute lengths and cache them
37030		// We cannot overwrite getLengths() because UtoT mapping uses it.
37031  
37032		getCurveLengths: function () {
37033  
37034			// We use cache values if curves and cache array are same length
37035  
37036			if ( this.cacheLengths && this.cacheLengths.length === this.curves.length ) {
37037  
37038				return this.cacheLengths;
37039  
37040			}
37041  
37042			// Get length of sub-curve
37043			// Push sums into cached array
37044  
37045			var lengths = [], sums = 0;
37046  
37047			for ( var i = 0, l = this.curves.length; i < l; i ++ ) {
37048  
37049				sums += this.curves[ i ].getLength();
37050				lengths.push( sums );
37051  
37052			}
37053  
37054			this.cacheLengths = lengths;
37055  
37056			return lengths;
37057  
37058		},
37059  
37060		getSpacedPoints: function ( divisions ) {
37061  
37062			if ( divisions === undefined ) divisions = 40;
37063  
37064			var points = [];
37065  
37066			for ( var i = 0; i <= divisions; i ++ ) {
37067  
37068				points.push( this.getPoint( i / divisions ) );
37069  
37070			}
37071  
37072			if ( this.autoClose ) {
37073  
37074				points.push( points[ 0 ] );
37075  
37076			}
37077  
37078			return points;
37079  
37080		},
37081  
37082		getPoints: function ( divisions ) {
37083  
37084			divisions = divisions || 12;
37085  
37086			var points = [], last;
37087  
37088			for ( var i = 0, curves = this.curves; i < curves.length; i ++ ) {
37089  
37090				var curve = curves[ i ];
37091				var resolution = ( curve && curve.isEllipseCurve ) ? divisions * 2
37092					: ( curve && curve.isLineCurve ) ? 1
37093						: ( curve && curve.isSplineCurve ) ? divisions * curve.points.length
37094							: divisions;
37095  
37096				var pts = curve.getPoints( resolution );
37097  
37098				for ( var j = 0; j < pts.length; j ++ ) {
37099  
37100					var point = pts[ j ];
37101  
37102					if ( last && last.equals( point ) ) continue; // ensures no consecutive points are duplicates
37103  
37104					points.push( point );
37105					last = point;
37106  
37107				}
37108  
37109			}
37110  
37111			if ( this.autoClose && points.length > 1 && ! points[ points.length - 1 ].equals( points[ 0 ] ) ) {
37112  
37113				points.push( points[ 0 ] );
37114  
37115			}
37116  
37117			return points;
37118  
37119		},
37120  
37121		copy: function ( source ) {
37122  
37123			Curve.prototype.copy.call( this, source );
37124  
37125			this.curves = [];
37126  
37127			for ( var i = 0, l = source.curves.length; i < l; i ++ ) {
37128  
37129				var curve = source.curves[ i ];
37130  
37131				this.curves.push( curve.clone() );
37132  
37133			}
37134  
37135			this.autoClose = source.autoClose;
37136  
37137			return this;
37138  
37139		},
37140  
37141		toJSON: function () {
37142  
37143			var data = Curve.prototype.toJSON.call( this );
37144  
37145			data.autoClose = this.autoClose;
37146			data.curves = [];
37147  
37148			for ( var i = 0, l = this.curves.length; i < l; i ++ ) {
37149  
37150				var curve = this.curves[ i ];
37151				data.curves.push( curve.toJSON() );
37152  
37153			}
37154  
37155			return data;
37156  
37157		},
37158  
37159		fromJSON: function ( json ) {
37160  
37161			Curve.prototype.fromJSON.call( this, json );
37162  
37163			this.autoClose = json.autoClose;
37164			this.curves = [];
37165  
37166			for ( var i = 0, l = json.curves.length; i < l; i ++ ) {
37167  
37168				var curve = json.curves[ i ];
37169				this.curves.push( new Curves[ curve.type ]().fromJSON( curve ) );
37170  
37171			}
37172  
37173			return this;
37174  
37175		}
37176  
37177	} );
37178  
37179	/**
37180	 * @author zz85 / http://www.lab4games.net/zz85/blog
37181	 * Creates free form 2d path using series of points, lines or curves.
37182	 **/
37183  
37184	function Path( points ) {
37185  
37186		CurvePath.call( this );
37187  
37188		this.type = 'Path';
37189  
37190		this.currentPoint = new Vector2();
37191  
37192		if ( points ) {
37193  
37194			this.setFromPoints( points );
37195  
37196		}
37197  
37198	}
37199  
37200	Path.prototype = Object.assign( Object.create( CurvePath.prototype ), {
37201  
37202		constructor: Path,
37203  
37204		setFromPoints: function ( points ) {
37205  
37206			this.moveTo( points[ 0 ].x, points[ 0 ].y );
37207  
37208			for ( var i = 1, l = points.length; i < l; i ++ ) {
37209  
37210				this.lineTo( points[ i ].x, points[ i ].y );
37211  
37212			}
37213  
37214		},
37215  
37216		moveTo: function ( x, y ) {
37217  
37218			this.currentPoint.set( x, y ); // TODO consider referencing vectors instead of copying?
37219  
37220		},
37221  
37222		lineTo: function ( x, y ) {
37223  
37224			var curve = new LineCurve( this.currentPoint.clone(), new Vector2( x, y ) );
37225			this.curves.push( curve );
37226  
37227			this.currentPoint.set( x, y );
37228  
37229		},
37230  
37231		quadraticCurveTo: function ( aCPx, aCPy, aX, aY ) {
37232  
37233			var curve = new QuadraticBezierCurve(
37234				this.currentPoint.clone(),
37235				new Vector2( aCPx, aCPy ),
37236				new Vector2( aX, aY )
37237			);
37238  
37239			this.curves.push( curve );
37240  
37241			this.currentPoint.set( aX, aY );
37242  
37243		},
37244  
37245		bezierCurveTo: function ( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY ) {
37246  
37247			var curve = new CubicBezierCurve(
37248				this.currentPoint.clone(),
37249				new Vector2( aCP1x, aCP1y ),
37250				new Vector2( aCP2x, aCP2y ),
37251				new Vector2( aX, aY )
37252			);
37253  
37254			this.curves.push( curve );
37255  
37256			this.currentPoint.set( aX, aY );
37257  
37258		},
37259  
37260		splineThru: function ( pts /*Array of Vector*/ ) {
37261  
37262			var npts = [ this.currentPoint.clone() ].concat( pts );
37263  
37264			var curve = new SplineCurve( npts );
37265			this.curves.push( curve );
37266  
37267			this.currentPoint.copy( pts[ pts.length - 1 ] );
37268  
37269		},
37270  
37271		arc: function ( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) {
37272  
37273			var x0 = this.currentPoint.x;
37274			var y0 = this.currentPoint.y;
37275  
37276			this.absarc( aX + x0, aY + y0, aRadius,
37277				aStartAngle, aEndAngle, aClockwise );
37278  
37279		},
37280  
37281		absarc: function ( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) {
37282  
37283			this.absellipse( aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise );
37284  
37285		},
37286  
37287		ellipse: function ( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ) {
37288  
37289			var x0 = this.currentPoint.x;
37290			var y0 = this.currentPoint.y;
37291  
37292			this.absellipse( aX + x0, aY + y0, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation );
37293  
37294		},
37295  
37296		absellipse: function ( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ) {
37297  
37298			var curve = new EllipseCurve( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation );
37299  
37300			if ( this.curves.length > 0 ) {
37301  
37302				// if a previous curve is present, attempt to join
37303				var firstPoint = curve.getPoint( 0 );
37304  
37305				if ( ! firstPoint.equals( this.currentPoint ) ) {
37306  
37307					this.lineTo( firstPoint.x, firstPoint.y );
37308  
37309				}
37310  
37311			}
37312  
37313			this.curves.push( curve );
37314  
37315			var lastPoint = curve.getPoint( 1 );
37316			this.currentPoint.copy( lastPoint );
37317  
37318		},
37319  
37320		copy: function ( source ) {
37321  
37322			CurvePath.prototype.copy.call( this, source );
37323  
37324			this.currentPoint.copy( source.currentPoint );
37325  
37326			return this;
37327  
37328		},
37329  
37330		toJSON: function () {
37331  
37332			var data = CurvePath.prototype.toJSON.call( this );
37333  
37334			data.currentPoint = this.currentPoint.toArray();
37335  
37336			return data;
37337  
37338		},
37339  
37340		fromJSON: function ( json ) {
37341  
37342			CurvePath.prototype.fromJSON.call( this, json );
37343  
37344			this.currentPoint.fromArray( json.currentPoint );
37345  
37346			return this;
37347  
37348		}
37349  
37350	} );
37351  
37352	/**
37353	 * @author zz85 / http://www.lab4games.net/zz85/blog
37354	 * Defines a 2d shape plane using paths.
37355	 **/
37356  
37357	// STEP 1 Create a path.
37358	// STEP 2 Turn path into shape.
37359	// STEP 3 ExtrudeGeometry takes in Shape/Shapes
37360	// STEP 3a - Extract points from each shape, turn to vertices
37361	// STEP 3b - Triangulate each shape, add faces.
37362  
37363	function Shape( points ) {
37364  
37365		Path.call( this, points );
37366  
37367		this.uuid = _Math.generateUUID();
37368  
37369		this.type = 'Shape';
37370  
37371		this.holes = [];
37372  
37373	}
37374  
37375	Shape.prototype = Object.assign( Object.create( Path.prototype ), {
37376  
37377		constructor: Shape,
37378  
37379		getPointsHoles: function ( divisions ) {
37380  
37381			var holesPts = [];
37382  
37383			for ( var i = 0, l = this.holes.length; i < l; i ++ ) {
37384  
37385				holesPts[ i ] = this.holes[ i ].getPoints( divisions );
37386  
37387			}
37388  
37389			return holesPts;
37390  
37391		},
37392  
37393		// get points of shape and holes (keypoints based on segments parameter)
37394  
37395		extractPoints: function ( divisions ) {
37396  
37397			return {
37398  
37399				shape: this.getPoints( divisions ),
37400				holes: this.getPointsHoles( divisions )
37401  
37402			};
37403  
37404		},
37405  
37406		copy: function ( source ) {
37407  
37408			Path.prototype.copy.call( this, source );
37409  
37410			this.holes = [];
37411  
37412			for ( var i = 0, l = source.holes.length; i < l; i ++ ) {
37413  
37414				var hole = source.holes[ i ];
37415  
37416				this.holes.push( hole.clone() );
37417  
37418			}
37419  
37420			return this;
37421  
37422		},
37423  
37424		toJSON: function () {
37425  
37426			var data = Path.prototype.toJSON.call( this );
37427  
37428			data.uuid = this.uuid;
37429			data.holes = [];
37430  
37431			for ( var i = 0, l = this.holes.length; i < l; i ++ ) {
37432  
37433				var hole = this.holes[ i ];
37434				data.holes.push( hole.toJSON() );
37435  
37436			}
37437  
37438			return data;
37439  
37440		},
37441  
37442		fromJSON: function ( json ) {
37443  
37444			Path.prototype.fromJSON.call( this, json );
37445  
37446			this.uuid = json.uuid;
37447			this.holes = [];
37448  
37449			for ( var i = 0, l = json.holes.length; i < l; i ++ ) {
37450  
37451				var hole = json.holes[ i ];
37452				this.holes.push( new Path().fromJSON( hole ) );
37453  
37454			}
37455  
37456			return this;
37457  
37458		}
37459  
37460	} );
37461  
37462	/**
37463	 * @author mrdoob / http://mrdoob.com/
37464	 * @author alteredq / http://alteredqualia.com/
37465	 */
37466  
37467	function Light( color, intensity ) {
37468  
37469		Object3D.call( this );
37470  
37471		this.type = 'Light';
37472  
37473		this.color = new Color( color );
37474		this.intensity = intensity !== undefined ? intensity : 1;
37475  
37476		this.receiveShadow = undefined;
37477  
37478	}
37479  
37480	Light.prototype = Object.assign( Object.create( Object3D.prototype ), {
37481  
37482		constructor: Light,
37483  
37484		isLight: true,
37485  
37486		copy: function ( source ) {
37487  
37488			Object3D.prototype.copy.call( this, source );
37489  
37490			this.color.copy( source.color );
37491			this.intensity = source.intensity;
37492  
37493			return this;
37494  
37495		},
37496  
37497		toJSON: function ( meta ) {
37498  
37499			var data = Object3D.prototype.toJSON.call( this, meta );
37500  
37501			data.object.color = this.color.getHex();
37502			data.object.intensity = this.intensity;
37503  
37504			if ( this.groundColor !== undefined ) data.object.groundColor = this.groundColor.getHex();
37505  
37506			if ( this.distance !== undefined ) data.object.distance = this.distance;
37507			if ( this.angle !== undefined ) data.object.angle = this.angle;
37508			if ( this.decay !== undefined ) data.object.decay = this.decay;
37509			if ( this.penumbra !== undefined ) data.object.penumbra = this.penumbra;
37510  
37511			if ( this.shadow !== undefined ) data.object.shadow = this.shadow.toJSON();
37512  
37513			return data;
37514  
37515		}
37516  
37517	} );
37518  
37519	/**
37520	 * @author alteredq / http://alteredqualia.com/
37521	 */
37522  
37523	function HemisphereLight( skyColor, groundColor, intensity ) {
37524  
37525		Light.call( this, skyColor, intensity );
37526  
37527		this.type = 'HemisphereLight';
37528  
37529		this.castShadow = undefined;
37530  
37531		this.position.copy( Object3D.DefaultUp );
37532		this.updateMatrix();
37533  
37534		this.groundColor = new Color( groundColor );
37535  
37536	}
37537  
37538	HemisphereLight.prototype = Object.assign( Object.create( Light.prototype ), {
37539  
37540		constructor: HemisphereLight,
37541  
37542		isHemisphereLight: true,
37543  
37544		copy: function ( source ) {
37545  
37546			Light.prototype.copy.call( this, source );
37547  
37548			this.groundColor.copy( source.groundColor );
37549  
37550			return this;
37551  
37552		}
37553  
37554	} );
37555  
37556	/**
37557	 * @author mrdoob / http://mrdoob.com/
37558	 */
37559  
37560	function LightShadow( camera ) {
37561  
37562		this.camera = camera;
37563  
37564		this.bias = 0;
37565		this.radius = 1;
37566  
37567		this.mapSize = new Vector2( 512, 512 );
37568  
37569		this.map = null;
37570		this.matrix = new Matrix4();
37571  
37572	}
37573  
37574	Object.assign( LightShadow.prototype, {
37575  
37576		copy: function ( source ) {
37577  
37578			this.camera = source.camera.clone();
37579  
37580			this.bias = source.bias;
37581			this.radius = source.radius;
37582  
37583			this.mapSize.copy( source.mapSize );
37584  
37585			return this;
37586  
37587		},
37588  
37589		clone: function () {
37590  
37591			return new this.constructor().copy( this );
37592  
37593		},
37594  
37595		toJSON: function () {
37596  
37597			var object = {};
37598  
37599			if ( this.bias !== 0 ) object.bias = this.bias;
37600			if ( this.radius !== 1 ) object.radius = this.radius;
37601			if ( this.mapSize.x !== 512 || this.mapSize.y !== 512 ) object.mapSize = this.mapSize.toArray();
37602  
37603			object.camera = this.camera.toJSON( false ).object;
37604			delete object.camera.matrix;
37605  
37606			return object;
37607  
37608		}
37609  
37610	} );
37611  
37612	/**
37613	 * @author mrdoob / http://mrdoob.com/
37614	 */
37615  
37616	function SpotLightShadow() {
37617  
37618		LightShadow.call( this, new PerspectiveCamera( 50, 1, 0.5, 500 ) );
37619  
37620	}
37621  
37622	SpotLightShadow.prototype = Object.assign( Object.create( LightShadow.prototype ), {
37623  
37624		constructor: SpotLightShadow,
37625  
37626		isSpotLightShadow: true,
37627  
37628		update: function ( light ) {
37629  
37630			var camera = this.camera;
37631  
37632			var fov = _Math.RAD2DEG * 2 * light.angle;
37633			var aspect = this.mapSize.width / this.mapSize.height;
37634			var far = light.distance || camera.far;
37635  
37636			if ( fov !== camera.fov || aspect !== camera.aspect || far !== camera.far ) {
37637  
37638				camera.fov = fov;
37639				camera.aspect = aspect;
37640				camera.far = far;
37641				camera.updateProjectionMatrix();
37642  
37643			}
37644  
37645		}
37646  
37647	} );
37648  
37649	/**
37650	 * @author alteredq / http://alteredqualia.com/
37651	 */
37652  
37653	function SpotLight( color, intensity, distance, angle, penumbra, decay ) {
37654  
37655		Light.call( this, color, intensity );
37656  
37657		this.type = 'SpotLight';
37658  
37659		this.position.copy( Object3D.DefaultUp );
37660		this.updateMatrix();
37661  
37662		this.target = new Object3D();
37663  
37664		Object.defineProperty( this, 'power', {
37665			get: function () {
37666  
37667				// intensity = power per solid angle.
37668				// ref: equation (17) from https://seblagarde.files.wordpress.com/2015/07/course_notes_moving_frostbite_to_pbr_v32.pdf
37669				return this.intensity * Math.PI;
37670  
37671			},
37672			set: function ( power ) {
37673  
37674				// intensity = power per solid angle.
37675				// ref: equation (17) from https://seblagarde.files.wordpress.com/2015/07/course_notes_moving_frostbite_to_pbr_v32.pdf
37676				this.intensity = power / Math.PI;
37677  
37678			}
37679		} );
37680  
37681		this.distance = ( distance !== undefined ) ? distance : 0;
37682		this.angle = ( angle !== undefined ) ? angle : Math.PI / 3;
37683		this.penumbra = ( penumbra !== undefined ) ? penumbra : 0;
37684		this.decay = ( decay !== undefined ) ? decay : 1;	// for physically correct lights, should be 2.
37685  
37686		this.shadow = new SpotLightShadow();
37687  
37688	}
37689  
37690	SpotLight.prototype = Object.assign( Object.create( Light.prototype ), {
37691  
37692		constructor: SpotLight,
37693  
37694		isSpotLight: true,
37695  
37696		copy: function ( source ) {
37697  
37698			Light.prototype.copy.call( this, source );
37699  
37700			this.distance = source.distance;
37701			this.angle = source.angle;
37702			this.penumbra = source.penumbra;
37703			this.decay = source.decay;
37704  
37705			this.target = source.target.clone();
37706  
37707			this.shadow = source.shadow.clone();
37708  
37709			return this;
37710  
37711		}
37712  
37713	} );
37714  
37715	/**
37716	 * @author mrdoob / http://mrdoob.com/
37717	 */
37718  
37719  
37720	function PointLight( color, intensity, distance, decay ) {
37721  
37722		Light.call( this, color, intensity );
37723  
37724		this.type = 'PointLight';
37725  
37726		Object.defineProperty( this, 'power', {
37727			get: function () {
37728  
37729				// intensity = power per solid angle.
37730				// ref: equation (15) from https://seblagarde.files.wordpress.com/2015/07/course_notes_moving_frostbite_to_pbr_v32.pdf
37731				return this.intensity * 4 * Math.PI;
37732  
37733			},
37734			set: function ( power ) {
37735  
37736				// intensity = power per solid angle.
37737				// ref: equation (15) from https://seblagarde.files.wordpress.com/2015/07/course_notes_moving_frostbite_to_pbr_v32.pdf
37738				this.intensity = power / ( 4 * Math.PI );
37739  
37740			}
37741		} );
37742  
37743		this.distance = ( distance !== undefined ) ? distance : 0;
37744		this.decay = ( decay !== undefined ) ? decay : 1;	// for physically correct lights, should be 2.
37745  
37746		this.shadow = new LightShadow( new PerspectiveCamera( 90, 1, 0.5, 500 ) );
37747  
37748	}
37749  
37750	PointLight.prototype = Object.assign( Object.create( Light.prototype ), {
37751  
37752		constructor: PointLight,
37753  
37754		isPointLight: true,
37755  
37756		copy: function ( source ) {
37757  
37758			Light.prototype.copy.call( this, source );
37759  
37760			this.distance = source.distance;
37761			this.decay = source.decay;
37762  
37763			this.shadow = source.shadow.clone();
37764  
37765			return this;
37766  
37767		}
37768  
37769	} );
37770  
37771	/**
37772	 * @author mrdoob / http://mrdoob.com/
37773	 */
37774  
37775	function DirectionalLightShadow( ) {
37776  
37777		LightShadow.call( this, new OrthographicCamera( - 5, 5, 5, - 5, 0.5, 500 ) );
37778  
37779	}
37780  
37781	DirectionalLightShadow.prototype = Object.assign( Object.create( LightShadow.prototype ), {
37782  
37783		constructor: DirectionalLightShadow
37784  
37785	} );
37786  
37787	/**
37788	 * @author mrdoob / http://mrdoob.com/
37789	 * @author alteredq / http://alteredqualia.com/
37790	 */
37791  
37792	function DirectionalLight( color, intensity ) {
37793  
37794		Light.call( this, color, intensity );
37795  
37796		this.type = 'DirectionalLight';
37797  
37798		this.position.copy( Object3D.DefaultUp );
37799		this.updateMatrix();
37800  
37801		this.target = new Object3D();
37802  
37803		this.shadow = new DirectionalLightShadow();
37804  
37805	}
37806  
37807	DirectionalLight.prototype = Object.assign( Object.create( Light.prototype ), {
37808  
37809		constructor: DirectionalLight,
37810  
37811		isDirectionalLight: true,
37812  
37813		copy: function ( source ) {
37814  
37815			Light.prototype.copy.call( this, source );
37816  
37817			this.target = source.target.clone();
37818  
37819			this.shadow = source.shadow.clone();
37820  
37821			return this;
37822  
37823		}
37824  
37825	} );
37826  
37827	/**
37828	 * @author mrdoob / http://mrdoob.com/
37829	 */
37830  
37831	function AmbientLight( color, intensity ) {
37832  
37833		Light.call( this, color, intensity );
37834  
37835		this.type = 'AmbientLight';
37836  
37837		this.castShadow = undefined;
37838  
37839	}
37840  
37841	AmbientLight.prototype = Object.assign( Object.create( Light.prototype ), {
37842  
37843		constructor: AmbientLight,
37844  
37845		isAmbientLight: true
37846  
37847	} );
37848  
37849	/**
37850	 * @author abelnation / http://github.com/abelnation
37851	 */
37852  
37853	function RectAreaLight( color, intensity, width, height ) {
37854  
37855		Light.call( this, color, intensity );
37856  
37857		this.type = 'RectAreaLight';
37858  
37859		this.width = ( width !== undefined ) ? width : 10;
37860		this.height = ( height !== undefined ) ? height : 10;
37861  
37862	}
37863  
37864	RectAreaLight.prototype = Object.assign( Object.create( Light.prototype ), {
37865  
37866		constructor: RectAreaLight,
37867  
37868		isRectAreaLight: true,
37869  
37870		copy: function ( source ) {
37871  
37872			Light.prototype.copy.call( this, source );
37873  
37874			this.width = source.width;
37875			this.height = source.height;
37876  
37877			return this;
37878  
37879		},
37880  
37881		toJSON: function ( meta ) {
37882  
37883			var data = Light.prototype.toJSON.call( this, meta );
37884  
37885			data.object.width = this.width;
37886			data.object.height = this.height;
37887  
37888			return data;
37889  
37890		}
37891  
37892	} );
37893  
37894	/**
37895	 *
37896	 * A Track that interpolates Strings
37897	 *
37898	 *
37899	 * @author Ben Houston / http://clara.io/
37900	 * @author David Sarno / http://lighthaus.us/
37901	 * @author tschw
37902	 */
37903  
37904	function StringKeyframeTrack( name, times, values, interpolation ) {
37905  
37906		KeyframeTrack.call( this, name, times, values, interpolation );
37907  
37908	}
37909  
37910	StringKeyframeTrack.prototype = Object.assign( Object.create( KeyframeTrack.prototype ), {
37911  
37912		constructor: StringKeyframeTrack,
37913  
37914		ValueTypeName: 'string',
37915		ValueBufferType: Array,
37916  
37917		DefaultInterpolation: InterpolateDiscrete,
37918  
37919		InterpolantFactoryMethodLinear: undefined,
37920  
37921		InterpolantFactoryMethodSmooth: undefined
37922  
37923	} );
37924  
37925	/**
37926	 *
37927	 * A Track of Boolean keyframe values.
37928	 *
37929	 *
37930	 * @author Ben Houston / http://clara.io/
37931	 * @author David Sarno / http://lighthaus.us/
37932	 * @author tschw
37933	 */
37934  
37935	function BooleanKeyframeTrack( name, times, values ) {
37936  
37937		KeyframeTrack.call( this, name, times, values );
37938  
37939	}
37940  
37941	BooleanKeyframeTrack.prototype = Object.assign( Object.create( KeyframeTrack.prototype ), {
37942  
37943		constructor: BooleanKeyframeTrack,
37944  
37945		ValueTypeName: 'bool',
37946		ValueBufferType: Array,
37947  
37948		DefaultInterpolation: InterpolateDiscrete,
37949  
37950		InterpolantFactoryMethodLinear: undefined,
37951		InterpolantFactoryMethodSmooth: undefined
37952  
37953		// Note: Actually this track could have a optimized / compressed
37954		// representation of a single value and a custom interpolant that
37955		// computes "firstValue ^ isOdd( index )".
37956  
37957	} );
37958  
37959	/**
37960	 * Abstract base class of interpolants over parametric samples.
37961	 *
37962	 * The parameter domain is one dimensional, typically the time or a path
37963	 * along a curve defined by the data.
37964	 *
37965	 * The sample values can have any dimensionality and derived classes may
37966	 * apply special interpretations to the data.
37967	 *
37968	 * This class provides the interval seek in a Template Method, deferring
37969	 * the actual interpolation to derived classes.
37970	 *
37971	 * Time complexity is O(1) for linear access crossing at most two points
37972	 * and O(log N) for random access, where N is the number of positions.
37973	 *
37974	 * References:
37975	 *
37976	 * 		http://www.oodesign.com/template-method-pattern.html
37977	 *
37978	 * @author tschw
37979	 */
37980  
37981	function Interpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) {
37982  
37983		this.parameterPositions = parameterPositions;
37984		this._cachedIndex = 0;
37985  
37986		this.resultBuffer = resultBuffer !== undefined ?
37987			resultBuffer : new sampleValues.constructor( sampleSize );
37988		this.sampleValues = sampleValues;
37989		this.valueSize = sampleSize;
37990  
37991	}
37992  
37993	Object.assign( Interpolant.prototype, {
37994  
37995		evaluate: function ( t ) {
37996  
37997			var pp = this.parameterPositions,
37998				i1 = this._cachedIndex,
37999  
38000				t1 = pp[ i1 ],
38001				t0 = pp[ i1 - 1 ];
38002  
38003			validate_interval: {
38004  
38005				seek: {
38006  
38007					var right;
38008  
38009					linear_scan: {
38010  
38011						//- See http://jsperf.com/comparison-to-undefined/3
38012						//- slower code:
38013						//-
38014						//- 				if ( t >= t1 || t1 === undefined ) {
38015						forward_scan: if ( ! ( t < t1 ) ) {
38016  
38017							for ( var giveUpAt = i1 + 2; ; ) {
38018  
38019								if ( t1 === undefined ) {
38020  
38021									if ( t < t0 ) break forward_scan;
38022  
38023									// after end
38024  
38025									i1 = pp.length;
38026									this._cachedIndex = i1;
38027									return this.afterEnd_( i1 - 1, t, t0 );
38028  
38029								}
38030  
38031								if ( i1 === giveUpAt ) break; // this loop
38032  
38033								t0 = t1;
38034								t1 = pp[ ++ i1 ];
38035  
38036								if ( t < t1 ) {
38037  
38038									// we have arrived at the sought interval
38039									break seek;
38040  
38041								}
38042  
38043							}
38044  
38045							// prepare binary search on the right side of the index
38046							right = pp.length;
38047							break linear_scan;
38048  
38049						}
38050  
38051						//- slower code:
38052						//-					if ( t < t0 || t0 === undefined ) {
38053						if ( ! ( t >= t0 ) ) {
38054  
38055							// looping?
38056  
38057							var t1global = pp[ 1 ];
38058  
38059							if ( t < t1global ) {
38060  
38061								i1 = 2; // + 1, using the scan for the details
38062								t0 = t1global;
38063  
38064							}
38065  
38066							// linear reverse scan
38067  
38068							for ( var giveUpAt = i1 - 2; ; ) {
38069  
38070								if ( t0 === undefined ) {
38071  
38072									// before start
38073  
38074									this._cachedIndex = 0;
38075									return this.beforeStart_( 0, t, t1 );
38076  
38077								}
38078  
38079								if ( i1 === giveUpAt ) break; // this loop
38080  
38081								t1 = t0;
38082								t0 = pp[ -- i1 - 1 ];
38083  
38084								if ( t >= t0 ) {
38085  
38086									// we have arrived at the sought interval
38087									break seek;
38088  
38089								}
38090  
38091							}
38092  
38093							// prepare binary search on the left side of the index
38094							right = i1;
38095							i1 = 0;
38096							break linear_scan;
38097  
38098						}
38099  
38100						// the interval is valid
38101  
38102						break validate_interval;
38103  
38104					} // linear scan
38105  
38106					// binary search
38107  
38108					while ( i1 < right ) {
38109  
38110						var mid = ( i1 + right ) >>> 1;
38111  
38112						if ( t < pp[ mid ] ) {
38113  
38114							right = mid;
38115  
38116						} else {
38117  
38118							i1 = mid + 1;
38119  
38120						}
38121  
38122					}
38123  
38124					t1 = pp[ i1 ];
38125					t0 = pp[ i1 - 1 ];
38126  
38127					// check boundary cases, again
38128  
38129					if ( t0 === undefined ) {
38130  
38131						this._cachedIndex = 0;
38132						return this.beforeStart_( 0, t, t1 );
38133  
38134					}
38135  
38136					if ( t1 === undefined ) {
38137  
38138						i1 = pp.length;
38139						this._cachedIndex = i1;
38140						return this.afterEnd_( i1 - 1, t0, t );
38141  
38142					}
38143  
38144				} // seek
38145  
38146				this._cachedIndex = i1;
38147  
38148				this.intervalChanged_( i1, t0, t1 );
38149  
38150			} // validate_interval
38151  
38152			return this.interpolate_( i1, t0, t, t1 );
38153  
38154		},
38155  
38156		settings: null, // optional, subclass-specific settings structure
38157		// Note: The indirection allows central control of many interpolants.
38158  
38159		// --- Protected interface
38160  
38161		DefaultSettings_: {},
38162  
38163		getSettings_: function () {
38164  
38165			return this.settings || this.DefaultSettings_;
38166  
38167		},
38168  
38169		copySampleValue_: function ( index ) {
38170  
38171			// copies a sample value to the result buffer
38172  
38173			var result = this.resultBuffer,
38174				values = this.sampleValues,
38175				stride = this.valueSize,
38176				offset = index * stride;
38177  
38178			for ( var i = 0; i !== stride; ++ i ) {
38179  
38180				result[ i ] = values[ offset + i ];
38181  
38182			}
38183  
38184			return result;
38185  
38186		},
38187  
38188		// Template methods for derived classes:
38189  
38190		interpolate_: function ( /* i1, t0, t, t1 */ ) {
38191  
38192			throw new Error( 'call to abstract method' );
38193			// implementations shall return this.resultBuffer
38194  
38195		},
38196  
38197		intervalChanged_: function ( /* i1, t0, t1 */ ) {
38198  
38199			// empty
38200  
38201		}
38202  
38203	} );
38204  
38205	//!\ DECLARE ALIAS AFTER assign prototype !
38206	Object.assign( Interpolant.prototype, {
38207  
38208		//( 0, t, t0 ), returns this.resultBuffer
38209		beforeStart_: Interpolant.prototype.copySampleValue_,
38210  
38211		//( N-1, tN-1, t ), returns this.resultBuffer
38212		afterEnd_: Interpolant.prototype.copySampleValue_,
38213  
38214	} );
38215  
38216	/**
38217	 * Spherical linear unit quaternion interpolant.
38218	 *
38219	 * @author tschw
38220	 */
38221  
38222	function QuaternionLinearInterpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) {
38223  
38224		Interpolant.call( this, parameterPositions, sampleValues, sampleSize, resultBuffer );
38225  
38226	}
38227  
38228	QuaternionLinearInterpolant.prototype = Object.assign( Object.create( Interpolant.prototype ), {
38229  
38230		constructor: QuaternionLinearInterpolant,
38231  
38232		interpolate_: function ( i1, t0, t, t1 ) {
38233  
38234			var result = this.resultBuffer,
38235				values = this.sampleValues,
38236				stride = this.valueSize,
38237  
38238				offset = i1 * stride,
38239  
38240				alpha = ( t - t0 ) / ( t1 - t0 );
38241  
38242			for ( var end = offset + stride; offset !== end; offset += 4 ) {
38243  
38244				Quaternion.slerpFlat( result, 0, values, offset - stride, values, offset, alpha );
38245  
38246			}
38247  
38248			return result;
38249  
38250		}
38251  
38252	} );
38253  
38254	/**
38255	 *
38256	 * A Track of quaternion keyframe values.
38257	 *
38258	 * @author Ben Houston / http://clara.io/
38259	 * @author David Sarno / http://lighthaus.us/
38260	 * @author tschw
38261	 */
38262  
38263	function QuaternionKeyframeTrack( name, times, values, interpolation ) {
38264  
38265		KeyframeTrack.call( this, name, times, values, interpolation );
38266  
38267	}
38268  
38269	QuaternionKeyframeTrack.prototype = Object.assign( Object.create( KeyframeTrack.prototype ), {
38270  
38271		constructor: QuaternionKeyframeTrack,
38272  
38273		ValueTypeName: 'quaternion',
38274  
38275		// ValueBufferType is inherited
38276  
38277		DefaultInterpolation: InterpolateLinear,
38278  
38279		InterpolantFactoryMethodLinear: function ( result ) {
38280  
38281			return new QuaternionLinearInterpolant( this.times, this.values, this.getValueSize(), result );
38282  
38283		},
38284  
38285		InterpolantFactoryMethodSmooth: undefined // not yet implemented
38286  
38287	} );
38288  
38289	/**
38290	 *
38291	 * A Track of keyframe values that represent color.
38292	 *
38293	 *
38294	 * @author Ben Houston / http://clara.io/
38295	 * @author David Sarno / http://lighthaus.us/
38296	 * @author tschw
38297	 */
38298  
38299	function ColorKeyframeTrack( name, times, values, interpolation ) {
38300  
38301		KeyframeTrack.call( this, name, times, values, interpolation );
38302  
38303	}
38304  
38305	ColorKeyframeTrack.prototype = Object.assign( Object.create( KeyframeTrack.prototype ), {
38306  
38307		constructor: ColorKeyframeTrack,
38308  
38309		ValueTypeName: 'color'
38310  
38311		// ValueBufferType is inherited
38312  
38313		// DefaultInterpolation is inherited
38314  
38315		// Note: Very basic implementation and nothing special yet.
38316		// However, this is the place for color space parameterization.
38317  
38318	} );
38319  
38320	/**
38321	 *
38322	 * A Track of numeric keyframe values.
38323	 *
38324	 * @author Ben Houston / http://clara.io/
38325	 * @author David Sarno / http://lighthaus.us/
38326	 * @author tschw
38327	 */
38328  
38329	function NumberKeyframeTrack( name, times, values, interpolation ) {
38330  
38331		KeyframeTrack.call( this, name, times, values, interpolation );
38332  
38333	}
38334  
38335	NumberKeyframeTrack.prototype = Object.assign( Object.create( KeyframeTrack.prototype ), {
38336  
38337		constructor: NumberKeyframeTrack,
38338  
38339		ValueTypeName: 'number'
38340  
38341		// ValueBufferType is inherited
38342  
38343		// DefaultInterpolation is inherited
38344  
38345	} );
38346  
38347	/**
38348	 * Fast and simple cubic spline interpolant.
38349	 *
38350	 * It was derived from a Hermitian construction setting the first derivative
38351	 * at each sample position to the linear slope between neighboring positions
38352	 * over their parameter interval.
38353	 *
38354	 * @author tschw
38355	 */
38356  
38357	function CubicInterpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) {
38358  
38359		Interpolant.call( this, parameterPositions, sampleValues, sampleSize, resultBuffer );
38360  
38361		this._weightPrev = - 0;
38362		this._offsetPrev = - 0;
38363		this._weightNext = - 0;
38364		this._offsetNext = - 0;
38365  
38366	}
38367  
38368	CubicInterpolant.prototype = Object.assign( Object.create( Interpolant.prototype ), {
38369  
38370		constructor: CubicInterpolant,
38371  
38372		DefaultSettings_: {
38373  
38374			endingStart: ZeroCurvatureEnding,
38375			endingEnd: ZeroCurvatureEnding
38376  
38377		},
38378  
38379		intervalChanged_: function ( i1, t0, t1 ) {
38380  
38381			var pp = this.parameterPositions,
38382				iPrev = i1 - 2,
38383				iNext = i1 + 1,
38384  
38385				tPrev = pp[ iPrev ],
38386				tNext = pp[ iNext ];
38387  
38388			if ( tPrev === undefined ) {
38389  
38390				switch ( this.getSettings_().endingStart ) {
38391  
38392					case ZeroSlopeEnding:
38393  
38394						// f'(t0) = 0
38395						iPrev = i1;
38396						tPrev = 2 * t0 - t1;
38397  
38398						break;
38399  
38400					case WrapAroundEnding:
38401  
38402						// use the other end of the curve
38403						iPrev = pp.length - 2;
38404						tPrev = t0 + pp[ iPrev ] - pp[ iPrev + 1 ];
38405  
38406						break;
38407  
38408					default: // ZeroCurvatureEnding
38409  
38410						// f''(t0) = 0 a.k.a. Natural Spline
38411						iPrev = i1;
38412						tPrev = t1;
38413  
38414				}
38415  
38416			}
38417  
38418			if ( tNext === undefined ) {
38419  
38420				switch ( this.getSettings_().endingEnd ) {
38421  
38422					case ZeroSlopeEnding:
38423  
38424						// f'(tN) = 0
38425						iNext = i1;
38426						tNext = 2 * t1 - t0;
38427  
38428						break;
38429  
38430					case WrapAroundEnding:
38431  
38432						// use the other end of the curve
38433						iNext = 1;
38434						tNext = t1 + pp[ 1 ] - pp[ 0 ];
38435  
38436						break;
38437  
38438					default: // ZeroCurvatureEnding
38439  
38440						// f''(tN) = 0, a.k.a. Natural Spline
38441						iNext = i1 - 1;
38442						tNext = t0;
38443  
38444				}
38445  
38446			}
38447  
38448			var halfDt = ( t1 - t0 ) * 0.5,
38449				stride = this.valueSize;
38450  
38451			this._weightPrev = halfDt / ( t0 - tPrev );
38452			this._weightNext = halfDt / ( tNext - t1 );
38453			this._offsetPrev = iPrev * stride;
38454			this._offsetNext = iNext * stride;
38455  
38456		},
38457  
38458		interpolate_: function ( i1, t0, t, t1 ) {
38459  
38460			var result = this.resultBuffer,
38461				values = this.sampleValues,
38462				stride = this.valueSize,
38463  
38464				o1 = i1 * stride,		o0 = o1 - stride,
38465				oP = this._offsetPrev, 	oN = this._offsetNext,
38466				wP = this._weightPrev,	wN = this._weightNext,
38467  
38468				p = ( t - t0 ) / ( t1 - t0 ),
38469				pp = p * p,
38470				ppp = pp * p;
38471  
38472			// evaluate polynomials
38473  
38474			var sP = - wP * ppp + 2 * wP * pp - wP * p;
38475			var s0 = ( 1 + wP ) * ppp + ( - 1.5 - 2 * wP ) * pp + ( - 0.5 + wP ) * p + 1;
38476			var s1 = ( - 1 - wN ) * ppp + ( 1.5 + wN ) * pp + 0.5 * p;
38477			var sN = wN * ppp - wN * pp;
38478  
38479			// combine data linearly
38480  
38481			for ( var i = 0; i !== stride; ++ i ) {
38482  
38483				result[ i ] =
38484						sP * values[ oP + i ] +
38485						s0 * values[ o0 + i ] +
38486						s1 * values[ o1 + i ] +
38487						sN * values[ oN + i ];
38488  
38489			}
38490  
38491			return result;
38492  
38493		}
38494  
38495	} );
38496  
38497	/**
38498	 * @author tschw
38499	 */
38500  
38501	function LinearInterpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) {
38502  
38503		Interpolant.call( this, parameterPositions, sampleValues, sampleSize, resultBuffer );
38504  
38505	}
38506  
38507	LinearInterpolant.prototype = Object.assign( Object.create( Interpolant.prototype ), {
38508  
38509		constructor: LinearInterpolant,
38510  
38511		interpolate_: function ( i1, t0, t, t1 ) {
38512  
38513			var result = this.resultBuffer,
38514				values = this.sampleValues,
38515				stride = this.valueSize,
38516  
38517				offset1 = i1 * stride,
38518				offset0 = offset1 - stride,
38519  
38520				weight1 = ( t - t0 ) / ( t1 - t0 ),
38521				weight0 = 1 - weight1;
38522  
38523			for ( var i = 0; i !== stride; ++ i ) {
38524  
38525				result[ i ] =
38526						values[ offset0 + i ] * weight0 +
38527						values[ offset1 + i ] * weight1;
38528  
38529			}
38530  
38531			return result;
38532  
38533		}
38534  
38535	} );
38536  
38537	/**
38538	 *
38539	 * Interpolant that evaluates to the sample value at the position preceeding
38540	 * the parameter.
38541	 *
38542	 * @author tschw
38543	 */
38544  
38545	function DiscreteInterpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) {
38546  
38547		Interpolant.call( this, parameterPositions, sampleValues, sampleSize, resultBuffer );
38548  
38549	}
38550  
38551	DiscreteInterpolant.prototype = Object.assign( Object.create( Interpolant.prototype ), {
38552  
38553		constructor: DiscreteInterpolant,
38554  
38555		interpolate_: function ( i1 /*, t0, t, t1 */ ) {
38556  
38557			return this.copySampleValue_( i1 - 1 );
38558  
38559		}
38560  
38561	} );
38562  
38563	/**
38564	 * @author tschw
38565	 * @author Ben Houston / http://clara.io/
38566	 * @author David Sarno / http://lighthaus.us/
38567	 */
38568  
38569	var AnimationUtils = {
38570  
38571		// same as Array.prototype.slice, but also works on typed arrays
38572		arraySlice: function ( array, from, to ) {
38573  
38574			if ( AnimationUtils.isTypedArray( array ) ) {
38575  
38576				// in ios9 array.subarray(from, undefined) will return empty array
38577				// but array.subarray(from) or array.subarray(from, len) is correct
38578				return new array.constructor( array.subarray( from, to !== undefined ? to : array.length ) );
38579  
38580			}
38581  
38582			return array.slice( from, to );
38583  
38584		},
38585  
38586		// converts an array to a specific type
38587		convertArray: function ( array, type, forceClone ) {
38588  
38589			if ( ! array || // let 'undefined' and 'null' pass
38590					! forceClone && array.constructor === type ) return array;
38591  
38592			if ( typeof type.BYTES_PER_ELEMENT === 'number' ) {
38593  
38594				return new type( array ); // create typed array
38595  
38596			}
38597  
38598			return Array.prototype.slice.call( array ); // create Array
38599  
38600		},
38601  
38602		isTypedArray: function ( object ) {
38603  
38604			return ArrayBuffer.isView( object ) &&
38605					! ( object instanceof DataView );
38606  
38607		},
38608  
38609		// returns an array by which times and values can be sorted
38610		getKeyframeOrder: function ( times ) {
38611  
38612			function compareTime( i, j ) {
38613  
38614				return times[ i ] - times[ j ];
38615  
38616			}
38617  
38618			var n = times.length;
38619			var result = new Array( n );
38620			for ( var i = 0; i !== n; ++ i ) result[ i ] = i;
38621  
38622			result.sort( compareTime );
38623  
38624			return result;
38625  
38626		},
38627  
38628		// uses the array previously returned by 'getKeyframeOrder' to sort data
38629		sortedArray: function ( values, stride, order ) {
38630  
38631			var nValues = values.length;
38632			var result = new values.constructor( nValues );
38633  
38634			for ( var i = 0, dstOffset = 0; dstOffset !== nValues; ++ i ) {
38635  
38636				var srcOffset = order[ i ] * stride;
38637  
38638				for ( var j = 0; j !== stride; ++ j ) {
38639  
38640					result[ dstOffset ++ ] = values[ srcOffset + j ];
38641  
38642				}
38643  
38644			}
38645  
38646			return result;
38647  
38648		},
38649  
38650		// function for parsing AOS keyframe formats
38651		flattenJSON: function ( jsonKeys, times, values, valuePropertyName ) {
38652  
38653			var i = 1, key = jsonKeys[ 0 ];
38654  
38655			while ( key !== undefined && key[ valuePropertyName ] === undefined ) {
38656  
38657				key = jsonKeys[ i ++ ];
38658  
38659			}
38660  
38661			if ( key === undefined ) return; // no data
38662  
38663			var value = key[ valuePropertyName ];
38664			if ( value === undefined ) return; // no data
38665  
38666			if ( Array.isArray( value ) ) {
38667  
38668				do {
38669  
38670					value = key[ valuePropertyName ];
38671  
38672					if ( value !== undefined ) {
38673  
38674						times.push( key.time );
38675						values.push.apply( values, value ); // push all elements
38676  
38677					}
38678  
38679					key = jsonKeys[ i ++ ];
38680  
38681				} while ( key !== undefined );
38682  
38683			} else if ( value.toArray !== undefined ) {
38684  
38685				// ...assume THREE.Math-ish
38686  
38687				do {
38688  
38689					value = key[ valuePropertyName ];
38690  
38691					if ( value !== undefined ) {
38692  
38693						times.push( key.time );
38694						value.toArray( values, values.length );
38695  
38696					}
38697  
38698					key = jsonKeys[ i ++ ];
38699  
38700				} while ( key !== undefined );
38701  
38702			} else {
38703  
38704				// otherwise push as-is
38705  
38706				do {
38707  
38708					value = key[ valuePropertyName ];
38709  
38710					if ( value !== undefined ) {
38711  
38712						times.push( key.time );
38713						values.push( value );
38714  
38715					}
38716  
38717					key = jsonKeys[ i ++ ];
38718  
38719				} while ( key !== undefined );
38720  
38721			}
38722  
38723		}
38724  
38725	};
38726  
38727	/**
38728	 *
38729	 * A timed sequence of keyframes for a specific property.
38730	 *
38731	 *
38732	 * @author Ben Houston / http://clara.io/
38733	 * @author David Sarno / http://lighthaus.us/
38734	 * @author tschw
38735	 */
38736  
38737	function KeyframeTrack( name, times, values, interpolation ) {
38738  
38739		if ( name === undefined ) throw new Error( 'THREE.KeyframeTrack: track name is undefined' );
38740		if ( times === undefined || times.length === 0 ) throw new Error( 'THREE.KeyframeTrack: no keyframes in track named ' + name );
38741  
38742		this.name = name;
38743  
38744		this.times = AnimationUtils.convertArray( times, this.TimeBufferType );
38745		this.values = AnimationUtils.convertArray( values, this.ValueBufferType );
38746  
38747		this.setInterpolation( interpolation || this.DefaultInterpolation );
38748  
38749		this.validate();
38750		this.optimize();
38751  
38752	}
38753  
38754	// Static methods:
38755  
38756	Object.assign( KeyframeTrack, {
38757  
38758		// Serialization (in static context, because of constructor invocation
38759		// and automatic invocation of .toJSON):
38760  
38761		parse: function ( json ) {
38762  
38763			if ( json.type === undefined ) {
38764  
38765				throw new Error( 'THREE.KeyframeTrack: track type undefined, can not parse' );
38766  
38767			}
38768  
38769			var trackType = KeyframeTrack._getTrackTypeForValueTypeName( json.type );
38770  
38771			if ( json.times === undefined ) {
38772  
38773				var times = [], values = [];
38774  
38775				AnimationUtils.flattenJSON( json.keys, times, values, 'value' );
38776  
38777				json.times = times;
38778				json.values = values;
38779  
38780			}
38781  
38782			// derived classes can define a static parse method
38783			if ( trackType.parse !== undefined ) {
38784  
38785				return trackType.parse( json );
38786  
38787			} else {
38788  
38789				// by default, we assume a constructor compatible with the base
38790				return new trackType( json.name, json.times, json.values, json.interpolation );
38791  
38792			}
38793  
38794		},
38795  
38796		toJSON: function ( track ) {
38797  
38798			var trackType = track.constructor;
38799  
38800			var json;
38801  
38802			// derived classes can define a static toJSON method
38803			if ( trackType.toJSON !== undefined ) {
38804  
38805				json = trackType.toJSON( track );
38806  
38807			} else {
38808  
38809				// by default, we assume the data can be serialized as-is
38810				json = {
38811  
38812					'name': track.name,
38813					'times': AnimationUtils.convertArray( track.times, Array ),
38814					'values': AnimationUtils.convertArray( track.values, Array )
38815  
38816				};
38817  
38818				var interpolation = track.getInterpolation();
38819  
38820				if ( interpolation !== track.DefaultInterpolation ) {
38821  
38822					json.interpolation = interpolation;
38823  
38824				}
38825  
38826			}
38827  
38828			json.type = track.ValueTypeName; // mandatory
38829  
38830			return json;
38831  
38832		},
38833  
38834		_getTrackTypeForValueTypeName: function ( typeName ) {
38835  
38836			switch ( typeName.toLowerCase() ) {
38837  
38838				case 'scalar':
38839				case 'double':
38840				case 'float':
38841				case 'number':
38842				case 'integer':
38843  
38844					return NumberKeyframeTrack;
38845  
38846				case 'vector':
38847				case 'vector2':
38848				case 'vector3':
38849				case 'vector4':
38850  
38851					return VectorKeyframeTrack;
38852  
38853				case 'color':
38854  
38855					return ColorKeyframeTrack;
38856  
38857				case 'quaternion':
38858  
38859					return QuaternionKeyframeTrack;
38860  
38861				case 'bool':
38862				case 'boolean':
38863  
38864					return BooleanKeyframeTrack;
38865  
38866				case 'string':
38867  
38868					return StringKeyframeTrack;
38869  
38870			}
38871  
38872			throw new Error( 'THREE.KeyframeTrack: Unsupported typeName: ' + typeName );
38873  
38874		}
38875  
38876	} );
38877  
38878	Object.assign( KeyframeTrack.prototype, {
38879  
38880		constructor: KeyframeTrack,
38881  
38882		TimeBufferType: Float32Array,
38883  
38884		ValueBufferType: Float32Array,
38885  
38886		DefaultInterpolation: InterpolateLinear,
38887  
38888		InterpolantFactoryMethodDiscrete: function ( result ) {
38889  
38890			return new DiscreteInterpolant( this.times, this.values, this.getValueSize(), result );
38891  
38892		},
38893  
38894		InterpolantFactoryMethodLinear: function ( result ) {
38895  
38896			return new LinearInterpolant( this.times, this.values, this.getValueSize(), result );
38897  
38898		},
38899  
38900		InterpolantFactoryMethodSmooth: function ( result ) {
38901  
38902			return new CubicInterpolant( this.times, this.values, this.getValueSize(), result );
38903  
38904		},
38905  
38906		setInterpolation: function ( interpolation ) {
38907  
38908			var factoryMethod;
38909  
38910			switch ( interpolation ) {
38911  
38912				case InterpolateDiscrete:
38913  
38914					factoryMethod = this.InterpolantFactoryMethodDiscrete;
38915  
38916					break;
38917  
38918				case InterpolateLinear:
38919  
38920					factoryMethod = this.InterpolantFactoryMethodLinear;
38921  
38922					break;
38923  
38924				case InterpolateSmooth:
38925  
38926					factoryMethod = this.InterpolantFactoryMethodSmooth;
38927  
38928					break;
38929  
38930			}
38931  
38932			if ( factoryMethod === undefined ) {
38933  
38934				var message = "unsupported interpolation for " +
38935					this.ValueTypeName + " keyframe track named " + this.name;
38936  
38937				if ( this.createInterpolant === undefined ) {
38938  
38939					// fall back to default, unless the default itself is messed up
38940					if ( interpolation !== this.DefaultInterpolation ) {
38941  
38942						this.setInterpolation( this.DefaultInterpolation );
38943  
38944					} else {
38945  
38946						throw new Error( message ); // fatal, in this case
38947  
38948					}
38949  
38950				}
38951  
38952				console.warn( 'THREE.KeyframeTrack:', message );
38953				return;
38954  
38955			}
38956  
38957			this.createInterpolant = factoryMethod;
38958  
38959		},
38960  
38961		getInterpolation: function () {
38962  
38963			switch ( this.createInterpolant ) {
38964  
38965				case this.InterpolantFactoryMethodDiscrete:
38966  
38967					return InterpolateDiscrete;
38968  
38969				case this.InterpolantFactoryMethodLinear:
38970  
38971					return InterpolateLinear;
38972  
38973				case this.InterpolantFactoryMethodSmooth:
38974  
38975					return InterpolateSmooth;
38976  
38977			}
38978  
38979		},
38980  
38981		getValueSize: function () {
38982  
38983			return this.values.length / this.times.length;
38984  
38985		},
38986  
38987		// move all keyframes either forwards or backwards in time
38988		shift: function ( timeOffset ) {
38989  
38990			if ( timeOffset !== 0.0 ) {
38991  
38992				var times = this.times;
38993  
38994				for ( var i = 0, n = times.length; i !== n; ++ i ) {
38995  
38996					times[ i ] += timeOffset;
38997  
38998				}
38999  
39000			}
39001  
39002			return this;
39003  
39004		},
39005  
39006		// scale all keyframe times by a factor (useful for frame <-> seconds conversions)
39007		scale: function ( timeScale ) {
39008  
39009			if ( timeScale !== 1.0 ) {
39010  
39011				var times = this.times;
39012  
39013				for ( var i = 0, n = times.length; i !== n; ++ i ) {
39014  
39015					times[ i ] *= timeScale;
39016  
39017				}
39018  
39019			}
39020  
39021			return this;
39022  
39023		},
39024  
39025		// removes keyframes before and after animation without changing any values within the range [startTime, endTime].
39026		// IMPORTANT: We do not shift around keys to the start of the track time, because for interpolated keys this will change their values
39027		trim: function ( startTime, endTime ) {
39028  
39029			var times = this.times,
39030				nKeys = times.length,
39031				from = 0,
39032				to = nKeys - 1;
39033  
39034			while ( from !== nKeys && times[ from ] < startTime ) {
39035  
39036				++ from;
39037  
39038			}
39039  
39040			while ( to !== - 1 && times[ to ] > endTime ) {
39041  
39042				-- to;
39043  
39044			}
39045  
39046			++ to; // inclusive -> exclusive bound
39047  
39048			if ( from !== 0 || to !== nKeys ) {
39049  
39050				// empty tracks are forbidden, so keep at least one keyframe
39051				if ( from >= to ) to = Math.max( to, 1 ), from = to - 1;
39052  
39053				var stride = this.getValueSize();
39054				this.times = AnimationUtils.arraySlice( times, from, to );
39055				this.values = AnimationUtils.arraySlice( this.values, from * stride, to * stride );
39056  
39057			}
39058  
39059			return this;
39060  
39061		},
39062  
39063		// ensure we do not get a GarbageInGarbageOut situation, make sure tracks are at least minimally viable
39064		validate: function () {
39065  
39066			var valid = true;
39067  
39068			var valueSize = this.getValueSize();
39069			if ( valueSize - Math.floor( valueSize ) !== 0 ) {
39070  
39071				console.error( 'THREE.KeyframeTrack: Invalid value size in track.', this );
39072				valid = false;
39073  
39074			}
39075  
39076			var times = this.times,
39077				values = this.values,
39078  
39079				nKeys = times.length;
39080  
39081			if ( nKeys === 0 ) {
39082  
39083				console.error( 'THREE.KeyframeTrack: Track is empty.', this );
39084				valid = false;
39085  
39086			}
39087  
39088			var prevTime = null;
39089  
39090			for ( var i = 0; i !== nKeys; i ++ ) {
39091  
39092				var currTime = times[ i ];
39093  
39094				if ( typeof currTime === 'number' && isNaN( currTime ) ) {
39095  
39096					console.error( 'THREE.KeyframeTrack: Time is not a valid number.', this, i, currTime );
39097					valid = false;
39098					break;
39099  
39100				}
39101  
39102				if ( prevTime !== null && prevTime > currTime ) {
39103  
39104					console.error( 'THREE.KeyframeTrack: Out of order keys.', this, i, currTime, prevTime );
39105					valid = false;
39106					break;
39107  
39108				}
39109  
39110				prevTime = currTime;
39111  
39112			}
39113  
39114			if ( values !== undefined ) {
39115  
39116				if ( AnimationUtils.isTypedArray( values ) ) {
39117  
39118					for ( var i = 0, n = values.length; i !== n; ++ i ) {
39119  
39120						var value = values[ i ];
39121  
39122						if ( isNaN( value ) ) {
39123  
39124							console.error( 'THREE.KeyframeTrack: Value is not a valid number.', this, i, value );
39125							valid = false;
39126							break;
39127  
39128						}
39129  
39130					}
39131  
39132				}
39133  
39134			}
39135  
39136			return valid;
39137  
39138		},
39139  
39140		// removes equivalent sequential keys as common in morph target sequences
39141		// (0,0,0,0,1,1,1,0,0,0,0,0,0,0) --> (0,0,1,1,0,0)
39142		optimize: function () {
39143  
39144			var times = this.times,
39145				values = this.values,
39146				stride = this.getValueSize(),
39147  
39148				smoothInterpolation = this.getInterpolation() === InterpolateSmooth,
39149  
39150				writeIndex = 1,
39151				lastIndex = times.length - 1;
39152  
39153			for ( var i = 1; i < lastIndex; ++ i ) {
39154  
39155				var keep = false;
39156  
39157				var time = times[ i ];
39158				var timeNext = times[ i + 1 ];
39159  
39160				// remove adjacent keyframes scheduled at the same time
39161  
39162				if ( time !== timeNext && ( i !== 1 || time !== time[ 0 ] ) ) {
39163  
39164					if ( ! smoothInterpolation ) {
39165  
39166						// remove unnecessary keyframes same as their neighbors
39167  
39168						var offset = i * stride,
39169							offsetP = offset - stride,
39170							offsetN = offset + stride;
39171  
39172						for ( var j = 0; j !== stride; ++ j ) {
39173  
39174							var value = values[ offset + j ];
39175  
39176							if ( value !== values[ offsetP + j ] ||
39177								value !== values[ offsetN + j ] ) {
39178  
39179								keep = true;
39180								break;
39181  
39182							}
39183  
39184						}
39185  
39186					} else {
39187  
39188						keep = true;
39189  
39190					}
39191  
39192				}
39193  
39194				// in-place compaction
39195  
39196				if ( keep ) {
39197  
39198					if ( i !== writeIndex ) {
39199  
39200						times[ writeIndex ] = times[ i ];
39201  
39202						var readOffset = i * stride,
39203							writeOffset = writeIndex * stride;
39204  
39205						for ( var j = 0; j !== stride; ++ j ) {
39206  
39207							values[ writeOffset + j ] = values[ readOffset + j ];
39208  
39209						}
39210  
39211					}
39212  
39213					++ writeIndex;
39214  
39215				}
39216  
39217			}
39218  
39219			// flush last keyframe (compaction looks ahead)
39220  
39221			if ( lastIndex > 0 ) {
39222  
39223				times[ writeIndex ] = times[ lastIndex ];
39224  
39225				for ( var readOffset = lastIndex * stride, writeOffset = writeIndex * stride, j = 0; j !== stride; ++ j ) {
39226  
39227					values[ writeOffset + j ] = values[ readOffset + j ];
39228  
39229				}
39230  
39231				++ writeIndex;
39232  
39233			}
39234  
39235			if ( writeIndex !== times.length ) {
39236  
39237				this.times = AnimationUtils.arraySlice( times, 0, writeIndex );
39238				this.values = AnimationUtils.arraySlice( values, 0, writeIndex * stride );
39239  
39240			}
39241  
39242			return this;
39243  
39244		}
39245  
39246	} );
39247  
39248	/**
39249	 *
39250	 * A Track of vectored keyframe values.
39251	 *
39252	 *
39253	 * @author Ben Houston / http://clara.io/
39254	 * @author David Sarno / http://lighthaus.us/
39255	 * @author tschw
39256	 */
39257  
39258	function VectorKeyframeTrack( name, times, values, interpolation ) {
39259  
39260		KeyframeTrack.call( this, name, times, values, interpolation );
39261  
39262	}
39263  
39264	VectorKeyframeTrack.prototype = Object.assign( Object.create( KeyframeTrack.prototype ), {
39265  
39266		constructor: VectorKeyframeTrack,
39267  
39268		ValueTypeName: 'vector'
39269  
39270		// ValueBufferType is inherited
39271  
39272		// DefaultInterpolation is inherited
39273  
39274	} );
39275  
39276	/**
39277	 *
39278	 * Reusable set of Tracks that represent an animation.
39279	 *
39280	 * @author Ben Houston / http://clara.io/
39281	 * @author David Sarno / http://lighthaus.us/
39282	 */
39283  
39284	function AnimationClip( name, duration, tracks ) {
39285  
39286		this.name = name;
39287		this.tracks = tracks;
39288		this.duration = ( duration !== undefined ) ? duration : - 1;
39289  
39290		this.uuid = _Math.generateUUID();
39291  
39292		// this means it should figure out its duration by scanning the tracks
39293		if ( this.duration < 0 ) {
39294  
39295			this.resetDuration();
39296  
39297		}
39298  
39299		this.optimize();
39300  
39301	}
39302  
39303	Object.assign( AnimationClip, {
39304  
39305		parse: function ( json ) {
39306  
39307			var tracks = [],
39308				jsonTracks = json.tracks,
39309				frameTime = 1.0 / ( json.fps || 1.0 );
39310  
39311			for ( var i = 0, n = jsonTracks.length; i !== n; ++ i ) {
39312  
39313				tracks.push( KeyframeTrack.parse( jsonTracks[ i ] ).scale( frameTime ) );
39314  
39315			}
39316  
39317			return new AnimationClip( json.name, json.duration, tracks );
39318  
39319		},
39320  
39321		toJSON: function ( clip ) {
39322  
39323			var tracks = [],
39324				clipTracks = clip.tracks;
39325  
39326			var json = {
39327  
39328				'name': clip.name,
39329				'duration': clip.duration,
39330				'tracks': tracks,
39331				'uuid': clip.uuid
39332  
39333			};
39334  
39335			for ( var i = 0, n = clipTracks.length; i !== n; ++ i ) {
39336  
39337				tracks.push( KeyframeTrack.toJSON( clipTracks[ i ] ) );
39338  
39339			}
39340  
39341			return json;
39342  
39343		},
39344  
39345		CreateFromMorphTargetSequence: function ( name, morphTargetSequence, fps, noLoop ) {
39346  
39347			var numMorphTargets = morphTargetSequence.length;
39348			var tracks = [];
39349  
39350			for ( var i = 0; i < numMorphTargets; i ++ ) {
39351  
39352				var times = [];
39353				var values = [];
39354  
39355				times.push(
39356					( i + numMorphTargets - 1 ) % numMorphTargets,
39357					i,
39358					( i + 1 ) % numMorphTargets );
39359  
39360				values.push( 0, 1, 0 );
39361  
39362				var order = AnimationUtils.getKeyframeOrder( times );
39363				times = AnimationUtils.sortedArray( times, 1, order );
39364				values = AnimationUtils.sortedArray( values, 1, order );
39365  
39366				// if there is a key at the first frame, duplicate it as the
39367				// last frame as well for perfect loop.
39368				if ( ! noLoop && times[ 0 ] === 0 ) {
39369  
39370					times.push( numMorphTargets );
39371					values.push( values[ 0 ] );
39372  
39373				}
39374  
39375				tracks.push(
39376					new NumberKeyframeTrack(
39377						'.morphTargetInfluences[' + morphTargetSequence[ i ].name + ']',
39378						times, values
39379					).scale( 1.0 / fps ) );
39380  
39381			}
39382  
39383			return new AnimationClip( name, - 1, tracks );
39384  
39385		},
39386  
39387		findByName: function ( objectOrClipArray, name ) {
39388  
39389			var clipArray = objectOrClipArray;
39390  
39391			if ( ! Array.isArray( objectOrClipArray ) ) {
39392  
39393				var o = objectOrClipArray;
39394				clipArray = o.geometry && o.geometry.animations || o.animations;
39395  
39396			}
39397  
39398			for ( var i = 0; i < clipArray.length; i ++ ) {
39399  
39400				if ( clipArray[ i ].name === name ) {
39401  
39402					return clipArray[ i ];
39403  
39404				}
39405  
39406			}
39407  
39408			return null;
39409  
39410		},
39411  
39412		CreateClipsFromMorphTargetSequences: function ( morphTargets, fps, noLoop ) {
39413  
39414			var animationToMorphTargets = {};
39415  
39416			// tested with https://regex101.com/ on trick sequences
39417			// such flamingo_flyA_003, flamingo_run1_003, crdeath0059
39418			var pattern = /^([\w-]*?)([\d]+)$/;
39419  
39420			// sort morph target names into animation groups based
39421			// patterns like Walk_001, Walk_002, Run_001, Run_002
39422			for ( var i = 0, il = morphTargets.length; i < il; i ++ ) {
39423  
39424				var morphTarget = morphTargets[ i ];
39425				var parts = morphTarget.name.match( pattern );
39426  
39427				if ( parts && parts.length > 1 ) {
39428  
39429					var name = parts[ 1 ];
39430  
39431					var animationMorphTargets = animationToMorphTargets[ name ];
39432					if ( ! animationMorphTargets ) {
39433  
39434						animationToMorphTargets[ name ] = animationMorphTargets = [];
39435  
39436					}
39437  
39438					animationMorphTargets.push( morphTarget );
39439  
39440				}
39441  
39442			}
39443  
39444			var clips = [];
39445  
39446			for ( var name in animationToMorphTargets ) {
39447  
39448				clips.push( AnimationClip.CreateFromMorphTargetSequence( name, animationToMorphTargets[ name ], fps, noLoop ) );
39449  
39450			}
39451  
39452			return clips;
39453  
39454		},
39455  
39456		// parse the animation.hierarchy format
39457		parseAnimation: function ( animation, bones ) {
39458  
39459			if ( ! animation ) {
39460  
39461				console.error( 'THREE.AnimationClip: No animation in JSONLoader data.' );
39462				return null;
39463  
39464			}
39465  
39466			var addNonemptyTrack = function ( trackType, trackName, animationKeys, propertyName, destTracks ) {
39467  
39468				// only return track if there are actually keys.
39469				if ( animationKeys.length !== 0 ) {
39470  
39471					var times = [];
39472					var values = [];
39473  
39474					AnimationUtils.flattenJSON( animationKeys, times, values, propertyName );
39475  
39476					// empty keys are filtered out, so check again
39477					if ( times.length !== 0 ) {
39478  
39479						destTracks.push( new trackType( trackName, times, values ) );
39480  
39481					}
39482  
39483				}
39484  
39485			};
39486  
39487			var tracks = [];
39488  
39489			var clipName = animation.name || 'default';
39490			// automatic length determination in AnimationClip.
39491			var duration = animation.length || - 1;
39492			var fps = animation.fps || 30;
39493  
39494			var hierarchyTracks = animation.hierarchy || [];
39495  
39496			for ( var h = 0; h < hierarchyTracks.length; h ++ ) {
39497  
39498				var animationKeys = hierarchyTracks[ h ].keys;
39499  
39500				// skip empty tracks
39501				if ( ! animationKeys || animationKeys.length === 0 ) continue;
39502  
39503				// process morph targets
39504				if ( animationKeys[ 0 ].morphTargets ) {
39505  
39506					// figure out all morph targets used in this track
39507					var morphTargetNames = {};
39508  
39509					for ( var k = 0; k < animationKeys.length; k ++ ) {
39510  
39511						if ( animationKeys[ k ].morphTargets ) {
39512  
39513							for ( var m = 0; m < animationKeys[ k ].morphTargets.length; m ++ ) {
39514  
39515								morphTargetNames[ animationKeys[ k ].morphTargets[ m ] ] = - 1;
39516  
39517							}
39518  
39519						}
39520  
39521					}
39522  
39523					// create a track for each morph target with all zero
39524					// morphTargetInfluences except for the keys in which
39525					// the morphTarget is named.
39526					for ( var morphTargetName in morphTargetNames ) {
39527  
39528						var times = [];
39529						var values = [];
39530  
39531						for ( var m = 0; m !== animationKeys[ k ].morphTargets.length; ++ m ) {
39532  
39533							var animationKey = animationKeys[ k ];
39534  
39535							times.push( animationKey.time );
39536							values.push( ( animationKey.morphTarget === morphTargetName ) ? 1 : 0 );
39537  
39538						}
39539  
39540						tracks.push( new NumberKeyframeTrack( '.morphTargetInfluence[' + morphTargetName + ']', times, values ) );
39541  
39542					}
39543  
39544					duration = morphTargetNames.length * ( fps || 1.0 );
39545  
39546				} else {
39547  
39548					// ...assume skeletal animation
39549  
39550					var boneName = '.bones[' + bones[ h ].name + ']';
39551  
39552					addNonemptyTrack(
39553						VectorKeyframeTrack, boneName + '.position',
39554						animationKeys, 'pos', tracks );
39555  
39556					addNonemptyTrack(
39557						QuaternionKeyframeTrack, boneName + '.quaternion',
39558						animationKeys, 'rot', tracks );
39559  
39560					addNonemptyTrack(
39561						VectorKeyframeTrack, boneName + '.scale',
39562						animationKeys, 'scl', tracks );
39563  
39564				}
39565  
39566			}
39567  
39568			if ( tracks.length === 0 ) {
39569  
39570				return null;
39571  
39572			}
39573  
39574			var clip = new AnimationClip( clipName, duration, tracks );
39575  
39576			return clip;
39577  
39578		}
39579  
39580	} );
39581  
39582	Object.assign( AnimationClip.prototype, {
39583  
39584		resetDuration: function () {
39585  
39586			var tracks = this.tracks, duration = 0;
39587  
39588			for ( var i = 0, n = tracks.length; i !== n; ++ i ) {
39589  
39590				var track = this.tracks[ i ];
39591  
39592				duration = Math.max( duration, track.times[ track.times.length - 1 ] );
39593  
39594			}
39595  
39596			this.duration = duration;
39597  
39598		},
39599  
39600		trim: function () {
39601  
39602			for ( var i = 0; i < this.tracks.length; i ++ ) {
39603  
39604				this.tracks[ i ].trim( 0, this.duration );
39605  
39606			}
39607  
39608			return this;
39609  
39610		},
39611  
39612		optimize: function () {
39613  
39614			for ( var i = 0; i < this.tracks.length; i ++ ) {
39615  
39616				this.tracks[ i ].optimize();
39617  
39618			}
39619  
39620			return this;
39621  
39622		}
39623  
39624	} );
39625  
39626	/**
39627	 * @author mrdoob / http://mrdoob.com/
39628	 */
39629  
39630	function MaterialLoader( manager ) {
39631  
39632		this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager;
39633		this.textures = {};
39634  
39635	}
39636  
39637	Object.assign( MaterialLoader.prototype, {
39638  
39639		load: function ( url, onLoad, onProgress, onError ) {
39640  
39641			var scope = this;
39642  
39643			var loader = new FileLoader( scope.manager );
39644			loader.load( url, function ( text ) {
39645  
39646				onLoad( scope.parse( JSON.parse( text ) ) );
39647  
39648			}, onProgress, onError );
39649  
39650		},
39651  
39652		setTextures: function ( value ) {
39653  
39654			this.textures = value;
39655  
39656		},
39657  
39658		parse: function ( json ) {
39659  
39660			var textures = this.textures;
39661  
39662			function getTexture( name ) {
39663  
39664				if ( textures[ name ] === undefined ) {
39665  
39666					console.warn( 'THREE.MaterialLoader: Undefined texture', name );
39667  
39668				}
39669  
39670				return textures[ name ];
39671  
39672			}
39673  
39674			var material = new Materials[ json.type ]();
39675  
39676			if ( json.uuid !== undefined ) material.uuid = json.uuid;
39677			if ( json.name !== undefined ) material.name = json.name;
39678			if ( json.color !== undefined ) material.color.setHex( json.color );
39679			if ( json.roughness !== undefined ) material.roughness = json.roughness;
39680			if ( json.metalness !== undefined ) material.metalness = json.metalness;
39681			if ( json.emissive !== undefined ) material.emissive.setHex( json.emissive );
39682			if ( json.specular !== undefined ) material.specular.setHex( json.specular );
39683			if ( json.shininess !== undefined ) material.shininess = json.shininess;
39684			if ( json.clearCoat !== undefined ) material.clearCoat = json.clearCoat;
39685			if ( json.clearCoatRoughness !== undefined ) material.clearCoatRoughness = json.clearCoatRoughness;
39686			if ( json.uniforms !== undefined ) material.uniforms = json.uniforms;
39687			if ( json.vertexShader !== undefined ) material.vertexShader = json.vertexShader;
39688			if ( json.fragmentShader !== undefined ) material.fragmentShader = json.fragmentShader;
39689			if ( json.vertexColors !== undefined ) material.vertexColors = json.vertexColors;
39690			if ( json.fog !== undefined ) material.fog = json.fog;
39691			if ( json.flatShading !== undefined ) material.flatShading = json.flatShading;
39692			if ( json.blending !== undefined ) material.blending = json.blending;
39693			if ( json.side !== undefined ) material.side = json.side;
39694			if ( json.opacity !== undefined ) material.opacity = json.opacity;
39695			if ( json.transparent !== undefined ) material.transparent = json.transparent;
39696			if ( json.alphaTest !== undefined ) material.alphaTest = json.alphaTest;
39697			if ( json.depthTest !== undefined ) material.depthTest = json.depthTest;
39698			if ( json.depthWrite !== undefined ) material.depthWrite = json.depthWrite;
39699			if ( json.colorWrite !== undefined ) material.colorWrite = json.colorWrite;
39700			if ( json.wireframe !== undefined ) material.wireframe = json.wireframe;
39701			if ( json.wireframeLinewidth !== undefined ) material.wireframeLinewidth = json.wireframeLinewidth;
39702			if ( json.wireframeLinecap !== undefined ) material.wireframeLinecap = json.wireframeLinecap;
39703			if ( json.wireframeLinejoin !== undefined ) material.wireframeLinejoin = json.wireframeLinejoin;
39704  
39705			if ( json.rotation !== undefined ) material.rotation = json.rotation;
39706  
39707			if ( json.linewidth !== 1 ) material.linewidth = json.linewidth;
39708			if ( json.dashSize !== undefined ) material.dashSize = json.dashSize;
39709			if ( json.gapSize !== undefined ) material.gapSize = json.gapSize;
39710			if ( json.scale !== undefined ) material.scale = json.scale;
39711  
39712			if ( json.polygonOffset !== undefined ) material.polygonOffset = json.polygonOffset;
39713			if ( json.polygonOffsetFactor !== undefined ) material.polygonOffsetFactor = json.polygonOffsetFactor;
39714			if ( json.polygonOffsetUnits !== undefined ) material.polygonOffsetUnits = json.polygonOffsetUnits;
39715  
39716			if ( json.skinning !== undefined ) material.skinning = json.skinning;
39717			if ( json.morphTargets !== undefined ) material.morphTargets = json.morphTargets;
39718			if ( json.dithering !== undefined ) material.dithering = json.dithering;
39719  
39720			if ( json.visible !== undefined ) material.visible = json.visible;
39721			if ( json.userData !== undefined ) material.userData = json.userData;
39722  
39723			// Deprecated
39724  
39725			if ( json.shading !== undefined ) material.flatShading = json.shading === 1; // THREE.FlatShading
39726  
39727			// for PointsMaterial
39728  
39729			if ( json.size !== undefined ) material.size = json.size;
39730			if ( json.sizeAttenuation !== undefined ) material.sizeAttenuation = json.sizeAttenuation;
39731  
39732			// maps
39733  
39734			if ( json.map !== undefined ) material.map = getTexture( json.map );
39735  
39736			if ( json.alphaMap !== undefined ) {
39737  
39738				material.alphaMap = getTexture( json.alphaMap );
39739				material.transparent = true;
39740  
39741			}
39742  
39743			if ( json.bumpMap !== undefined ) material.bumpMap = getTexture( json.bumpMap );
39744			if ( json.bumpScale !== undefined ) material.bumpScale = json.bumpScale;
39745  
39746			if ( json.normalMap !== undefined ) material.normalMap = getTexture( json.normalMap );
39747			if ( json.normalScale !== undefined ) {
39748  
39749				var normalScale = json.normalScale;
39750  
39751				if ( Array.isArray( normalScale ) === false ) {
39752  
39753					// Blender exporter used to export a scalar. See #7459
39754  
39755					normalScale = [ normalScale, normalScale ];
39756  
39757				}
39758  
39759				material.normalScale = new Vector2().fromArray( normalScale );
39760  
39761			}
39762  
39763			if ( json.displacementMap !== undefined ) material.displacementMap = getTexture( json.displacementMap );
39764			if ( json.displacementScale !== undefined ) material.displacementScale = json.displacementScale;
39765			if ( json.displacementBias !== undefined ) material.displacementBias = json.displacementBias;
39766  
39767			if ( json.roughnessMap !== undefined ) material.roughnessMap = getTexture( json.roughnessMap );
39768			if ( json.metalnessMap !== undefined ) material.metalnessMap = getTexture( json.metalnessMap );
39769  
39770			if ( json.emissiveMap !== undefined ) material.emissiveMap = getTexture( json.emissiveMap );
39771			if ( json.emissiveIntensity !== undefined ) material.emissiveIntensity = json.emissiveIntensity;
39772  
39773			if ( json.specularMap !== undefined ) material.specularMap = getTexture( json.specularMap );
39774  
39775			if ( json.envMap !== undefined ) material.envMap = getTexture( json.envMap );
39776  
39777			if ( json.reflectivity !== undefined ) material.reflectivity = json.reflectivity;
39778  
39779			if ( json.lightMap !== undefined ) material.lightMap = getTexture( json.lightMap );
39780			if ( json.lightMapIntensity !== undefined ) material.lightMapIntensity = json.lightMapIntensity;
39781  
39782			if ( json.aoMap !== undefined ) material.aoMap = getTexture( json.aoMap );
39783			if ( json.aoMapIntensity !== undefined ) material.aoMapIntensity = json.aoMapIntensity;
39784  
39785			if ( json.gradientMap !== undefined ) material.gradientMap = getTexture( json.gradientMap );
39786  
39787			return material;
39788  
39789		}
39790  
39791	} );
39792  
39793	/**
39794	 * @author mrdoob / http://mrdoob.com/
39795	 */
39796  
39797	function BufferGeometryLoader( manager ) {
39798  
39799		this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager;
39800  
39801	}
39802  
39803	Object.assign( BufferGeometryLoader.prototype, {
39804  
39805		load: function ( url, onLoad, onProgress, onError ) {
39806  
39807			var scope = this;
39808  
39809			var loader = new FileLoader( scope.manager );
39810			loader.load( url, function ( text ) {
39811  
39812				onLoad( scope.parse( JSON.parse( text ) ) );
39813  
39814			}, onProgress, onError );
39815  
39816		},
39817  
39818		parse: function ( json ) {
39819  
39820			var geometry = new BufferGeometry();
39821  
39822			var index = json.data.index;
39823  
39824			if ( index !== undefined ) {
39825  
39826				var typedArray = new TYPED_ARRAYS[ index.type ]( index.array );
39827				geometry.setIndex( new BufferAttribute( typedArray, 1 ) );
39828  
39829			}
39830  
39831			var attributes = json.data.attributes;
39832  
39833			for ( var key in attributes ) {
39834  
39835				var attribute = attributes[ key ];
39836				var typedArray = new TYPED_ARRAYS[ attribute.type ]( attribute.array );
39837  
39838				geometry.addAttribute( key, new BufferAttribute( typedArray, attribute.itemSize, attribute.normalized ) );
39839  
39840			}
39841  
39842			var groups = json.data.groups || json.data.drawcalls || json.data.offsets;
39843  
39844			if ( groups !== undefined ) {
39845  
39846				for ( var i = 0, n = groups.length; i !== n; ++ i ) {
39847  
39848					var group = groups[ i ];
39849  
39850					geometry.addGroup( group.start, group.count, group.materialIndex );
39851  
39852				}
39853  
39854			}
39855  
39856			var boundingSphere = json.data.boundingSphere;
39857  
39858			if ( boundingSphere !== undefined ) {
39859  
39860				var center = new Vector3();
39861  
39862				if ( boundingSphere.center !== undefined ) {
39863  
39864					center.fromArray( boundingSphere.center );
39865  
39866				}
39867  
39868				geometry.boundingSphere = new Sphere( center, boundingSphere.radius );
39869  
39870			}
39871  
39872			return geometry;
39873  
39874		}
39875  
39876	} );
39877  
39878	var TYPED_ARRAYS = {
39879		Int8Array: Int8Array,
39880		Uint8Array: Uint8Array,
39881		// Workaround for IE11 pre KB2929437. See #11440
39882		Uint8ClampedArray: typeof Uint8ClampedArray !== 'undefined' ? Uint8ClampedArray : Uint8Array,
39883		Int16Array: Int16Array,
39884		Uint16Array: Uint16Array,
39885		Int32Array: Int32Array,
39886		Uint32Array: Uint32Array,
39887		Float32Array: Float32Array,
39888		Float64Array: Float64Array
39889	};
39890  
39891	/**
39892	 * @author alteredq / http://alteredqualia.com/
39893	 */
39894  
39895	function Loader() {}
39896  
39897	Loader.Handlers = {
39898  
39899		handlers: [],
39900  
39901		add: function ( regex, loader ) {
39902  
39903			this.handlers.push( regex, loader );
39904  
39905		},
39906  
39907		get: function ( file ) {
39908  
39909			var handlers = this.handlers;
39910  
39911			for ( var i = 0, l = handlers.length; i < l; i += 2 ) {
39912  
39913				var regex = handlers[ i ];
39914				var loader = handlers[ i + 1 ];
39915  
39916				if ( regex.test( file ) ) {
39917  
39918					return loader;
39919  
39920				}
39921  
39922			}
39923  
39924			return null;
39925  
39926		}
39927  
39928	};
39929  
39930	Object.assign( Loader.prototype, {
39931  
vendor: 6,349 bytes, lines 39932-40155
39932		crossOrigin: undefined,
39933  
39934		onLoadStart: function () {},
39935  
39936		onLoadProgress: function () {},
39937  
39938		onLoadComplete: function () {},
39939  
39940		initMaterials: function ( materials, texturePath, crossOrigin ) {
39941  
39942			var array = [];
39943  
39944			for ( var i = 0; i < materials.length; ++ i ) {
39945  
39946				array[ i ] = this.createMaterial( materials[ i ], texturePath, crossOrigin );
39947  
39948			}
39949  
39950			return array;
39951  
39952		},
39953  
39954		createMaterial: ( function () {
39955  
39956			var BlendingMode = {
39957				NoBlending: NoBlending,
39958				NormalBlending: NormalBlending,
39959				AdditiveBlending: AdditiveBlending,
39960				SubtractiveBlending: SubtractiveBlending,
39961				MultiplyBlending: MultiplyBlending,
39962				CustomBlending: CustomBlending
39963			};
39964  
39965			var color = new Color();
39966			var textureLoader = new TextureLoader();
39967			var materialLoader = new MaterialLoader();
39968  
39969			return function createMaterial( m, texturePath, crossOrigin ) {
39970  
39971				// convert from old material format
39972  
39973				var textures = {};
39974  
39975				function loadTexture( path, repeat, offset, wrap, anisotropy ) {
39976  
39977					var fullPath = texturePath + path;
39978					var loader = Loader.Handlers.get( fullPath );
39979  
39980					var texture;
39981  
39982					if ( loader !== null ) {
39983  
39984						texture = loader.load( fullPath );
39985  
39986					} else {
39987  
39988						textureLoader.setCrossOrigin( crossOrigin );
39989						texture = textureLoader.load( fullPath );
39990  
39991					}
39992  
39993					if ( repeat !== undefined ) {
39994  
39995						texture.repeat.fromArray( repeat );
39996  
39997						if ( repeat[ 0 ] !== 1 ) texture.wrapS = RepeatWrapping;
39998						if ( repeat[ 1 ] !== 1 ) texture.wrapT = RepeatWrapping;
39999  
40000					}
40001  
40002					if ( offset !== undefined ) {
40003  
40004						texture.offset.fromArray( offset );
40005  
40006					}
40007  
40008					if ( wrap !== undefined ) {
40009  
40010						if ( wrap[ 0 ] === 'repeat' ) texture.wrapS = RepeatWrapping;
40011						if ( wrap[ 0 ] === 'mirror' ) texture.wrapS = MirroredRepeatWrapping;
40012  
40013						if ( wrap[ 1 ] === 'repeat' ) texture.wrapT = RepeatWrapping;
40014						if ( wrap[ 1 ] === 'mirror' ) texture.wrapT = MirroredRepeatWrapping;
40015  
40016					}
40017  
40018					if ( anisotropy !== undefined ) {
40019  
40020						texture.anisotropy = anisotropy;
40021  
40022					}
40023  
40024					var uuid = _Math.generateUUID();
40025  
40026					textures[ uuid ] = texture;
40027  
40028					return uuid;
40029  
40030				}
40031  
40032				//
40033  
40034				var json = {
40035					uuid: _Math.generateUUID(),
40036					type: 'MeshLambertMaterial'
40037				};
40038  
40039				for ( var name in m ) {
40040  
40041					var value = m[ name ];
40042  
40043					switch ( name ) {
40044  
40045						case 'DbgColor':
40046						case 'DbgIndex':
40047						case 'opticalDensity':
40048						case 'illumination':
40049							break;
40050						case 'DbgName':
40051							json.name = value;
40052							break;
40053						case 'blending':
40054							json.blending = BlendingMode[ value ];
40055							break;
40056						case 'colorAmbient':
40057						case 'mapAmbient':
40058							console.warn( 'THREE.Loader.createMaterial:', name, 'is no longer supported.' );
40059							break;
40060						case 'colorDiffuse':
40061							json.color = color.fromArray( value ).getHex();
40062							break;
40063						case 'colorSpecular':
40064							json.specular = color.fromArray( value ).getHex();
40065							break;
40066						case 'colorEmissive':
40067							json.emissive = color.fromArray( value ).getHex();
40068							break;
40069						case 'specularCoef':
40070							json.shininess = value;
40071							break;
40072						case 'shading':
40073							if ( value.toLowerCase() === 'basic' ) json.type = 'MeshBasicMaterial';
40074							if ( value.toLowerCase() === 'phong' ) json.type = 'MeshPhongMaterial';
40075							if ( value.toLowerCase() === 'standard' ) json.type = 'MeshStandardMaterial';
40076							break;
40077						case 'mapDiffuse':
40078							json.map = loadTexture( value, m.mapDiffuseRepeat, m.mapDiffuseOffset, m.mapDiffuseWrap, m.mapDiffuseAnisotropy );
40079							break;
40080						case 'mapDiffuseRepeat':
40081						case 'mapDiffuseOffset':
40082						case 'mapDiffuseWrap':
40083						case 'mapDiffuseAnisotropy':
40084							break;
40085						case 'mapEmissive':
40086							json.emissiveMap = loadTexture( value, m.mapEmissiveRepeat, m.mapEmissiveOffset, m.mapEmissiveWrap, m.mapEmissiveAnisotropy );
40087							break;
40088						case 'mapEmissiveRepeat':
40089						case 'mapEmissiveOffset':
40090						case 'mapEmissiveWrap':
40091						case 'mapEmissiveAnisotropy':
40092							break;
40093						case 'mapLight':
40094							json.lightMap = loadTexture( value, m.mapLightRepeat, m.mapLightOffset, m.mapLightWrap, m.mapLightAnisotropy );
40095							break;
40096						case 'mapLightRepeat':
40097						case 'mapLightOffset':
40098						case 'mapLightWrap':
40099						case 'mapLightAnisotropy':
40100							break;
40101						case 'mapAO':
40102							json.aoMap = loadTexture( value, m.mapAORepeat, m.mapAOOffset, m.mapAOWrap, m.mapAOAnisotropy );
40103							break;
40104						case 'mapAORepeat':
40105						case 'mapAOOffset':
40106						case 'mapAOWrap':
40107						case 'mapAOAnisotropy':
40108							break;
40109						case 'mapBump':
40110							json.bumpMap = loadTexture( value, m.mapBumpRepeat, m.mapBumpOffset, m.mapBumpWrap, m.mapBumpAnisotropy );
40111							break;
40112						case 'mapBumpScale':
40113							json.bumpScale = value;
40114							break;
40115						case 'mapBumpRepeat':
40116						case 'mapBumpOffset':
40117						case 'mapBumpWrap':
40118						case 'mapBumpAnisotropy':
40119							break;
40120						case 'mapNormal':
40121							json.normalMap = loadTexture( value, m.mapNormalRepeat, m.mapNormalOffset, m.mapNormalWrap, m.mapNormalAnisotropy );
40122							break;
40123						case 'mapNormalFactor':
40124							json.normalScale = value;
40125							break;
40126						case 'mapNormalRepeat':
40127						case 'mapNormalOffset':
40128						case 'mapNormalWrap':
40129						case 'mapNormalAnisotropy':
40130							break;
40131						case 'mapSpecular':
40132							json.specularMap = loadTexture( value, m.mapSpecularRepeat, m.mapSpecularOffset, m.mapSpecularWrap, m.mapSpecularAnisotropy );
40133							break;
40134						case 'mapSpecularRepeat':
40135						case 'mapSpecularOffset':
40136						case 'mapSpecularWrap':
40137						case 'mapSpecularAnisotropy':
40138							break;
40139						case 'mapMetalness':
40140							json.metalnessMap = loadTexture( value, m.mapMetalnessRepeat, m.mapMetalnessOffset, m.mapMetalnessWrap, m.mapMetalnessAnisotropy );
40141							break;
40142						case 'mapMetalnessRepeat':
40143						case 'mapMetalnessOffset':
40144						case 'mapMetalnessWrap':
40145						case 'mapMetalnessAnisotropy':
40146							break;
40147						case 'mapRoughness':
40148							json.roughnessMap = loadTexture( value, m.mapRoughnessRepeat, m.mapRoughnessOffset, m.mapRoughnessWrap, m.mapRoughnessAnisotropy );
40149							break;
40150						case 'mapRoughnessRepeat':
40151						case 'mapRoughnessOffset':
40152						case 'mapRoughnessWrap':
40153						case 'mapRoughnessAnisotropy':
40154							break;
40155						case 'mapAlpha':
40156							json.alphaMap = loadTexture( value, m.mapAlphaRepeat, m.mapAlphaOffset, m.mapAlphaWrap, m.mapAlphaAnisotropy );
40157							break;
40158						case 'mapAlphaRepeat':
40159						case 'mapAlphaOffset':
40160						case 'mapAlphaWrap':
40161						case 'mapAlphaAnisotropy':
40162							break;
40163						case 'flipSided':
40164							json.side = BackSide;
40165							break;
40166						case 'doubleSided':
40167							json.side = DoubleSide;
40168							break;
40169						case 'transparency':
40170							console.warn( 'THREE.Loader.createMaterial: transparency has been renamed to opacity' );
40171							json.opacity = value;
40172							break;
40173						case 'depthTest':
40174						case 'depthWrite':
40175						case 'colorWrite':
40176						case 'opacity':
40177						case 'reflectivity':
40178						case 'transparent':
40179						case 'visible':
40180						case 'wireframe':
40181							json[ name ] = value;
40182							break;
40183						case 'vertexColors':
40184							if ( value === true ) json.vertexColors = VertexColors;
40185							if ( value === 'face' ) json.vertexColors = FaceColors;
40186							break;
40187						default:
40188							console.error( 'THREE.Loader.createMaterial: Unsupported', name, value );
40189							break;
40190  
40191					}
40192  
40193				}
40194  
40195				if ( json.type === 'MeshBasicMaterial' ) delete json.emissive;
40196				if ( json.type !== 'MeshPhongMaterial' ) delete json.specular;
40197  
40198				if ( json.opacity < 1 ) json.transparent = true;
40199  
40200				materialLoader.setTextures( textures );
40201  
40202				return materialLoader.parse( json );
40203  
40204			};
40205  
40206		} )()
40207  
40208	} );
40209  
40210	/**
40211	 * @author Don McCurdy / https://www.donmccurdy.com
40212	 */
40213  
40214	var LoaderUtils = {
40215  
40216		decodeText: function ( array ) {
40217  
40218			if ( typeof TextDecoder !== 'undefined' ) {
40219  
40220				return new TextDecoder().decode( array );
40221  
40222			}
40223  
40224			// Avoid the String.fromCharCode.apply(null, array) shortcut, which
40225			// throws a "maximum call stack size exceeded" error for large arrays.
40226  
40227			var s = '';
40228  
40229			for ( var i = 0, il = array.length; i < il; i ++ ) {
40230  
40231				// Implicitly assumes little-endian.
40232				s += String.fromCharCode( array[ i ] );
40233  
40234			}
40235  
40236			// Merges multi-byte utf-8 characters.
40237			return decodeURIComponent( escape( s ) );
40238  
40239		},
40240  
40241		extractUrlBase: function ( url ) {
40242  
40243			var index = url.lastIndexOf( '/' );
40244  
40245			if ( index === - 1 ) return './';
40246  
40247			return url.substr( 0, index + 1 );
40248  
40249		}
40250  
40251	};
40252  
40253	/**
40254	 * @author mrdoob / http://mrdoob.com/
40255	 * @author alteredq / http://alteredqualia.com/
40256	 */
40257  
40258	function JSONLoader( manager ) {
40259  
40260		if ( typeof manager === 'boolean' ) {
40261  
40262			console.warn( 'THREE.JSONLoader: showStatus parameter has been removed from constructor.' );
40263			manager = undefined;
40264  
40265		}
40266  
40267		this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager;
40268  
40269		this.withCredentials = false;
40270  
40271	}
40272  
40273	Object.assign( JSONLoader.prototype, {
40274  
vendor: 11,331 bytes, lines 40275-40775
40275		load: function ( url, onLoad, onProgress, onError ) {
40276  
40277			var scope = this;
40278  
40279			var texturePath = this.texturePath && ( typeof this.texturePath === 'string' ) ? this.texturePath : LoaderUtils.extractUrlBase( url );
40280  
40281			var loader = new FileLoader( this.manager );
40282			loader.setWithCredentials( this.withCredentials );
40283			loader.load( url, function ( text ) {
40284  
40285				var json = JSON.parse( text );
40286				var metadata = json.metadata;
40287  
40288				if ( metadata !== undefined ) {
40289  
40290					var type = metadata.type;
40291  
40292					if ( type !== undefined ) {
40293  
40294						if ( type.toLowerCase() === 'object' ) {
40295  
40296							console.error( 'THREE.JSONLoader: ' + url + ' should be loaded with THREE.ObjectLoader instead.' );
40297							return;
40298  
40299						}
40300  
40301					}
40302  
40303				}
40304  
40305				var object = scope.parse( json, texturePath );
40306				onLoad( object.geometry, object.materials );
40307  
40308			}, onProgress, onError );
40309  
40310		},
40311  
40312		setTexturePath: function ( value ) {
40313  
40314			this.texturePath = value;
40315  
40316		},
40317  
40318		parse: ( function () {
40319  
40320			function parseModel( json, geometry ) {
40321  
40322				function isBitSet( value, position ) {
40323  
40324					return value & ( 1 << position );
40325  
40326				}
40327  
40328				var i, j, fi,
40329  
40330					offset, zLength,
40331  
40332					colorIndex, normalIndex, uvIndex, materialIndex,
40333  
40334					type,
40335					isQuad,
40336					hasMaterial,
40337					hasFaceVertexUv,
40338					hasFaceNormal, hasFaceVertexNormal,
40339					hasFaceColor, hasFaceVertexColor,
40340  
40341					vertex, face, faceA, faceB, hex, normal,
40342  
40343					uvLayer, uv, u, v,
40344  
40345					faces = json.faces,
40346					vertices = json.vertices,
40347					normals = json.normals,
40348					colors = json.colors,
40349  
40350					scale = json.scale,
40351  
40352					nUvLayers = 0;
40353  
40354  
40355				if ( json.uvs !== undefined ) {
40356  
40357					// disregard empty arrays
40358  
40359					for ( i = 0; i < json.uvs.length; i ++ ) {
40360  
40361						if ( json.uvs[ i ].length ) nUvLayers ++;
40362  
40363					}
40364  
40365					for ( i = 0; i < nUvLayers; i ++ ) {
40366  
40367						geometry.faceVertexUvs[ i ] = [];
40368  
40369					}
40370  
40371				}
40372  
40373				offset = 0;
40374				zLength = vertices.length;
40375  
40376				while ( offset < zLength ) {
40377  
40378					vertex = new Vector3();
40379  
40380					vertex.x = vertices[ offset ++ ] * scale;
40381					vertex.y = vertices[ offset ++ ] * scale;
40382					vertex.z = vertices[ offset ++ ] * scale;
40383  
40384					geometry.vertices.push( vertex );
40385  
40386				}
40387  
40388				offset = 0;
40389				zLength = faces.length;
40390  
40391				while ( offset < zLength ) {
40392  
40393					type = faces[ offset ++ ];
40394  
40395					isQuad = isBitSet( type, 0 );
40396					hasMaterial = isBitSet( type, 1 );
40397					hasFaceVertexUv = isBitSet( type, 3 );
40398					hasFaceNormal = isBitSet( type, 4 );
40399					hasFaceVertexNormal = isBitSet( type, 5 );
40400					hasFaceColor = isBitSet( type, 6 );
40401					hasFaceVertexColor = isBitSet( type, 7 );
40402  
40403					// console.log("type", type, "bits", isQuad, hasMaterial, hasFaceVertexUv, hasFaceNormal, hasFaceVertexNormal, hasFaceColor, hasFaceVertexColor);
40404  
40405					if ( isQuad ) {
40406  
40407						faceA = new Face3();
40408						faceA.a = faces[ offset ];
40409						faceA.b = faces[ offset + 1 ];
40410						faceA.c = faces[ offset + 3 ];
40411  
40412						faceB = new Face3();
40413						faceB.a = faces[ offset + 1 ];
40414						faceB.b = faces[ offset + 2 ];
40415						faceB.c = faces[ offset + 3 ];
40416  
40417						offset += 4;
40418  
40419						if ( hasMaterial ) {
40420  
40421							materialIndex = faces[ offset ++ ];
40422							faceA.materialIndex = materialIndex;
40423							faceB.materialIndex = materialIndex;
40424  
40425						}
40426  
40427						// to get face <=> uv index correspondence
40428  
40429						fi = geometry.faces.length;
40430  
40431						if ( hasFaceVertexUv ) {
40432  
40433							for ( i = 0; i < nUvLayers; i ++ ) {
40434  
40435								uvLayer = json.uvs[ i ];
40436  
40437								geometry.faceVertexUvs[ i ][ fi ] = [];
40438								geometry.faceVertexUvs[ i ][ fi + 1 ] = [];
40439  
40440								for ( j = 0; j < 4; j ++ ) {
40441  
40442									uvIndex = faces[ offset ++ ];
40443  
40444									u = uvLayer[ uvIndex * 2 ];
40445									v = uvLayer[ uvIndex * 2 + 1 ];
40446  
40447									uv = new Vector2( u, v );
40448  
40449									if ( j !== 2 ) geometry.faceVertexUvs[ i ][ fi ].push( uv );
40450									if ( j !== 0 ) geometry.faceVertexUvs[ i ][ fi + 1 ].push( uv );
40451  
40452								}
40453  
40454							}
40455  
40456						}
40457  
40458						if ( hasFaceNormal ) {
40459  
40460							normalIndex = faces[ offset ++ ] * 3;
40461  
40462							faceA.normal.set(
40463								normals[ normalIndex ++ ],
40464								normals[ normalIndex ++ ],
40465								normals[ normalIndex ]
40466							);
40467  
40468							faceB.normal.copy( faceA.normal );
40469  
40470						}
40471  
40472						if ( hasFaceVertexNormal ) {
40473  
40474							for ( i = 0; i < 4; i ++ ) {
40475  
40476								normalIndex = faces[ offset ++ ] * 3;
40477  
40478								normal = new Vector3(
40479									normals[ normalIndex ++ ],
40480									normals[ normalIndex ++ ],
40481									normals[ normalIndex ]
40482								);
40483  
40484  
40485								if ( i !== 2 ) faceA.vertexNormals.push( normal );
40486								if ( i !== 0 ) faceB.vertexNormals.push( normal );
40487  
40488							}
40489  
40490						}
40491  
40492  
40493						if ( hasFaceColor ) {
40494  
40495							colorIndex = faces[ offset ++ ];
40496							hex = colors[ colorIndex ];
40497  
40498							faceA.color.setHex( hex );
40499							faceB.color.setHex( hex );
40500  
40501						}
40502  
40503  
40504						if ( hasFaceVertexColor ) {
40505  
40506							for ( i = 0; i < 4; i ++ ) {
40507  
40508								colorIndex = faces[ offset ++ ];
40509								hex = colors[ colorIndex ];
40510  
40511								if ( i !== 2 ) faceA.vertexColors.push( new Color( hex ) );
40512								if ( i !== 0 ) faceB.vertexColors.push( new Color( hex ) );
40513  
40514							}
40515  
40516						}
40517  
40518						geometry.faces.push( faceA );
40519						geometry.faces.push( faceB );
40520  
40521					} else {
40522  
40523						face = new Face3();
40524						face.a = faces[ offset ++ ];
40525						face.b = faces[ offset ++ ];
40526						face.c = faces[ offset ++ ];
40527  
40528						if ( hasMaterial ) {
40529  
40530							materialIndex = faces[ offset ++ ];
40531							face.materialIndex = materialIndex;
40532  
40533						}
40534  
40535						// to get face <=> uv index correspondence
40536  
40537						fi = geometry.faces.length;
40538  
40539						if ( hasFaceVertexUv ) {
40540  
40541							for ( i = 0; i < nUvLayers; i ++ ) {
40542  
40543								uvLayer = json.uvs[ i ];
40544  
40545								geometry.faceVertexUvs[ i ][ fi ] = [];
40546  
40547								for ( j = 0; j < 3; j ++ ) {
40548  
40549									uvIndex = faces[ offset ++ ];
40550  
40551									u = uvLayer[ uvIndex * 2 ];
40552									v = uvLayer[ uvIndex * 2 + 1 ];
40553  
40554									uv = new Vector2( u, v );
40555  
40556									geometry.faceVertexUvs[ i ][ fi ].push( uv );
40557  
40558								}
40559  
40560							}
40561  
40562						}
40563  
40564						if ( hasFaceNormal ) {
40565  
40566							normalIndex = faces[ offset ++ ] * 3;
40567  
40568							face.normal.set(
40569								normals[ normalIndex ++ ],
40570								normals[ normalIndex ++ ],
40571								normals[ normalIndex ]
40572							);
40573  
40574						}
40575  
40576						if ( hasFaceVertexNormal ) {
40577  
40578							for ( i = 0; i < 3; i ++ ) {
40579  
40580								normalIndex = faces[ offset ++ ] * 3;
40581  
40582								normal = new Vector3(
40583									normals[ normalIndex ++ ],
40584									normals[ normalIndex ++ ],
40585									normals[ normalIndex ]
40586								);
40587  
40588								face.vertexNormals.push( normal );
40589  
40590							}
40591  
40592						}
40593  
40594  
40595						if ( hasFaceColor ) {
40596  
40597							colorIndex = faces[ offset ++ ];
40598							face.color.setHex( colors[ colorIndex ] );
40599  
40600						}
40601  
40602  
40603						if ( hasFaceVertexColor ) {
40604  
40605							for ( i = 0; i < 3; i ++ ) {
40606  
40607								colorIndex = faces[ offset ++ ];
40608								face.vertexColors.push( new Color( colors[ colorIndex ] ) );
40609  
40610							}
40611  
40612						}
40613  
40614						geometry.faces.push( face );
40615  
40616					}
40617  
40618				}
40619  
40620			}
40621  
40622			function parseSkin( json, geometry ) {
40623  
40624				var influencesPerVertex = ( json.influencesPerVertex !== undefined ) ? json.influencesPerVertex : 2;
40625  
40626				if ( json.skinWeights ) {
40627  
40628					for ( var i = 0, l = json.skinWeights.length; i < l; i += influencesPerVertex ) {
40629  
40630						var x = json.skinWeights[ i ];
40631						var y = ( influencesPerVertex > 1 ) ? json.skinWeights[ i + 1 ] : 0;
40632						var z = ( influencesPerVertex > 2 ) ? json.skinWeights[ i + 2 ] : 0;
40633						var w = ( influencesPerVertex > 3 ) ? json.skinWeights[ i + 3 ] : 0;
40634  
40635						geometry.skinWeights.push( new Vector4( x, y, z, w ) );
40636  
40637					}
40638  
40639				}
40640  
40641				if ( json.skinIndices ) {
40642  
40643					for ( var i = 0, l = json.skinIndices.length; i < l; i += influencesPerVertex ) {
40644  
40645						var a = json.skinIndices[ i ];
40646						var b = ( influencesPerVertex > 1 ) ? json.skinIndices[ i + 1 ] : 0;
40647						var c = ( influencesPerVertex > 2 ) ? json.skinIndices[ i + 2 ] : 0;
40648						var d = ( influencesPerVertex > 3 ) ? json.skinIndices[ i + 3 ] : 0;
40649  
40650						geometry.skinIndices.push( new Vector4( a, b, c, d ) );
40651  
40652					}
40653  
40654				}
40655  
40656				geometry.bones = json.bones;
40657  
40658				if ( geometry.bones && geometry.bones.length > 0 && ( geometry.skinWeights.length !== geometry.skinIndices.length || geometry.skinIndices.length !== geometry.vertices.length ) ) {
40659  
40660					console.warn( 'When skinning, number of vertices (' + geometry.vertices.length + '), skinIndices (' +
40661						geometry.skinIndices.length + '), and skinWeights (' + geometry.skinWeights.length + ') should match.' );
40662  
40663				}
40664  
40665			}
40666  
40667			function parseMorphing( json, geometry ) {
40668  
40669				var scale = json.scale;
40670  
40671				if ( json.morphTargets !== undefined ) {
40672  
40673					for ( var i = 0, l = json.morphTargets.length; i < l; i ++ ) {
40674  
40675						geometry.morphTargets[ i ] = {};
40676						geometry.morphTargets[ i ].name = json.morphTargets[ i ].name;
40677						geometry.morphTargets[ i ].vertices = [];
40678  
40679						var dstVertices = geometry.morphTargets[ i ].vertices;
40680						var srcVertices = json.morphTargets[ i ].vertices;
40681  
40682						for ( var v = 0, vl = srcVertices.length; v < vl; v += 3 ) {
40683  
40684							var vertex = new Vector3();
40685							vertex.x = srcVertices[ v ] * scale;
40686							vertex.y = srcVertices[ v + 1 ] * scale;
40687							vertex.z = srcVertices[ v + 2 ] * scale;
40688  
40689							dstVertices.push( vertex );
40690  
40691						}
40692  
40693					}
40694  
40695				}
40696  
40697				if ( json.morphColors !== undefined && json.morphColors.length > 0 ) {
40698  
40699					console.warn( 'THREE.JSONLoader: "morphColors" no longer supported. Using them as face colors.' );
40700  
40701					var faces = geometry.faces;
40702					var morphColors = json.morphColors[ 0 ].colors;
40703  
40704					for ( var i = 0, l = faces.length; i < l; i ++ ) {
40705  
40706						faces[ i ].color.fromArray( morphColors, i * 3 );
40707  
40708					}
40709  
40710				}
40711  
40712			}
40713  
40714			function parseAnimations( json, geometry ) {
40715  
40716				var outputAnimations = [];
40717  
40718				// parse old style Bone/Hierarchy animations
40719				var animations = [];
40720  
40721				if ( json.animation !== undefined ) {
40722  
40723					animations.push( json.animation );
40724  
40725				}
40726  
40727				if ( json.animations !== undefined ) {
40728  
40729					if ( json.animations.length ) {
40730  
40731						animations = animations.concat( json.animations );
40732  
40733					} else {
40734  
40735						animations.push( json.animations );
40736  
40737					}
40738  
40739				}
40740  
40741				for ( var i = 0; i < animations.length; i ++ ) {
40742  
40743					var clip = AnimationClip.parseAnimation( animations[ i ], geometry.bones );
40744					if ( clip ) outputAnimations.push( clip );
40745  
40746				}
40747  
40748				// parse implicit morph animations
40749				if ( geometry.morphTargets ) {
40750  
40751					// TODO: Figure out what an appropraite FPS is for morph target animations -- defaulting to 10, but really it is completely arbitrary.
40752					var morphAnimationClips = AnimationClip.CreateClipsFromMorphTargetSequences( geometry.morphTargets, 10 );
40753					outputAnimations = outputAnimations.concat( morphAnimationClips );
40754  
40755				}
40756  
40757				if ( outputAnimations.length > 0 ) geometry.animations = outputAnimations;
40758  
40759			}
40760  
40761			return function parse( json, texturePath ) {
40762  
40763				if ( json.data !== undefined ) {
40764  
40765					// Geometry 4.0 spec
40766					json = json.data;
40767  
40768				}
40769  
40770				if ( json.scale !== undefined ) {
40771  
40772					json.scale = 1.0 / json.scale;
40773  
40774				} else {
40775  
vendor: 20,413 bytes, lines 40776-41701
40776					json.scale = 1.0;
40777  
40778				}
40779  
40780				var geometry = new Geometry();
40781  
40782				parseModel( json, geometry );
40783				parseSkin( json, geometry );
40784				parseMorphing( json, geometry );
40785				parseAnimations( json, geometry );
40786  
40787				geometry.computeFaceNormals();
40788				geometry.computeBoundingSphere();
40789  
40790				if ( json.materials === undefined || json.materials.length === 0 ) {
40791  
40792					return { geometry: geometry };
40793  
40794				} else {
40795  
40796					var materials = Loader.prototype.initMaterials( json.materials, texturePath, this.crossOrigin );
40797  
40798					return { geometry: geometry, materials: materials };
40799  
40800				}
40801  
40802			};
40803  
40804		} )()
40805  
40806	} );
40807  
40808	/**
40809	 * @author mrdoob / http://mrdoob.com/
40810	 */
40811  
40812	function ObjectLoader( manager ) {
40813  
40814		this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager;
40815		this.texturePath = '';
40816  
40817	}
40818  
40819	Object.assign( ObjectLoader.prototype, {
40820  
40821		load: function ( url, onLoad, onProgress, onError ) {
40822  
40823			if ( this.texturePath === '' ) {
40824  
40825				this.texturePath = url.substring( 0, url.lastIndexOf( '/' ) + 1 );
40826  
40827			}
40828  
40829			var scope = this;
40830  
40831			var loader = new FileLoader( scope.manager );
40832			loader.load( url, function ( text ) {
40833  
40834				var json = null;
40835  
40836				try {
40837  
40838					json = JSON.parse( text );
40839  
40840				} catch ( error ) {
40841  
40842					if ( onError !== undefined ) onError( error );
40843  
40844					console.error( 'THREE:ObjectLoader: Can\'t parse ' + url + '.', error.message );
40845  
40846					return;
40847  
40848				}
40849  
40850				var metadata = json.metadata;
40851  
40852				if ( metadata === undefined || metadata.type === undefined || metadata.type.toLowerCase() === 'geometry' ) {
40853  
40854					console.error( 'THREE.ObjectLoader: Can\'t load ' + url + '. Use THREE.JSONLoader instead.' );
40855					return;
40856  
40857				}
40858  
40859				scope.parse( json, onLoad );
40860  
40861			}, onProgress, onError );
40862  
40863		},
40864  
40865		setTexturePath: function ( value ) {
40866  
40867			this.texturePath = value;
40868			return this;
40869  
40870		},
40871  
40872		setCrossOrigin: function ( value ) {
40873  
40874			this.crossOrigin = value;
40875			return this;
40876  
40877		},
40878  
40879		parse: function ( json, onLoad ) {
40880  
40881			var shapes = this.parseShape( json.shapes );
40882			var geometries = this.parseGeometries( json.geometries, shapes );
40883  
40884			var images = this.parseImages( json.images, function () {
40885  
40886				if ( onLoad !== undefined ) onLoad( object );
40887  
40888			} );
40889  
40890			var textures = this.parseTextures( json.textures, images );
40891			var materials = this.parseMaterials( json.materials, textures );
40892  
40893			var object = this.parseObject( json.object, geometries, materials );
40894  
40895			if ( json.animations ) {
40896  
40897				object.animations = this.parseAnimations( json.animations );
40898  
40899			}
40900  
40901			if ( json.images === undefined || json.images.length === 0 ) {
40902  
40903				if ( onLoad !== undefined ) onLoad( object );
40904  
40905			}
40906  
40907			return object;
40908  
40909		},
40910  
40911		parseShape: function ( json ) {
40912  
40913			var shapes = {};
40914  
40915			if ( json !== undefined ) {
40916  
40917				for ( var i = 0, l = json.length; i < l; i ++ ) {
40918  
40919					var shape = new Shape().fromJSON( json[ i ] );
40920  
40921					shapes[ shape.uuid ] = shape;
40922  
40923				}
40924  
40925			}
40926  
40927			return shapes;
40928  
40929		},
40930  
40931		parseGeometries: function ( json, shapes ) {
40932  
40933			var geometries = {};
40934  
40935			if ( json !== undefined ) {
40936  
40937				var geometryLoader = new JSONLoader();
40938				var bufferGeometryLoader = new BufferGeometryLoader();
40939  
40940				for ( var i = 0, l = json.length; i < l; i ++ ) {
40941  
40942					var geometry;
40943					var data = json[ i ];
40944  
40945					switch ( data.type ) {
40946  
40947						case 'PlaneGeometry':
40948						case 'PlaneBufferGeometry':
40949  
40950							geometry = new Geometries[ data.type ](
40951								data.width,
40952								data.height,
40953								data.widthSegments,
40954								data.heightSegments
40955							);
40956  
40957							break;
40958  
40959						case 'BoxGeometry':
40960						case 'BoxBufferGeometry':
40961						case 'CubeGeometry': // backwards compatible
40962  
40963							geometry = new Geometries[ data.type ](
40964								data.width,
40965								data.height,
40966								data.depth,
40967								data.widthSegments,
40968								data.heightSegments,
40969								data.depthSegments
40970							);
40971  
40972							break;
40973  
40974						case 'CircleGeometry':
40975						case 'CircleBufferGeometry':
40976  
40977							geometry = new Geometries[ data.type ](
40978								data.radius,
40979								data.segments,
40980								data.thetaStart,
40981								data.thetaLength
40982							);
40983  
40984							break;
40985  
40986						case 'CylinderGeometry':
40987						case 'CylinderBufferGeometry':
40988  
40989							geometry = new Geometries[ data.type ](
40990								data.radiusTop,
40991								data.radiusBottom,
40992								data.height,
40993								data.radialSegments,
40994								data.heightSegments,
40995								data.openEnded,
40996								data.thetaStart,
40997								data.thetaLength
40998							);
40999  
41000							break;
41001  
41002						case 'ConeGeometry':
41003						case 'ConeBufferGeometry':
41004  
41005							geometry = new Geometries[ data.type ](
41006								data.radius,
41007								data.height,
41008								data.radialSegments,
41009								data.heightSegments,
41010								data.openEnded,
41011								data.thetaStart,
41012								data.thetaLength
41013							);
41014  
41015							break;
41016  
41017						case 'SphereGeometry':
41018						case 'SphereBufferGeometry':
41019  
41020							geometry = new Geometries[ data.type ](
41021								data.radius,
41022								data.widthSegments,
41023								data.heightSegments,
41024								data.phiStart,
41025								data.phiLength,
41026								data.thetaStart,
41027								data.thetaLength
41028							);
41029  
41030							break;
41031  
41032						case 'DodecahedronGeometry':
41033						case 'DodecahedronBufferGeometry':
41034						case 'IcosahedronGeometry':
41035						case 'IcosahedronBufferGeometry':
41036						case 'OctahedronGeometry':
41037						case 'OctahedronBufferGeometry':
41038						case 'TetrahedronGeometry':
41039						case 'TetrahedronBufferGeometry':
41040  
41041							geometry = new Geometries[ data.type ](
41042								data.radius,
41043								data.detail
41044							);
41045  
41046							break;
41047  
41048						case 'RingGeometry':
41049						case 'RingBufferGeometry':
41050  
41051							geometry = new Geometries[ data.type ](
41052								data.innerRadius,
41053								data.outerRadius,
41054								data.thetaSegments,
41055								data.phiSegments,
41056								data.thetaStart,
41057								data.thetaLength
41058							);
41059  
41060							break;
41061  
41062						case 'TorusGeometry':
41063						case 'TorusBufferGeometry':
41064  
41065							geometry = new Geometries[ data.type ](
41066								data.radius,
41067								data.tube,
41068								data.radialSegments,
41069								data.tubularSegments,
41070								data.arc
41071							);
41072  
41073							break;
41074  
41075						case 'TorusKnotGeometry':
41076						case 'TorusKnotBufferGeometry':
41077  
41078							geometry = new Geometries[ data.type ](
41079								data.radius,
41080								data.tube,
41081								data.tubularSegments,
41082								data.radialSegments,
41083								data.p,
41084								data.q
41085							);
41086  
41087							break;
41088  
41089						case 'LatheGeometry':
41090						case 'LatheBufferGeometry':
41091  
41092							geometry = new Geometries[ data.type ](
41093								data.points,
41094								data.segments,
41095								data.phiStart,
41096								data.phiLength
41097							);
41098  
41099							break;
41100  
41101						case 'PolyhedronGeometry':
41102						case 'PolyhedronBufferGeometry':
41103  
41104							geometry = new Geometries[ data.type ](
41105								data.vertices,
41106								data.indices,
41107								data.radius,
41108								data.details
41109							);
41110  
41111							break;
41112  
41113						case 'ShapeGeometry':
41114						case 'ShapeBufferGeometry':
41115  
41116							var geometryShapes = [];
41117  
41118							for ( var j = 0, jl = data.shapes.length; j < jl; j ++ ) {
41119  
41120								var shape = shapes[ data.shapes[ j ] ];
41121  
41122								geometryShapes.push( shape );
41123  
41124							}
41125  
41126							geometry = new Geometries[ data.type ](
41127								geometryShapes,
41128								data.curveSegments
41129							);
41130  
41131							break;
41132  
41133  
41134						case 'ExtrudeGeometry':
41135						case 'ExtrudeBufferGeometry':
41136  
41137							var geometryShapes = [];
41138  
41139							for ( var j = 0, jl = data.shapes.length; j < jl; j ++ ) {
41140  
41141								var shape = shapes[ data.shapes[ j ] ];
41142  
41143								geometryShapes.push( shape );
41144  
41145							}
41146  
41147							var extrudePath = data.options.extrudePath;
41148  
41149							if ( extrudePath !== undefined ) {
41150  
41151								data.options.extrudePath = new Curves[ extrudePath.type ]().fromJSON( extrudePath );
41152  
41153							}
41154  
41155							geometry = new Geometries[ data.type ](
41156								geometryShapes,
41157								data.options
41158							);
41159  
41160							break;
41161  
41162						case 'BufferGeometry':
41163  
41164							geometry = bufferGeometryLoader.parse( data );
41165  
41166							break;
41167  
41168						case 'Geometry':
41169  
41170							geometry = geometryLoader.parse( data, this.texturePath ).geometry;
41171  
41172							break;
41173  
41174						default:
41175  
41176							console.warn( 'THREE.ObjectLoader: Unsupported geometry type "' + data.type + '"' );
41177  
41178							continue;
41179  
41180					}
41181  
41182					geometry.uuid = data.uuid;
41183  
41184					if ( data.name !== undefined ) geometry.name = data.name;
41185					if ( geometry.isBufferGeometry === true && data.userData !== undefined ) geometry.userData = data.userData;
41186  
41187					geometries[ data.uuid ] = geometry;
41188  
41189				}
41190  
41191			}
41192  
41193			return geometries;
41194  
41195		},
41196  
41197		parseMaterials: function ( json, textures ) {
41198  
41199			var materials = {};
41200  
41201			if ( json !== undefined ) {
41202  
41203				var loader = new MaterialLoader();
41204				loader.setTextures( textures );
41205  
41206				for ( var i = 0, l = json.length; i < l; i ++ ) {
41207  
41208					var data = json[ i ];
41209  
41210					if ( data.type === 'MultiMaterial' ) {
41211  
41212						// Deprecated
41213  
41214						var array = [];
41215  
41216						for ( var j = 0; j < data.materials.length; j ++ ) {
41217  
41218							array.push( loader.parse( data.materials[ j ] ) );
41219  
41220						}
41221  
41222						materials[ data.uuid ] = array;
41223  
41224					} else {
41225  
41226						materials[ data.uuid ] = loader.parse( data );
41227  
41228					}
41229  
41230				}
41231  
41232			}
41233  
41234			return materials;
41235  
41236		},
41237  
41238		parseAnimations: function ( json ) {
41239  
41240			var animations = [];
41241  
41242			for ( var i = 0; i < json.length; i ++ ) {
41243  
41244				var data = json[ i ];
41245  
41246				var clip = AnimationClip.parse( data );
41247  
41248				if ( data.uuid !== undefined ) clip.uuid = data.uuid;
41249  
41250				animations.push( clip );
41251  
41252			}
41253  
41254			return animations;
41255  
41256		},
41257  
41258		parseImages: function ( json, onLoad ) {
41259  
41260			var scope = this;
41261			var images = {};
41262  
41263			function loadImage( url ) {
41264  
41265				scope.manager.itemStart( url );
41266  
41267				return loader.load( url, function () {
41268  
41269					scope.manager.itemEnd( url );
41270  
41271				}, undefined, function () {
41272  
41273					scope.manager.itemEnd( url );
41274					scope.manager.itemError( url );
41275  
41276				} );
41277  
41278			}
41279  
41280			if ( json !== undefined && json.length > 0 ) {
41281  
41282				var manager = new LoadingManager( onLoad );
41283  
41284				var loader = new ImageLoader( manager );
41285				loader.setCrossOrigin( this.crossOrigin );
41286  
41287				for ( var i = 0, l = json.length; i < l; i ++ ) {
41288  
41289					var image = json[ i ];
41290					var path = /^(\/\/)|([a-z]+:(\/\/)?)/i.test( image.url ) ? image.url : scope.texturePath + image.url;
41291  
41292					images[ image.uuid ] = loadImage( path );
41293  
41294				}
41295  
41296			}
41297  
41298			return images;
41299  
41300		},
41301  
41302		parseTextures: function ( json, images ) {
41303  
41304			function parseConstant( value, type ) {
41305  
41306				if ( typeof value === 'number' ) return value;
41307  
41308				console.warn( 'THREE.ObjectLoader.parseTexture: Constant should be in numeric form.', value );
41309  
41310				return type[ value ];
41311  
41312			}
41313  
41314			var textures = {};
41315  
41316			if ( json !== undefined ) {
41317  
41318				for ( var i = 0, l = json.length; i < l; i ++ ) {
41319  
41320					var data = json[ i ];
41321  
41322					if ( data.image === undefined ) {
41323  
41324						console.warn( 'THREE.ObjectLoader: No "image" specified for', data.uuid );
41325  
41326					}
41327  
41328					if ( images[ data.image ] === undefined ) {
41329  
41330						console.warn( 'THREE.ObjectLoader: Undefined image', data.image );
41331  
41332					}
41333  
41334					var texture = new Texture( images[ data.image ] );
41335					texture.needsUpdate = true;
41336  
41337					texture.uuid = data.uuid;
41338  
41339					if ( data.name !== undefined ) texture.name = data.name;
41340  
41341					if ( data.mapping !== undefined ) texture.mapping = parseConstant( data.mapping, TEXTURE_MAPPING );
41342  
41343					if ( data.offset !== undefined ) texture.offset.fromArray( data.offset );
41344					if ( data.repeat !== undefined ) texture.repeat.fromArray( data.repeat );
41345					if ( data.center !== undefined ) texture.center.fromArray( data.center );
41346					if ( data.rotation !== undefined ) texture.rotation = data.rotation;
41347  
41348					if ( data.wrap !== undefined ) {
41349  
41350						texture.wrapS = parseConstant( data.wrap[ 0 ], TEXTURE_WRAPPING );
41351						texture.wrapT = parseConstant( data.wrap[ 1 ], TEXTURE_WRAPPING );
41352  
41353					}
41354  
41355					if ( data.format !== undefined ) texture.format = data.format;
41356  
41357					if ( data.minFilter !== undefined ) texture.minFilter = parseConstant( data.minFilter, TEXTURE_FILTER );
41358					if ( data.magFilter !== undefined ) texture.magFilter = parseConstant( data.magFilter, TEXTURE_FILTER );
41359					if ( data.anisotropy !== undefined ) texture.anisotropy = data.anisotropy;
41360  
41361					if ( data.flipY !== undefined ) texture.flipY = data.flipY;
41362  
41363					textures[ data.uuid ] = texture;
41364  
41365				}
41366  
41367			}
41368  
41369			return textures;
41370  
41371		},
41372  
41373		parseObject: function ( data, geometries, materials ) {
41374  
41375			var object;
41376  
41377			function getGeometry( name ) {
41378  
41379				if ( geometries[ name ] === undefined ) {
41380  
41381					console.warn( 'THREE.ObjectLoader: Undefined geometry', name );
41382  
41383				}
41384  
41385				return geometries[ name ];
41386  
41387			}
41388  
41389			function getMaterial( name ) {
41390  
41391				if ( name === undefined ) return undefined;
41392  
41393				if ( Array.isArray( name ) ) {
41394  
41395					var array = [];
41396  
41397					for ( var i = 0, l = name.length; i < l; i ++ ) {
41398  
41399						var uuid = name[ i ];
41400  
41401						if ( materials[ uuid ] === undefined ) {
41402  
41403							console.warn( 'THREE.ObjectLoader: Undefined material', uuid );
41404  
41405						}
41406  
41407						array.push( materials[ uuid ] );
41408  
41409					}
41410  
41411					return array;
41412  
41413				}
41414  
41415				if ( materials[ name ] === undefined ) {
41416  
41417					console.warn( 'THREE.ObjectLoader: Undefined material', name );
41418  
41419				}
41420  
41421				return materials[ name ];
41422  
41423			}
41424  
41425			switch ( data.type ) {
41426  
41427				case 'Scene':
41428  
41429					object = new Scene();
41430  
41431					if ( data.background !== undefined ) {
41432  
41433						if ( Number.isInteger( data.background ) ) {
41434  
41435							object.background = new Color( data.background );
41436  
41437						}
41438  
41439					}
41440  
41441					if ( data.fog !== undefined ) {
41442  
41443						if ( data.fog.type === 'Fog' ) {
41444  
41445							object.fog = new Fog( data.fog.color, data.fog.near, data.fog.far );
41446  
41447						} else if ( data.fog.type === 'FogExp2' ) {
41448  
41449							object.fog = new FogExp2( data.fog.color, data.fog.density );
41450  
41451						}
41452  
41453					}
41454  
41455					break;
41456  
41457				case 'PerspectiveCamera':
41458  
41459					object = new PerspectiveCamera( data.fov, data.aspect, data.near, data.far );
41460  
41461					if ( data.focus !== undefined ) object.focus = data.focus;
41462					if ( data.zoom !== undefined ) object.zoom = data.zoom;
41463					if ( data.filmGauge !== undefined ) object.filmGauge = data.filmGauge;
41464					if ( data.filmOffset !== undefined ) object.filmOffset = data.filmOffset;
41465					if ( data.view !== undefined ) object.view = Object.assign( {}, data.view );
41466  
41467					break;
41468  
41469				case 'OrthographicCamera':
41470  
41471					object = new OrthographicCamera( data.left, data.right, data.top, data.bottom, data.near, data.far );
41472  
41473					if ( data.zoom !== undefined ) object.zoom = data.zoom;
41474					if ( data.view !== undefined ) object.view = Object.assign( {}, data.view );
41475  
41476					break;
41477  
41478				case 'AmbientLight':
41479  
41480					object = new AmbientLight( data.color, data.intensity );
41481  
41482					break;
41483  
41484				case 'DirectionalLight':
41485  
41486					object = new DirectionalLight( data.color, data.intensity );
41487  
41488					break;
41489  
41490				case 'PointLight':
41491  
41492					object = new PointLight( data.color, data.intensity, data.distance, data.decay );
41493  
41494					break;
41495  
41496				case 'RectAreaLight':
41497  
41498					object = new RectAreaLight( data.color, data.intensity, data.width, data.height );
41499  
41500					break;
41501  
41502				case 'SpotLight':
41503  
41504					object = new SpotLight( data.color, data.intensity, data.distance, data.angle, data.penumbra, data.decay );
41505  
41506					break;
41507  
41508				case 'HemisphereLight':
41509  
41510					object = new HemisphereLight( data.color, data.groundColor, data.intensity );
41511  
41512					break;
41513  
41514				case 'SkinnedMesh':
41515  
41516					console.warn( 'THREE.ObjectLoader.parseObject() does not support SkinnedMesh yet.' );
41517  
41518				case 'Mesh':
41519  
41520					var geometry = getGeometry( data.geometry );
41521					var material = getMaterial( data.material );
41522  
41523					if ( geometry.bones && geometry.bones.length > 0 ) {
41524  
41525						object = new SkinnedMesh( geometry, material );
41526  
41527					} else {
41528  
41529						object = new Mesh( geometry, material );
41530  
41531					}
41532  
41533					break;
41534  
41535				case 'LOD':
41536  
41537					object = new LOD();
41538  
41539					break;
41540  
41541				case 'Line':
41542  
41543					object = new Line( getGeometry( data.geometry ), getMaterial( data.material ), data.mode );
41544  
41545					break;
41546  
41547				case 'LineLoop':
41548  
41549					object = new LineLoop( getGeometry( data.geometry ), getMaterial( data.material ) );
41550  
41551					break;
41552  
41553				case 'LineSegments':
41554  
41555					object = new LineSegments( getGeometry( data.geometry ), getMaterial( data.material ) );
41556  
41557					break;
41558  
41559				case 'PointCloud':
41560				case 'Points':
41561  
41562					object = new Points( getGeometry( data.geometry ), getMaterial( data.material ) );
41563  
41564					break;
41565  
41566				case 'Sprite':
41567  
41568					object = new Sprite( getMaterial( data.material ) );
41569  
41570					break;
41571  
41572				case 'Group':
41573  
41574					object = new Group();
41575  
41576					break;
41577  
41578				default:
41579  
41580					object = new Object3D();
41581  
41582			}
41583  
41584			object.uuid = data.uuid;
41585  
41586			if ( data.name !== undefined ) object.name = data.name;
41587  
41588			if ( data.matrix !== undefined ) {
41589  
41590				object.matrix.fromArray( data.matrix );
41591  
41592				if ( data.matrixAutoUpdate !== undefined ) object.matrixAutoUpdate = data.matrixAutoUpdate;
41593				if ( object.matrixAutoUpdate ) object.matrix.decompose( object.position, object.quaternion, object.scale );
41594  
41595			} else {
41596  
41597				if ( data.position !== undefined ) object.position.fromArray( data.position );
41598				if ( data.rotation !== undefined ) object.rotation.fromArray( data.rotation );
41599				if ( data.quaternion !== undefined ) object.quaternion.fromArray( data.quaternion );
41600				if ( data.scale !== undefined ) object.scale.fromArray( data.scale );
41601  
41602			}
41603  
41604			if ( data.castShadow !== undefined ) object.castShadow = data.castShadow;
41605			if ( data.receiveShadow !== undefined ) object.receiveShadow = data.receiveShadow;
41606  
41607			if ( data.shadow ) {
41608  
41609				if ( data.shadow.bias !== undefined ) object.shadow.bias = data.shadow.bias;
41610				if ( data.shadow.radius !== undefined ) object.shadow.radius = data.shadow.radius;
41611				if ( data.shadow.mapSize !== undefined ) object.shadow.mapSize.fromArray( data.shadow.mapSize );
41612				if ( data.shadow.camera !== undefined ) object.shadow.camera = this.parseObject( data.shadow.camera );
41613  
41614			}
41615  
41616			if ( data.visible !== undefined ) object.visible = data.visible;
41617			if ( data.frustumCulled !== undefined ) object.frustumCulled = data.frustumCulled;
41618			if ( data.renderOrder !== undefined ) object.renderOrder = data.renderOrder;
41619			if ( data.userData !== undefined ) object.userData = data.userData;
41620  
41621			if ( data.children !== undefined ) {
41622  
41623				var children = data.children;
41624  
41625				for ( var i = 0; i < children.length; i ++ ) {
41626  
41627					object.add( this.parseObject( children[ i ], geometries, materials ) );
41628  
41629				}
41630  
41631			}
41632  
41633			if ( data.type === 'LOD' ) {
41634  
41635				var levels = data.levels;
41636  
41637				for ( var l = 0; l < levels.length; l ++ ) {
41638  
41639					var level = levels[ l ];
41640					var child = object.getObjectByProperty( 'uuid', level.object );
41641  
41642					if ( child !== undefined ) {
41643  
41644						object.addLevel( child, level.distance );
41645  
41646					}
41647  
41648				}
41649  
41650			}
41651  
41652			return object;
41653  
41654		}
41655  
41656	} );
41657  
41658	var TEXTURE_MAPPING = {
41659		UVMapping: UVMapping,
41660		CubeReflectionMapping: CubeReflectionMapping,
41661		CubeRefractionMapping: CubeRefractionMapping,
41662		EquirectangularReflectionMapping: EquirectangularReflectionMapping,
41663		EquirectangularRefractionMapping: EquirectangularRefractionMapping,
41664		SphericalReflectionMapping: SphericalReflectionMapping,
41665		CubeUVReflectionMapping: CubeUVReflectionMapping,
41666		CubeUVRefractionMapping: CubeUVRefractionMapping
41667	};
41668  
41669	var TEXTURE_WRAPPING = {
41670		RepeatWrapping: RepeatWrapping,
41671		ClampToEdgeWrapping: ClampToEdgeWrapping,
41672		MirroredRepeatWrapping: MirroredRepeatWrapping
41673	};
41674  
41675	var TEXTURE_FILTER = {
41676		NearestFilter: NearestFilter,
41677		NearestMipMapNearestFilter: NearestMipMapNearestFilter,
41678		NearestMipMapLinearFilter: NearestMipMapLinearFilter,
41679		LinearFilter: LinearFilter,
41680		LinearMipMapNearestFilter: LinearMipMapNearestFilter,
41681		LinearMipMapLinearFilter: LinearMipMapLinearFilter
41682	};
41683  
41684	/**
41685	 * @author zz85 / http://www.lab4games.net/zz85/blog
41686	 * minimal class for proxing functions to Path. Replaces old "extractSubpaths()"
41687	 **/
41688  
41689	function ShapePath() {
41690  
41691		this.type = 'ShapePath';
41692  
41693		this.color = new Color();
41694  
41695		this.subPaths = [];
41696		this.currentPath = null;
41697  
41698	}
41699  
41700	Object.assign( ShapePath.prototype, {
41701  
41702		moveTo: function ( x, y ) {
41703  
41704			this.currentPath = new Path();
41705			this.subPaths.push( this.currentPath );
41706			this.currentPath.moveTo( x, y );
41707  
41708		},
41709  
41710		lineTo: function ( x, y ) {
41711  
41712			this.currentPath.lineTo( x, y );
41713  
41714		},
41715  
41716		quadraticCurveTo: function ( aCPx, aCPy, aX, aY ) {
41717  
41718			this.currentPath.quadraticCurveTo( aCPx, aCPy, aX, aY );
41719  
41720		},
41721  
41722		bezierCurveTo: function ( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY ) {
41723  
41724			this.currentPath.bezierCurveTo( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY );
41725  
41726		},
41727  
41728		splineThru: function ( pts ) {
41729  
41730			this.currentPath.splineThru( pts );
41731  
41732		},
41733  
41734		toShapes: function ( isCCW, noHoles ) {
41735  
41736			function toShapesNoHoles( inSubpaths ) {
41737  
41738				var shapes = [];
41739  
41740				for ( var i = 0, l = inSubpaths.length; i < l; i ++ ) {
41741  
41742					var tmpPath = inSubpaths[ i ];
41743  
41744					var tmpShape = new Shape();
41745					tmpShape.curves = tmpPath.curves;
41746  
41747					shapes.push( tmpShape );
41748  
41749				}
41750  
41751				return shapes;
41752  
41753			}
41754  
41755			function isPointInsidePolygon( inPt, inPolygon ) {
41756  
41757				var polyLen = inPolygon.length;
41758  
41759				// inPt on polygon contour => immediate success    or
41760				// toggling of inside/outside at every single! intersection point of an edge
41761				//  with the horizontal line through inPt, left of inPt
41762				//  not counting lowerY endpoints of edges and whole edges on that line
41763				var inside = false;
vendor: 9,176 bytes, lines 41764-42201
41764				for ( var p = polyLen - 1, q = 0; q < polyLen; p = q ++ ) {
41765  
41766					var edgeLowPt = inPolygon[ p ];
41767					var edgeHighPt = inPolygon[ q ];
41768  
41769					var edgeDx = edgeHighPt.x - edgeLowPt.x;
41770					var edgeDy = edgeHighPt.y - edgeLowPt.y;
41771  
41772					if ( Math.abs( edgeDy ) > Number.EPSILON ) {
41773  
41774						// not parallel
41775						if ( edgeDy < 0 ) {
41776  
41777							edgeLowPt = inPolygon[ q ]; edgeDx = - edgeDx;
41778							edgeHighPt = inPolygon[ p ]; edgeDy = - edgeDy;
41779  
41780						}
41781						if ( ( inPt.y < edgeLowPt.y ) || ( inPt.y > edgeHighPt.y ) ) 		continue;
41782  
41783						if ( inPt.y === edgeLowPt.y ) {
41784  
41785							if ( inPt.x === edgeLowPt.x )		return	true;		// inPt is on contour ?
41786							// continue;				// no intersection or edgeLowPt => doesn't count !!!
41787  
41788						} else {
41789  
41790							var perpEdge = edgeDy * ( inPt.x - edgeLowPt.x ) - edgeDx * ( inPt.y - edgeLowPt.y );
41791							if ( perpEdge === 0 )				return	true;		// inPt is on contour ?
41792							if ( perpEdge < 0 ) 				continue;
41793							inside = ! inside;		// true intersection left of inPt
41794  
41795						}
41796  
41797					} else {
41798  
41799						// parallel or collinear
41800						if ( inPt.y !== edgeLowPt.y ) 		continue;			// parallel
41801						// edge lies on the same horizontal line as inPt
41802						if ( ( ( edgeHighPt.x <= inPt.x ) && ( inPt.x <= edgeLowPt.x ) ) ||
41803							 ( ( edgeLowPt.x <= inPt.x ) && ( inPt.x <= edgeHighPt.x ) ) )		return	true;	// inPt: Point on contour !
41804						// continue;
41805  
41806					}
41807  
41808				}
41809  
41810				return	inside;
41811  
41812			}
41813  
41814			var isClockWise = ShapeUtils.isClockWise;
41815  
41816			var subPaths = this.subPaths;
41817			if ( subPaths.length === 0 ) return [];
41818  
41819			if ( noHoles === true )	return	toShapesNoHoles( subPaths );
41820  
41821  
41822			var solid, tmpPath, tmpShape, shapes = [];
41823  
41824			if ( subPaths.length === 1 ) {
41825  
41826				tmpPath = subPaths[ 0 ];
41827				tmpShape = new Shape();
41828				tmpShape.curves = tmpPath.curves;
41829				shapes.push( tmpShape );
41830				return shapes;
41831  
41832			}
41833  
41834			var holesFirst = ! isClockWise( subPaths[ 0 ].getPoints() );
41835			holesFirst = isCCW ? ! holesFirst : holesFirst;
41836  
41837			// console.log("Holes first", holesFirst);
41838  
41839			var betterShapeHoles = [];
41840			var newShapes = [];
41841			var newShapeHoles = [];
41842			var mainIdx = 0;
41843			var tmpPoints;
41844  
41845			newShapes[ mainIdx ] = undefined;
41846			newShapeHoles[ mainIdx ] = [];
41847  
41848			for ( var i = 0, l = subPaths.length; i < l; i ++ ) {
41849  
41850				tmpPath = subPaths[ i ];
41851				tmpPoints = tmpPath.getPoints();
41852				solid = isClockWise( tmpPoints );
41853				solid = isCCW ? ! solid : solid;
41854  
41855				if ( solid ) {
41856  
41857					if ( ( ! holesFirst ) && ( newShapes[ mainIdx ] ) )	mainIdx ++;
41858  
41859					newShapes[ mainIdx ] = { s: new Shape(), p: tmpPoints };
41860					newShapes[ mainIdx ].s.curves = tmpPath.curves;
41861  
41862					if ( holesFirst )	mainIdx ++;
41863					newShapeHoles[ mainIdx ] = [];
41864  
41865					//console.log('cw', i);
41866  
41867				} else {
41868  
41869					newShapeHoles[ mainIdx ].push( { h: tmpPath, p: tmpPoints[ 0 ] } );
41870  
41871					//console.log('ccw', i);
41872  
41873				}
41874  
41875			}
41876  
41877			// only Holes? -> probably all Shapes with wrong orientation
41878			if ( ! newShapes[ 0 ] )	return	toShapesNoHoles( subPaths );
41879  
41880  
41881			if ( newShapes.length > 1 ) {
41882  
41883				var ambiguous = false;
41884				var toChange = [];
41885  
41886				for ( var sIdx = 0, sLen = newShapes.length; sIdx < sLen; sIdx ++ ) {
41887  
41888					betterShapeHoles[ sIdx ] = [];
41889  
41890				}
41891  
41892				for ( var sIdx = 0, sLen = newShapes.length; sIdx < sLen; sIdx ++ ) {
41893  
41894					var sho = newShapeHoles[ sIdx ];
41895  
41896					for ( var hIdx = 0; hIdx < sho.length; hIdx ++ ) {
41897  
41898						var ho = sho[ hIdx ];
41899						var hole_unassigned = true;
41900  
41901						for ( var s2Idx = 0; s2Idx < newShapes.length; s2Idx ++ ) {
41902  
41903							if ( isPointInsidePolygon( ho.p, newShapes[ s2Idx ].p ) ) {
41904  
41905								if ( sIdx !== s2Idx )	toChange.push( { froms: sIdx, tos: s2Idx, hole: hIdx } );
41906								if ( hole_unassigned ) {
41907  
41908									hole_unassigned = false;
41909									betterShapeHoles[ s2Idx ].push( ho );
41910  
41911								} else {
41912  
41913									ambiguous = true;
41914  
41915								}
41916  
41917							}
41918  
41919						}
41920						if ( hole_unassigned ) {
41921  
41922							betterShapeHoles[ sIdx ].push( ho );
41923  
41924						}
41925  
41926					}
41927  
41928				}
41929				// console.log("ambiguous: ", ambiguous);
41930				if ( toChange.length > 0 ) {
41931  
41932					// console.log("to change: ", toChange);
41933					if ( ! ambiguous )	newShapeHoles = betterShapeHoles;
41934  
41935				}
41936  
41937			}
41938  
41939			var tmpHoles;
41940  
41941			for ( var i = 0, il = newShapes.length; i < il; i ++ ) {
41942  
41943				tmpShape = newShapes[ i ].s;
41944				shapes.push( tmpShape );
41945				tmpHoles = newShapeHoles[ i ];
41946  
41947				for ( var j = 0, jl = tmpHoles.length; j < jl; j ++ ) {
41948  
41949					tmpShape.holes.push( tmpHoles[ j ].h );
41950  
41951				}
41952  
41953			}
41954  
41955			//console.log("shape", shapes);
41956  
41957			return shapes;
41958  
41959		}
41960  
41961	} );
41962  
41963	/**
41964	 * @author zz85 / http://www.lab4games.net/zz85/blog
41965	 * @author mrdoob / http://mrdoob.com/
41966	 */
41967  
41968  
41969	function Font( data ) {
41970  
41971		this.type = 'Font';
41972  
41973		this.data = data;
41974  
41975	}
41976  
41977	Object.assign( Font.prototype, {
41978  
41979		isFont: true,
41980  
41981		generateShapes: function ( text, size, divisions ) {
41982  
41983			if ( size === undefined ) size = 100;
41984			if ( divisions === undefined ) divisions = 4;
41985  
41986			var shapes = [];
41987			var paths = createPaths( text, size, divisions, this.data );
41988  
41989			for ( var p = 0, pl = paths.length; p < pl; p ++ ) {
41990  
41991				Array.prototype.push.apply( shapes, paths[ p ].toShapes() );
41992  
41993			}
41994  
41995			return shapes;
41996  
41997		}
41998  
41999	} );
42000  
42001	function createPaths( text, size, divisions, data ) {
42002  
42003		var chars = Array.from ? Array.from( text ) : String( text ).split( '' ); // see #13988
42004		var scale = size / data.resolution;
42005		var line_height = ( data.boundingBox.yMax - data.boundingBox.yMin + data.underlineThickness ) * scale;
42006  
42007		var paths = [];
42008  
42009		var offsetX = 0, offsetY = 0;
42010  
42011		for ( var i = 0; i < chars.length; i ++ ) {
42012  
42013			var char = chars[ i ];
42014  
42015			if ( char === '\n' ) {
42016  
42017				offsetX = 0;
42018				offsetY -= line_height;
42019  
42020			} else {
42021  
42022				var ret = createPath( char, divisions, scale, offsetX, offsetY, data );
42023				offsetX += ret.offsetX;
42024				paths.push( ret.path );
42025  
42026			}
42027  
42028		}
42029  
42030		return paths;
42031  
42032	}
42033  
42034	function createPath( char, divisions, scale, offsetX, offsetY, data ) {
42035  
42036		var glyph = data.glyphs[ char ] || data.glyphs[ '?' ];
42037  
42038		if ( ! glyph ) return;
42039  
42040		var path = new ShapePath();
42041  
42042		var x, y, cpx, cpy, cpx1, cpy1, cpx2, cpy2;
42043  
42044		if ( glyph.o ) {
42045  
42046			var outline = glyph._cachedOutline || ( glyph._cachedOutline = glyph.o.split( ' ' ) );
42047  
42048			for ( var i = 0, l = outline.length; i < l; ) {
42049  
42050				var action = outline[ i ++ ];
42051  
42052				switch ( action ) {
42053  
42054					case 'm': // moveTo
42055  
42056						x = outline[ i ++ ] * scale + offsetX;
42057						y = outline[ i ++ ] * scale + offsetY;
42058  
42059						path.moveTo( x, y );
42060  
42061						break;
42062  
42063					case 'l': // lineTo
42064  
42065						x = outline[ i ++ ] * scale + offsetX;
42066						y = outline[ i ++ ] * scale + offsetY;
42067  
42068						path.lineTo( x, y );
42069  
42070						break;
42071  
42072					case 'q': // quadraticCurveTo
42073  
42074						cpx = outline[ i ++ ] * scale + offsetX;
42075						cpy = outline[ i ++ ] * scale + offsetY;
42076						cpx1 = outline[ i ++ ] * scale + offsetX;
42077						cpy1 = outline[ i ++ ] * scale + offsetY;
42078  
42079						path.quadraticCurveTo( cpx1, cpy1, cpx, cpy );
42080  
42081						break;
42082  
42083					case 'b': // bezierCurveTo
42084  
42085						cpx = outline[ i ++ ] * scale + offsetX;
42086						cpy = outline[ i ++ ] * scale + offsetY;
42087						cpx1 = outline[ i ++ ] * scale + offsetX;
42088						cpy1 = outline[ i ++ ] * scale + offsetY;
42089						cpx2 = outline[ i ++ ] * scale + offsetX;
42090						cpy2 = outline[ i ++ ] * scale + offsetY;
42091  
42092						path.bezierCurveTo( cpx1, cpy1, cpx2, cpy2, cpx, cpy );
42093  
42094						break;
42095  
42096				}
42097  
42098			}
42099  
42100		}
42101  
42102		return { offsetX: glyph.ha * scale, path: path };
42103  
42104	}
42105  
42106	/**
42107	 * @author mrdoob / http://mrdoob.com/
42108	 */
42109  
42110	function FontLoader( manager ) {
42111  
42112		this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager;
42113  
42114	}
42115  
42116	Object.assign( FontLoader.prototype, {
42117  
42118		load: function ( url, onLoad, onProgress, onError ) {
42119  
42120			var scope = this;
42121  
42122			var loader = new FileLoader( this.manager );
42123			loader.setPath( this.path );
42124			loader.load( url, function ( text ) {
42125  
42126				var json;
42127  
42128				try {
42129  
42130					json = JSON.parse( text );
42131  
42132				} catch ( e ) {
42133  
42134					console.warn( 'THREE.FontLoader: typeface.js support is being deprecated. Use typeface.json instead.' );
42135					json = JSON.parse( text.substring( 65, text.length - 2 ) );
42136  
42137				}
42138  
42139				var font = scope.parse( json );
42140  
42141				if ( onLoad ) onLoad( font );
42142  
42143			}, onProgress, onError );
42144  
42145		},
42146  
42147		parse: function ( json ) {
42148  
42149			return new Font( json );
42150  
42151		},
42152  
42153		setPath: function ( value ) {
42154  
42155			this.path = value;
42156			return this;
42157  
42158		}
42159  
42160	} );
42161  
42162	/**
42163	 * @author mrdoob / http://mrdoob.com/
42164	 */
42165  
42166	var context;
42167  
42168	var AudioContext = {
42169  
42170		getContext: function () {
42171  
42172			if ( context === undefined ) {
42173  
42174				context = new ( window.AudioContext || window.webkitAudioContext )();
42175  
42176			}
42177  
42178			return context;
42179  
42180		},
42181  
42182		setContext: function ( value ) {
42183  
42184			context = value;
42185  
42186		}
42187  
42188	};
42189  
42190	/**
42191	 * @author Reece Aaron Lecrivain / http://reecenotes.com/
42192	 */
42193  
42194	function AudioLoader( manager ) {
42195  
42196		this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager;
42197  
42198	}
42199  
42200	Object.assign( AudioLoader.prototype, {
42201  
42202		load: function ( url, onLoad, onProgress, onError ) {
42203  
42204			var loader = new FileLoader( this.manager );
42205			loader.setResponseType( 'arraybuffer' );
42206			loader.load( url, function ( buffer ) {
42207  
42208				var context = AudioContext.getContext();
42209  
42210				context.decodeAudioData( buffer, function ( audioBuffer ) {
42211  
42212					onLoad( audioBuffer );
42213  
42214				} );
42215  
42216			}, onProgress, onError );
42217  
42218		}
42219  
42220	} );
42221  
42222	/**
42223	 * @author mrdoob / http://mrdoob.com/
42224	 */
42225  
42226	function StereoCamera() {
42227  
42228		this.type = 'StereoCamera';
42229  
42230		this.aspect = 1;
42231  
42232		this.eyeSep = 0.064;
42233  
42234		this.cameraL = new PerspectiveCamera();
42235		this.cameraL.layers.enable( 1 );
42236		this.cameraL.matrixAutoUpdate = false;
42237  
42238		this.cameraR = new PerspectiveCamera();
42239		this.cameraR.layers.enable( 2 );
42240		this.cameraR.matrixAutoUpdate = false;
42241  
42242	}
42243  
42244	Object.assign( StereoCamera.prototype, {
42245  
42246		update: ( function () {
42247  
42248			var instance, focus, fov, aspect, near, far, zoom, eyeSep;
42249  
42250			var eyeRight = new Matrix4();
42251			var eyeLeft = new Matrix4();
42252  
42253			return function update( camera ) {
42254  
42255				var needsUpdate = instance !== this || focus !== camera.focus || fov !== camera.fov ||
42256													aspect !== camera.aspect * this.aspect || near !== camera.near ||
42257													far !== camera.far || zoom !== camera.zoom || eyeSep !== this.eyeSep;
42258  
42259				if ( needsUpdate ) {
42260  
42261					instance = this;
42262					focus = camera.focus;
42263					fov = camera.fov;
42264					aspect = camera.aspect * this.aspect;
42265					near = camera.near;
42266					far = camera.far;
42267					zoom = camera.zoom;
42268  
42269					// Off-axis stereoscopic effect based on
42270					// http://paulbourke.net/stereographics/stereorender/
42271  
42272					var projectionMatrix = camera.projectionMatrix.clone();
42273					eyeSep = this.eyeSep / 2;
42274					var eyeSepOnProjection = eyeSep * near / focus;
42275					var ymax = ( near * Math.tan( _Math.DEG2RAD * fov * 0.5 ) ) / zoom;
42276					var xmin, xmax;
42277  
42278					// translate xOffset
42279  
42280					eyeLeft.elements[ 12 ] = - eyeSep;
42281					eyeRight.elements[ 12 ] = eyeSep;
42282  
42283					// for left eye
42284  
42285					xmin = - ymax * aspect + eyeSepOnProjection;
42286					xmax = ymax * aspect + eyeSepOnProjection;
42287  
42288					projectionMatrix.elements[ 0 ] = 2 * near / ( xmax - xmin );
42289					projectionMatrix.elements[ 8 ] = ( xmax + xmin ) / ( xmax - xmin );
42290  
42291					this.cameraL.projectionMatrix.copy( projectionMatrix );
42292  
42293					// for right eye
42294  
42295					xmin = - ymax * aspect - eyeSepOnProjection;
42296					xmax = ymax * aspect - eyeSepOnProjection;
42297  
42298					projectionMatrix.elements[ 0 ] = 2 * near / ( xmax - xmin );
42299					projectionMatrix.elements[ 8 ] = ( xmax + xmin ) / ( xmax - xmin );
42300  
42301					this.cameraR.projectionMatrix.copy( projectionMatrix );
42302  
42303				}
42304  
42305				this.cameraL.matrixWorld.copy( camera.matrixWorld ).multiply( eyeLeft );
42306				this.cameraR.matrixWorld.copy( camera.matrixWorld ).multiply( eyeRight );
42307  
42308			};
42309  
42310		} )()
42311  
42312	} );
42313  
42314	/**
42315	 * Camera for rendering cube maps
42316	 *	- renders scene into axis-aligned cube
42317	 *
42318	 * @author alteredq / http://alteredqualia.com/
42319	 */
42320  
42321	function CubeCamera( near, far, cubeResolution ) {
42322  
42323		Object3D.call( this );
42324  
42325		this.type = 'CubeCamera';
42326  
42327		var fov = 90, aspect = 1;
42328  
42329		var cameraPX = new PerspectiveCamera( fov, aspect, near, far );
42330		cameraPX.up.set( 0, - 1, 0 );
42331		cameraPX.lookAt( new Vector3( 1, 0, 0 ) );
42332		this.add( cameraPX );
42333  
42334		var cameraNX = new PerspectiveCamera( fov, aspect, near, far );
42335		cameraNX.up.set( 0, - 1, 0 );
42336		cameraNX.lookAt( new Vector3( - 1, 0, 0 ) );
42337		this.add( cameraNX );
42338  
42339		var cameraPY = new PerspectiveCamera( fov, aspect, near, far );
42340		cameraPY.up.set( 0, 0, 1 );
42341		cameraPY.lookAt( new Vector3( 0, 1, 0 ) );
42342		this.add( cameraPY );
42343  
42344		var cameraNY = new PerspectiveCamera( fov, aspect, near, far );
42345		cameraNY.up.set( 0, 0, - 1 );
42346		cameraNY.lookAt( new Vector3( 0, - 1, 0 ) );
42347		this.add( cameraNY );
42348  
42349		var cameraPZ = new PerspectiveCamera( fov, aspect, near, far );
42350		cameraPZ.up.set( 0, - 1, 0 );
42351		cameraPZ.lookAt( new Vector3( 0, 0, 1 ) );
42352		this.add( cameraPZ );
42353  
42354		var cameraNZ = new PerspectiveCamera( fov, aspect, near, far );
42355		cameraNZ.up.set( 0, - 1, 0 );
42356		cameraNZ.lookAt( new Vector3( 0, 0, - 1 ) );
42357		this.add( cameraNZ );
42358  
42359		var options = { format: RGBFormat, magFilter: LinearFilter, minFilter: LinearFilter };
42360  
42361		this.renderTarget = new WebGLRenderTargetCube( cubeResolution, cubeResolution, options );
42362		this.renderTarget.texture.name = "CubeCamera";
42363  
42364		this.update = function ( renderer, scene ) {
42365  
42366			if ( this.parent === null ) this.updateMatrixWorld();
42367  
42368			var renderTarget = this.renderTarget;
42369			var generateMipmaps = renderTarget.texture.generateMipmaps;
42370  
42371			renderTarget.texture.generateMipmaps = false;
42372  
42373			renderTarget.activeCubeFace = 0;
42374			renderer.render( scene, cameraPX, renderTarget );
42375  
42376			renderTarget.activeCubeFace = 1;
42377			renderer.render( scene, cameraNX, renderTarget );
42378  
42379			renderTarget.activeCubeFace = 2;
42380			renderer.render( scene, cameraPY, renderTarget );
42381  
42382			renderTarget.activeCubeFace = 3;
42383			renderer.render( scene, cameraNY, renderTarget );
42384  
42385			renderTarget.activeCubeFace = 4;
42386			renderer.render( scene, cameraPZ, renderTarget );
42387  
42388			renderTarget.texture.generateMipmaps = generateMipmaps;
42389  
42390			renderTarget.activeCubeFace = 5;
42391			renderer.render( scene, cameraNZ, renderTarget );
42392  
42393			renderer.setRenderTarget( null );
42394  
42395		};
42396  
42397		this.clear = function ( renderer, color, depth, stencil ) {
42398  
42399			var renderTarget = this.renderTarget;
42400  
42401			for ( var i = 0; i < 6; i ++ ) {
42402  
42403				renderTarget.activeCubeFace = i;
42404				renderer.setRenderTarget( renderTarget );
42405  
42406				renderer.clear( color, depth, stencil );
42407  
42408			}
42409  
42410			renderer.setRenderTarget( null );
42411  
42412		};
42413  
42414	}
42415  
42416	CubeCamera.prototype = Object.create( Object3D.prototype );
42417	CubeCamera.prototype.constructor = CubeCamera;
42418  
42419	/**
42420	 * @author mrdoob / http://mrdoob.com/
42421	 */
42422  
42423	function AudioListener() {
42424  
42425		Object3D.call( this );
42426  
42427		this.type = 'AudioListener';
42428  
42429		this.context = AudioContext.getContext();
42430  
42431		this.gain = this.context.createGain();
42432		this.gain.connect( this.context.destination );
42433  
42434		this.filter = null;
42435  
42436	}
42437  
42438	AudioListener.prototype = Object.assign( Object.create( Object3D.prototype ), {
42439  
42440		constructor: AudioListener,
42441  
42442		getInput: function () {
42443  
42444			return this.gain;
42445  
42446		},
42447  
42448		removeFilter: function ( ) {
42449  
42450			if ( this.filter !== null ) {
42451  
42452				this.gain.disconnect( this.filter );
42453				this.filter.disconnect( this.context.destination );
42454				this.gain.connect( this.context.destination );
42455				this.filter = null;
42456  
42457			}
42458  
42459		},
42460  
42461		getFilter: function () {
42462  
42463			return this.filter;
42464  
42465		},
42466  
42467		setFilter: function ( value ) {
42468  
42469			if ( this.filter !== null ) {
42470  
42471				this.gain.disconnect( this.filter );
42472				this.filter.disconnect( this.context.destination );
42473  
42474			} else {
42475  
42476				this.gain.disconnect( this.context.destination );
42477  
42478			}
42479  
42480			this.filter = value;
42481			this.gain.connect( this.filter );
42482			this.filter.connect( this.context.destination );
42483  
42484		},
42485  
42486		getMasterVolume: function () {
42487  
42488			return this.gain.gain.value;
42489  
42490		},
42491  
42492		setMasterVolume: function ( value ) {
42493  
42494			this.gain.gain.setTargetAtTime( value, this.context.currentTime, 0.01 );
42495  
42496		},
42497  
42498		updateMatrixWorld: ( function () {
42499  
42500			var position = new Vector3();
42501			var quaternion = new Quaternion();
42502			var scale = new Vector3();
42503  
42504			var orientation = new Vector3();
42505  
42506			return function updateMatrixWorld( force ) {
42507  
42508				Object3D.prototype.updateMatrixWorld.call( this, force );
42509  
42510				var listener = this.context.listener;
42511				var up = this.up;
42512  
42513				this.matrixWorld.decompose( position, quaternion, scale );
42514  
42515				orientation.set( 0, 0, - 1 ).applyQuaternion( quaternion );
42516  
42517				if ( listener.positionX ) {
42518  
42519					listener.positionX.setValueAtTime( position.x, this.context.currentTime );
42520					listener.positionY.setValueAtTime( position.y, this.context.currentTime );
42521					listener.positionZ.setValueAtTime( position.z, this.context.currentTime );
42522					listener.forwardX.setValueAtTime( orientation.x, this.context.currentTime );
42523					listener.forwardY.setValueAtTime( orientation.y, this.context.currentTime );
42524					listener.forwardZ.setValueAtTime( orientation.z, this.context.currentTime );
42525					listener.upX.setValueAtTime( up.x, this.context.currentTime );
42526					listener.upY.setValueAtTime( up.y, this.context.currentTime );
42527					listener.upZ.setValueAtTime( up.z, this.context.currentTime );
42528  
42529				} else {
42530  
42531					listener.setPosition( position.x, position.y, position.z );
42532					listener.setOrientation( orientation.x, orientation.y, orientation.z, up.x, up.y, up.z );
42533  
42534				}
42535  
42536			};
42537  
42538		} )()
42539  
42540	} );
42541  
42542	/**
42543	 * @author mrdoob / http://mrdoob.com/
42544	 * @author Reece Aaron Lecrivain / http://reecenotes.com/
42545	 */
42546  
42547	function Audio( listener ) {
42548  
42549		Object3D.call( this );
42550  
42551		this.type = 'Audio';
42552  
42553		this.context = listener.context;
42554  
42555		this.gain = this.context.createGain();
42556		this.gain.connect( listener.getInput() );
42557  
42558		this.autoplay = false;
vendor: 4,143 bytes, lines 42559-42793
42559  
42560		this.buffer = null;
42561		this.loop = false;
42562		this.startTime = 0;
42563		this.offset = 0;
42564		this.playbackRate = 1;
42565		this.isPlaying = false;
42566		this.hasPlaybackControl = true;
42567		this.sourceType = 'empty';
42568  
42569		this.filters = [];
42570  
42571	}
42572  
42573	Audio.prototype = Object.assign( Object.create( Object3D.prototype ), {
42574  
42575		constructor: Audio,
42576  
42577		getOutput: function () {
42578  
42579			return this.gain;
42580  
42581		},
42582  
42583		setNodeSource: function ( audioNode ) {
42584  
42585			this.hasPlaybackControl = false;
42586			this.sourceType = 'audioNode';
42587			this.source = audioNode;
42588			this.connect();
42589  
42590			return this;
42591  
42592		},
42593  
42594		setMediaElementSource: function ( mediaElement ) {
42595  
42596			this.hasPlaybackControl = false;
42597			this.sourceType = 'mediaNode';
42598			this.source = this.context.createMediaElementSource( mediaElement );
42599			this.connect();
42600  
42601			return this;
42602  
42603		},
42604  
42605		setBuffer: function ( audioBuffer ) {
42606  
42607			this.buffer = audioBuffer;
42608			this.sourceType = 'buffer';
42609  
42610			if ( this.autoplay ) this.play();
42611  
42612			return this;
42613  
42614		},
42615  
42616		play: function () {
42617  
42618			if ( this.isPlaying === true ) {
42619  
42620				console.warn( 'THREE.Audio: Audio is already playing.' );
42621				return;
42622  
42623			}
42624  
42625			if ( this.hasPlaybackControl === false ) {
42626  
42627				console.warn( 'THREE.Audio: this Audio has no playback control.' );
42628				return;
42629  
42630			}
42631  
42632			var source = this.context.createBufferSource();
42633  
42634			source.buffer = this.buffer;
42635			source.loop = this.loop;
42636			source.onended = this.onEnded.bind( this );
42637			source.playbackRate.setValueAtTime( this.playbackRate, this.startTime );
42638			this.startTime = this.context.currentTime;
42639			source.start( this.startTime, this.offset );
42640  
42641			this.isPlaying = true;
42642  
42643			this.source = source;
42644  
42645			return this.connect();
42646  
42647		},
42648  
42649		pause: function () {
42650  
42651			if ( this.hasPlaybackControl === false ) {
42652  
42653				console.warn( 'THREE.Audio: this Audio has no playback control.' );
42654				return;
42655  
42656			}
42657  
42658			if ( this.isPlaying === true ) {
42659  
42660				this.source.stop();
42661				this.offset += ( this.context.currentTime - this.startTime ) * this.playbackRate;
42662				this.isPlaying = false;
42663  
42664			}
42665  
42666			return this;
42667  
42668		},
42669  
42670		stop: function () {
42671  
42672			if ( this.hasPlaybackControl === false ) {
42673  
42674				console.warn( 'THREE.Audio: this Audio has no playback control.' );
42675				return;
42676  
42677			}
42678  
42679			this.source.stop();
42680			this.offset = 0;
42681			this.isPlaying = false;
42682  
42683			return this;
42684  
42685		},
42686  
42687		connect: function () {
42688  
42689			if ( this.filters.length > 0 ) {
42690  
42691				this.source.connect( this.filters[ 0 ] );
42692  
42693				for ( var i = 1, l = this.filters.length; i < l; i ++ ) {
42694  
42695					this.filters[ i - 1 ].connect( this.filters[ i ] );
42696  
42697				}
42698  
42699				this.filters[ this.filters.length - 1 ].connect( this.getOutput() );
42700  
42701			} else {
42702  
42703				this.source.connect( this.getOutput() );
42704  
42705			}
42706  
42707			return this;
42708  
42709		},
42710  
42711		disconnect: function () {
42712  
42713			if ( this.filters.length > 0 ) {
42714  
42715				this.source.disconnect( this.filters[ 0 ] );
42716  
42717				for ( var i = 1, l = this.filters.length; i < l; i ++ ) {
42718  
42719					this.filters[ i - 1 ].disconnect( this.filters[ i ] );
42720  
42721				}
42722  
42723				this.filters[ this.filters.length - 1 ].disconnect( this.getOutput() );
42724  
42725			} else {
42726  
42727				this.source.disconnect( this.getOutput() );
42728  
42729			}
42730  
42731			return this;
42732  
42733		},
42734  
42735		getFilters: function () {
42736  
42737			return this.filters;
42738  
42739		},
42740  
42741		setFilters: function ( value ) {
42742  
42743			if ( ! value ) value = [];
42744  
42745			if ( this.isPlaying === true ) {
42746  
42747				this.disconnect();
42748				this.filters = value;
42749				this.connect();
42750  
42751			} else {
42752  
42753				this.filters = value;
42754  
42755			}
42756  
42757			return this;
42758  
42759		},
42760  
42761		getFilter: function () {
42762  
42763			return this.getFilters()[ 0 ];
42764  
42765		},
42766  
42767		setFilter: function ( filter ) {
42768  
42769			return this.setFilters( filter ? [ filter ] : [] );
42770  
42771		},
42772  
42773		setPlaybackRate: function ( value ) {
42774  
42775			if ( this.hasPlaybackControl === false ) {
42776  
42777				console.warn( 'THREE.Audio: this Audio has no playback control.' );
42778				return;
42779  
42780			}
42781  
42782			this.playbackRate = value;
42783  
42784			if ( this.isPlaying === true ) {
42785  
42786				this.source.playbackRate.setValueAtTime( this.playbackRate, this.context.currentTime );
42787  
42788			}
42789  
42790			return this;
42791  
42792		},
42793  
vendor: 40,587 bytes, lines 42794-44581
42794		getPlaybackRate: function () {
42795  
42796			return this.playbackRate;
42797  
42798		},
42799  
42800		onEnded: function () {
42801  
42802			this.isPlaying = false;
42803  
42804		},
42805  
42806		getLoop: function () {
42807  
42808			if ( this.hasPlaybackControl === false ) {
42809  
42810				console.warn( 'THREE.Audio: this Audio has no playback control.' );
42811				return false;
42812  
42813			}
42814  
42815			return this.loop;
42816  
42817		},
42818  
42819		setLoop: function ( value ) {
42820  
42821			if ( this.hasPlaybackControl === false ) {
42822  
42823				console.warn( 'THREE.Audio: this Audio has no playback control.' );
42824				return;
42825  
42826			}
42827  
42828			this.loop = value;
42829  
42830			if ( this.isPlaying === true ) {
42831  
42832				this.source.loop = this.loop;
42833  
42834			}
42835  
42836			return this;
42837  
42838		},
42839  
42840		getVolume: function () {
42841  
42842			return this.gain.gain.value;
42843  
42844		},
42845  
42846		setVolume: function ( value ) {
42847  
42848			this.gain.gain.setTargetAtTime( value, this.context.currentTime, 0.01 );
42849  
42850			return this;
42851  
42852		}
42853  
42854	} );
42855  
42856	/**
42857	 * @author mrdoob / http://mrdoob.com/
42858	 */
42859  
42860	function PositionalAudio( listener ) {
42861  
42862		Audio.call( this, listener );
42863  
42864		this.panner = this.context.createPanner();
42865		this.panner.connect( this.gain );
42866  
42867	}
42868  
42869	PositionalAudio.prototype = Object.assign( Object.create( Audio.prototype ), {
42870  
42871		constructor: PositionalAudio,
42872  
42873		getOutput: function () {
42874  
42875			return this.panner;
42876  
42877		},
42878  
42879		getRefDistance: function () {
42880  
42881			return this.panner.refDistance;
42882  
42883		},
42884  
42885		setRefDistance: function ( value ) {
42886  
42887			this.panner.refDistance = value;
42888  
42889		},
42890  
42891		getRolloffFactor: function () {
42892  
42893			return this.panner.rolloffFactor;
42894  
42895		},
42896  
42897		setRolloffFactor: function ( value ) {
42898  
42899			this.panner.rolloffFactor = value;
42900  
42901		},
42902  
42903		getDistanceModel: function () {
42904  
42905			return this.panner.distanceModel;
42906  
42907		},
42908  
42909		setDistanceModel: function ( value ) {
42910  
42911			this.panner.distanceModel = value;
42912  
42913		},
42914  
42915		getMaxDistance: function () {
42916  
42917			return this.panner.maxDistance;
42918  
42919		},
42920  
42921		setMaxDistance: function ( value ) {
42922  
42923			this.panner.maxDistance = value;
42924  
42925		},
42926  
42927		updateMatrixWorld: ( function () {
42928  
42929			var position = new Vector3();
42930  
42931			return function updateMatrixWorld( force ) {
42932  
42933				Object3D.prototype.updateMatrixWorld.call( this, force );
42934  
42935				position.setFromMatrixPosition( this.matrixWorld );
42936  
42937				this.panner.setPosition( position.x, position.y, position.z );
42938  
42939			};
42940  
42941		} )()
42942  
42943  
42944	} );
42945  
42946	/**
42947	 * @author mrdoob / http://mrdoob.com/
42948	 */
42949  
42950	function AudioAnalyser( audio, fftSize ) {
42951  
42952		this.analyser = audio.context.createAnalyser();
42953		this.analyser.fftSize = fftSize !== undefined ? fftSize : 2048;
42954  
42955		this.data = new Uint8Array( this.analyser.frequencyBinCount );
42956  
42957		audio.getOutput().connect( this.analyser );
42958  
42959	}
42960  
42961	Object.assign( AudioAnalyser.prototype, {
42962  
42963		getFrequencyData: function () {
42964  
42965			this.analyser.getByteFrequencyData( this.data );
42966  
42967			return this.data;
42968  
42969		},
42970  
42971		getAverageFrequency: function () {
42972  
42973			var value = 0, data = this.getFrequencyData();
42974  
42975			for ( var i = 0; i < data.length; i ++ ) {
42976  
42977				value += data[ i ];
42978  
42979			}
42980  
42981			return value / data.length;
42982  
42983		}
42984  
42985	} );
42986  
42987	/**
42988	 *
42989	 * Buffered scene graph property that allows weighted accumulation.
42990	 *
42991	 *
42992	 * @author Ben Houston / http://clara.io/
42993	 * @author David Sarno / http://lighthaus.us/
42994	 * @author tschw
42995	 */
42996  
42997	function PropertyMixer( binding, typeName, valueSize ) {
42998  
42999		this.binding = binding;
43000		this.valueSize = valueSize;
43001  
43002		var bufferType = Float64Array,
43003			mixFunction;
43004  
43005		switch ( typeName ) {
43006  
43007			case 'quaternion':
43008				mixFunction = this._slerp;
43009				break;
43010  
43011			case 'string':
43012			case 'bool':
43013				bufferType = Array;
43014				mixFunction = this._select;
43015				break;
43016  
43017			default:
43018				mixFunction = this._lerp;
43019  
43020		}
43021  
43022		this.buffer = new bufferType( valueSize * 4 );
43023		// layout: [ incoming | accu0 | accu1 | orig ]
43024		//
43025		// interpolators can use .buffer as their .result
43026		// the data then goes to 'incoming'
43027		//
43028		// 'accu0' and 'accu1' are used frame-interleaved for
43029		// the cumulative result and are compared to detect
43030		// changes
43031		//
43032		// 'orig' stores the original state of the property
43033  
43034		this._mixBufferRegion = mixFunction;
43035  
43036		this.cumulativeWeight = 0;
43037  
43038		this.useCount = 0;
43039		this.referenceCount = 0;
43040  
43041	}
43042  
43043	Object.assign( PropertyMixer.prototype, {
43044  
43045		// accumulate data in the 'incoming' region into 'accu<i>'
43046		accumulate: function ( accuIndex, weight ) {
43047  
43048			// note: happily accumulating nothing when weight = 0, the caller knows
43049			// the weight and shouldn't have made the call in the first place
43050  
43051			var buffer = this.buffer,
43052				stride = this.valueSize,
43053				offset = accuIndex * stride + stride,
43054  
43055				currentWeight = this.cumulativeWeight;
43056  
43057			if ( currentWeight === 0 ) {
43058  
43059				// accuN := incoming * weight
43060  
43061				for ( var i = 0; i !== stride; ++ i ) {
43062  
43063					buffer[ offset + i ] = buffer[ i ];
43064  
43065				}
43066  
43067				currentWeight = weight;
43068  
43069			} else {
43070  
43071				// accuN := accuN + incoming * weight
43072  
43073				currentWeight += weight;
43074				var mix = weight / currentWeight;
43075				this._mixBufferRegion( buffer, offset, 0, mix, stride );
43076  
43077			}
43078  
43079			this.cumulativeWeight = currentWeight;
43080  
43081		},
43082  
43083		// apply the state of 'accu<i>' to the binding when accus differ
43084		apply: function ( accuIndex ) {
43085  
43086			var stride = this.valueSize,
43087				buffer = this.buffer,
43088				offset = accuIndex * stride + stride,
43089  
43090				weight = this.cumulativeWeight,
43091  
43092				binding = this.binding;
43093  
43094			this.cumulativeWeight = 0;
43095  
43096			if ( weight < 1 ) {
43097  
43098				// accuN := accuN + original * ( 1 - cumulativeWeight )
43099  
43100				var originalValueOffset = stride * 3;
43101  
43102				this._mixBufferRegion(
43103					buffer, offset, originalValueOffset, 1 - weight, stride );
43104  
43105			}
43106  
43107			for ( var i = stride, e = stride + stride; i !== e; ++ i ) {
43108  
43109				if ( buffer[ i ] !== buffer[ i + stride ] ) {
43110  
43111					// value has changed -> update scene graph
43112  
43113					binding.setValue( buffer, offset );
43114					break;
43115  
43116				}
43117  
43118			}
43119  
43120		},
43121  
43122		// remember the state of the bound property and copy it to both accus
43123		saveOriginalState: function () {
43124  
43125			var binding = this.binding;
43126  
43127			var buffer = this.buffer,
43128				stride = this.valueSize,
43129  
43130				originalValueOffset = stride * 3;
43131  
43132			binding.getValue( buffer, originalValueOffset );
43133  
43134			// accu[0..1] := orig -- initially detect changes against the original
43135			for ( var i = stride, e = originalValueOffset; i !== e; ++ i ) {
43136  
43137				buffer[ i ] = buffer[ originalValueOffset + ( i % stride ) ];
43138  
43139			}
43140  
43141			this.cumulativeWeight = 0;
43142  
43143		},
43144  
43145		// apply the state previously taken via 'saveOriginalState' to the binding
43146		restoreOriginalState: function () {
43147  
43148			var originalValueOffset = this.valueSize * 3;
43149			this.binding.setValue( this.buffer, originalValueOffset );
43150  
43151		},
43152  
43153  
43154		// mix functions
43155  
43156		_select: function ( buffer, dstOffset, srcOffset, t, stride ) {
43157  
43158			if ( t >= 0.5 ) {
43159  
43160				for ( var i = 0; i !== stride; ++ i ) {
43161  
43162					buffer[ dstOffset + i ] = buffer[ srcOffset + i ];
43163  
43164				}
43165  
43166			}
43167  
43168		},
43169  
43170		_slerp: function ( buffer, dstOffset, srcOffset, t ) {
43171  
43172			Quaternion.slerpFlat( buffer, dstOffset, buffer, dstOffset, buffer, srcOffset, t );
43173  
43174		},
43175  
43176		_lerp: function ( buffer, dstOffset, srcOffset, t, stride ) {
43177  
43178			var s = 1 - t;
43179  
43180			for ( var i = 0; i !== stride; ++ i ) {
43181  
43182				var j = dstOffset + i;
43183  
43184				buffer[ j ] = buffer[ j ] * s + buffer[ srcOffset + i ] * t;
43185  
43186			}
43187  
43188		}
43189  
43190	} );
43191  
43192	/**
43193	 *
43194	 * A reference to a real property in the scene graph.
43195	 *
43196	 *
43197	 * @author Ben Houston / http://clara.io/
43198	 * @author David Sarno / http://lighthaus.us/
43199	 * @author tschw
43200	 */
43201  
43202	// Characters [].:/ are reserved for track binding syntax.
43203	var RESERVED_CHARS_RE = '\\[\\]\\.:\\/';
43204  
43205	function Composite( targetGroup, path, optionalParsedPath ) {
43206  
43207		var parsedPath = optionalParsedPath || PropertyBinding.parseTrackName( path );
43208  
43209		this._targetGroup = targetGroup;
43210		this._bindings = targetGroup.subscribe_( path, parsedPath );
43211  
43212	}
43213  
43214	Object.assign( Composite.prototype, {
43215  
43216		getValue: function ( array, offset ) {
43217  
43218			this.bind(); // bind all binding
43219  
43220			var firstValidIndex = this._targetGroup.nCachedObjects_,
43221				binding = this._bindings[ firstValidIndex ];
43222  
43223			// and only call .getValue on the first
43224			if ( binding !== undefined ) binding.getValue( array, offset );
43225  
43226		},
43227  
43228		setValue: function ( array, offset ) {
43229  
43230			var bindings = this._bindings;
43231  
43232			for ( var i = this._targetGroup.nCachedObjects_,
43233					  n = bindings.length; i !== n; ++ i ) {
43234  
43235				bindings[ i ].setValue( array, offset );
43236  
43237			}
43238  
43239		},
43240  
43241		bind: function () {
43242  
43243			var bindings = this._bindings;
43244  
43245			for ( var i = this._targetGroup.nCachedObjects_,
43246					  n = bindings.length; i !== n; ++ i ) {
43247  
43248				bindings[ i ].bind();
43249  
43250			}
43251  
43252		},
43253  
43254		unbind: function () {
43255  
43256			var bindings = this._bindings;
43257  
43258			for ( var i = this._targetGroup.nCachedObjects_,
43259					  n = bindings.length; i !== n; ++ i ) {
43260  
43261				bindings[ i ].unbind();
43262  
43263			}
43264  
43265		}
43266  
43267	} );
43268  
43269  
43270	function PropertyBinding( rootNode, path, parsedPath ) {
43271  
43272		this.path = path;
43273		this.parsedPath = parsedPath || PropertyBinding.parseTrackName( path );
43274  
43275		this.node = PropertyBinding.findNode( rootNode, this.parsedPath.nodeName ) || rootNode;
43276  
43277		this.rootNode = rootNode;
43278  
43279	}
43280  
43281	Object.assign( PropertyBinding, {
43282  
43283		Composite: Composite,
43284  
43285		create: function ( root, path, parsedPath ) {
43286  
43287			if ( ! ( root && root.isAnimationObjectGroup ) ) {
43288  
43289				return new PropertyBinding( root, path, parsedPath );
43290  
43291			} else {
43292  
43293				return new PropertyBinding.Composite( root, path, parsedPath );
43294  
43295			}
43296  
43297		},
43298  
43299		/**
43300		 * Replaces spaces with underscores and removes unsupported characters from
43301		 * node names, to ensure compatibility with parseTrackName().
43302		 *
43303		 * @param  {string} name Node name to be sanitized.
43304		 * @return {string}
43305		 */
43306		sanitizeNodeName: ( function () {
43307  
43308			var reservedRe = new RegExp( '[' + RESERVED_CHARS_RE + ']', 'g' );
43309  
43310			return function sanitizeNodeName( name ) {
43311  
43312				return name.replace( /\s/g, '_' ).replace( reservedRe, '' );
43313  
43314			};
43315  
43316		}() ),
43317  
43318		parseTrackName: function () {
43319  
43320			// Attempts to allow node names from any language. ES5's `\w` regexp matches
43321			// only latin characters, and the unicode \p{L} is not yet supported. So
43322			// instead, we exclude reserved characters and match everything else.
43323			var wordChar = '[^' + RESERVED_CHARS_RE + ']';
43324			var wordCharOrDot = '[^' + RESERVED_CHARS_RE.replace( '\\.', '' ) + ']';
43325  
43326			// Parent directories, delimited by '/' or ':'. Currently unused, but must
43327			// be matched to parse the rest of the track name.
43328			var directoryRe = /((?:WC+[\/:])*)/.source.replace( 'WC', wordChar );
43329  
43330			// Target node. May contain word characters (a-zA-Z0-9_) and '.' or '-'.
43331			var nodeRe = /(WCOD+)?/.source.replace( 'WCOD', wordCharOrDot );
43332  
43333			// Object on target node, and accessor. May not contain reserved
43334			// characters. Accessor may contain any character except closing bracket.
43335			var objectRe = /(?:\.(WC+)(?:\[(.+)\])?)?/.source.replace( 'WC', wordChar );
43336  
43337			// Property and accessor. May not contain reserved characters. Accessor may
43338			// contain any non-bracket characters.
43339			var propertyRe = /\.(WC+)(?:\[(.+)\])?/.source.replace( 'WC', wordChar );
43340  
43341			var trackRe = new RegExp( ''
43342				+ '^'
43343				+ directoryRe
43344				+ nodeRe
43345				+ objectRe
43346				+ propertyRe
43347				+ '$'
43348			);
43349  
43350			var supportedObjectNames = [ 'material', 'materials', 'bones' ];
43351  
43352			return function parseTrackName( trackName ) {
43353  
43354				var matches = trackRe.exec( trackName );
43355  
43356				if ( ! matches ) {
43357  
43358					throw new Error( 'PropertyBinding: Cannot parse trackName: ' + trackName );
43359  
43360				}
43361  
43362				var results = {
43363					// directoryName: matches[ 1 ], // (tschw) currently unused
43364					nodeName: matches[ 2 ],
43365					objectName: matches[ 3 ],
43366					objectIndex: matches[ 4 ],
43367					propertyName: matches[ 5 ], // required
43368					propertyIndex: matches[ 6 ]
43369				};
43370  
43371				var lastDot = results.nodeName && results.nodeName.lastIndexOf( '.' );
43372  
43373				if ( lastDot !== undefined && lastDot !== - 1 ) {
43374  
43375					var objectName = results.nodeName.substring( lastDot + 1 );
43376  
43377					// Object names must be checked against a whitelist. Otherwise, there
43378					// is no way to parse 'foo.bar.baz': 'baz' must be a property, but
43379					// 'bar' could be the objectName, or part of a nodeName (which can
43380					// include '.' characters).
43381					if ( supportedObjectNames.indexOf( objectName ) !== - 1 ) {
43382  
43383						results.nodeName = results.nodeName.substring( 0, lastDot );
43384						results.objectName = objectName;
43385  
43386					}
43387  
43388				}
43389  
43390				if ( results.propertyName === null || results.propertyName.length === 0 ) {
43391  
43392					throw new Error( 'PropertyBinding: can not parse propertyName from trackName: ' + trackName );
43393  
43394				}
43395  
43396				return results;
43397  
43398			};
43399  
43400		}(),
43401  
43402		findNode: function ( root, nodeName ) {
43403  
43404			if ( ! nodeName || nodeName === "" || nodeName === "root" || nodeName === "." || nodeName === - 1 || nodeName === root.name || nodeName === root.uuid ) {
43405  
43406				return root;
43407  
43408			}
43409  
43410			// search into skeleton bones.
43411			if ( root.skeleton ) {
43412  
43413				var bone = root.skeleton.getBoneByName( nodeName );
43414  
43415				if ( bone !== undefined ) {
43416  
43417					return bone;
43418  
43419				}
43420  
43421			}
43422  
43423			// search into node subtree.
43424			if ( root.children ) {
43425  
43426				var searchNodeSubtree = function ( children ) {
43427  
43428					for ( var i = 0; i < children.length; i ++ ) {
43429  
43430						var childNode = children[ i ];
43431  
43432						if ( childNode.name === nodeName || childNode.uuid === nodeName ) {
43433  
43434							return childNode;
43435  
43436						}
43437  
43438						var result = searchNodeSubtree( childNode.children );
43439  
43440						if ( result ) return result;
43441  
43442					}
43443  
43444					return null;
43445  
43446				};
43447  
43448				var subTreeNode = searchNodeSubtree( root.children );
43449  
43450				if ( subTreeNode ) {
43451  
43452					return subTreeNode;
43453  
43454				}
43455  
43456			}
43457  
43458			return null;
43459  
43460		}
43461  
43462	} );
43463  
43464	Object.assign( PropertyBinding.prototype, { // prototype, continued
43465  
43466		// these are used to "bind" a nonexistent property
43467		_getValue_unavailable: function () {},
43468		_setValue_unavailable: function () {},
43469  
43470		BindingType: {
43471			Direct: 0,
43472			EntireArray: 1,
43473			ArrayElement: 2,
43474			HasFromToArray: 3
43475		},
43476  
43477		Versioning: {
43478			None: 0,
43479			NeedsUpdate: 1,
43480			MatrixWorldNeedsUpdate: 2
43481		},
43482  
43483		GetterByBindingType: [
43484  
43485			function getValue_direct( buffer, offset ) {
43486  
43487				buffer[ offset ] = this.node[ this.propertyName ];
43488  
43489			},
43490  
43491			function getValue_array( buffer, offset ) {
43492  
43493				var source = this.resolvedProperty;
43494  
43495				for ( var i = 0, n = source.length; i !== n; ++ i ) {
43496  
43497					buffer[ offset ++ ] = source[ i ];
43498  
43499				}
43500  
43501			},
43502  
43503			function getValue_arrayElement( buffer, offset ) {
43504  
43505				buffer[ offset ] = this.resolvedProperty[ this.propertyIndex ];
43506  
43507			},
43508  
43509			function getValue_toArray( buffer, offset ) {
43510  
43511				this.resolvedProperty.toArray( buffer, offset );
43512  
43513			}
43514  
43515		],
43516  
43517		SetterByBindingTypeAndVersioning: [
43518  
43519			[
43520				// Direct
43521  
43522				function setValue_direct( buffer, offset ) {
43523  
43524					this.targetObject[ this.propertyName ] = buffer[ offset ];
43525  
43526				},
43527  
43528				function setValue_direct_setNeedsUpdate( buffer, offset ) {
43529  
43530					this.targetObject[ this.propertyName ] = buffer[ offset ];
43531					this.targetObject.needsUpdate = true;
43532  
43533				},
43534  
43535				function setValue_direct_setMatrixWorldNeedsUpdate( buffer, offset ) {
43536  
43537					this.targetObject[ this.propertyName ] = buffer[ offset ];
43538					this.targetObject.matrixWorldNeedsUpdate = true;
43539  
43540				}
43541  
43542			], [
43543  
43544				// EntireArray
43545  
43546				function setValue_array( buffer, offset ) {
43547  
43548					var dest = this.resolvedProperty;
43549  
43550					for ( var i = 0, n = dest.length; i !== n; ++ i ) {
43551  
43552						dest[ i ] = buffer[ offset ++ ];
43553  
43554					}
43555  
43556				},
43557  
43558				function setValue_array_setNeedsUpdate( buffer, offset ) {
43559  
43560					var dest = this.resolvedProperty;
43561  
43562					for ( var i = 0, n = dest.length; i !== n; ++ i ) {
43563  
43564						dest[ i ] = buffer[ offset ++ ];
43565  
43566					}
43567  
43568					this.targetObject.needsUpdate = true;
43569  
43570				},
43571  
43572				function setValue_array_setMatrixWorldNeedsUpdate( buffer, offset ) {
43573  
43574					var dest = this.resolvedProperty;
43575  
43576					for ( var i = 0, n = dest.length; i !== n; ++ i ) {
43577  
43578						dest[ i ] = buffer[ offset ++ ];
43579  
43580					}
43581  
43582					this.targetObject.matrixWorldNeedsUpdate = true;
43583  
43584				}
43585  
43586			], [
43587  
43588				// ArrayElement
43589  
43590				function setValue_arrayElement( buffer, offset ) {
43591  
43592					this.resolvedProperty[ this.propertyIndex ] = buffer[ offset ];
43593  
43594				},
43595  
43596				function setValue_arrayElement_setNeedsUpdate( buffer, offset ) {
43597  
43598					this.resolvedProperty[ this.propertyIndex ] = buffer[ offset ];
43599					this.targetObject.needsUpdate = true;
43600  
43601				},
43602  
43603				function setValue_arrayElement_setMatrixWorldNeedsUpdate( buffer, offset ) {
43604  
43605					this.resolvedProperty[ this.propertyIndex ] = buffer[ offset ];
43606					this.targetObject.matrixWorldNeedsUpdate = true;
43607  
43608				}
43609  
43610			], [
43611  
43612				// HasToFromArray
43613  
43614				function setValue_fromArray( buffer, offset ) {
43615  
43616					this.resolvedProperty.fromArray( buffer, offset );
43617  
43618				},
43619  
43620				function setValue_fromArray_setNeedsUpdate( buffer, offset ) {
43621  
43622					this.resolvedProperty.fromArray( buffer, offset );
43623					this.targetObject.needsUpdate = true;
43624  
43625				},
43626  
43627				function setValue_fromArray_setMatrixWorldNeedsUpdate( buffer, offset ) {
43628  
43629					this.resolvedProperty.fromArray( buffer, offset );
43630					this.targetObject.matrixWorldNeedsUpdate = true;
43631  
43632				}
43633  
43634			]
43635  
43636		],
43637  
43638		getValue: function getValue_unbound( targetArray, offset ) {
43639  
43640			this.bind();
43641			this.getValue( targetArray, offset );
43642  
43643			// Note: This class uses a State pattern on a per-method basis:
43644			// 'bind' sets 'this.getValue' / 'setValue' and shadows the
43645			// prototype version of these methods with one that represents
43646			// the bound state. When the property is not found, the methods
43647			// become no-ops.
43648  
43649		},
43650  
43651		setValue: function getValue_unbound( sourceArray, offset ) {
43652  
43653			this.bind();
43654			this.setValue( sourceArray, offset );
43655  
43656		},
43657  
43658		// create getter / setter pair for a property in the scene graph
43659		bind: function () {
43660  
43661			var targetObject = this.node,
43662				parsedPath = this.parsedPath,
43663  
43664				objectName = parsedPath.objectName,
43665				propertyName = parsedPath.propertyName,
43666				propertyIndex = parsedPath.propertyIndex;
43667  
43668			if ( ! targetObject ) {
43669  
43670				targetObject = PropertyBinding.findNode( this.rootNode, parsedPath.nodeName ) || this.rootNode;
43671  
43672				this.node = targetObject;
43673  
43674			}
43675  
43676			// set fail state so we can just 'return' on error
43677			this.getValue = this._getValue_unavailable;
43678			this.setValue = this._setValue_unavailable;
43679  
43680			// ensure there is a value node
43681			if ( ! targetObject ) {
43682  
43683				console.error( 'THREE.PropertyBinding: Trying to update node for track: ' + this.path + ' but it wasn\'t found.' );
43684				return;
43685  
43686			}
43687  
43688			if ( objectName ) {
43689  
43690				var objectIndex = parsedPath.objectIndex;
43691  
43692				// special cases were we need to reach deeper into the hierarchy to get the face materials....
43693				switch ( objectName ) {
43694  
43695					case 'materials':
43696  
43697						if ( ! targetObject.material ) {
43698  
43699							console.error( 'THREE.PropertyBinding: Can not bind to material as node does not have a material.', this );
43700							return;
43701  
43702						}
43703  
43704						if ( ! targetObject.material.materials ) {
43705  
43706							console.error( 'THREE.PropertyBinding: Can not bind to material.materials as node.material does not have a materials array.', this );
43707							return;
43708  
43709						}
43710  
43711						targetObject = targetObject.material.materials;
43712  
43713						break;
43714  
43715					case 'bones':
43716  
43717						if ( ! targetObject.skeleton ) {
43718  
43719							console.error( 'THREE.PropertyBinding: Can not bind to bones as node does not have a skeleton.', this );
43720							return;
43721  
43722						}
43723  
43724						// potential future optimization: skip this if propertyIndex is already an integer
43725						// and convert the integer string to a true integer.
43726  
43727						targetObject = targetObject.skeleton.bones;
43728  
43729						// support resolving morphTarget names into indices.
43730						for ( var i = 0; i < targetObject.length; i ++ ) {
43731  
43732							if ( targetObject[ i ].name === objectIndex ) {
43733  
43734								objectIndex = i;
43735								break;
43736  
43737							}
43738  
43739						}
43740  
43741						break;
43742  
43743					default:
43744  
43745						if ( targetObject[ objectName ] === undefined ) {
43746  
43747							console.error( 'THREE.PropertyBinding: Can not bind to objectName of node undefined.', this );
43748							return;
43749  
43750						}
43751  
43752						targetObject = targetObject[ objectName ];
43753  
43754				}
43755  
43756  
43757				if ( objectIndex !== undefined ) {
43758  
43759					if ( targetObject[ objectIndex ] === undefined ) {
43760  
43761						console.error( 'THREE.PropertyBinding: Trying to bind to objectIndex of objectName, but is undefined.', this, targetObject );
43762						return;
43763  
43764					}
43765  
43766					targetObject = targetObject[ objectIndex ];
43767  
43768				}
43769  
43770			}
43771  
43772			// resolve property
43773			var nodeProperty = targetObject[ propertyName ];
43774  
43775			if ( nodeProperty === undefined ) {
43776  
43777				var nodeName = parsedPath.nodeName;
43778  
43779				console.error( 'THREE.PropertyBinding: Trying to update property for track: ' + nodeName +
43780					'.' + propertyName + ' but it wasn\'t found.', targetObject );
43781				return;
43782  
43783			}
43784  
43785			// determine versioning scheme
43786			var versioning = this.Versioning.None;
43787  
43788			if ( targetObject.needsUpdate !== undefined ) { // material
43789  
43790				versioning = this.Versioning.NeedsUpdate;
43791				this.targetObject = targetObject;
43792  
43793			} else if ( targetObject.matrixWorldNeedsUpdate !== undefined ) { // node transform
43794  
43795				versioning = this.Versioning.MatrixWorldNeedsUpdate;
43796				this.targetObject = targetObject;
43797  
43798			}
43799  
43800			// determine how the property gets bound
43801			var bindingType = this.BindingType.Direct;
43802  
43803			if ( propertyIndex !== undefined ) {
43804  
43805				// access a sub element of the property array (only primitives are supported right now)
43806  
43807				if ( propertyName === "morphTargetInfluences" ) {
43808  
43809					// potential optimization, skip this if propertyIndex is already an integer, and convert the integer string to a true integer.
43810  
43811					// support resolving morphTarget names into indices.
43812					if ( ! targetObject.geometry ) {
43813  
43814						console.error( 'THREE.PropertyBinding: Can not bind to morphTargetInfluences because node does not have a geometry.', this );
43815						return;
43816  
43817					}
43818  
43819					if ( targetObject.geometry.isBufferGeometry ) {
43820  
43821						if ( ! targetObject.geometry.morphAttributes ) {
43822  
43823							console.error( 'THREE.PropertyBinding: Can not bind to morphTargetInfluences because node does not have a geometry.morphAttributes.', this );
43824							return;
43825  
43826						}
43827  
43828						for ( var i = 0; i < this.node.geometry.morphAttributes.position.length; i ++ ) {
43829  
43830							if ( targetObject.geometry.morphAttributes.position[ i ].name === propertyIndex ) {
43831  
43832								propertyIndex = i;
43833								break;
43834  
43835							}
43836  
43837						}
43838  
43839  
43840					} else {
43841  
43842						if ( ! targetObject.geometry.morphTargets ) {
43843  
43844							console.error( 'THREE.PropertyBinding: Can not bind to morphTargetInfluences because node does not have a geometry.morphTargets.', this );
43845							return;
43846  
43847						}
43848  
43849						for ( var i = 0; i < this.node.geometry.morphTargets.length; i ++ ) {
43850  
43851							if ( targetObject.geometry.morphTargets[ i ].name === propertyIndex ) {
43852  
43853								propertyIndex = i;
43854								break;
43855  
43856							}
43857  
43858						}
43859  
43860					}
43861  
43862				}
43863  
43864				bindingType = this.BindingType.ArrayElement;
43865  
43866				this.resolvedProperty = nodeProperty;
43867				this.propertyIndex = propertyIndex;
43868  
43869			} else if ( nodeProperty.fromArray !== undefined && nodeProperty.toArray !== undefined ) {
43870  
43871				// must use copy for Object3D.Euler/Quaternion
43872  
43873				bindingType = this.BindingType.HasFromToArray;
43874  
43875				this.resolvedProperty = nodeProperty;
43876  
43877			} else if ( Array.isArray( nodeProperty ) ) {
43878  
43879				bindingType = this.BindingType.EntireArray;
43880  
43881				this.resolvedProperty = nodeProperty;
43882  
43883			} else {
43884  
43885				this.propertyName = propertyName;
43886  
43887			}
43888  
43889			// select getter / setter
43890			this.getValue = this.GetterByBindingType[ bindingType ];
43891			this.setValue = this.SetterByBindingTypeAndVersioning[ bindingType ][ versioning ];
43892  
43893		},
43894  
43895		unbind: function () {
43896  
43897			this.node = null;
43898  
43899			// back to the prototype version of getValue / setValue
43900			// note: avoiding to mutate the shape of 'this' via 'delete'
43901			this.getValue = this._getValue_unbound;
43902			this.setValue = this._setValue_unbound;
43903  
43904		}
43905  
43906	} );
43907  
43908	//!\ DECLARE ALIAS AFTER assign prototype !
43909	Object.assign( PropertyBinding.prototype, {
43910  
43911		// initial state of these methods that calls 'bind'
43912		_getValue_unbound: PropertyBinding.prototype.getValue,
43913		_setValue_unbound: PropertyBinding.prototype.setValue,
43914  
43915	} );
43916  
43917	/**
43918	 *
43919	 * A group of objects that receives a shared animation state.
43920	 *
43921	 * Usage:
43922	 *
43923	 * 	-	Add objects you would otherwise pass as 'root' to the
43924	 * 		constructor or the .clipAction method of AnimationMixer.
43925	 *
43926	 * 	-	Instead pass this object as 'root'.
43927	 *
43928	 * 	-	You can also add and remove objects later when the mixer
43929	 * 		is running.
43930	 *
43931	 * Note:
43932	 *
43933	 *  	Objects of this class appear as one object to the mixer,
43934	 *  	so cache control of the individual objects must be done
43935	 *  	on the group.
43936	 *
43937	 * Limitation:
43938	 *
43939	 * 	- 	The animated properties must be compatible among the
43940	 * 		all objects in the group.
43941	 *
43942	 *  -	A single property can either be controlled through a
43943	 *  	target group or directly, but not both.
43944	 *
43945	 * @author tschw
43946	 */
43947  
43948	function AnimationObjectGroup() {
43949  
43950		this.uuid = _Math.generateUUID();
43951  
43952		// cached objects followed by the active ones
43953		this._objects = Array.prototype.slice.call( arguments );
43954  
43955		this.nCachedObjects_ = 0;			// threshold
43956		// note: read by PropertyBinding.Composite
43957  
43958		var indices = {};
43959		this._indicesByUUID = indices;		// for bookkeeping
43960  
43961		for ( var i = 0, n = arguments.length; i !== n; ++ i ) {
43962  
43963			indices[ arguments[ i ].uuid ] = i;
43964  
43965		}
43966  
43967		this._paths = [];					// inside: string
43968		this._parsedPaths = [];				// inside: { we don't care, here }
43969		this._bindings = []; 				// inside: Array< PropertyBinding >
43970		this._bindingsIndicesByPath = {}; 	// inside: indices in these arrays
43971  
43972		var scope = this;
43973  
43974		this.stats = {
43975  
43976			objects: {
43977				get total() {
43978  
43979					return scope._objects.length;
43980  
43981				},
43982				get inUse() {
43983  
43984					return this.total - scope.nCachedObjects_;
43985  
43986				}
43987			},
43988			get bindingsPerObject() {
43989  
43990				return scope._bindings.length;
43991  
43992			}
43993  
43994		};
43995  
43996	}
43997  
43998	Object.assign( AnimationObjectGroup.prototype, {
43999  
44000		isAnimationObjectGroup: true,
44001  
44002		add: function () {
44003  
44004			var objects = this._objects,
44005				nObjects = objects.length,
44006				nCachedObjects = this.nCachedObjects_,
44007				indicesByUUID = this._indicesByUUID,
44008				paths = this._paths,
44009				parsedPaths = this._parsedPaths,
44010				bindings = this._bindings,
44011				nBindings = bindings.length,
44012				knownObject = undefined;
44013  
44014			for ( var i = 0, n = arguments.length; i !== n; ++ i ) {
44015  
44016				var object = arguments[ i ],
44017					uuid = object.uuid,
44018					index = indicesByUUID[ uuid ];
44019  
44020				if ( index === undefined ) {
44021  
44022					// unknown object -> add it to the ACTIVE region
44023  
44024					index = nObjects ++;
44025					indicesByUUID[ uuid ] = index;
44026					objects.push( object );
44027  
44028					// accounting is done, now do the same for all bindings
44029  
44030					for ( var j = 0, m = nBindings; j !== m; ++ j ) {
44031  
44032						bindings[ j ].push( new PropertyBinding( object, paths[ j ], parsedPaths[ j ] ) );
44033  
44034					}
44035  
44036				} else if ( index < nCachedObjects ) {
44037  
44038					knownObject = objects[ index ];
44039  
44040					// move existing object to the ACTIVE region
44041  
44042					var firstActiveIndex = -- nCachedObjects,
44043						lastCachedObject = objects[ firstActiveIndex ];
44044  
44045					indicesByUUID[ lastCachedObject.uuid ] = index;
44046					objects[ index ] = lastCachedObject;
44047  
44048					indicesByUUID[ uuid ] = firstActiveIndex;
44049					objects[ firstActiveIndex ] = object;
44050  
44051					// accounting is done, now do the same for all bindings
44052  
44053					for ( var j = 0, m = nBindings; j !== m; ++ j ) {
44054  
44055						var bindingsForPath = bindings[ j ],
44056							lastCached = bindingsForPath[ firstActiveIndex ],
44057							binding = bindingsForPath[ index ];
44058  
44059						bindingsForPath[ index ] = lastCached;
44060  
44061						if ( binding === undefined ) {
44062  
44063							// since we do not bother to create new bindings
44064							// for objects that are cached, the binding may
44065							// or may not exist
44066  
44067							binding = new PropertyBinding( object, paths[ j ], parsedPaths[ j ] );
44068  
44069						}
44070  
44071						bindingsForPath[ firstActiveIndex ] = binding;
44072  
44073					}
44074  
44075				} else if ( objects[ index ] !== knownObject ) {
44076  
44077					console.error( 'THREE.AnimationObjectGroup: Different objects with the same UUID ' +
44078							'detected. Clean the caches or recreate your infrastructure when reloading scenes.' );
44079  
44080				} // else the object is already where we want it to be
44081  
44082			} // for arguments
44083  
44084			this.nCachedObjects_ = nCachedObjects;
44085  
44086		},
44087  
44088		remove: function () {
44089  
44090			var objects = this._objects,
44091				nCachedObjects = this.nCachedObjects_,
44092				indicesByUUID = this._indicesByUUID,
44093				bindings = this._bindings,
44094				nBindings = bindings.length;
44095  
44096			for ( var i = 0, n = arguments.length; i !== n; ++ i ) {
44097  
44098				var object = arguments[ i ],
44099					uuid = object.uuid,
44100					index = indicesByUUID[ uuid ];
44101  
44102				if ( index !== undefined && index >= nCachedObjects ) {
44103  
44104					// move existing object into the CACHED region
44105  
44106					var lastCachedIndex = nCachedObjects ++,
44107						firstActiveObject = objects[ lastCachedIndex ];
44108  
44109					indicesByUUID[ firstActiveObject.uuid ] = index;
44110					objects[ index ] = firstActiveObject;
44111  
44112					indicesByUUID[ uuid ] = lastCachedIndex;
44113					objects[ lastCachedIndex ] = object;
44114  
44115					// accounting is done, now do the same for all bindings
44116  
44117					for ( var j = 0, m = nBindings; j !== m; ++ j ) {
44118  
44119						var bindingsForPath = bindings[ j ],
44120							firstActive = bindingsForPath[ lastCachedIndex ],
44121							binding = bindingsForPath[ index ];
44122  
44123						bindingsForPath[ index ] = firstActive;
44124						bindingsForPath[ lastCachedIndex ] = binding;
44125  
44126					}
44127  
44128				}
44129  
44130			} // for arguments
44131  
44132			this.nCachedObjects_ = nCachedObjects;
44133  
44134		},
44135  
44136		// remove & forget
44137		uncache: function () {
44138  
44139			var objects = this._objects,
44140				nObjects = objects.length,
44141				nCachedObjects = this.nCachedObjects_,
44142				indicesByUUID = this._indicesByUUID,
44143				bindings = this._bindings,
44144				nBindings = bindings.length;
44145  
44146			for ( var i = 0, n = arguments.length; i !== n; ++ i ) {
44147  
44148				var object = arguments[ i ],
44149					uuid = object.uuid,
44150					index = indicesByUUID[ uuid ];
44151  
44152				if ( index !== undefined ) {
44153  
44154					delete indicesByUUID[ uuid ];
44155  
44156					if ( index < nCachedObjects ) {
44157  
44158						// object is cached, shrink the CACHED region
44159  
44160						var firstActiveIndex = -- nCachedObjects,
44161							lastCachedObject = objects[ firstActiveIndex ],
44162							lastIndex = -- nObjects,
44163							lastObject = objects[ lastIndex ];
44164  
44165						// last cached object takes this object's place
44166						indicesByUUID[ lastCachedObject.uuid ] = index;
44167						objects[ index ] = lastCachedObject;
44168  
44169						// last object goes to the activated slot and pop
44170						indicesByUUID[ lastObject.uuid ] = firstActiveIndex;
44171						objects[ firstActiveIndex ] = lastObject;
44172						objects.pop();
44173  
44174						// accounting is done, now do the same for all bindings
44175  
44176						for ( var j = 0, m = nBindings; j !== m; ++ j ) {
44177  
44178							var bindingsForPath = bindings[ j ],
44179								lastCached = bindingsForPath[ firstActiveIndex ],
44180								last = bindingsForPath[ lastIndex ];
44181  
44182							bindingsForPath[ index ] = lastCached;
44183							bindingsForPath[ firstActiveIndex ] = last;
44184							bindingsForPath.pop();
44185  
44186						}
44187  
44188					} else {
44189  
44190						// object is active, just swap with the last and pop
44191  
44192						var lastIndex = -- nObjects,
44193							lastObject = objects[ lastIndex ];
44194  
44195						indicesByUUID[ lastObject.uuid ] = index;
44196						objects[ index ] = lastObject;
44197						objects.pop();
44198  
44199						// accounting is done, now do the same for all bindings
44200  
44201						for ( var j = 0, m = nBindings; j !== m; ++ j ) {
44202  
44203							var bindingsForPath = bindings[ j ];
44204  
44205							bindingsForPath[ index ] = bindingsForPath[ lastIndex ];
44206							bindingsForPath.pop();
44207  
44208						}
44209  
44210					} // cached or active
44211  
44212				} // if object is known
44213  
44214			} // for arguments
44215  
44216			this.nCachedObjects_ = nCachedObjects;
44217  
44218		},
44219  
44220		// Internal interface used by befriended PropertyBinding.Composite:
44221  
44222		subscribe_: function ( path, parsedPath ) {
44223  
44224			// returns an array of bindings for the given path that is changed
44225			// according to the contained objects in the group
44226  
44227			var indicesByPath = this._bindingsIndicesByPath,
44228				index = indicesByPath[ path ],
44229				bindings = this._bindings;
44230  
44231			if ( index !== undefined ) return bindings[ index ];
44232  
44233			var paths = this._paths,
44234				parsedPaths = this._parsedPaths,
44235				objects = this._objects,
44236				nObjects = objects.length,
44237				nCachedObjects = this.nCachedObjects_,
44238				bindingsForPath = new Array( nObjects );
44239  
44240			index = bindings.length;
44241  
44242			indicesByPath[ path ] = index;
44243  
44244			paths.push( path );
44245			parsedPaths.push( parsedPath );
44246			bindings.push( bindingsForPath );
44247  
44248			for ( var i = nCachedObjects, n = objects.length; i !== n; ++ i ) {
44249  
44250				var object = objects[ i ];
44251				bindingsForPath[ i ] = new PropertyBinding( object, path, parsedPath );
44252  
44253			}
44254  
44255			return bindingsForPath;
44256  
44257		},
44258  
44259		unsubscribe_: function ( path ) {
44260  
44261			// tells the group to forget about a property path and no longer
44262			// update the array previously obtained with 'subscribe_'
44263  
44264			var indicesByPath = this._bindingsIndicesByPath,
44265				index = indicesByPath[ path ];
44266  
44267			if ( index !== undefined ) {
44268  
44269				var paths = this._paths,
44270					parsedPaths = this._parsedPaths,
44271					bindings = this._bindings,
44272					lastBindingsIndex = bindings.length - 1,
44273					lastBindings = bindings[ lastBindingsIndex ],
44274					lastBindingsPath = path[ lastBindingsIndex ];
44275  
44276				indicesByPath[ lastBindingsPath ] = index;
44277  
44278				bindings[ index ] = lastBindings;
44279				bindings.pop();
44280  
44281				parsedPaths[ index ] = parsedPaths[ lastBindingsIndex ];
44282				parsedPaths.pop();
44283  
44284				paths[ index ] = paths[ lastBindingsIndex ];
44285				paths.pop();
44286  
44287			}
44288  
44289		}
44290  
44291	} );
44292  
44293	/**
44294	 *
44295	 * Action provided by AnimationMixer for scheduling clip playback on specific
44296	 * objects.
44297	 *
44298	 * @author Ben Houston / http://clara.io/
44299	 * @author David Sarno / http://lighthaus.us/
44300	 * @author tschw
44301	 *
44302	 */
44303  
44304	function AnimationAction( mixer, clip, localRoot ) {
44305  
44306		this._mixer = mixer;
44307		this._clip = clip;
44308		this._localRoot = localRoot || null;
44309  
44310		var tracks = clip.tracks,
44311			nTracks = tracks.length,
44312			interpolants = new Array( nTracks );
44313  
44314		var interpolantSettings = {
44315			endingStart: ZeroCurvatureEnding,
44316			endingEnd: ZeroCurvatureEnding
44317		};
44318  
44319		for ( var i = 0; i !== nTracks; ++ i ) {
44320  
44321			var interpolant = tracks[ i ].createInterpolant( null );
44322			interpolants[ i ] = interpolant;
44323			interpolant.settings = interpolantSettings;
44324  
44325		}
44326  
44327		this._interpolantSettings = interpolantSettings;
44328  
44329		this._interpolants = interpolants;	// bound by the mixer
44330  
44331		// inside: PropertyMixer (managed by the mixer)
44332		this._propertyBindings = new Array( nTracks );
44333  
44334		this._cacheIndex = null;			// for the memory manager
44335		this._byClipCacheIndex = null;		// for the memory manager
44336  
44337		this._timeScaleInterpolant = null;
44338		this._weightInterpolant = null;
44339  
44340		this.loop = LoopRepeat;
44341		this._loopCount = - 1;
44342  
44343		// global mixer time when the action is to be started
44344		// it's set back to 'null' upon start of the action
44345		this._startTime = null;
44346  
44347		// scaled local time of the action
44348		// gets clamped or wrapped to 0..clip.duration according to loop
44349		this.time = 0;
44350  
44351		this.timeScale = 1;
44352		this._effectiveTimeScale = 1;
44353  
44354		this.weight = 1;
44355		this._effectiveWeight = 1;
44356  
44357		this.repetitions = Infinity; 		// no. of repetitions when looping
44358  
44359		this.paused = false;				// true -> zero effective time scale
44360		this.enabled = true;				// false -> zero effective weight
44361  
44362		this.clampWhenFinished 	= false;	// keep feeding the last frame?
44363  
44364		this.zeroSlopeAtStart 	= true;		// for smooth interpolation w/o separate
44365		this.zeroSlopeAtEnd		= true;		// clips for start, loop and end
44366  
44367	}
44368  
44369	Object.assign( AnimationAction.prototype, {
44370  
44371		// State & Scheduling
44372  
44373		play: function () {
44374  
44375			this._mixer._activateAction( this );
44376  
44377			return this;
44378  
44379		},
44380  
44381		stop: function () {
44382  
44383			this._mixer._deactivateAction( this );
44384  
44385			return this.reset();
44386  
44387		},
44388  
44389		reset: function () {
44390  
44391			this.paused = false;
44392			this.enabled = true;
44393  
44394			this.time = 0;			// restart clip
44395			this._loopCount = - 1;	// forget previous loops
44396			this._startTime = null;	// forget scheduling
44397  
44398			return this.stopFading().stopWarping();
44399  
44400		},
44401  
44402		isRunning: function () {
44403  
44404			return this.enabled && ! this.paused && this.timeScale !== 0 &&
44405					this._startTime === null && this._mixer._isActiveAction( this );
44406  
44407		},
44408  
44409		// return true when play has been called
44410		isScheduled: function () {
44411  
44412			return this._mixer._isActiveAction( this );
44413  
44414		},
44415  
44416		startAt: function ( time ) {
44417  
44418			this._startTime = time;
44419  
44420			return this;
44421  
44422		},
44423  
44424		setLoop: function ( mode, repetitions ) {
44425  
44426			this.loop = mode;
44427			this.repetitions = repetitions;
44428  
44429			return this;
44430  
44431		},
44432  
44433		// Weight
44434  
44435		// set the weight stopping any scheduled fading
44436		// although .enabled = false yields an effective weight of zero, this
44437		// method does *not* change .enabled, because it would be confusing
44438		setEffectiveWeight: function ( weight ) {
44439  
44440			this.weight = weight;
44441  
44442			// note: same logic as when updated at runtime
44443			this._effectiveWeight = this.enabled ? weight : 0;
44444  
44445			return this.stopFading();
44446  
44447		},
44448  
44449		// return the weight considering fading and .enabled
44450		getEffectiveWeight: function () {
44451  
44452			return this._effectiveWeight;
44453  
44454		},
44455  
44456		fadeIn: function ( duration ) {
44457  
44458			return this._scheduleFading( duration, 0, 1 );
44459  
44460		},
44461  
44462		fadeOut: function ( duration ) {
44463  
44464			return this._scheduleFading( duration, 1, 0 );
44465  
44466		},
44467  
44468		crossFadeFrom: function ( fadeOutAction, duration, warp ) {
44469  
44470			fadeOutAction.fadeOut( duration );
44471			this.fadeIn( duration );
44472  
44473			if ( warp ) {
44474  
44475				var fadeInDuration = this._clip.duration,
44476					fadeOutDuration = fadeOutAction._clip.duration,
44477  
44478					startEndRatio = fadeOutDuration / fadeInDuration,
44479					endStartRatio = fadeInDuration / fadeOutDuration;
44480  
44481				fadeOutAction.warp( 1.0, startEndRatio, duration );
44482				this.warp( endStartRatio, 1.0, duration );
44483  
44484			}
44485  
44486			return this;
44487  
44488		},
44489  
44490		crossFadeTo: function ( fadeInAction, duration, warp ) {
44491  
44492			return fadeInAction.crossFadeFrom( this, duration, warp );
44493  
44494		},
44495  
44496		stopFading: function () {
44497  
44498			var weightInterpolant = this._weightInterpolant;
44499  
44500			if ( weightInterpolant !== null ) {
44501  
44502				this._weightInterpolant = null;
44503				this._mixer._takeBackControlInterpolant( weightInterpolant );
44504  
44505			}
44506  
44507			return this;
44508  
44509		},
44510  
44511		// Time Scale Control
44512  
44513		// set the time scale stopping any scheduled warping
44514		// although .paused = true yields an effective time scale of zero, this
44515		// method does *not* change .paused, because it would be confusing
44516		setEffectiveTimeScale: function ( timeScale ) {
44517  
44518			this.timeScale = timeScale;
44519			this._effectiveTimeScale = this.paused ? 0 : timeScale;
44520  
44521			return this.stopWarping();
44522  
44523		},
44524  
44525		// return the time scale considering warping and .paused
44526		getEffectiveTimeScale: function () {
44527  
44528			return this._effectiveTimeScale;
44529  
44530		},
44531  
44532		setDuration: function ( duration ) {
44533  
44534			this.timeScale = this._clip.duration / duration;
44535  
44536			return this.stopWarping();
44537  
44538		},
44539  
44540		syncWith: function ( action ) {
44541  
44542			this.time = action.time;
44543			this.timeScale = action.timeScale;
44544  
44545			return this.stopWarping();
44546  
44547		},
44548  
44549		halt: function ( duration ) {
44550  
44551			return this.warp( this._effectiveTimeScale, 0, duration );
44552  
44553		},
44554  
44555		warp: function ( startTimeScale, endTimeScale, duration ) {
44556  
44557			var mixer = this._mixer, now = mixer.time,
44558				interpolant = this._timeScaleInterpolant,
44559  
44560				timeScale = this.timeScale;
44561  
44562			if ( interpolant === null ) {
44563  
44564				interpolant = mixer._lendControlInterpolant();
44565				this._timeScaleInterpolant = interpolant;
44566  
44567			}
44568  
44569			var times = interpolant.parameterPositions,
44570				values = interpolant.sampleValues;
44571  
44572			times[ 0 ] = now;
44573			times[ 1 ] = now + duration;
44574  
44575			values[ 0 ] = startTimeScale / timeScale;
44576			values[ 1 ] = endTimeScale / timeScale;
44577  
44578			return this;
44579  
44580		},
44581  
vendor: 4,213 bytes, lines 44582-44817
44582		stopWarping: function () {
44583  
44584			var timeScaleInterpolant = this._timeScaleInterpolant;
44585  
44586			if ( timeScaleInterpolant !== null ) {
44587  
44588				this._timeScaleInterpolant = null;
44589				this._mixer._takeBackControlInterpolant( timeScaleInterpolant );
44590  
44591			}
44592  
44593			return this;
44594  
44595		},
44596  
44597		// Object Accessors
44598  
44599		getMixer: function () {
44600  
44601			return this._mixer;
44602  
44603		},
44604  
44605		getClip: function () {
44606  
44607			return this._clip;
44608  
44609		},
44610  
44611		getRoot: function () {
44612  
44613			return this._localRoot || this._mixer._root;
44614  
44615		},
44616  
44617		// Interna
44618  
44619		_update: function ( time, deltaTime, timeDirection, accuIndex ) {
44620  
44621			// called by the mixer
44622  
44623			if ( ! this.enabled ) {
44624  
44625				// call ._updateWeight() to update ._effectiveWeight
44626  
44627				this._updateWeight( time );
44628				return;
44629  
44630			}
44631  
44632			var startTime = this._startTime;
44633  
44634			if ( startTime !== null ) {
44635  
44636				// check for scheduled start of action
44637  
44638				var timeRunning = ( time - startTime ) * timeDirection;
44639				if ( timeRunning < 0 || timeDirection === 0 ) {
44640  
44641					return; // yet to come / don't decide when delta = 0
44642  
44643				}
44644  
44645				// start
44646  
44647				this._startTime = null; // unschedule
44648				deltaTime = timeDirection * timeRunning;
44649  
44650			}
44651  
44652			// apply time scale and advance time
44653  
44654			deltaTime *= this._updateTimeScale( time );
44655			var clipTime = this._updateTime( deltaTime );
44656  
44657			// note: _updateTime may disable the action resulting in
44658			// an effective weight of 0
44659  
44660			var weight = this._updateWeight( time );
44661  
44662			if ( weight > 0 ) {
44663  
44664				var interpolants = this._interpolants;
44665				var propertyMixers = this._propertyBindings;
44666  
44667				for ( var j = 0, m = interpolants.length; j !== m; ++ j ) {
44668  
44669					interpolants[ j ].evaluate( clipTime );
44670					propertyMixers[ j ].accumulate( accuIndex, weight );
44671  
44672				}
44673  
44674			}
44675  
44676		},
44677  
44678		_updateWeight: function ( time ) {
44679  
44680			var weight = 0;
44681  
44682			if ( this.enabled ) {
44683  
44684				weight = this.weight;
44685				var interpolant = this._weightInterpolant;
44686  
44687				if ( interpolant !== null ) {
44688  
44689					var interpolantValue = interpolant.evaluate( time )[ 0 ];
44690  
44691					weight *= interpolantValue;
44692  
44693					if ( time > interpolant.parameterPositions[ 1 ] ) {
44694  
44695						this.stopFading();
44696  
44697						if ( interpolantValue === 0 ) {
44698  
44699							// faded out, disable
44700							this.enabled = false;
44701  
44702						}
44703  
44704					}
44705  
44706				}
44707  
44708			}
44709  
44710			this._effectiveWeight = weight;
44711			return weight;
44712  
44713		},
44714  
44715		_updateTimeScale: function ( time ) {
44716  
44717			var timeScale = 0;
44718  
44719			if ( ! this.paused ) {
44720  
44721				timeScale = this.timeScale;
44722  
44723				var interpolant = this._timeScaleInterpolant;
44724  
44725				if ( interpolant !== null ) {
44726  
44727					var interpolantValue = interpolant.evaluate( time )[ 0 ];
44728  
44729					timeScale *= interpolantValue;
44730  
44731					if ( time > interpolant.parameterPositions[ 1 ] ) {
44732  
44733						this.stopWarping();
44734  
44735						if ( timeScale === 0 ) {
44736  
44737							// motion has halted, pause
44738							this.paused = true;
44739  
44740						} else {
44741  
44742							// warp done - apply final time scale
44743							this.timeScale = timeScale;
44744  
44745						}
44746  
44747					}
44748  
44749				}
44750  
44751			}
44752  
44753			this._effectiveTimeScale = timeScale;
44754			return timeScale;
44755  
44756		},
44757  
44758		_updateTime: function ( deltaTime ) {
44759  
44760			var time = this.time + deltaTime;
44761  
44762			if ( deltaTime === 0 ) return time;
44763  
44764			var duration = this._clip.duration,
44765  
44766				loop = this.loop,
44767				loopCount = this._loopCount;
44768  
44769			if ( loop === LoopOnce ) {
44770  
44771				if ( loopCount === - 1 ) {
44772  
44773					// just started
44774  
44775					this._loopCount = 0;
44776					this._setEndings( true, true, false );
44777  
44778				}
44779  
44780				handle_stop: {
44781  
44782					if ( time >= duration ) {
44783  
44784						time = duration;
44785  
44786					} else if ( time < 0 ) {
44787  
44788						time = 0;
44789  
44790					} else break handle_stop;
44791  
44792					if ( this.clampWhenFinished ) this.paused = true;
44793					else this.enabled = false;
44794  
44795					this._mixer.dispatchEvent( {
44796						type: 'finished', action: this,
44797						direction: deltaTime < 0 ? - 1 : 1
44798					} );
44799  
44800				}
44801  
44802			} else { // repetitive Repeat or PingPong
44803  
44804				var pingPong = ( loop === LoopPingPong );
44805  
44806				if ( loopCount === - 1 ) {
44807  
44808					// just started
44809  
44810					if ( deltaTime >= 0 ) {
44811  
44812						loopCount = 0;
44813  
44814						this._setEndings( true, this.repetitions === 0, pingPong );
44815  
44816					} else {
44817  
vendor: 8,768 bytes, lines 44818-45246
44818						// when looping in reverse direction, the initial
44819						// transition through zero counts as a repetition,
44820						// so leave loopCount at -1
44821  
44822						this._setEndings( this.repetitions === 0, true, pingPong );
44823  
44824					}
44825  
44826				}
44827  
44828				if ( time >= duration || time < 0 ) {
44829  
44830					// wrap around
44831  
44832					var loopDelta = Math.floor( time / duration ); // signed
44833					time -= duration * loopDelta;
44834  
44835					loopCount += Math.abs( loopDelta );
44836  
44837					var pending = this.repetitions - loopCount;
44838  
44839					if ( pending <= 0 ) {
44840  
44841						// have to stop (switch state, clamp time, fire event)
44842  
44843						if ( this.clampWhenFinished ) this.paused = true;
44844						else this.enabled = false;
44845  
44846						time = deltaTime > 0 ? duration : 0;
44847  
44848						this._mixer.dispatchEvent( {
44849							type: 'finished', action: this,
44850							direction: deltaTime > 0 ? 1 : - 1
44851						} );
44852  
44853					} else {
44854  
44855						// keep running
44856  
44857						if ( pending === 1 ) {
44858  
44859							// entering the last round
44860  
44861							var atStart = deltaTime < 0;
44862							this._setEndings( atStart, ! atStart, pingPong );
44863  
44864						} else {
44865  
44866							this._setEndings( false, false, pingPong );
44867  
44868						}
44869  
44870						this._loopCount = loopCount;
44871  
44872						this._mixer.dispatchEvent( {
44873							type: 'loop', action: this, loopDelta: loopDelta
44874						} );
44875  
44876					}
44877  
44878				}
44879  
44880				if ( pingPong && ( loopCount & 1 ) === 1 ) {
44881  
44882					// invert time for the "pong round"
44883  
44884					this.time = time;
44885					return duration - time;
44886  
44887				}
44888  
44889			}
44890  
44891			this.time = time;
44892			return time;
44893  
44894		},
44895  
44896		_setEndings: function ( atStart, atEnd, pingPong ) {
44897  
44898			var settings = this._interpolantSettings;
44899  
44900			if ( pingPong ) {
44901  
44902				settings.endingStart 	= ZeroSlopeEnding;
44903				settings.endingEnd		= ZeroSlopeEnding;
44904  
44905			} else {
44906  
44907				// assuming for LoopOnce atStart == atEnd == true
44908  
44909				if ( atStart ) {
44910  
44911					settings.endingStart = this.zeroSlopeAtStart ? ZeroSlopeEnding : ZeroCurvatureEnding;
44912  
44913				} else {
44914  
44915					settings.endingStart = WrapAroundEnding;
44916  
44917				}
44918  
44919				if ( atEnd ) {
44920  
44921					settings.endingEnd = this.zeroSlopeAtEnd ? ZeroSlopeEnding : ZeroCurvatureEnding;
44922  
44923				} else {
44924  
44925					settings.endingEnd 	 = WrapAroundEnding;
44926  
44927				}
44928  
44929			}
44930  
44931		},
44932  
44933		_scheduleFading: function ( duration, weightNow, weightThen ) {
44934  
44935			var mixer = this._mixer, now = mixer.time,
44936				interpolant = this._weightInterpolant;
44937  
44938			if ( interpolant === null ) {
44939  
44940				interpolant = mixer._lendControlInterpolant();
44941				this._weightInterpolant = interpolant;
44942  
44943			}
44944  
44945			var times = interpolant.parameterPositions,
44946				values = interpolant.sampleValues;
44947  
44948			times[ 0 ] = now; 				values[ 0 ] = weightNow;
44949			times[ 1 ] = now + duration;	values[ 1 ] = weightThen;
44950  
44951			return this;
44952  
44953		}
44954  
44955	} );
44956  
44957	/**
44958	 *
44959	 * Player for AnimationClips.
44960	 *
44961	 *
44962	 * @author Ben Houston / http://clara.io/
44963	 * @author David Sarno / http://lighthaus.us/
44964	 * @author tschw
44965	 */
44966  
44967	function AnimationMixer( root ) {
44968  
44969		this._root = root;
44970		this._initMemoryManager();
44971		this._accuIndex = 0;
44972  
44973		this.time = 0;
44974  
44975		this.timeScale = 1.0;
44976  
44977	}
44978  
44979	AnimationMixer.prototype = Object.assign( Object.create( EventDispatcher.prototype ), {
44980  
44981		constructor: AnimationMixer,
44982  
44983		_bindAction: function ( action, prototypeAction ) {
44984  
44985			var root = action._localRoot || this._root,
44986				tracks = action._clip.tracks,
44987				nTracks = tracks.length,
44988				bindings = action._propertyBindings,
44989				interpolants = action._interpolants,
44990				rootUuid = root.uuid,
44991				bindingsByRoot = this._bindingsByRootAndName,
44992				bindingsByName = bindingsByRoot[ rootUuid ];
44993  
44994			if ( bindingsByName === undefined ) {
44995  
44996				bindingsByName = {};
44997				bindingsByRoot[ rootUuid ] = bindingsByName;
44998  
44999			}
45000  
45001			for ( var i = 0; i !== nTracks; ++ i ) {
45002  
45003				var track = tracks[ i ],
45004					trackName = track.name,
45005					binding = bindingsByName[ trackName ];
45006  
45007				if ( binding !== undefined ) {
45008  
45009					bindings[ i ] = binding;
45010  
45011				} else {
45012  
45013					binding = bindings[ i ];
45014  
45015					if ( binding !== undefined ) {
45016  
45017						// existing binding, make sure the cache knows
45018  
45019						if ( binding._cacheIndex === null ) {
45020  
45021							++ binding.referenceCount;
45022							this._addInactiveBinding( binding, rootUuid, trackName );
45023  
45024						}
45025  
45026						continue;
45027  
45028					}
45029  
45030					var path = prototypeAction && prototypeAction.
45031						_propertyBindings[ i ].binding.parsedPath;
45032  
45033					binding = new PropertyMixer(
45034						PropertyBinding.create( root, trackName, path ),
45035						track.ValueTypeName, track.getValueSize() );
45036  
45037					++ binding.referenceCount;
45038					this._addInactiveBinding( binding, rootUuid, trackName );
45039  
45040					bindings[ i ] = binding;
45041  
45042				}
45043  
45044				interpolants[ i ].resultBuffer = binding.buffer;
45045  
45046			}
45047  
45048		},
45049  
45050		_activateAction: function ( action ) {
45051  
45052			if ( ! this._isActiveAction( action ) ) {
45053  
45054				if ( action._cacheIndex === null ) {
45055  
45056					// this action has been forgotten by the cache, but the user
45057					// appears to be still using it -> rebind
45058  
45059					var rootUuid = ( action._localRoot || this._root ).uuid,
45060						clipUuid = action._clip.uuid,
45061						actionsForClip = this._actionsByClip[ clipUuid ];
45062  
45063					this._bindAction( action,
45064						actionsForClip && actionsForClip.knownActions[ 0 ] );
45065  
45066					this._addInactiveAction( action, clipUuid, rootUuid );
45067  
45068				}
45069  
45070				var bindings = action._propertyBindings;
45071  
45072				// increment reference counts / sort out state
45073				for ( var i = 0, n = bindings.length; i !== n; ++ i ) {
45074  
45075					var binding = bindings[ i ];
45076  
45077					if ( binding.useCount ++ === 0 ) {
45078  
45079						this._lendBinding( binding );
45080						binding.saveOriginalState();
45081  
45082					}
45083  
45084				}
45085  
45086				this._lendAction( action );
45087  
45088			}
45089  
45090		},
45091  
45092		_deactivateAction: function ( action ) {
45093  
45094			if ( this._isActiveAction( action ) ) {
45095  
45096				var bindings = action._propertyBindings;
45097  
45098				// decrement reference counts / sort out state
45099				for ( var i = 0, n = bindings.length; i !== n; ++ i ) {
45100  
45101					var binding = bindings[ i ];
45102  
45103					if ( -- binding.useCount === 0 ) {
45104  
45105						binding.restoreOriginalState();
45106						this._takeBackBinding( binding );
45107  
45108					}
45109  
45110				}
45111  
45112				this._takeBackAction( action );
45113  
45114			}
45115  
45116		},
45117  
45118		// Memory manager
45119  
45120		_initMemoryManager: function () {
45121  
45122			this._actions = []; // 'nActiveActions' followed by inactive ones
45123			this._nActiveActions = 0;
45124  
45125			this._actionsByClip = {};
45126			// inside:
45127			// {
45128			// 		knownActions: Array< AnimationAction >	- used as prototypes
45129			// 		actionByRoot: AnimationAction			- lookup
45130			// }
45131  
45132  
45133			this._bindings = []; // 'nActiveBindings' followed by inactive ones
45134			this._nActiveBindings = 0;
45135  
45136			this._bindingsByRootAndName = {}; // inside: Map< name, PropertyMixer >
45137  
45138  
45139			this._controlInterpolants = []; // same game as above
45140			this._nActiveControlInterpolants = 0;
45141  
45142			var scope = this;
45143  
45144			this.stats = {
45145  
45146				actions: {
45147					get total() {
45148  
45149						return scope._actions.length;
45150  
45151					},
45152					get inUse() {
45153  
45154						return scope._nActiveActions;
45155  
45156					}
45157				},
45158				bindings: {
45159					get total() {
45160  
45161						return scope._bindings.length;
45162  
45163					},
45164					get inUse() {
45165  
45166						return scope._nActiveBindings;
45167  
45168					}
45169				},
45170				controlInterpolants: {
45171					get total() {
45172  
45173						return scope._controlInterpolants.length;
45174  
45175					},
45176					get inUse() {
45177  
45178						return scope._nActiveControlInterpolants;
45179  
45180					}
45181				}
45182  
45183			};
45184  
45185		},
45186  
45187		// Memory management for AnimationAction objects
45188  
45189		_isActiveAction: function ( action ) {
45190  
45191			var index = action._cacheIndex;
45192			return index !== null && index < this._nActiveActions;
45193  
45194		},
45195  
45196		_addInactiveAction: function ( action, clipUuid, rootUuid ) {
45197  
45198			var actions = this._actions,
45199				actionsByClip = this._actionsByClip,
45200				actionsForClip = actionsByClip[ clipUuid ];
45201  
45202			if ( actionsForClip === undefined ) {
45203  
45204				actionsForClip = {
45205  
45206					knownActions: [ action ],
45207					actionByRoot: {}
45208  
45209				};
45210  
45211				action._byClipCacheIndex = 0;
45212  
45213				actionsByClip[ clipUuid ] = actionsForClip;
45214  
45215			} else {
45216  
45217				var knownActions = actionsForClip.knownActions;
45218  
45219				action._byClipCacheIndex = knownActions.length;
45220				knownActions.push( action );
45221  
45222			}
45223  
45224			action._cacheIndex = actions.length;
45225			actions.push( action );
45226  
45227			actionsForClip.actionByRoot[ rootUuid ] = action;
45228  
45229		},
45230  
45231		_removeInactiveAction: function ( action ) {
45232  
45233			var actions = this._actions,
45234				lastInactiveAction = actions[ actions.length - 1 ],
45235				cacheIndex = action._cacheIndex;
45236  
45237			lastInactiveAction._cacheIndex = cacheIndex;
45238			actions[ cacheIndex ] = lastInactiveAction;
45239			actions.pop();
45240  
45241			action._cacheIndex = null;
45242  
45243  
45244			var clipUuid = action._clip.uuid,
45245				actionsByClip = this._actionsByClip,
45246				actionsForClip = actionsByClip[ clipUuid ],
vendor: 4,311 bytes, lines 45247-45423
45247				knownActionsForClip = actionsForClip.knownActions,
45248  
45249				lastKnownAction =
45250					knownActionsForClip[ knownActionsForClip.length - 1 ],
45251  
45252				byClipCacheIndex = action._byClipCacheIndex;
45253  
45254			lastKnownAction._byClipCacheIndex = byClipCacheIndex;
45255			knownActionsForClip[ byClipCacheIndex ] = lastKnownAction;
45256			knownActionsForClip.pop();
45257  
45258			action._byClipCacheIndex = null;
45259  
45260  
45261			var actionByRoot = actionsForClip.actionByRoot,
45262				rootUuid = ( action._localRoot || this._root ).uuid;
45263  
45264			delete actionByRoot[ rootUuid ];
45265  
45266			if ( knownActionsForClip.length === 0 ) {
45267  
45268				delete actionsByClip[ clipUuid ];
45269  
45270			}
45271  
45272			this._removeInactiveBindingsForAction( action );
45273  
45274		},
45275  
45276		_removeInactiveBindingsForAction: function ( action ) {
45277  
45278			var bindings = action._propertyBindings;
45279			for ( var i = 0, n = bindings.length; i !== n; ++ i ) {
45280  
45281				var binding = bindings[ i ];
45282  
45283				if ( -- binding.referenceCount === 0 ) {
45284  
45285					this._removeInactiveBinding( binding );
45286  
45287				}
45288  
45289			}
45290  
45291		},
45292  
45293		_lendAction: function ( action ) {
45294  
45295			// [ active actions |  inactive actions  ]
45296			// [  active actions >| inactive actions ]
45297			//                 s        a
45298			//                  <-swap->
45299			//                 a        s
45300  
45301			var actions = this._actions,
45302				prevIndex = action._cacheIndex,
45303  
45304				lastActiveIndex = this._nActiveActions ++,
45305  
45306				firstInactiveAction = actions[ lastActiveIndex ];
45307  
45308			action._cacheIndex = lastActiveIndex;
45309			actions[ lastActiveIndex ] = action;
45310  
45311			firstInactiveAction._cacheIndex = prevIndex;
45312			actions[ prevIndex ] = firstInactiveAction;
45313  
45314		},
45315  
45316		_takeBackAction: function ( action ) {
45317  
45318			// [  active actions  | inactive actions ]
45319			// [ active actions |< inactive actions  ]
45320			//        a        s
45321			//         <-swap->
45322			//        s        a
45323  
45324			var actions = this._actions,
45325				prevIndex = action._cacheIndex,
45326  
45327				firstInactiveIndex = -- this._nActiveActions,
45328  
45329				lastActiveAction = actions[ firstInactiveIndex ];
45330  
45331			action._cacheIndex = firstInactiveIndex;
45332			actions[ firstInactiveIndex ] = action;
45333  
45334			lastActiveAction._cacheIndex = prevIndex;
45335			actions[ prevIndex ] = lastActiveAction;
45336  
45337		},
45338  
45339		// Memory management for PropertyMixer objects
45340  
45341		_addInactiveBinding: function ( binding, rootUuid, trackName ) {
45342  
45343			var bindingsByRoot = this._bindingsByRootAndName,
45344				bindingByName = bindingsByRoot[ rootUuid ],
45345  
45346				bindings = this._bindings;
45347  
45348			if ( bindingByName === undefined ) {
45349  
45350				bindingByName = {};
45351				bindingsByRoot[ rootUuid ] = bindingByName;
45352  
45353			}
45354  
45355			bindingByName[ trackName ] = binding;
45356  
45357			binding._cacheIndex = bindings.length;
45358			bindings.push( binding );
45359  
45360		},
45361  
45362		_removeInactiveBinding: function ( binding ) {
45363  
45364			var bindings = this._bindings,
45365				propBinding = binding.binding,
45366				rootUuid = propBinding.rootNode.uuid,
45367				trackName = propBinding.path,
45368				bindingsByRoot = this._bindingsByRootAndName,
45369				bindingByName = bindingsByRoot[ rootUuid ],
45370  
45371				lastInactiveBinding = bindings[ bindings.length - 1 ],
45372				cacheIndex = binding._cacheIndex;
45373  
45374			lastInactiveBinding._cacheIndex = cacheIndex;
45375			bindings[ cacheIndex ] = lastInactiveBinding;
45376			bindings.pop();
45377  
45378			delete bindingByName[ trackName ];
45379  
45380			remove_empty_map: {
45381  
45382				for ( var _ in bindingByName ) break remove_empty_map; // eslint-disable-line no-unused-vars
45383  
45384				delete bindingsByRoot[ rootUuid ];
45385  
45386			}
45387  
45388		},
45389  
45390		_lendBinding: function ( binding ) {
45391  
45392			var bindings = this._bindings,
45393				prevIndex = binding._cacheIndex,
45394  
45395				lastActiveIndex = this._nActiveBindings ++,
45396  
45397				firstInactiveBinding = bindings[ lastActiveIndex ];
45398  
45399			binding._cacheIndex = lastActiveIndex;
45400			bindings[ lastActiveIndex ] = binding;
45401  
45402			firstInactiveBinding._cacheIndex = prevIndex;
45403			bindings[ prevIndex ] = firstInactiveBinding;
45404  
45405		},
45406  
45407		_takeBackBinding: function ( binding ) {
45408  
45409			var bindings = this._bindings,
45410				prevIndex = binding._cacheIndex,
45411  
45412				firstInactiveIndex = -- this._nActiveBindings,
45413  
45414				lastActiveBinding = bindings[ firstInactiveIndex ];
45415  
45416			binding._cacheIndex = firstInactiveIndex;
45417			bindings[ firstInactiveIndex ] = binding;
45418  
45419			lastActiveBinding._cacheIndex = prevIndex;
45420			bindings[ prevIndex ] = lastActiveBinding;
45421  
45422		},
45423  
vendor: 17,907 bytes, lines 45424-46295
45424  
45425		// Memory management of Interpolants for weight and time scale
45426  
45427		_lendControlInterpolant: function () {
45428  
45429			var interpolants = this._controlInterpolants,
45430				lastActiveIndex = this._nActiveControlInterpolants ++,
45431				interpolant = interpolants[ lastActiveIndex ];
45432  
45433			if ( interpolant === undefined ) {
45434  
45435				interpolant = new LinearInterpolant(
45436					new Float32Array( 2 ), new Float32Array( 2 ),
45437					1, this._controlInterpolantsResultBuffer );
45438  
45439				interpolant.__cacheIndex = lastActiveIndex;
45440				interpolants[ lastActiveIndex ] = interpolant;
45441  
45442			}
45443  
45444			return interpolant;
45445  
45446		},
45447  
45448		_takeBackControlInterpolant: function ( interpolant ) {
45449  
45450			var interpolants = this._controlInterpolants,
45451				prevIndex = interpolant.__cacheIndex,
45452  
45453				firstInactiveIndex = -- this._nActiveControlInterpolants,
45454  
45455				lastActiveInterpolant = interpolants[ firstInactiveIndex ];
45456  
45457			interpolant.__cacheIndex = firstInactiveIndex;
45458			interpolants[ firstInactiveIndex ] = interpolant;
45459  
45460			lastActiveInterpolant.__cacheIndex = prevIndex;
45461			interpolants[ prevIndex ] = lastActiveInterpolant;
45462  
45463		},
45464  
45465		_controlInterpolantsResultBuffer: new Float32Array( 1 ),
45466  
45467		// return an action for a clip optionally using a custom root target
45468		// object (this method allocates a lot of dynamic memory in case a
45469		// previously unknown clip/root combination is specified)
45470		clipAction: function ( clip, optionalRoot ) {
45471  
45472			var root = optionalRoot || this._root,
45473				rootUuid = root.uuid,
45474  
45475				clipObject = typeof clip === 'string' ?
45476					AnimationClip.findByName( root, clip ) : clip,
45477  
45478				clipUuid = clipObject !== null ? clipObject.uuid : clip,
45479  
45480				actionsForClip = this._actionsByClip[ clipUuid ],
45481				prototypeAction = null;
45482  
45483			if ( actionsForClip !== undefined ) {
45484  
45485				var existingAction =
45486						actionsForClip.actionByRoot[ rootUuid ];
45487  
45488				if ( existingAction !== undefined ) {
45489  
45490					return existingAction;
45491  
45492				}
45493  
45494				// we know the clip, so we don't have to parse all
45495				// the bindings again but can just copy
45496				prototypeAction = actionsForClip.knownActions[ 0 ];
45497  
45498				// also, take the clip from the prototype action
45499				if ( clipObject === null )
45500					clipObject = prototypeAction._clip;
45501  
45502			}
45503  
45504			// clip must be known when specified via string
45505			if ( clipObject === null ) return null;
45506  
45507			// allocate all resources required to run it
45508			var newAction = new AnimationAction( this, clipObject, optionalRoot );
45509  
45510			this._bindAction( newAction, prototypeAction );
45511  
45512			// and make the action known to the memory manager
45513			this._addInactiveAction( newAction, clipUuid, rootUuid );
45514  
45515			return newAction;
45516  
45517		},
45518  
45519		// get an existing action
45520		existingAction: function ( clip, optionalRoot ) {
45521  
45522			var root = optionalRoot || this._root,
45523				rootUuid = root.uuid,
45524  
45525				clipObject = typeof clip === 'string' ?
45526					AnimationClip.findByName( root, clip ) : clip,
45527  
45528				clipUuid = clipObject ? clipObject.uuid : clip,
45529  
45530				actionsForClip = this._actionsByClip[ clipUuid ];
45531  
45532			if ( actionsForClip !== undefined ) {
45533  
45534				return actionsForClip.actionByRoot[ rootUuid ] || null;
45535  
45536			}
45537  
45538			return null;
45539  
45540		},
45541  
45542		// deactivates all previously scheduled actions
45543		stopAllAction: function () {
45544  
45545			var actions = this._actions,
45546				nActions = this._nActiveActions,
45547				bindings = this._bindings,
45548				nBindings = this._nActiveBindings;
45549  
45550			this._nActiveActions = 0;
45551			this._nActiveBindings = 0;
45552  
45553			for ( var i = 0; i !== nActions; ++ i ) {
45554  
45555				actions[ i ].reset();
45556  
45557			}
45558  
45559			for ( var i = 0; i !== nBindings; ++ i ) {
45560  
45561				bindings[ i ].useCount = 0;
45562  
45563			}
45564  
45565			return this;
45566  
45567		},
45568  
45569		// advance the time and update apply the animation
45570		update: function ( deltaTime ) {
45571  
45572			deltaTime *= this.timeScale;
45573  
45574			var actions = this._actions,
45575				nActions = this._nActiveActions,
45576  
45577				time = this.time += deltaTime,
45578				timeDirection = Math.sign( deltaTime ),
45579  
45580				accuIndex = this._accuIndex ^= 1;
45581  
45582			// run active actions
45583  
45584			for ( var i = 0; i !== nActions; ++ i ) {
45585  
45586				var action = actions[ i ];
45587  
45588				action._update( time, deltaTime, timeDirection, accuIndex );
45589  
45590			}
45591  
45592			// update scene graph
45593  
45594			var bindings = this._bindings,
45595				nBindings = this._nActiveBindings;
45596  
45597			for ( var i = 0; i !== nBindings; ++ i ) {
45598  
45599				bindings[ i ].apply( accuIndex );
45600  
45601			}
45602  
45603			return this;
45604  
45605		},
45606  
45607		// return this mixer's root target object
45608		getRoot: function () {
45609  
45610			return this._root;
45611  
45612		},
45613  
45614		// free all resources specific to a particular clip
45615		uncacheClip: function ( clip ) {
45616  
45617			var actions = this._actions,
45618				clipUuid = clip.uuid,
45619				actionsByClip = this._actionsByClip,
45620				actionsForClip = actionsByClip[ clipUuid ];
45621  
45622			if ( actionsForClip !== undefined ) {
45623  
45624				// note: just calling _removeInactiveAction would mess up the
45625				// iteration state and also require updating the state we can
45626				// just throw away
45627  
45628				var actionsToRemove = actionsForClip.knownActions;
45629  
45630				for ( var i = 0, n = actionsToRemove.length; i !== n; ++ i ) {
45631  
45632					var action = actionsToRemove[ i ];
45633  
45634					this._deactivateAction( action );
45635  
45636					var cacheIndex = action._cacheIndex,
45637						lastInactiveAction = actions[ actions.length - 1 ];
45638  
45639					action._cacheIndex = null;
45640					action._byClipCacheIndex = null;
45641  
45642					lastInactiveAction._cacheIndex = cacheIndex;
45643					actions[ cacheIndex ] = lastInactiveAction;
45644					actions.pop();
45645  
45646					this._removeInactiveBindingsForAction( action );
45647  
45648				}
45649  
45650				delete actionsByClip[ clipUuid ];
45651  
45652			}
45653  
45654		},
45655  
45656		// free all resources specific to a particular root target object
45657		uncacheRoot: function ( root ) {
45658  
45659			var rootUuid = root.uuid,
45660				actionsByClip = this._actionsByClip;
45661  
45662			for ( var clipUuid in actionsByClip ) {
45663  
45664				var actionByRoot = actionsByClip[ clipUuid ].actionByRoot,
45665					action = actionByRoot[ rootUuid ];
45666  
45667				if ( action !== undefined ) {
45668  
45669					this._deactivateAction( action );
45670					this._removeInactiveAction( action );
45671  
45672				}
45673  
45674			}
45675  
45676			var bindingsByRoot = this._bindingsByRootAndName,
45677				bindingByName = bindingsByRoot[ rootUuid ];
45678  
45679			if ( bindingByName !== undefined ) {
45680  
45681				for ( var trackName in bindingByName ) {
45682  
45683					var binding = bindingByName[ trackName ];
45684					binding.restoreOriginalState();
45685					this._removeInactiveBinding( binding );
45686  
45687				}
45688  
45689			}
45690  
45691		},
45692  
45693		// remove a targeted clip from the cache
45694		uncacheAction: function ( clip, optionalRoot ) {
45695  
45696			var action = this.existingAction( clip, optionalRoot );
45697  
45698			if ( action !== null ) {
45699  
45700				this._deactivateAction( action );
45701				this._removeInactiveAction( action );
45702  
45703			}
45704  
45705		}
45706  
45707	} );
45708  
45709	/**
45710	 * @author mrdoob / http://mrdoob.com/
45711	 */
45712  
45713	function Uniform( value ) {
45714  
45715		if ( typeof value === 'string' ) {
45716  
45717			console.warn( 'THREE.Uniform: Type parameter is no longer needed.' );
45718			value = arguments[ 1 ];
45719  
45720		}
45721  
45722		this.value = value;
45723  
45724	}
45725  
45726	Uniform.prototype.clone = function () {
45727  
45728		return new Uniform( this.value.clone === undefined ? this.value : this.value.clone() );
45729  
45730	};
45731  
45732	/**
45733	 * @author benaadams / https://twitter.com/ben_a_adams
45734	 */
45735  
45736	function InstancedBufferGeometry() {
45737  
45738		BufferGeometry.call( this );
45739  
45740		this.type = 'InstancedBufferGeometry';
45741		this.maxInstancedCount = undefined;
45742  
45743	}
45744  
45745	InstancedBufferGeometry.prototype = Object.assign( Object.create( BufferGeometry.prototype ), {
45746  
45747		constructor: InstancedBufferGeometry,
45748  
45749		isInstancedBufferGeometry: true,
45750  
45751		copy: function ( source ) {
45752  
45753			BufferGeometry.prototype.copy.call( this, source );
45754  
45755			this.maxInstancedCount = source.maxInstancedCount;
45756  
45757			return this;
45758  
45759		},
45760  
45761		clone: function () {
45762  
45763			return new this.constructor().copy( this );
45764  
45765		}
45766  
45767	} );
45768  
45769	/**
45770	 * @author benaadams / https://twitter.com/ben_a_adams
45771	 */
45772  
45773	function InterleavedBufferAttribute( interleavedBuffer, itemSize, offset, normalized ) {
45774  
45775		this.data = interleavedBuffer;
45776		this.itemSize = itemSize;
45777		this.offset = offset;
45778  
45779		this.normalized = normalized === true;
45780  
45781	}
45782  
45783	Object.defineProperties( InterleavedBufferAttribute.prototype, {
45784  
45785		count: {
45786  
45787			get: function () {
45788  
45789				return this.data.count;
45790  
45791			}
45792  
45793		},
45794  
45795		array: {
45796  
45797			get: function () {
45798  
45799				return this.data.array;
45800  
45801			}
45802  
45803		}
45804  
45805	} );
45806  
45807	Object.assign( InterleavedBufferAttribute.prototype, {
45808  
45809		isInterleavedBufferAttribute: true,
45810  
45811		setX: function ( index, x ) {
45812  
45813			this.data.array[ index * this.data.stride + this.offset ] = x;
45814  
45815			return this;
45816  
45817		},
45818  
45819		setY: function ( index, y ) {
45820  
45821			this.data.array[ index * this.data.stride + this.offset + 1 ] = y;
45822  
45823			return this;
45824  
45825		},
45826  
45827		setZ: function ( index, z ) {
45828  
45829			this.data.array[ index * this.data.stride + this.offset + 2 ] = z;
45830  
45831			return this;
45832  
45833		},
45834  
45835		setW: function ( index, w ) {
45836  
45837			this.data.array[ index * this.data.stride + this.offset + 3 ] = w;
45838  
45839			return this;
45840  
45841		},
45842  
45843		getX: function ( index ) {
45844  
45845			return this.data.array[ index * this.data.stride + this.offset ];
45846  
45847		},
45848  
45849		getY: function ( index ) {
45850  
45851			return this.data.array[ index * this.data.stride + this.offset + 1 ];
45852  
45853		},
45854  
45855		getZ: function ( index ) {
45856  
45857			return this.data.array[ index * this.data.stride + this.offset + 2 ];
45858  
45859		},
45860  
45861		getW: function ( index ) {
45862  
45863			return this.data.array[ index * this.data.stride + this.offset + 3 ];
45864  
45865		},
45866  
45867		setXY: function ( index, x, y ) {
45868  
45869			index = index * this.data.stride + this.offset;
45870  
45871			this.data.array[ index + 0 ] = x;
45872			this.data.array[ index + 1 ] = y;
45873  
45874			return this;
45875  
45876		},
45877  
45878		setXYZ: function ( index, x, y, z ) {
45879  
45880			index = index * this.data.stride + this.offset;
45881  
45882			this.data.array[ index + 0 ] = x;
45883			this.data.array[ index + 1 ] = y;
45884			this.data.array[ index + 2 ] = z;
45885  
45886			return this;
45887  
45888		},
45889  
45890		setXYZW: function ( index, x, y, z, w ) {
45891  
45892			index = index * this.data.stride + this.offset;
45893  
45894			this.data.array[ index + 0 ] = x;
45895			this.data.array[ index + 1 ] = y;
45896			this.data.array[ index + 2 ] = z;
45897			this.data.array[ index + 3 ] = w;
45898  
45899			return this;
45900  
45901		}
45902  
45903	} );
45904  
45905	/**
45906	 * @author benaadams / https://twitter.com/ben_a_adams
45907	 */
45908  
45909	function InterleavedBuffer( array, stride ) {
45910  
45911		this.array = array;
45912		this.stride = stride;
45913		this.count = array !== undefined ? array.length / stride : 0;
45914  
45915		this.dynamic = false;
45916		this.updateRange = { offset: 0, count: - 1 };
45917  
45918		this.version = 0;
45919  
45920	}
45921  
45922	Object.defineProperty( InterleavedBuffer.prototype, 'needsUpdate', {
45923  
45924		set: function ( value ) {
45925  
45926			if ( value === true ) this.version ++;
45927  
45928		}
45929  
45930	} );
45931  
45932	Object.assign( InterleavedBuffer.prototype, {
45933  
45934		isInterleavedBuffer: true,
45935  
45936		onUploadCallback: function () {},
45937  
45938		setArray: function ( array ) {
45939  
45940			if ( Array.isArray( array ) ) {
45941  
45942				throw new TypeError( 'THREE.BufferAttribute: array should be a Typed Array.' );
45943  
45944			}
45945  
45946			this.count = array !== undefined ? array.length / this.stride : 0;
45947			this.array = array;
45948  
45949			return this;
45950  
45951		},
45952  
45953		setDynamic: function ( value ) {
45954  
45955			this.dynamic = value;
45956  
45957			return this;
45958  
45959		},
45960  
45961		copy: function ( source ) {
45962  
45963			this.array = new source.array.constructor( source.array );
45964			this.count = source.count;
45965			this.stride = source.stride;
45966			this.dynamic = source.dynamic;
45967  
45968			return this;
45969  
45970		},
45971  
45972		copyAt: function ( index1, attribute, index2 ) {
45973  
45974			index1 *= this.stride;
45975			index2 *= attribute.stride;
45976  
45977			for ( var i = 0, l = this.stride; i < l; i ++ ) {
45978  
45979				this.array[ index1 + i ] = attribute.array[ index2 + i ];
45980  
45981			}
45982  
45983			return this;
45984  
45985		},
45986  
45987		set: function ( value, offset ) {
45988  
45989			if ( offset === undefined ) offset = 0;
45990  
45991			this.array.set( value, offset );
45992  
45993			return this;
45994  
45995		},
45996  
45997		clone: function () {
45998  
45999			return new this.constructor().copy( this );
46000  
46001		},
46002  
46003		onUpload: function ( callback ) {
46004  
46005			this.onUploadCallback = callback;
46006  
46007			return this;
46008  
46009		}
46010  
46011	} );
46012  
46013	/**
46014	 * @author benaadams / https://twitter.com/ben_a_adams
46015	 */
46016  
46017	function InstancedInterleavedBuffer( array, stride, meshPerAttribute ) {
46018  
46019		InterleavedBuffer.call( this, array, stride );
46020  
46021		this.meshPerAttribute = meshPerAttribute || 1;
46022  
46023	}
46024  
46025	InstancedInterleavedBuffer.prototype = Object.assign( Object.create( InterleavedBuffer.prototype ), {
46026  
46027		constructor: InstancedInterleavedBuffer,
46028  
46029		isInstancedInterleavedBuffer: true,
46030  
46031		copy: function ( source ) {
46032  
46033			InterleavedBuffer.prototype.copy.call( this, source );
46034  
46035			this.meshPerAttribute = source.meshPerAttribute;
46036  
46037			return this;
46038  
46039		}
46040  
46041	} );
46042  
46043	/**
46044	 * @author benaadams / https://twitter.com/ben_a_adams
46045	 */
46046  
46047	function InstancedBufferAttribute( array, itemSize, meshPerAttribute ) {
46048  
46049		BufferAttribute.call( this, array, itemSize );
46050  
46051		this.meshPerAttribute = meshPerAttribute || 1;
46052  
46053	}
46054  
46055	InstancedBufferAttribute.prototype = Object.assign( Object.create( BufferAttribute.prototype ), {
46056  
46057		constructor: InstancedBufferAttribute,
46058  
46059		isInstancedBufferAttribute: true,
46060  
46061		copy: function ( source ) {
46062  
46063			BufferAttribute.prototype.copy.call( this, source );
46064  
46065			this.meshPerAttribute = source.meshPerAttribute;
46066  
46067			return this;
46068  
46069		}
46070  
46071	} );
46072  
46073	/**
46074	 * @author mrdoob / http://mrdoob.com/
46075	 * @author bhouston / http://clara.io/
46076	 * @author stephomi / http://stephaneginier.com/
46077	 */
46078  
46079	function Raycaster( origin, direction, near, far ) {
46080  
46081		this.ray = new Ray( origin, direction );
46082		// direction is assumed to be normalized (for accurate distance calculations)
46083  
46084		this.near = near || 0;
46085		this.far = far || Infinity;
46086  
46087		this.params = {
46088			Mesh: {},
46089			Line: {},
46090			LOD: {},
46091			Points: { threshold: 1 },
46092			Sprite: {}
46093		};
46094  
46095		Object.defineProperties( this.params, {
46096			PointCloud: {
46097				get: function () {
46098  
46099					console.warn( 'THREE.Raycaster: params.PointCloud has been renamed to params.Points.' );
46100					return this.Points;
46101  
46102				}
46103			}
46104		} );
46105  
46106	}
46107  
46108	function ascSort( a, b ) {
46109  
46110		return a.distance - b.distance;
46111  
46112	}
46113  
46114	function intersectObject( object, raycaster, intersects, recursive ) {
46115  
46116		if ( object.visible === false ) return;
46117  
46118		object.raycast( raycaster, intersects );
46119  
46120		if ( recursive === true ) {
46121  
46122			var children = object.children;
46123  
46124			for ( var i = 0, l = children.length; i < l; i ++ ) {
46125  
46126				intersectObject( children[ i ], raycaster, intersects, true );
46127  
46128			}
46129  
46130		}
46131  
46132	}
46133  
46134	Object.assign( Raycaster.prototype, {
46135  
46136		linePrecision: 1,
46137  
46138		set: function ( origin, direction ) {
46139  
46140			// direction is assumed to be normalized (for accurate distance calculations)
46141  
46142			this.ray.set( origin, direction );
46143  
46144		},
46145  
46146		setFromCamera: function ( coords, camera ) {
46147  
46148			if ( ( camera && camera.isPerspectiveCamera ) ) {
46149  
46150				this.ray.origin.setFromMatrixPosition( camera.matrixWorld );
46151				this.ray.direction.set( coords.x, coords.y, 0.5 ).unproject( camera ).sub( this.ray.origin ).normalize();
46152  
46153			} else if ( ( camera && camera.isOrthographicCamera ) ) {
46154  
46155				this.ray.origin.set( coords.x, coords.y, ( camera.near + camera.far ) / ( camera.near - camera.far ) ).unproject( camera ); // set origin in plane of camera
46156				this.ray.direction.set( 0, 0, - 1 ).transformDirection( camera.matrixWorld );
46157  
46158			} else {
46159  
46160				console.error( 'THREE.Raycaster: Unsupported camera type.' );
46161  
46162			}
46163  
46164		},
46165  
46166		intersectObject: function ( object, recursive, optionalTarget ) {
46167  
46168			var intersects = optionalTarget || [];
46169  
46170			intersectObject( object, this, intersects, recursive );
46171  
46172			intersects.sort( ascSort );
46173  
46174			return intersects;
46175  
46176		},
46177  
46178		intersectObjects: function ( objects, recursive, optionalTarget ) {
46179  
46180			var intersects = optionalTarget || [];
46181  
46182			if ( Array.isArray( objects ) === false ) {
46183  
46184				console.warn( 'THREE.Raycaster.intersectObjects: objects is not an Array.' );
46185				return intersects;
46186  
46187			}
46188  
46189			for ( var i = 0, l = objects.length; i < l; i ++ ) {
46190  
46191				intersectObject( objects[ i ], this, intersects, recursive );
46192  
46193			}
46194  
46195			intersects.sort( ascSort );
46196  
46197			return intersects;
46198  
46199		}
46200  
46201	} );
46202  
46203	/**
46204	 * @author alteredq / http://alteredqualia.com/
46205	 */
46206  
46207	function Clock( autoStart ) {
46208  
46209		this.autoStart = ( autoStart !== undefined ) ? autoStart : true;
46210  
46211		this.startTime = 0;
46212		this.oldTime = 0;
46213		this.elapsedTime = 0;
46214  
46215		this.running = false;
46216  
46217	}
46218  
46219	Object.assign( Clock.prototype, {
46220  
46221		start: function () {
46222  
46223			this.startTime = ( typeof performance === 'undefined' ? Date : performance ).now(); // see #10732
46224  
46225			this.oldTime = this.startTime;
46226			this.elapsedTime = 0;
46227			this.running = true;
46228  
46229		},
46230  
46231		stop: function () {
46232  
46233			this.getElapsedTime();
46234			this.running = false;
46235			this.autoStart = false;
46236  
46237		},
46238  
46239		getElapsedTime: function () {
46240  
46241			this.getDelta();
46242			return this.elapsedTime;
46243  
46244		},
46245  
46246		getDelta: function () {
46247  
46248			var diff = 0;
46249  
46250			if ( this.autoStart && ! this.running ) {
46251  
46252				this.start();
46253				return 0;
46254  
46255			}
46256  
46257			if ( this.running ) {
46258  
46259				var newTime = ( typeof performance === 'undefined' ? Date : performance ).now();
46260  
46261				diff = ( newTime - this.oldTime ) / 1000;
46262				this.oldTime = newTime;
46263  
46264				this.elapsedTime += diff;
46265  
46266			}
46267  
46268			return diff;
46269  
46270		}
46271  
46272	} );
46273  
46274	/**
46275	 * @author bhouston / http://clara.io
46276	 * @author WestLangley / http://github.com/WestLangley
46277	 *
46278	 * Ref: https://en.wikipedia.org/wiki/Spherical_coordinate_system
46279	 *
46280	 * The poles (phi) are at the positive and negative y axis.
46281	 * The equator starts at positive z.
46282	 */
46283  
46284	function Spherical( radius, phi, theta ) {
46285  
46286		this.radius = ( radius !== undefined ) ? radius : 1.0;
46287		this.phi = ( phi !== undefined ) ? phi : 0; // up / down towards top and bottom pole
46288		this.theta = ( theta !== undefined ) ? theta : 0; // around the equator of the sphere
46289  
46290		return this;
46291  
46292	}
46293  
46294	Object.assign( Spherical.prototype, {
46295  
vendor: 1,528 bytes, lines 46296-46372
46296		set: function ( radius, phi, theta ) {
46297  
46298			this.radius = radius;
46299			this.phi = phi;
46300			this.theta = theta;
46301  
46302			return this;
46303  
46304		},
46305  
46306		clone: function () {
46307  
46308			return new this.constructor().copy( this );
46309  
46310		},
46311  
46312		copy: function ( other ) {
46313  
46314			this.radius = other.radius;
46315			this.phi = other.phi;
46316			this.theta = other.theta;
46317  
46318			return this;
46319  
46320		},
46321  
46322		// restrict phi to be betwee EPS and PI-EPS
46323		makeSafe: function () {
46324  
46325			var EPS = 0.000001;
46326			this.phi = Math.max( EPS, Math.min( Math.PI - EPS, this.phi ) );
46327  
46328			return this;
46329  
46330		},
46331  
46332		setFromVector3: function ( vec3 ) {
46333  
46334			this.radius = vec3.length();
46335  
46336			if ( this.radius === 0 ) {
46337  
46338				this.theta = 0;
46339				this.phi = 0;
46340  
46341			} else {
46342  
46343				this.theta = Math.atan2( vec3.x, vec3.z ); // equator angle around y-up axis
46344				this.phi = Math.acos( _Math.clamp( vec3.y / this.radius, - 1, 1 ) ); // polar angle
46345  
46346			}
46347  
46348			return this;
46349  
46350		}
46351  
46352	} );
46353  
46354	/**
46355	 * @author Mugen87 / https://github.com/Mugen87
46356	 *
46357	 * Ref: https://en.wikipedia.org/wiki/Cylindrical_coordinate_system
46358	 *
46359	 */
46360  
46361	function Cylindrical( radius, theta, y ) {
46362  
46363		this.radius = ( radius !== undefined ) ? radius : 1.0; // distance from the origin to a point in the x-z plane
46364		this.theta = ( theta !== undefined ) ? theta : 0; // counterclockwise angle in the x-z plane measured in radians from the positive z-axis
46365		this.y = ( y !== undefined ) ? y : 0; // height above the x-z plane
46366  
46367		return this;
46368  
46369	}
46370  
46371	Object.assign( Cylindrical.prototype, {
46372  
vendor: 4,357 bytes, lines 46373-46602
46373		set: function ( radius, theta, y ) {
46374  
46375			this.radius = radius;
46376			this.theta = theta;
46377			this.y = y;
46378  
46379			return this;
46380  
46381		},
46382  
46383		clone: function () {
46384  
46385			return new this.constructor().copy( this );
46386  
46387		},
46388  
46389		copy: function ( other ) {
46390  
46391			this.radius = other.radius;
46392			this.theta = other.theta;
46393			this.y = other.y;
46394  
46395			return this;
46396  
46397		},
46398  
46399		setFromVector3: function ( vec3 ) {
46400  
46401			this.radius = Math.sqrt( vec3.x * vec3.x + vec3.z * vec3.z );
46402			this.theta = Math.atan2( vec3.x, vec3.z );
46403			this.y = vec3.y;
46404  
46405			return this;
46406  
46407		}
46408  
46409	} );
46410  
46411	/**
46412	 * @author bhouston / http://clara.io
46413	 */
46414  
46415	function Box2( min, max ) {
46416  
46417		this.min = ( min !== undefined ) ? min : new Vector2( + Infinity, + Infinity );
46418		this.max = ( max !== undefined ) ? max : new Vector2( - Infinity, - Infinity );
46419  
46420	}
46421  
46422	Object.assign( Box2.prototype, {
46423  
46424		set: function ( min, max ) {
46425  
46426			this.min.copy( min );
46427			this.max.copy( max );
46428  
46429			return this;
46430  
46431		},
46432  
46433		setFromPoints: function ( points ) {
46434  
46435			this.makeEmpty();
46436  
46437			for ( var i = 0, il = points.length; i < il; i ++ ) {
46438  
46439				this.expandByPoint( points[ i ] );
46440  
46441			}
46442  
46443			return this;
46444  
46445		},
46446  
46447		setFromCenterAndSize: function () {
46448  
46449			var v1 = new Vector2();
46450  
46451			return function setFromCenterAndSize( center, size ) {
46452  
46453				var halfSize = v1.copy( size ).multiplyScalar( 0.5 );
46454				this.min.copy( center ).sub( halfSize );
46455				this.max.copy( center ).add( halfSize );
46456  
46457				return this;
46458  
46459			};
46460  
46461		}(),
46462  
46463		clone: function () {
46464  
46465			return new this.constructor().copy( this );
46466  
46467		},
46468  
46469		copy: function ( box ) {
46470  
46471			this.min.copy( box.min );
46472			this.max.copy( box.max );
46473  
46474			return this;
46475  
46476		},
46477  
46478		makeEmpty: function () {
46479  
46480			this.min.x = this.min.y = + Infinity;
46481			this.max.x = this.max.y = - Infinity;
46482  
46483			return this;
46484  
46485		},
46486  
46487		isEmpty: function () {
46488  
46489			// this is a more robust check for empty than ( volume <= 0 ) because volume can get positive with two negative axes
46490  
46491			return ( this.max.x < this.min.x ) || ( this.max.y < this.min.y );
46492  
46493		},
46494  
46495		getCenter: function ( target ) {
46496  
46497			if ( target === undefined ) {
46498  
46499				console.warn( 'THREE.Box2: .getCenter() target is now required' );
46500				target = new Vector2();
46501  
46502			}
46503  
46504			return this.isEmpty() ? target.set( 0, 0 ) : target.addVectors( this.min, this.max ).multiplyScalar( 0.5 );
46505  
46506		},
46507  
46508		getSize: function ( target ) {
46509  
46510			if ( target === undefined ) {
46511  
46512				console.warn( 'THREE.Box2: .getSize() target is now required' );
46513				target = new Vector2();
46514  
46515			}
46516  
46517			return this.isEmpty() ? target.set( 0, 0 ) : target.subVectors( this.max, this.min );
46518  
46519		},
46520  
46521		expandByPoint: function ( point ) {
46522  
46523			this.min.min( point );
46524			this.max.max( point );
46525  
46526			return this;
46527  
46528		},
46529  
46530		expandByVector: function ( vector ) {
46531  
46532			this.min.sub( vector );
46533			this.max.add( vector );
46534  
46535			return this;
46536  
46537		},
46538  
46539		expandByScalar: function ( scalar ) {
46540  
46541			this.min.addScalar( - scalar );
46542			this.max.addScalar( scalar );
46543  
46544			return this;
46545  
46546		},
46547  
46548		containsPoint: function ( point ) {
46549  
46550			return point.x < this.min.x || point.x > this.max.x ||
46551				point.y < this.min.y || point.y > this.max.y ? false : true;
46552  
46553		},
46554  
46555		containsBox: function ( box ) {
46556  
46557			return this.min.x <= box.min.x && box.max.x <= this.max.x &&
46558				this.min.y <= box.min.y && box.max.y <= this.max.y;
46559  
46560		},
46561  
46562		getParameter: function ( point, target ) {
46563  
46564			// This can potentially have a divide by zero if the box
46565			// has a size dimension of 0.
46566  
46567			if ( target === undefined ) {
46568  
46569				console.warn( 'THREE.Box2: .getParameter() target is now required' );
46570				target = new Vector2();
46571  
46572			}
46573  
46574			return target.set(
46575				( point.x - this.min.x ) / ( this.max.x - this.min.x ),
46576				( point.y - this.min.y ) / ( this.max.y - this.min.y )
46577			);
46578  
46579		},
46580  
46581		intersectsBox: function ( box ) {
46582  
46583			// using 4 splitting planes to rule out intersections
46584  
46585			return box.max.x < this.min.x || box.min.x > this.max.x ||
46586				box.max.y < this.min.y || box.min.y > this.max.y ? false : true;
46587  
46588		},
46589  
46590		clampPoint: function ( point, target ) {
46591  
46592			if ( target === undefined ) {
46593  
46594				console.warn( 'THREE.Box2: .clampPoint() target is now required' );
46595				target = new Vector2();
46596  
46597			}
46598  
46599			return target.copy( point ).clamp( this.min, this.max );
46600  
46601		},
46602  
46603		distanceToPoint: function () {
46604  
46605			var v1 = new Vector2();
46606  
46607			return function distanceToPoint( point ) {
46608  
46609				var clampedPoint = v1.copy( point ).clamp( this.min, this.max );
46610				return clampedPoint.sub( point ).length();
46611  
46612			};
46613  
46614		}(),
46615  
46616		intersect: function ( box ) {
46617  
46618			this.min.max( box.min );
46619			this.max.min( box.max );
46620  
46621			return this;
46622  
46623		},
46624  
46625		union: function ( box ) {
46626  
46627			this.min.min( box.min );
46628			this.max.max( box.max );
46629  
46630			return this;
46631  
46632		},
46633  
46634		translate: function ( offset ) {
46635  
46636			this.min.add( offset );
46637			this.max.add( offset );
46638  
46639			return this;
46640  
46641		},
46642  
46643		equals: function ( box ) {
46644  
46645			return box.min.equals( this.min ) && box.max.equals( this.max );
46646  
46647		}
46648  
46649	} );
46650  
46651	/**
46652	 * @author alteredq / http://alteredqualia.com/
46653	 */
46654  
46655	function ImmediateRenderObject( material ) {
46656  
46657		Object3D.call( this );
46658  
46659		this.material = material;
46660		this.render = function ( /* renderCallback */ ) {};
46661  
46662	}
46663  
46664	ImmediateRenderObject.prototype = Object.create( Object3D.prototype );
46665	ImmediateRenderObject.prototype.constructor = ImmediateRenderObject;
46666  
46667	ImmediateRenderObject.prototype.isImmediateRenderObject = true;
46668  
46669	/**
46670	 * @author mrdoob / http://mrdoob.com/
46671	 * @author WestLangley / http://github.com/WestLangley
46672	 */
46673  
46674	function VertexNormalsHelper( object, size, hex, linewidth ) {
46675  
46676		this.object = object;
46677  
46678		this.size = ( size !== undefined ) ? size : 1;
46679  
46680		var color = ( hex !== undefined ) ? hex : 0xff0000;
46681  
46682		var width = ( linewidth !== undefined ) ? linewidth : 1;
46683  
46684		//
46685  
46686		var nNormals = 0;
46687  
46688		var objGeometry = this.object.geometry;
46689  
46690		if ( objGeometry && objGeometry.isGeometry ) {
46691  
46692			nNormals = objGeometry.faces.length * 3;
46693  
46694		} else if ( objGeometry && objGeometry.isBufferGeometry ) {
46695  
46696			nNormals = objGeometry.attributes.normal.count;
46697  
46698		}
46699  
46700		//
46701  
46702		var geometry = new BufferGeometry();
46703  
46704		var positions = new Float32BufferAttribute( nNormals * 2 * 3, 3 );
46705  
46706		geometry.addAttribute( 'position', positions );
46707  
46708		LineSegments.call( this, geometry, new LineBasicMaterial( { color: color, linewidth: width } ) );
46709  
46710		//
46711  
46712		this.matrixAutoUpdate = false;
46713  
46714		this.update();
46715  
46716	}
46717  
46718	VertexNormalsHelper.prototype = Object.create( LineSegments.prototype );
46719	VertexNormalsHelper.prototype.constructor = VertexNormalsHelper;
46720  
46721	VertexNormalsHelper.prototype.update = ( function () {
46722  
46723		var v1 = new Vector3();
46724		var v2 = new Vector3();
46725		var normalMatrix = new Matrix3();
46726  
46727		return function update() {
46728  
46729			var keys = [ 'a', 'b', 'c' ];
46730  
46731			this.object.updateMatrixWorld( true );
46732  
46733			normalMatrix.getNormalMatrix( this.object.matrixWorld );
46734  
46735			var matrixWorld = this.object.matrixWorld;
46736  
46737			var position = this.geometry.attributes.position;
46738  
46739			//
46740  
46741			var objGeometry = this.object.geometry;
46742  
46743			if ( objGeometry && objGeometry.isGeometry ) {
46744  
46745				var vertices = objGeometry.vertices;
46746  
46747				var faces = objGeometry.faces;
46748  
46749				var idx = 0;
46750  
46751				for ( var i = 0, l = faces.length; i < l; i ++ ) {
46752  
46753					var face = faces[ i ];
46754  
46755					for ( var j = 0, jl = face.vertexNormals.length; j < jl; j ++ ) {
46756  
46757						var vertex = vertices[ face[ keys[ j ] ] ];
46758  
46759						var normal = face.vertexNormals[ j ];
46760  
46761						v1.copy( vertex ).applyMatrix4( matrixWorld );
46762  
46763						v2.copy( normal ).applyMatrix3( normalMatrix ).normalize().multiplyScalar( this.size ).add( v1 );
46764  
46765						position.setXYZ( idx, v1.x, v1.y, v1.z );
46766  
46767						idx = idx + 1;
46768  
46769						position.setXYZ( idx, v2.x, v2.y, v2.z );
46770  
46771						idx = idx + 1;
46772  
46773					}
46774  
46775				}
46776  
46777			} else if ( objGeometry && objGeometry.isBufferGeometry ) {
46778  
46779				var objPos = objGeometry.attributes.position;
46780  
46781				var objNorm = objGeometry.attributes.normal;
46782  
46783				var idx = 0;
46784  
46785				// for simplicity, ignore index and drawcalls, and render every normal
46786  
46787				for ( var j = 0, jl = objPos.count; j < jl; j ++ ) {
46788  
46789					v1.set( objPos.getX( j ), objPos.getY( j ), objPos.getZ( j ) ).applyMatrix4( matrixWorld );
46790  
46791					v2.set( objNorm.getX( j ), objNorm.getY( j ), objNorm.getZ( j ) );
46792  
46793					v2.applyMatrix3( normalMatrix ).normalize().multiplyScalar( this.size ).add( v1 );
46794  
46795					position.setXYZ( idx, v1.x, v1.y, v1.z );
46796  
46797					idx = idx + 1;
46798  
46799					position.setXYZ( idx, v2.x, v2.y, v2.z );
46800  
46801					idx = idx + 1;
46802  
46803				}
46804  
46805			}
46806  
46807			position.needsUpdate = true;
46808  
46809		};
46810  
46811	}() );
46812  
46813	/**
46814	 * @author alteredq / http://alteredqualia.com/
46815	 * @author mrdoob / http://mrdoob.com/
46816	 * @author WestLangley / http://github.com/WestLangley
46817	 */
46818  
46819	function SpotLightHelper( light, color ) {
46820  
46821		Object3D.call( this );
46822  
46823		this.light = light;
46824		this.light.updateMatrixWorld();
46825  
46826		this.matrix = light.matrixWorld;
46827		this.matrixAutoUpdate = false;
vendor: 5,008 bytes, lines 46828-47042
46828  
46829		this.color = color;
46830  
46831		var geometry = new BufferGeometry();
46832  
46833		var positions = [
46834			0, 0, 0, 	0, 0, 1,
46835			0, 0, 0, 	1, 0, 1,
46836			0, 0, 0,	- 1, 0, 1,
46837			0, 0, 0, 	0, 1, 1,
46838			0, 0, 0, 	0, - 1, 1
46839		];
46840  
46841		for ( var i = 0, j = 1, l = 32; i < l; i ++, j ++ ) {
46842  
46843			var p1 = ( i / l ) * Math.PI * 2;
46844			var p2 = ( j / l ) * Math.PI * 2;
46845  
46846			positions.push(
46847				Math.cos( p1 ), Math.sin( p1 ), 1,
46848				Math.cos( p2 ), Math.sin( p2 ), 1
46849			);
46850  
46851		}
46852  
46853		geometry.addAttribute( 'position', new Float32BufferAttribute( positions, 3 ) );
46854  
46855		var material = new LineBasicMaterial( { fog: false } );
46856  
46857		this.cone = new LineSegments( geometry, material );
46858		this.add( this.cone );
46859  
46860		this.update();
46861  
46862	}
46863  
46864	SpotLightHelper.prototype = Object.create( Object3D.prototype );
46865	SpotLightHelper.prototype.constructor = SpotLightHelper;
46866  
46867	SpotLightHelper.prototype.dispose = function () {
46868  
46869		this.cone.geometry.dispose();
46870		this.cone.material.dispose();
46871  
46872	};
46873  
46874	SpotLightHelper.prototype.update = function () {
46875  
46876		var vector = new Vector3();
46877		var vector2 = new Vector3();
46878  
46879		return function update() {
46880  
46881			this.light.updateMatrixWorld();
46882  
46883			var coneLength = this.light.distance ? this.light.distance : 1000;
46884			var coneWidth = coneLength * Math.tan( this.light.angle );
46885  
46886			this.cone.scale.set( coneWidth, coneWidth, coneLength );
46887  
46888			vector.setFromMatrixPosition( this.light.matrixWorld );
46889			vector2.setFromMatrixPosition( this.light.target.matrixWorld );
46890  
46891			this.cone.lookAt( vector2.sub( vector ) );
46892  
46893			if ( this.color !== undefined ) {
46894  
46895				this.cone.material.color.set( this.color );
46896  
46897			} else {
46898  
46899				this.cone.material.color.copy( this.light.color );
46900  
46901			}
46902  
46903		};
46904  
46905	}();
46906  
46907	/**
46908	 * @author Sean Griffin / http://twitter.com/sgrif
46909	 * @author Michael Guerrero / http://realitymeltdown.com
46910	 * @author mrdoob / http://mrdoob.com/
46911	 * @author ikerr / http://verold.com
46912	 * @author Mugen87 / https://github.com/Mugen87
46913	 */
46914  
46915	function getBoneList( object ) {
46916  
46917		var boneList = [];
46918  
46919		if ( object && object.isBone ) {
46920  
46921			boneList.push( object );
46922  
46923		}
46924  
46925		for ( var i = 0; i < object.children.length; i ++ ) {
46926  
46927			boneList.push.apply( boneList, getBoneList( object.children[ i ] ) );
46928  
46929		}
46930  
46931		return boneList;
46932  
46933	}
46934  
46935	function SkeletonHelper( object ) {
46936  
46937		var bones = getBoneList( object );
46938  
46939		var geometry = new BufferGeometry();
46940  
46941		var vertices = [];
46942		var colors = [];
46943  
46944		var color1 = new Color( 0, 0, 1 );
46945		var color2 = new Color( 0, 1, 0 );
46946  
46947		for ( var i = 0; i < bones.length; i ++ ) {
46948  
46949			var bone = bones[ i ];
46950  
46951			if ( bone.parent && bone.parent.isBone ) {
46952  
46953				vertices.push( 0, 0, 0 );
46954				vertices.push( 0, 0, 0 );
46955				colors.push( color1.r, color1.g, color1.b );
46956				colors.push( color2.r, color2.g, color2.b );
46957  
46958			}
46959  
46960		}
46961  
46962		geometry.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
46963		geometry.addAttribute( 'color', new Float32BufferAttribute( colors, 3 ) );
46964  
46965		var material = new LineBasicMaterial( { vertexColors: VertexColors, depthTest: false, depthWrite: false, transparent: true } );
46966  
46967		LineSegments.call( this, geometry, material );
46968  
46969		this.root = object;
46970		this.bones = bones;
46971  
46972		this.matrix = object.matrixWorld;
46973		this.matrixAutoUpdate = false;
46974  
46975	}
46976  
46977	SkeletonHelper.prototype = Object.create( LineSegments.prototype );
46978	SkeletonHelper.prototype.constructor = SkeletonHelper;
46979  
46980	SkeletonHelper.prototype.updateMatrixWorld = function () {
46981  
46982		var vector = new Vector3();
46983  
46984		var boneMatrix = new Matrix4();
46985		var matrixWorldInv = new Matrix4();
46986  
46987		return function updateMatrixWorld( force ) {
46988  
46989			var bones = this.bones;
46990  
46991			var geometry = this.geometry;
46992			var position = geometry.getAttribute( 'position' );
46993  
46994			matrixWorldInv.getInverse( this.root.matrixWorld );
46995  
46996			for ( var i = 0, j = 0; i < bones.length; i ++ ) {
46997  
46998				var bone = bones[ i ];
46999  
47000				if ( bone.parent && bone.parent.isBone ) {
47001  
47002					boneMatrix.multiplyMatrices( matrixWorldInv, bone.matrixWorld );
47003					vector.setFromMatrixPosition( boneMatrix );
47004					position.setXYZ( j, vector.x, vector.y, vector.z );
47005  
47006					boneMatrix.multiplyMatrices( matrixWorldInv, bone.parent.matrixWorld );
47007					vector.setFromMatrixPosition( boneMatrix );
47008					position.setXYZ( j + 1, vector.x, vector.y, vector.z );
47009  
47010					j += 2;
47011  
47012				}
47013  
47014			}
47015  
47016			geometry.getAttribute( 'position' ).needsUpdate = true;
47017  
47018			Object3D.prototype.updateMatrixWorld.call( this, force );
47019  
47020		};
47021  
47022	}();
47023  
47024	/**
47025	 * @author alteredq / http://alteredqualia.com/
47026	 * @author mrdoob / http://mrdoob.com/
47027	 */
47028  
47029	function PointLightHelper( light, sphereSize, color ) {
47030  
47031		this.light = light;
47032		this.light.updateMatrixWorld();
47033  
47034		this.color = color;
47035  
47036		var geometry = new SphereBufferGeometry( sphereSize, 4, 2 );
47037		var material = new MeshBasicMaterial( { wireframe: true, fog: false } );
47038  
47039		Mesh.call( this, geometry, material );
47040  
47041		this.matrix = this.light.matrixWorld;
47042		this.matrixAutoUpdate = false;
47043  
47044		this.update();
47045  
47046  
47047		/*
47048		var distanceGeometry = new THREE.IcosahedronGeometry( 1, 2 );
47049		var distanceMaterial = new THREE.MeshBasicMaterial( { color: hexColor, fog: false, wireframe: true, opacity: 0.1, transparent: true } );
47050  
47051		this.lightSphere = new THREE.Mesh( bulbGeometry, bulbMaterial );
47052		this.lightDistance = new THREE.Mesh( distanceGeometry, distanceMaterial );
47053  
47054		var d = light.distance;
47055  
47056		if ( d === 0.0 ) {
47057  
47058			this.lightDistance.visible = false;
47059  
47060		} else {
47061  
47062			this.lightDistance.scale.set( d, d, d );
47063  
47064		}
47065  
47066		this.add( this.lightDistance );
47067		*/
47068  
47069	}
47070  
47071	PointLightHelper.prototype = Object.create( Mesh.prototype );
47072	PointLightHelper.prototype.constructor = PointLightHelper;
47073  
47074	PointLightHelper.prototype.dispose = function () {
47075  
47076		this.geometry.dispose();
47077		this.material.dispose();
47078  
47079	};
47080  
47081	PointLightHelper.prototype.update = function () {
47082  
47083		if ( this.color !== undefined ) {
47084  
47085			this.material.color.set( this.color );
47086  
47087		} else {
47088  
47089			this.material.color.copy( this.light.color );
47090  
47091		}
47092  
47093		/*
47094		var d = this.light.distance;
47095  
47096		if ( d === 0.0 ) {
47097  
47098			this.lightDistance.visible = false;
47099  
47100		} else {
47101  
47102			this.lightDistance.visible = true;
47103			this.lightDistance.scale.set( d, d, d );
47104  
47105		}
47106		*/
47107  
47108	};
47109  
47110	/**
47111	 * @author abelnation / http://github.com/abelnation
47112	 * @author Mugen87 / http://github.com/Mugen87
47113	 * @author WestLangley / http://github.com/WestLangley
47114	 */
47115  
47116	function RectAreaLightHelper( light, color ) {
47117  
47118		Object3D.call( this );
47119  
47120		this.light = light;
47121		this.light.updateMatrixWorld();
47122  
47123		this.matrix = light.matrixWorld;
47124		this.matrixAutoUpdate = false;
47125  
47126		this.color = color;
47127  
47128		var material = new LineBasicMaterial( { fog: false } );
47129  
47130		var geometry = new BufferGeometry();
47131  
47132		geometry.addAttribute( 'position', new BufferAttribute( new Float32Array( 5 * 3 ), 3 ) );
47133  
47134		this.line = new Line( geometry, material );
47135		this.add( this.line );
47136  
47137  
47138		this.update();
47139  
47140	}
47141  
47142	RectAreaLightHelper.prototype = Object.create( Object3D.prototype );
47143	RectAreaLightHelper.prototype.constructor = RectAreaLightHelper;
47144  
47145	RectAreaLightHelper.prototype.dispose = function () {
47146  
47147		this.children[ 0 ].geometry.dispose();
47148		this.children[ 0 ].material.dispose();
47149  
47150	};
47151  
47152	RectAreaLightHelper.prototype.update = function () {
47153  
47154		// calculate new dimensions of the helper
47155  
47156		var hx = this.light.width * 0.5;
47157		var hy = this.light.height * 0.5;
47158  
47159		var position = this.line.geometry.attributes.position;
47160		var array = position.array;
47161  
47162		// update vertices
47163  
47164		array[ 0 ] = hx; array[ 1 ] = - hy; array[ 2 ] = 0;
47165		array[ 3 ] = hx; array[ 4 ] = hy; array[ 5 ] = 0;
47166		array[ 6 ] = - hx; array[ 7 ] = hy; array[ 8 ] = 0;
47167		array[ 9 ] = - hx; array[ 10 ] = - hy; array[ 11 ] = 0;
47168		array[ 12 ] = hx; array[ 13 ] = - hy; array[ 14 ] = 0;
47169  
47170		position.needsUpdate = true;
47171  
47172		if ( this.color !== undefined ) {
47173  
47174			this.line.material.color.set( this.color );
47175  
47176		} else {
47177  
47178			this.line.material.color.copy( this.light.color );
47179  
47180		}
47181  
47182	};
47183  
47184	/**
47185	 * @author alteredq / http://alteredqualia.com/
47186	 * @author mrdoob / http://mrdoob.com/
47187	 * @author Mugen87 / https://github.com/Mugen87
47188	 */
47189  
47190	function HemisphereLightHelper( light, size, color ) {
47191  
47192		Object3D.call( this );
47193  
47194		this.light = light;
47195		this.light.updateMatrixWorld();
47196  
47197		this.matrix = light.matrixWorld;
47198		this.matrixAutoUpdate = false;
47199  
47200		this.color = color;
47201  
47202		var geometry = new OctahedronBufferGeometry( size );
47203		geometry.rotateY( Math.PI * 0.5 );
47204  
47205		this.material = new MeshBasicMaterial( { wireframe: true, fog: false } );
47206		if ( this.color === undefined ) this.material.vertexColors = VertexColors;
47207  
47208		var position = geometry.getAttribute( 'position' );
47209		var colors = new Float32Array( position.count * 3 );
47210  
47211		geometry.addAttribute( 'color', new BufferAttribute( colors, 3 ) );
47212  
47213		this.add( new Mesh( geometry, this.material ) );
47214  
47215		this.update();
47216  
47217	}
47218  
47219	HemisphereLightHelper.prototype = Object.create( Object3D.prototype );
47220	HemisphereLightHelper.prototype.constructor = HemisphereLightHelper;
47221  
47222	HemisphereLightHelper.prototype.dispose = function () {
47223  
47224		this.children[ 0 ].geometry.dispose();
47225		this.children[ 0 ].material.dispose();
47226  
47227	};
47228  
47229	HemisphereLightHelper.prototype.update = function () {
47230  
47231		var vector = new Vector3();
47232  
47233		var color1 = new Color();
47234		var color2 = new Color();
47235  
vendor: 4,151 bytes, lines 47236-47406
47236		return function update() {
47237  
47238			var mesh = this.children[ 0 ];
47239  
47240			if ( this.color !== undefined ) {
47241  
47242				this.material.color.set( this.color );
47243  
47244			} else {
47245  
47246				var colors = mesh.geometry.getAttribute( 'color' );
47247  
47248				color1.copy( this.light.color );
47249				color2.copy( this.light.groundColor );
47250  
47251				for ( var i = 0, l = colors.count; i < l; i ++ ) {
47252  
47253					var color = ( i < ( l / 2 ) ) ? color1 : color2;
47254  
47255					colors.setXYZ( i, color.r, color.g, color.b );
47256  
47257				}
47258  
47259				colors.needsUpdate = true;
47260  
47261			}
47262  
47263			mesh.lookAt( vector.setFromMatrixPosition( this.light.matrixWorld ).negate() );
47264  
47265		};
47266  
47267	}();
47268  
47269	/**
47270	 * @author mrdoob / http://mrdoob.com/
47271	 */
47272  
47273	function GridHelper( size, divisions, color1, color2 ) {
47274  
47275		size = size || 10;
47276		divisions = divisions || 10;
47277		color1 = new Color( color1 !== undefined ? color1 : 0x444444 );
47278		color2 = new Color( color2 !== undefined ? color2 : 0x888888 );
47279  
47280		var center = divisions / 2;
47281		var step = size / divisions;
47282		var halfSize = size / 2;
47283  
47284		var vertices = [], colors = [];
47285  
47286		for ( var i = 0, j = 0, k = - halfSize; i <= divisions; i ++, k += step ) {
47287  
47288			vertices.push( - halfSize, 0, k, halfSize, 0, k );
47289			vertices.push( k, 0, - halfSize, k, 0, halfSize );
47290  
47291			var color = i === center ? color1 : color2;
47292  
47293			color.toArray( colors, j ); j += 3;
47294			color.toArray( colors, j ); j += 3;
47295			color.toArray( colors, j ); j += 3;
47296			color.toArray( colors, j ); j += 3;
47297  
47298		}
47299  
47300		var geometry = new BufferGeometry();
47301		geometry.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
47302		geometry.addAttribute( 'color', new Float32BufferAttribute( colors, 3 ) );
47303  
47304		var material = new LineBasicMaterial( { vertexColors: VertexColors } );
47305  
47306		LineSegments.call( this, geometry, material );
47307  
47308	}
47309  
47310	GridHelper.prototype = Object.create( LineSegments.prototype );
47311	GridHelper.prototype.constructor = GridHelper;
47312  
47313	/**
47314	 * @author mrdoob / http://mrdoob.com/
47315	 * @author Mugen87 / http://github.com/Mugen87
47316	 * @author Hectate / http://www.github.com/Hectate
47317	 */
47318  
47319	function PolarGridHelper( radius, radials, circles, divisions, color1, color2 ) {
47320  
47321		radius = radius || 10;
47322		radials = radials || 16;
47323		circles = circles || 8;
47324		divisions = divisions || 64;
47325		color1 = new Color( color1 !== undefined ? color1 : 0x444444 );
47326		color2 = new Color( color2 !== undefined ? color2 : 0x888888 );
47327  
47328		var vertices = [];
47329		var colors = [];
47330  
47331		var x, z;
47332		var v, i, j, r, color;
47333  
47334		// create the radials
47335  
47336		for ( i = 0; i <= radials; i ++ ) {
47337  
47338			v = ( i / radials ) * ( Math.PI * 2 );
47339  
47340			x = Math.sin( v ) * radius;
47341			z = Math.cos( v ) * radius;
47342  
47343			vertices.push( 0, 0, 0 );
47344			vertices.push( x, 0, z );
47345  
47346			color = ( i & 1 ) ? color1 : color2;
47347  
47348			colors.push( color.r, color.g, color.b );
47349			colors.push( color.r, color.g, color.b );
47350  
47351		}
47352  
47353		// create the circles
47354  
47355		for ( i = 0; i <= circles; i ++ ) {
47356  
47357			color = ( i & 1 ) ? color1 : color2;
47358  
47359			r = radius - ( radius / circles * i );
47360  
47361			for ( j = 0; j < divisions; j ++ ) {
47362  
47363				// first vertex
47364  
47365				v = ( j / divisions ) * ( Math.PI * 2 );
47366  
47367				x = Math.sin( v ) * r;
47368				z = Math.cos( v ) * r;
47369  
47370				vertices.push( x, 0, z );
47371				colors.push( color.r, color.g, color.b );
47372  
47373				// second vertex
47374  
47375				v = ( ( j + 1 ) / divisions ) * ( Math.PI * 2 );
47376  
47377				x = Math.sin( v ) * r;
47378				z = Math.cos( v ) * r;
47379  
47380				vertices.push( x, 0, z );
47381				colors.push( color.r, color.g, color.b );
47382  
47383			}
47384  
47385		}
47386  
47387		var geometry = new BufferGeometry();
47388		geometry.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
47389		geometry.addAttribute( 'color', new Float32BufferAttribute( colors, 3 ) );
47390  
47391		var material = new LineBasicMaterial( { vertexColors: VertexColors } );
47392  
47393		LineSegments.call( this, geometry, material );
47394  
47395	}
47396  
47397	PolarGridHelper.prototype = Object.create( LineSegments.prototype );
47398	PolarGridHelper.prototype.constructor = PolarGridHelper;
47399  
47400	/**
47401	 * @author mrdoob / http://mrdoob.com/
47402	 * @author WestLangley / http://github.com/WestLangley
47403	 */
47404  
47405	function FaceNormalsHelper( object, size, hex, linewidth ) {
47406  
47407		// FaceNormalsHelper only supports THREE.Geometry
47408  
47409		this.object = object;
47410  
47411		this.size = ( size !== undefined ) ? size : 1;
47412  
47413		var color = ( hex !== undefined ) ? hex : 0xffff00;
47414  
47415		var width = ( linewidth !== undefined ) ? linewidth : 1;
47416  
47417		//
47418  
47419		var nNormals = 0;
47420  
47421		var objGeometry = this.object.geometry;
47422  
47423		if ( objGeometry && objGeometry.isGeometry ) {
47424  
47425			nNormals = objGeometry.faces.length;
47426  
47427		} else {
47428  
47429			console.warn( 'THREE.FaceNormalsHelper: only THREE.Geometry is supported. Use THREE.VertexNormalsHelper, instead.' );
47430  
47431		}
47432  
47433		//
47434  
47435		var geometry = new BufferGeometry();
47436  
47437		var positions = new Float32BufferAttribute( nNormals * 2 * 3, 3 );
47438  
47439		geometry.addAttribute( 'position', positions );
47440  
47441		LineSegments.call( this, geometry, new LineBasicMaterial( { color: color, linewidth: width } ) );
47442  
47443		//
47444  
47445		this.matrixAutoUpdate = false;
47446		this.update();
47447  
47448	}
47449  
47450	FaceNormalsHelper.prototype = Object.create( LineSegments.prototype );
47451	FaceNormalsHelper.prototype.constructor = FaceNormalsHelper;
47452  
47453	FaceNormalsHelper.prototype.update = ( function () {
47454  
47455		var v1 = new Vector3();
47456		var v2 = new Vector3();
47457		var normalMatrix = new Matrix3();
47458  
47459		return function update() {
47460  
47461			this.object.updateMatrixWorld( true );
47462  
47463			normalMatrix.getNormalMatrix( this.object.matrixWorld );
47464  
47465			var matrixWorld = this.object.matrixWorld;
47466  
47467			var position = this.geometry.attributes.position;
47468  
47469			//
47470  
47471			var objGeometry = this.object.geometry;
47472  
47473			var vertices = objGeometry.vertices;
47474  
47475			var faces = objGeometry.faces;
47476  
47477			var idx = 0;
47478  
47479			for ( var i = 0, l = faces.length; i < l; i ++ ) {
47480  
47481				var face = faces[ i ];
47482  
47483				var normal = face.normal;
47484  
47485				v1.copy( vertices[ face.a ] )
47486					.add( vertices[ face.b ] )
47487					.add( vertices[ face.c ] )
47488					.divideScalar( 3 )
47489					.applyMatrix4( matrixWorld );
47490  
47491				v2.copy( normal ).applyMatrix3( normalMatrix ).normalize().multiplyScalar( this.size ).add( v1 );
47492  
47493				position.setXYZ( idx, v1.x, v1.y, v1.z );
47494  
47495				idx = idx + 1;
47496  
47497				position.setXYZ( idx, v2.x, v2.y, v2.z );
47498  
47499				idx = idx + 1;
47500  
47501			}
47502  
47503			position.needsUpdate = true;
47504  
47505		};
47506  
47507	}() );
47508  
47509	/**
47510	 * @author alteredq / http://alteredqualia.com/
47511	 * @author mrdoob / http://mrdoob.com/
47512	 * @author WestLangley / http://github.com/WestLangley
47513	 */
47514  
47515	function DirectionalLightHelper( light, size, color ) {
47516  
47517		Object3D.call( this );
47518  
47519		this.light = light;
47520		this.light.updateMatrixWorld();
47521  
47522		this.matrix = light.matrixWorld;
47523		this.matrixAutoUpdate = false;
47524  
47525		this.color = color;
47526  
47527		if ( size === undefined ) size = 1;
47528  
47529		var geometry = new BufferGeometry();
47530		geometry.addAttribute( 'position', new Float32BufferAttribute( [
47531			- size, size, 0,
47532			size, size, 0,
47533			size, - size, 0,
47534			- size, - size, 0,
47535			- size, size, 0
47536		], 3 ) );
47537  
47538		var material = new LineBasicMaterial( { fog: false } );
47539  
47540		this.lightPlane = new Line( geometry, material );
47541		this.add( this.lightPlane );
47542  
47543		geometry = new BufferGeometry();
47544		geometry.addAttribute( 'position', new Float32BufferAttribute( [ 0, 0, 0, 0, 0, 1 ], 3 ) );
47545  
47546		this.targetLine = new Line( geometry, material );
47547		this.add( this.targetLine );
47548  
47549		this.update();
47550  
47551	}
47552  
47553	DirectionalLightHelper.prototype = Object.create( Object3D.prototype );
47554	DirectionalLightHelper.prototype.constructor = DirectionalLightHelper;
47555  
47556	DirectionalLightHelper.prototype.dispose = function () {
47557  
47558		this.lightPlane.geometry.dispose();
47559		this.lightPlane.material.dispose();
47560		this.targetLine.geometry.dispose();
47561		this.targetLine.material.dispose();
47562  
47563	};
47564  
47565	DirectionalLightHelper.prototype.update = function () {
47566  
47567		var v1 = new Vector3();
47568		var v2 = new Vector3();
47569		var v3 = new Vector3();
47570  
47571		return function update() {
47572  
47573			v1.setFromMatrixPosition( this.light.matrixWorld );
47574			v2.setFromMatrixPosition( this.light.target.matrixWorld );
47575			v3.subVectors( v2, v1 );
47576  
47577			this.lightPlane.lookAt( v3 );
47578  
47579			if ( this.color !== undefined ) {
47580  
47581				this.lightPlane.material.color.set( this.color );
47582				this.targetLine.material.color.set( this.color );
47583  
47584			} else {
47585  
47586				this.lightPlane.material.color.copy( this.light.color );
47587				this.targetLine.material.color.copy( this.light.color );
47588  
47589			}
47590  
47591			this.targetLine.lookAt( v3 );
47592			this.targetLine.scale.z = v3.length();
47593  
47594		};
47595  
47596	}();
47597  
47598	/**
47599	 * @author alteredq / http://alteredqualia.com/
47600	 * @author Mugen87 / https://github.com/Mugen87
47601	 *
47602	 *	- shows frustum, line of sight and up of the camera
47603	 *	- suitable for fast updates
47604	 * 	- based on frustum visualization in lightgl.js shadowmap example
47605	 *		http://evanw.github.com/lightgl.js/tests/shadowmap.html
47606	 */
47607  
47608	function CameraHelper( camera ) {
47609  
47610		var geometry = new BufferGeometry();
47611		var material = new LineBasicMaterial( { color: 0xffffff, vertexColors: FaceColors } );
47612  
47613		var vertices = [];
47614		var colors = [];
47615  
47616		var pointMap = {};
47617  
47618		// colors
47619  
47620		var colorFrustum = new Color( 0xffaa00 );
47621		var colorCone = new Color( 0xff0000 );
47622		var colorUp = new Color( 0x00aaff );
47623		var colorTarget = new Color( 0xffffff );
47624		var colorCross = new Color( 0x333333 );
47625  
47626		// near
47627  
47628		addLine( 'n1', 'n2', colorFrustum );
47629		addLine( 'n2', 'n4', colorFrustum );
47630		addLine( 'n4', 'n3', colorFrustum );
47631		addLine( 'n3', 'n1', colorFrustum );
47632  
47633		// far
47634  
47635		addLine( 'f1', 'f2', colorFrustum );
47636		addLine( 'f2', 'f4', colorFrustum );
47637		addLine( 'f4', 'f3', colorFrustum );
47638		addLine( 'f3', 'f1', colorFrustum );
47639  
47640		// sides
47641  
47642		addLine( 'n1', 'f1', colorFrustum );
47643		addLine( 'n2', 'f2', colorFrustum );
47644		addLine( 'n3', 'f3', colorFrustum );
47645		addLine( 'n4', 'f4', colorFrustum );
47646  
47647		// cone
47648  
47649		addLine( 'p', 'n1', colorCone );
47650		addLine( 'p', 'n2', colorCone );
47651		addLine( 'p', 'n3', colorCone );
47652		addLine( 'p', 'n4', colorCone );
47653  
47654		// up
47655  
47656		addLine( 'u1', 'u2', colorUp );
47657		addLine( 'u2', 'u3', colorUp );
47658		addLine( 'u3', 'u1', colorUp );
47659  
47660		// target
47661  
47662		addLine( 'c', 't', colorTarget );
47663		addLine( 'p', 'c', colorCross );
47664  
47665		// cross
47666  
47667		addLine( 'cn1', 'cn2', colorCross );
47668		addLine( 'cn3', 'cn4', colorCross );
47669  
47670		addLine( 'cf1', 'cf2', colorCross );
47671		addLine( 'cf3', 'cf4', colorCross );
47672  
47673		function addLine( a, b, color ) {
47674  
47675			addPoint( a, color );
47676			addPoint( b, color );
47677  
47678		}
47679  
47680		function addPoint( id, color ) {
47681  
47682			vertices.push( 0, 0, 0 );
47683			colors.push( color.r, color.g, color.b );
47684  
47685			if ( pointMap[ id ] === undefined ) {
47686  
47687				pointMap[ id ] = [];
47688  
47689			}
47690  
47691			pointMap[ id ].push( ( vertices.length / 3 ) - 1 );
47692  
47693		}
47694  
47695		geometry.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
47696		geometry.addAttribute( 'color', new Float32BufferAttribute( colors, 3 ) );
47697  
47698		LineSegments.call( this, geometry, material );
47699  
47700		this.camera = camera;
47701		if ( this.camera.updateProjectionMatrix ) this.camera.updateProjectionMatrix();
47702  
47703		this.matrix = camera.matrixWorld;
47704		this.matrixAutoUpdate = false;
47705  
47706		this.pointMap = pointMap;
47707  
47708		this.update();
47709  
47710	}
47711  
47712	CameraHelper.prototype = Object.create( LineSegments.prototype );
47713	CameraHelper.prototype.constructor = CameraHelper;
47714  
47715	CameraHelper.prototype.update = function () {
47716  
47717		var geometry, pointMap;
47718  
47719		var vector = new Vector3();
47720		var camera = new Camera();
47721  
47722		function setPoint( point, x, y, z ) {
47723  
47724			vector.set( x, y, z ).unproject( camera );
47725  
47726			var points = pointMap[ point ];
47727  
47728			if ( points !== undefined ) {
47729  
47730				var position = geometry.getAttribute( 'position' );
47731  
47732				for ( var i = 0, l = points.length; i < l; i ++ ) {
47733  
47734					position.setXYZ( points[ i ], vector.x, vector.y, vector.z );
47735  
47736				}
47737  
47738			}
47739  
47740		}
47741  
47742		return function update() {
47743  
47744			geometry = this.geometry;
47745			pointMap = this.pointMap;
47746  
47747			var w = 1, h = 1;
47748  
47749			// we need just camera projection matrix
47750			// world matrix must be identity
47751  
47752			camera.projectionMatrix.copy( this.camera.projectionMatrix );
47753  
47754			// center / target
47755  
47756			setPoint( 'c', 0, 0, - 1 );
47757			setPoint( 't', 0, 0, 1 );
47758  
47759			// near
47760  
47761			setPoint( 'n1', - w, - h, - 1 );
47762			setPoint( 'n2', w, - h, - 1 );
47763			setPoint( 'n3', - w, h, - 1 );
47764			setPoint( 'n4', w, h, - 1 );
47765  
47766			// far
47767  
47768			setPoint( 'f1', - w, - h, 1 );
47769			setPoint( 'f2', w, - h, 1 );
47770			setPoint( 'f3', - w, h, 1 );
47771			setPoint( 'f4', w, h, 1 );
47772  
47773			// up
47774  
47775			setPoint( 'u1', w * 0.7, h * 1.1, - 1 );
47776			setPoint( 'u2', - w * 0.7, h * 1.1, - 1 );
47777			setPoint( 'u3', 0, h * 2, - 1 );
47778  
47779			// cross
47780  
47781			setPoint( 'cf1', - w, 0, 1 );
47782			setPoint( 'cf2', w, 0, 1 );
47783			setPoint( 'cf3', 0, - h, 1 );
47784			setPoint( 'cf4', 0, h, 1 );
47785  
47786			setPoint( 'cn1', - w, 0, - 1 );
47787			setPoint( 'cn2', w, 0, - 1 );
47788			setPoint( 'cn3', 0, - h, - 1 );
47789			setPoint( 'cn4', 0, h, - 1 );
47790  
47791			geometry.getAttribute( 'position' ).needsUpdate = true;
47792  
47793		};
47794  
47795	}();
47796  
47797	/**
47798	 * @author mrdoob / http://mrdoob.com/
47799	 * @author Mugen87 / http://github.com/Mugen87
47800	 */
47801  
47802	function BoxHelper( object, color ) {
47803  
47804		this.object = object;
47805  
47806		if ( color === undefined ) color = 0xffff00;
47807  
47808		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 ] );
47809		var positions = new Float32Array( 8 * 3 );
47810  
47811		var geometry = new BufferGeometry();
47812		geometry.setIndex( new BufferAttribute( indices, 1 ) );
47813		geometry.addAttribute( 'position', new BufferAttribute( positions, 3 ) );
47814  
47815		LineSegments.call( this, geometry, new LineBasicMaterial( { color: color } ) );
47816  
47817		this.matrixAutoUpdate = false;
vendor: 8,404 bytes, lines 47818-48154
47818  
47819		this.update();
47820  
47821	}
47822  
47823	BoxHelper.prototype = Object.create( LineSegments.prototype );
47824	BoxHelper.prototype.constructor = BoxHelper;
47825  
47826	BoxHelper.prototype.update = ( function () {
47827  
47828		var box = new Box3();
47829  
47830		return function update( object ) {
47831  
47832			if ( object !== undefined ) {
47833  
47834				console.warn( 'THREE.BoxHelper: .update() has no longer arguments.' );
47835  
47836			}
47837  
47838			if ( this.object !== undefined ) {
47839  
47840				box.setFromObject( this.object );
47841  
47842			}
47843  
47844			if ( box.isEmpty() ) return;
47845  
47846			var min = box.min;
47847			var max = box.max;
47848  
47849			/*
47850			  5____4
47851			1/___0/|
47852			| 6__|_7
47853			2/___3/
47854  
47855			0: max.x, max.y, max.z
47856			1: min.x, max.y, max.z
47857			2: min.x, min.y, max.z
47858			3: max.x, min.y, max.z
47859			4: max.x, max.y, min.z
47860			5: min.x, max.y, min.z
47861			6: min.x, min.y, min.z
47862			7: max.x, min.y, min.z
47863			*/
47864  
47865			var position = this.geometry.attributes.position;
47866			var array = position.array;
47867  
47868			array[ 0 ] = max.x; array[ 1 ] = max.y; array[ 2 ] = max.z;
47869			array[ 3 ] = min.x; array[ 4 ] = max.y; array[ 5 ] = max.z;
47870			array[ 6 ] = min.x; array[ 7 ] = min.y; array[ 8 ] = max.z;
47871			array[ 9 ] = max.x; array[ 10 ] = min.y; array[ 11 ] = max.z;
47872			array[ 12 ] = max.x; array[ 13 ] = max.y; array[ 14 ] = min.z;
47873			array[ 15 ] = min.x; array[ 16 ] = max.y; array[ 17 ] = min.z;
47874			array[ 18 ] = min.x; array[ 19 ] = min.y; array[ 20 ] = min.z;
47875			array[ 21 ] = max.x; array[ 22 ] = min.y; array[ 23 ] = min.z;
47876  
47877			position.needsUpdate = true;
47878  
47879			this.geometry.computeBoundingSphere();
47880  
47881		};
47882  
47883	} )();
47884  
47885	BoxHelper.prototype.setFromObject = function ( object ) {
47886  
47887		this.object = object;
47888		this.update();
47889  
47890		return this;
47891  
47892	};
47893  
47894	/**
47895	 * @author WestLangley / http://github.com/WestLangley
47896	 */
47897  
47898	function Box3Helper( box, hex ) {
47899  
47900		this.type = 'Box3Helper';
47901  
47902		this.box = box;
47903  
47904		var color = ( hex !== undefined ) ? hex : 0xffff00;
47905  
47906		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 ] );
47907  
47908		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 ];
47909  
47910		var geometry = new BufferGeometry();
47911  
47912		geometry.setIndex( new BufferAttribute( indices, 1 ) );
47913  
47914		geometry.addAttribute( 'position', new Float32BufferAttribute( positions, 3 ) );
47915  
47916		LineSegments.call( this, geometry, new LineBasicMaterial( { color: color } ) );
47917  
47918		this.geometry.computeBoundingSphere();
47919  
47920	}
47921  
47922	Box3Helper.prototype = Object.create( LineSegments.prototype );
47923	Box3Helper.prototype.constructor = Box3Helper;
47924  
47925	Box3Helper.prototype.updateMatrixWorld = function ( force ) {
47926  
47927		var box = this.box;
47928  
47929		if ( box.isEmpty() ) return;
47930  
47931		box.getCenter( this.position );
47932  
47933		box.getSize( this.scale );
47934  
47935		this.scale.multiplyScalar( 0.5 );
47936  
47937		Object3D.prototype.updateMatrixWorld.call( this, force );
47938  
47939	};
47940  
47941	/**
47942	 * @author WestLangley / http://github.com/WestLangley
47943	 */
47944  
47945	function PlaneHelper( plane, size, hex ) {
47946  
47947		this.type = 'PlaneHelper';
47948  
47949		this.plane = plane;
47950  
47951		this.size = ( size === undefined ) ? 1 : size;
47952  
47953		var color = ( hex !== undefined ) ? hex : 0xffff00;
47954  
47955		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 ];
47956  
47957		var geometry = new BufferGeometry();
47958		geometry.addAttribute( 'position', new Float32BufferAttribute( positions, 3 ) );
47959		geometry.computeBoundingSphere();
47960  
47961		Line.call( this, geometry, new LineBasicMaterial( { color: color } ) );
47962  
47963		//
47964  
47965		var positions2 = [ 1, 1, 1, - 1, 1, 1, - 1, - 1, 1, 1, 1, 1, - 1, - 1, 1, 1, - 1, 1 ];
47966  
47967		var geometry2 = new BufferGeometry();
47968		geometry2.addAttribute( 'position', new Float32BufferAttribute( positions2, 3 ) );
47969		geometry2.computeBoundingSphere();
47970  
47971		this.add( new Mesh( geometry2, new MeshBasicMaterial( { color: color, opacity: 0.2, transparent: true, depthWrite: false } ) ) );
47972  
47973	}
47974  
47975	PlaneHelper.prototype = Object.create( Line.prototype );
47976	PlaneHelper.prototype.constructor = PlaneHelper;
47977  
47978	PlaneHelper.prototype.updateMatrixWorld = function ( force ) {
47979  
47980		var scale = - this.plane.constant;
47981  
47982		if ( Math.abs( scale ) < 1e-8 ) scale = 1e-8; // sign does not matter
47983  
47984		this.scale.set( 0.5 * this.size, 0.5 * this.size, scale );
47985  
47986		this.children[ 0 ].material.side = ( scale < 0 ) ? BackSide : FrontSide; // renderer flips side when determinant < 0; flipping not wanted here
47987  
47988		this.lookAt( this.plane.normal );
47989  
47990		Object3D.prototype.updateMatrixWorld.call( this, force );
47991  
47992	};
47993  
47994	/**
47995	 * @author WestLangley / http://github.com/WestLangley
47996	 * @author zz85 / http://github.com/zz85
47997	 * @author bhouston / http://clara.io
47998	 *
47999	 * Creates an arrow for visualizing directions
48000	 *
48001	 * Parameters:
48002	 *  dir - Vector3
48003	 *  origin - Vector3
48004	 *  length - Number
48005	 *  color - color in hex value
48006	 *  headLength - Number
48007	 *  headWidth - Number
48008	 */
48009  
48010	var lineGeometry, coneGeometry;
48011  
48012	function ArrowHelper( dir, origin, length, color, headLength, headWidth ) {
48013  
48014		// dir is assumed to be normalized
48015  
48016		Object3D.call( this );
48017  
48018		if ( color === undefined ) color = 0xffff00;
48019		if ( length === undefined ) length = 1;
48020		if ( headLength === undefined ) headLength = 0.2 * length;
48021		if ( headWidth === undefined ) headWidth = 0.2 * headLength;
48022  
48023		if ( lineGeometry === undefined ) {
48024  
48025			lineGeometry = new BufferGeometry();
48026			lineGeometry.addAttribute( 'position', new Float32BufferAttribute( [ 0, 0, 0, 0, 1, 0 ], 3 ) );
48027  
48028			coneGeometry = new CylinderBufferGeometry( 0, 0.5, 1, 5, 1 );
48029			coneGeometry.translate( 0, - 0.5, 0 );
48030  
48031		}
48032  
48033		this.position.copy( origin );
48034  
48035		this.line = new Line( lineGeometry, new LineBasicMaterial( { color: color } ) );
48036		this.line.matrixAutoUpdate = false;
48037		this.add( this.line );
48038  
48039		this.cone = new Mesh( coneGeometry, new MeshBasicMaterial( { color: color } ) );
48040		this.cone.matrixAutoUpdate = false;
48041		this.add( this.cone );
48042  
48043		this.setDirection( dir );
48044		this.setLength( length, headLength, headWidth );
48045  
48046	}
48047  
48048	ArrowHelper.prototype = Object.create( Object3D.prototype );
48049	ArrowHelper.prototype.constructor = ArrowHelper;
48050  
48051	ArrowHelper.prototype.setDirection = ( function () {
48052  
48053		var axis = new Vector3();
48054		var radians;
48055  
48056		return function setDirection( dir ) {
48057  
48058			// dir is assumed to be normalized
48059  
48060			if ( dir.y > 0.99999 ) {
48061  
48062				this.quaternion.set( 0, 0, 0, 1 );
48063  
48064			} else if ( dir.y < - 0.99999 ) {
48065  
48066				this.quaternion.set( 1, 0, 0, 0 );
48067  
48068			} else {
48069  
48070				axis.set( dir.z, 0, - dir.x ).normalize();
48071  
48072				radians = Math.acos( dir.y );
48073  
48074				this.quaternion.setFromAxisAngle( axis, radians );
48075  
48076			}
48077  
48078		};
48079  
48080	}() );
48081  
48082	ArrowHelper.prototype.setLength = function ( length, headLength, headWidth ) {
48083  
48084		if ( headLength === undefined ) headLength = 0.2 * length;
48085		if ( headWidth === undefined ) headWidth = 0.2 * headLength;
48086  
48087		this.line.scale.set( 1, Math.max( 0, length - headLength ), 1 );
48088		this.line.updateMatrix();
48089  
48090		this.cone.scale.set( headWidth, headLength, headWidth );
48091		this.cone.position.y = length;
48092		this.cone.updateMatrix();
48093  
48094	};
48095  
48096	ArrowHelper.prototype.setColor = function ( color ) {
48097  
48098		this.line.material.color.copy( color );
48099		this.cone.material.color.copy( color );
48100  
48101	};
48102  
48103	/**
48104	 * @author sroucheray / http://sroucheray.org/
48105	 * @author mrdoob / http://mrdoob.com/
48106	 */
48107  
48108	function AxesHelper( size ) {
48109  
48110		size = size || 1;
48111  
48112		var vertices = [
48113			0, 0, 0,	size, 0, 0,
48114			0, 0, 0,	0, size, 0,
48115			0, 0, 0,	0, 0, size
48116		];
48117  
48118		var colors = [
48119			1, 0, 0,	1, 0.6, 0,
48120			0, 1, 0,	0.6, 1, 0,
48121			0, 0, 1,	0, 0.6, 1
48122		];
48123  
48124		var geometry = new BufferGeometry();
48125		geometry.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
48126		geometry.addAttribute( 'color', new Float32BufferAttribute( colors, 3 ) );
48127  
48128		var material = new LineBasicMaterial( { vertexColors: VertexColors } );
48129  
48130		LineSegments.call( this, geometry, material );
48131  
48132	}
48133  
48134	AxesHelper.prototype = Object.create( LineSegments.prototype );
48135	AxesHelper.prototype.constructor = AxesHelper;
48136  
48137	//
48138  
48139	Curve.create = function ( construct, getPoint ) {
48140  
48141		console.log( 'THREE.Curve.create() has been deprecated' );
48142  
48143		construct.prototype = Object.create( Curve.prototype );
48144		construct.prototype.constructor = construct;
48145		construct.prototype.getPoint = getPoint;
48146  
48147		return construct;
48148  
48149	};
48150  
48151	//
48152  
48153	Object.assign( CurvePath.prototype, {
48154  
48155		createPointsGeometry: function ( divisions ) {
48156  
48157			console.warn( 'THREE.CurvePath: .createPointsGeometry() has been removed. Use new THREE.Geometry().setFromPoints( points ) instead.' );
48158  
48159			// generate geometry from path points (for Line or Points objects)
48160  
48161			var pts = this.getPoints( divisions );
48162			return this.createGeometry( pts );
48163  
48164		},
48165  
48166		createSpacedPointsGeometry: function ( divisions ) {
48167  
48168			console.warn( 'THREE.CurvePath: .createSpacedPointsGeometry() has been removed. Use new THREE.Geometry().setFromPoints( points ) instead.' );
48169  
48170			// generate geometry from equidistant sampling along the path
48171  
48172			var pts = this.getSpacedPoints( divisions );
48173			return this.createGeometry( pts );
48174  
48175		},
48176  
48177		createGeometry: function ( points ) {
48178  
48179			console.warn( 'THREE.CurvePath: .createGeometry() has been removed. Use new THREE.Geometry().setFromPoints( points ) instead.' );
48180  
48181			var geometry = new Geometry();
48182  
48183			for ( var i = 0, l = points.length; i < l; i ++ ) {
48184  
48185				var point = points[ i ];
48186				geometry.vertices.push( new Vector3( point.x, point.y, point.z || 0 ) );
48187  
48188			}
48189  
48190			return geometry;
48191  
48192		}
48193  
48194	} );
48195  
48196	//
48197  
48198	Object.assign( Path.prototype, {
48199  
48200		fromPoints: function ( points ) {
48201  
48202			console.warn( 'THREE.Path: .fromPoints() has been renamed to .setFromPoints().' );
48203			this.setFromPoints( points );
48204  
48205		}
48206  
48207	} );
48208  
48209	//
48210  
48211	function Spline( points ) {
48212  
48213		console.warn( 'THREE.Spline has been removed. Use THREE.CatmullRomCurve3 instead.' );
48214  
48215		CatmullRomCurve3.call( this, points );
48216		this.type = 'catmullrom';
48217  
48218	}
48219  
48220	Spline.prototype = Object.create( CatmullRomCurve3.prototype );
48221  
48222	Object.assign( Spline.prototype, {
48223  
48224		initFromArray: function ( /* a */ ) {
48225  
48226			console.error( 'THREE.Spline: .initFromArray() has been removed.' );
48227  
48228		},
48229		getControlPointsArray: function ( /* optionalTarget */ ) {
48230  
48231			console.error( 'THREE.Spline: .getControlPointsArray() has been removed.' );
48232  
48233		},
48234		reparametrizeByArcLength: function ( /* samplingCoef */ ) {
48235  
48236			console.error( 'THREE.Spline: .reparametrizeByArcLength() has been removed.' );
48237  
48238		}
48239  
48240	} );
48241  
48242	GridHelper.prototype.setColors = function () {
48243  
48244		console.error( 'THREE.GridHelper: setColors() has been deprecated, pass them in the constructor instead.' );
48245  
48246	};
48247  
48248	SkeletonHelper.prototype.update = function () {
48249  
48250		console.error( 'THREE.SkeletonHelper: update() no longer needs to be called.' );
48251  
48252	};
48253  
48254	//
48255  
48256	Object.assign( Loader.prototype, {
48257  
48258		extractUrlBase: function ( url ) {
48259  
48260			console.warn( 'THREE.Loader: .extractUrlBase() has been deprecated. Use THREE.LoaderUtils.extractUrlBase() instead.' );
48261			return LoaderUtils.extractUrlBase( url );
48262  
48263		}
48264  
48265	} );
48266  
48267	//
48268  
48269	Object.assign( Box2.prototype, {
48270  
48271		center: function ( optionalTarget ) {
48272  
48273			console.warn( 'THREE.Box2: .center() has been renamed to .getCenter().' );
48274			return this.getCenter( optionalTarget );
48275  
48276		},
48277		empty: function () {
48278  
48279			console.warn( 'THREE.Box2: .empty() has been renamed to .isEmpty().' );
48280			return this.isEmpty();
48281  
48282		},
48283		isIntersectionBox: function ( box ) {
48284  
48285			console.warn( 'THREE.Box2: .isIntersectionBox() has been renamed to .intersectsBox().' );
48286			return this.intersectsBox( box );
48287  
48288		},
48289		size: function ( optionalTarget ) {
48290  
48291			console.warn( 'THREE.Box2: .size() has been renamed to .getSize().' );
48292			return this.getSize( optionalTarget );
48293  
48294		}
48295	} );
48296  
48297	Object.assign( Box3.prototype, {
48298  
48299		center: function ( optionalTarget ) {
48300  
48301			console.warn( 'THREE.Box3: .center() has been renamed to .getCenter().' );
48302			return this.getCenter( optionalTarget );
48303  
48304		},
48305		empty: function () {
48306  
48307			console.warn( 'THREE.Box3: .empty() has been renamed to .isEmpty().' );
48308			return this.isEmpty();
48309  
48310		},
48311		isIntersectionBox: function ( box ) {
48312  
48313			console.warn( 'THREE.Box3: .isIntersectionBox() has been renamed to .intersectsBox().' );
48314			return this.intersectsBox( box );
48315  
48316		},
48317		isIntersectionSphere: function ( sphere ) {
48318  
48319			console.warn( 'THREE.Box3: .isIntersectionSphere() has been renamed to .intersectsSphere().' );
48320			return this.intersectsSphere( sphere );
48321  
48322		},
48323		size: function ( optionalTarget ) {
48324  
48325			console.warn( 'THREE.Box3: .size() has been renamed to .getSize().' );
48326			return this.getSize( optionalTarget );
48327  
48328		}
48329	} );
48330  
48331	Line3.prototype.center = function ( optionalTarget ) {
48332  
48333		console.warn( 'THREE.Line3: .center() has been renamed to .getCenter().' );
48334		return this.getCenter( optionalTarget );
48335  
48336	};
48337  
48338	Object.assign( _Math, {
48339  
48340		random16: function () {
48341  
48342			console.warn( 'THREE.Math: .random16() has been deprecated. Use Math.random() instead.' );
48343			return Math.random();
48344  
48345		},
48346  
48347		nearestPowerOfTwo: function ( value ) {
48348  
48349			console.warn( 'THREE.Math: .nearestPowerOfTwo() has been renamed to .floorPowerOfTwo().' );
48350			return _Math.floorPowerOfTwo( value );
48351  
48352		},
48353  
48354		nextPowerOfTwo: function ( value ) {
48355  
48356			console.warn( 'THREE.Math: .nextPowerOfTwo() has been renamed to .ceilPowerOfTwo().' );
48357			return _Math.ceilPowerOfTwo( value );
48358  
48359		}
48360  
48361	} );
48362  
48363	Object.assign( Matrix3.prototype, {
48364  
48365		flattenToArrayOffset: function ( array, offset ) {
48366  
48367			console.warn( "THREE.Matrix3: .flattenToArrayOffset() has been deprecated. Use .toArray() instead." );
48368			return this.toArray( array, offset );
48369  
48370		},
48371		multiplyVector3: function ( vector ) {
48372  
48373			console.warn( 'THREE.Matrix3: .multiplyVector3() has been removed. Use vector.applyMatrix3( matrix ) instead.' );
48374			return vector.applyMatrix3( this );
48375  
48376		},
48377		multiplyVector3Array: function ( /* a */ ) {
48378  
48379			console.error( 'THREE.Matrix3: .multiplyVector3Array() has been removed.' );
48380  
48381		},
48382		applyToBuffer: function ( buffer /*, offset, length */ ) {
48383  
48384			console.warn( 'THREE.Matrix3: .applyToBuffer() has been removed. Use matrix.applyToBufferAttribute( attribute ) instead.' );
48385			return this.applyToBufferAttribute( buffer );
48386  
48387		},
48388		applyToVector3Array: function ( /* array, offset, length */ ) {
48389  
48390			console.error( 'THREE.Matrix3: .applyToVector3Array() has been removed.' );
48391  
48392		}
48393  
48394	} );
48395  
48396	Object.assign( Matrix4.prototype, {
48397  
48398		extractPosition: function ( m ) {
48399  
48400			console.warn( 'THREE.Matrix4: .extractPosition() has been renamed to .copyPosition().' );
48401			return this.copyPosition( m );
48402  
48403		},
48404		flattenToArrayOffset: function ( array, offset ) {
48405  
48406			console.warn( "THREE.Matrix4: .flattenToArrayOffset() has been deprecated. Use .toArray() instead." );
48407			return this.toArray( array, offset );
48408  
48409		},
48410		getPosition: function () {
48411  
48412			var v1;
48413  
48414			return function getPosition() {
48415  
48416				if ( v1 === undefined ) v1 = new Vector3();
48417				console.warn( 'THREE.Matrix4: .getPosition() has been removed. Use Vector3.setFromMatrixPosition( matrix ) instead.' );
48418				return v1.setFromMatrixColumn( this, 3 );
48419  
48420			};
48421  
48422		}(),
48423		setRotationFromQuaternion: function ( q ) {
48424  
48425			console.warn( 'THREE.Matrix4: .setRotationFromQuaternion() has been renamed to .makeRotationFromQuaternion().' );
48426			return this.makeRotationFromQuaternion( q );
48427  
48428		},
48429		multiplyToArray: function () {
48430  
48431			console.warn( 'THREE.Matrix4: .multiplyToArray() has been removed.' );
48432  
48433		},
48434		multiplyVector3: function ( vector ) {
48435  
48436			console.warn( 'THREE.Matrix4: .multiplyVector3() has been removed. Use vector.applyMatrix4( matrix ) instead.' );
48437			return vector.applyMatrix4( this );
48438  
48439		},
48440		multiplyVector4: function ( vector ) {
48441  
48442			console.warn( 'THREE.Matrix4: .multiplyVector4() has been removed. Use vector.applyMatrix4( matrix ) instead.' );
48443			return vector.applyMatrix4( this );
48444  
48445		},
48446		multiplyVector3Array: function ( /* a */ ) {
48447  
48448			console.error( 'THREE.Matrix4: .multiplyVector3Array() has been removed.' );
48449  
48450		},
48451		rotateAxis: function ( v ) {
48452  
48453			console.warn( 'THREE.Matrix4: .rotateAxis() has been removed. Use Vector3.transformDirection( matrix ) instead.' );
48454			v.transformDirection( this );
48455  
48456		},
48457		crossVector: function ( vector ) {
48458  
48459			console.warn( 'THREE.Matrix4: .crossVector() has been removed. Use vector.applyMatrix4( matrix ) instead.' );
48460			return vector.applyMatrix4( this );
48461  
48462		},
48463		translate: function () {
48464  
48465			console.error( 'THREE.Matrix4: .translate() has been removed.' );
48466  
48467		},
48468		rotateX: function () {
48469  
48470			console.error( 'THREE.Matrix4: .rotateX() has been removed.' );
48471  
48472		},
48473		rotateY: function () {
48474  
48475			console.error( 'THREE.Matrix4: .rotateY() has been removed.' );
48476  
48477		},
48478		rotateZ: function () {
48479  
48480			console.error( 'THREE.Matrix4: .rotateZ() has been removed.' );
48481  
48482		},
48483		rotateByAxis: function () {
48484  
48485			console.error( 'THREE.Matrix4: .rotateByAxis() has been removed.' );
48486  
48487		},
48488		applyToBuffer: function ( buffer /*, offset, length */ ) {
48489  
48490			console.warn( 'THREE.Matrix4: .applyToBuffer() has been removed. Use matrix.applyToBufferAttribute( attribute ) instead.' );
48491			return this.applyToBufferAttribute( buffer );
48492  
48493		},
48494		applyToVector3Array: function ( /* array, offset, length */ ) {
48495  
48496			console.error( 'THREE.Matrix4: .applyToVector3Array() has been removed.' );
48497  
48498		},
48499		makeFrustum: function ( left, right, bottom, top, near, far ) {
48500  
48501			console.warn( 'THREE.Matrix4: .makeFrustum() has been removed. Use .makePerspective( left, right, top, bottom, near, far ) instead.' );
48502			return this.makePerspective( left, right, top, bottom, near, far );
48503  
48504		}
48505  
48506	} );
48507  
48508	Plane.prototype.isIntersectionLine = function ( line ) {
48509  
48510		console.warn( 'THREE.Plane: .isIntersectionLine() has been renamed to .intersectsLine().' );
48511		return this.intersectsLine( line );
48512  
48513	};
48514  
48515	Quaternion.prototype.multiplyVector3 = function ( vector ) {
48516  
48517		console.warn( 'THREE.Quaternion: .multiplyVector3() has been removed. Use is now vector.applyQuaternion( quaternion ) instead.' );
48518		return vector.applyQuaternion( this );
48519  
48520	};
48521  
48522	Object.assign( Ray.prototype, {
48523  
48524		isIntersectionBox: function ( box ) {
48525  
48526			console.warn( 'THREE.Ray: .isIntersectionBox() has been renamed to .intersectsBox().' );
48527			return this.intersectsBox( box );
48528  
48529		},
48530		isIntersectionPlane: function ( plane ) {
48531  
48532			console.warn( 'THREE.Ray: .isIntersectionPlane() has been renamed to .intersectsPlane().' );
48533			return this.intersectsPlane( plane );
48534  
48535		},
48536		isIntersectionSphere: function ( sphere ) {
48537  
48538			console.warn( 'THREE.Ray: .isIntersectionSphere() has been renamed to .intersectsSphere().' );
48539			return this.intersectsSphere( sphere );
48540  
48541		}
48542  
48543	} );
48544  
48545	Object.assign( Triangle.prototype, {
48546  
48547		area: function () {
48548  
48549			console.warn( 'THREE.Triangle: .area() has been renamed to .getArea().' );
48550			return this.getArea();
48551  
48552		},
48553		barycoordFromPoint: function ( point, target ) {
48554  
48555			console.warn( 'THREE.Triangle: .barycoordFromPoint() has been renamed to .getBarycoord().' );
48556			return this.getBarycoord( point, target );
48557  
48558		},
48559		midpoint: function ( target ) {
48560  
48561			console.warn( 'THREE.Triangle: .midpoint() has been renamed to .getMidpoint().' );
48562			return this.getMidpoint( target );
48563  
48564		},
48565		normal: function ( target ) {
48566  
48567			console.warn( 'THREE.Triangle: .normal() has been renamed to .getNormal().' );
48568			return this.getNormal( target );
48569  
48570		},
48571		plane: function ( target ) {
48572  
48573			console.warn( 'THREE.Triangle: .plane() has been renamed to .getPlane().' );
48574			return this.getPlane( target );
48575  
48576		}
48577  
48578	} );
48579  
48580	Object.assign( Triangle, {
48581  
48582		barycoordFromPoint: function ( point, a, b, c, target ) {
48583  
48584			console.warn( 'THREE.Triangle: .barycoordFromPoint() has been renamed to .getBarycoord().' );
48585			return Triangle.getBarycoord( point, a, b, c, target );
48586  
48587		},
48588		normal: function ( a, b, c, target ) {
48589  
48590			console.warn( 'THREE.Triangle: .normal() has been renamed to .getNormal().' );
48591			return Triangle.getNormal( a, b, c, target );
48592  
48593		}
48594  
48595	} );
48596  
48597	Object.assign( Shape.prototype, {
48598  
48599		extractAllPoints: function ( divisions ) {
48600  
48601			console.warn( 'THREE.Shape: .extractAllPoints() has been removed. Use .extractPoints() instead.' );
48602			return this.extractPoints( divisions );
48603  
48604		},
48605		extrude: function ( options ) {
48606  
48607			console.warn( 'THREE.Shape: .extrude() has been removed. Use ExtrudeGeometry() instead.' );
48608			return new ExtrudeGeometry( this, options );
48609  
48610		},
48611		makeGeometry: function ( options ) {
48612  
48613			console.warn( 'THREE.Shape: .makeGeometry() has been removed. Use ShapeGeometry() instead.' );
48614			return new ShapeGeometry( this, options );
48615  
48616		}
48617  
48618	} );
48619  
48620	Object.assign( Vector2.prototype, {
48621  
48622		fromAttribute: function ( attribute, index, offset ) {
48623  
48624			console.warn( 'THREE.Vector2: .fromAttribute() has been renamed to .fromBufferAttribute().' );
48625			return this.fromBufferAttribute( attribute, index, offset );
48626  
48627		},
48628		distanceToManhattan: function ( v ) {
48629  
48630			console.warn( 'THREE.Vector2: .distanceToManhattan() has been renamed to .manhattanDistanceTo().' );
48631			return this.manhattanDistanceTo( v );
48632  
48633		},
48634		lengthManhattan: function () {
48635  
48636			console.warn( 'THREE.Vector2: .lengthManhattan() has been renamed to .manhattanLength().' );
48637			return this.manhattanLength();
48638  
48639		}
48640  
48641	} );
48642  
48643	Object.assign( Vector3.prototype, {
48644  
48645		setEulerFromRotationMatrix: function () {
48646  
48647			console.error( 'THREE.Vector3: .setEulerFromRotationMatrix() has been removed. Use Euler.setFromRotationMatrix() instead.' );
48648  
48649		},
48650		setEulerFromQuaternion: function () {
48651  
48652			console.error( 'THREE.Vector3: .setEulerFromQuaternion() has been removed. Use Euler.setFromQuaternion() instead.' );
48653  
48654		},
48655		getPositionFromMatrix: function ( m ) {
48656  
48657			console.warn( 'THREE.Vector3: .getPositionFromMatrix() has been renamed to .setFromMatrixPosition().' );
48658			return this.setFromMatrixPosition( m );
48659  
48660		},
48661		getScaleFromMatrix: function ( m ) {
48662  
48663			console.warn( 'THREE.Vector3: .getScaleFromMatrix() has been renamed to .setFromMatrixScale().' );
48664			return this.setFromMatrixScale( m );
48665  
48666		},
48667		getColumnFromMatrix: function ( index, matrix ) {
48668  
48669			console.warn( 'THREE.Vector3: .getColumnFromMatrix() has been renamed to .setFromMatrixColumn().' );
48670			return this.setFromMatrixColumn( matrix, index );
48671  
48672		},
48673		applyProjection: function ( m ) {
48674  
48675			console.warn( 'THREE.Vector3: .applyProjection() has been removed. Use .applyMatrix4( m ) instead.' );
48676			return this.applyMatrix4( m );
48677  
48678		},
48679		fromAttribute: function ( attribute, index, offset ) {
48680  
48681			console.warn( 'THREE.Vector3: .fromAttribute() has been renamed to .fromBufferAttribute().' );
48682			return this.fromBufferAttribute( attribute, index, offset );
48683  
48684		},
48685		distanceToManhattan: function ( v ) {
48686  
48687			console.warn( 'THREE.Vector3: .distanceToManhattan() has been renamed to .manhattanDistanceTo().' );
48688			return this.manhattanDistanceTo( v );
48689  
48690		},
48691		lengthManhattan: function () {
48692  
48693			console.warn( 'THREE.Vector3: .lengthManhattan() has been renamed to .manhattanLength().' );
48694			return this.manhattanLength();
48695  
48696		}
48697  
48698	} );
48699  
48700	Object.assign( Vector4.prototype, {
48701  
48702		fromAttribute: function ( attribute, index, offset ) {
48703  
48704			console.warn( 'THREE.Vector4: .fromAttribute() has been renamed to .fromBufferAttribute().' );
48705			return this.fromBufferAttribute( attribute, index, offset );
48706  
48707		},
48708		lengthManhattan: function () {
48709  
48710			console.warn( 'THREE.Vector4: .lengthManhattan() has been renamed to .manhattanLength().' );
48711			return this.manhattanLength();
48712  
48713		}
48714  
48715	} );
48716  
48717	//
48718  
48719	Object.assign( Geometry.prototype, {
48720  
48721		computeTangents: function () {
48722  
48723			console.error( 'THREE.Geometry: .computeTangents() has been removed.' );
48724  
48725		},
48726		computeLineDistances: function () {
48727  
48728			console.error( 'THREE.Geometry: .computeLineDistances() has been removed. Use THREE.Line.computeLineDistances() instead.' );
48729  
48730		}
48731  
48732	} );
48733  
48734	Object.assign( Object3D.prototype, {
48735  
48736		getChildByName: function ( name ) {
48737  
48738			console.warn( 'THREE.Object3D: .getChildByName() has been renamed to .getObjectByName().' );
48739			return this.getObjectByName( name );
48740  
48741		},
48742		renderDepth: function () {
48743  
48744			console.warn( 'THREE.Object3D: .renderDepth has been removed. Use .renderOrder, instead.' );
48745  
48746		},
48747		translate: function ( distance, axis ) {
48748  
48749			console.warn( 'THREE.Object3D: .translate() has been removed. Use .translateOnAxis( axis, distance ) instead.' );
48750			return this.translateOnAxis( axis, distance );
48751  
48752		},
48753		getWorldRotation: function () {
48754  
48755			console.error( 'THREE.Object3D: .getWorldRotation() has been removed. Use THREE.Object3D.getWorldQuaternion( target ) instead.' );
48756  
48757		}
48758  
48759	} );
48760  
48761	Object.defineProperties( Object3D.prototype, {
48762  
vendor: 4,278 bytes, lines 48763-48958
48763		eulerOrder: {
48764			get: function () {
48765  
48766				console.warn( 'THREE.Object3D: .eulerOrder is now .rotation.order.' );
48767				return this.rotation.order;
48768  
48769			},
48770			set: function ( value ) {
48771  
48772				console.warn( 'THREE.Object3D: .eulerOrder is now .rotation.order.' );
48773				this.rotation.order = value;
48774  
48775			}
48776		},
48777		useQuaternion: {
48778			get: function () {
48779  
48780				console.warn( 'THREE.Object3D: .useQuaternion has been removed. The library now uses quaternions by default.' );
48781  
48782			},
48783			set: function () {
48784  
48785				console.warn( 'THREE.Object3D: .useQuaternion has been removed. The library now uses quaternions by default.' );
48786  
48787			}
48788		}
48789  
48790	} );
48791  
48792	Object.defineProperties( LOD.prototype, {
48793  
48794		objects: {
48795			get: function () {
48796  
48797				console.warn( 'THREE.LOD: .objects has been renamed to .levels.' );
48798				return this.levels;
48799  
48800			}
48801		}
48802  
48803	} );
48804  
48805	Object.defineProperty( Skeleton.prototype, 'useVertexTexture', {
48806  
48807		get: function () {
48808  
48809			console.warn( 'THREE.Skeleton: useVertexTexture has been removed.' );
48810  
48811		},
48812		set: function () {
48813  
48814			console.warn( 'THREE.Skeleton: useVertexTexture has been removed.' );
48815  
48816		}
48817  
48818	} );
48819  
48820	Object.defineProperty( Curve.prototype, '__arcLengthDivisions', {
48821  
48822		get: function () {
48823  
48824			console.warn( 'THREE.Curve: .__arcLengthDivisions is now .arcLengthDivisions.' );
48825			return this.arcLengthDivisions;
48826  
48827		},
48828		set: function ( value ) {
48829  
48830			console.warn( 'THREE.Curve: .__arcLengthDivisions is now .arcLengthDivisions.' );
48831			this.arcLengthDivisions = value;
48832  
48833		}
48834  
48835	} );
48836  
48837	//
48838  
48839	PerspectiveCamera.prototype.setLens = function ( focalLength, filmGauge ) {
48840  
48841		console.warn( "THREE.PerspectiveCamera.setLens is deprecated. " +
48842				"Use .setFocalLength and .filmGauge for a photographic setup." );
48843  
48844		if ( filmGauge !== undefined ) this.filmGauge = filmGauge;
48845		this.setFocalLength( focalLength );
48846  
48847	};
48848  
48849	//
48850  
48851	Object.defineProperties( Light.prototype, {
48852		onlyShadow: {
48853			set: function () {
48854  
48855				console.warn( 'THREE.Light: .onlyShadow has been removed.' );
48856  
48857			}
48858		},
48859		shadowCameraFov: {
48860			set: function ( value ) {
48861  
48862				console.warn( 'THREE.Light: .shadowCameraFov is now .shadow.camera.fov.' );
48863				this.shadow.camera.fov = value;
48864  
48865			}
48866		},
48867		shadowCameraLeft: {
48868			set: function ( value ) {
48869  
48870				console.warn( 'THREE.Light: .shadowCameraLeft is now .shadow.camera.left.' );
48871				this.shadow.camera.left = value;
48872  
48873			}
48874		},
48875		shadowCameraRight: {
48876			set: function ( value ) {
48877  
48878				console.warn( 'THREE.Light: .shadowCameraRight is now .shadow.camera.right.' );
48879				this.shadow.camera.right = value;
48880  
48881			}
48882		},
48883		shadowCameraTop: {
48884			set: function ( value ) {
48885  
48886				console.warn( 'THREE.Light: .shadowCameraTop is now .shadow.camera.top.' );
48887				this.shadow.camera.top = value;
48888  
48889			}
48890		},
48891		shadowCameraBottom: {
48892			set: function ( value ) {
48893  
48894				console.warn( 'THREE.Light: .shadowCameraBottom is now .shadow.camera.bottom.' );
48895				this.shadow.camera.bottom = value;
48896  
48897			}
48898		},
48899		shadowCameraNear: {
48900			set: function ( value ) {
48901  
48902				console.warn( 'THREE.Light: .shadowCameraNear is now .shadow.camera.near.' );
48903				this.shadow.camera.near = value;
48904  
48905			}
48906		},
48907		shadowCameraFar: {
48908			set: function ( value ) {
48909  
48910				console.warn( 'THREE.Light: .shadowCameraFar is now .shadow.camera.far.' );
48911				this.shadow.camera.far = value;
48912  
48913			}
48914		},
48915		shadowCameraVisible: {
48916			set: function () {
48917  
48918				console.warn( 'THREE.Light: .shadowCameraVisible has been removed. Use new THREE.CameraHelper( light.shadow.camera ) instead.' );
48919  
48920			}
48921		},
48922		shadowBias: {
48923			set: function ( value ) {
48924  
48925				console.warn( 'THREE.Light: .shadowBias is now .shadow.bias.' );
48926				this.shadow.bias = value;
48927  
48928			}
48929		},
48930		shadowDarkness: {
48931			set: function () {
48932  
48933				console.warn( 'THREE.Light: .shadowDarkness has been removed.' );
48934  
48935			}
48936		},
48937		shadowMapWidth: {
48938			set: function ( value ) {
48939  
48940				console.warn( 'THREE.Light: .shadowMapWidth is now .shadow.mapSize.width.' );
48941				this.shadow.mapSize.width = value;
48942  
48943			}
48944		},
48945		shadowMapHeight: {
48946			set: function ( value ) {
48947  
48948				console.warn( 'THREE.Light: .shadowMapHeight is now .shadow.mapSize.height.' );
48949				this.shadow.mapSize.height = value;
48950  
48951			}
48952		}
48953	} );
48954  
48955	//
48956  
48957	Object.defineProperties( BufferAttribute.prototype, {
48958  
vendor: 1,325 bytes, lines 48959-49014
48959		length: {
48960			get: function () {
48961  
48962				console.warn( 'THREE.BufferAttribute: .length has been deprecated. Use .count instead.' );
48963				return this.array.length;
48964  
48965			}
48966		},
48967		copyIndicesArray: function ( /* indices */ ) {
48968  
48969			console.error( 'THREE.BufferAttribute: .copyIndicesArray() has been removed.' );
48970  
48971		}
48972  
48973	} );
48974  
48975	Object.assign( BufferGeometry.prototype, {
48976  
48977		addIndex: function ( index ) {
48978  
48979			console.warn( 'THREE.BufferGeometry: .addIndex() has been renamed to .setIndex().' );
48980			this.setIndex( index );
48981  
48982		},
48983		addDrawCall: function ( start, count, indexOffset ) {
48984  
48985			if ( indexOffset !== undefined ) {
48986  
48987				console.warn( 'THREE.BufferGeometry: .addDrawCall() no longer supports indexOffset.' );
48988  
48989			}
48990			console.warn( 'THREE.BufferGeometry: .addDrawCall() is now .addGroup().' );
48991			this.addGroup( start, count );
48992  
48993		},
48994		clearDrawCalls: function () {
48995  
48996			console.warn( 'THREE.BufferGeometry: .clearDrawCalls() is now .clearGroups().' );
48997			this.clearGroups();
48998  
48999		},
49000		computeTangents: function () {
49001  
49002			console.warn( 'THREE.BufferGeometry: .computeTangents() has been removed.' );
49003  
49004		},
49005		computeOffsets: function () {
49006  
49007			console.warn( 'THREE.BufferGeometry: .computeOffsets() has been removed.' );
49008  
49009		}
49010  
49011	} );
49012  
49013	Object.defineProperties( BufferGeometry.prototype, {
49014  
vendor: 1,232 bytes, lines 49015-49083
49015		drawcalls: {
49016			get: function () {
49017  
49018				console.error( 'THREE.BufferGeometry: .drawcalls has been renamed to .groups.' );
49019				return this.groups;
49020  
49021			}
49022		},
49023		offsets: {
49024			get: function () {
49025  
49026				console.warn( 'THREE.BufferGeometry: .offsets has been renamed to .groups.' );
49027				return this.groups;
49028  
49029			}
49030		}
49031  
49032	} );
49033  
49034	//
49035  
49036	Object.assign( ExtrudeBufferGeometry.prototype, {
49037  
49038		getArrays: function () {
49039  
49040			console.error( 'THREE.ExtrudeBufferGeometry: .getArrays() has been removed.' );
49041  
49042		},
49043  
49044		addShapeList: function () {
49045  
49046			console.error( 'THREE.ExtrudeBufferGeometry: .addShapeList() has been removed.' );
49047  
49048		},
49049  
49050		addShape: function () {
49051  
49052			console.error( 'THREE.ExtrudeBufferGeometry: .addShape() has been removed.' );
49053  
49054		}
49055  
49056	} );
49057  
49058	//
49059  
49060	Object.defineProperties( Uniform.prototype, {
49061  
49062		dynamic: {
49063			set: function () {
49064  
49065				console.warn( 'THREE.Uniform: .dynamic has been removed. Use object.onBeforeRender() instead.' );
49066  
49067			}
49068		},
49069		onUpdate: {
49070			value: function () {
49071  
49072				console.warn( 'THREE.Uniform: .onUpdate() has been removed. Use object.onBeforeRender() instead.' );
49073				return this;
49074  
49075			}
49076		}
49077  
49078	} );
49079  
49080	//
49081  
49082	Object.defineProperties( Material.prototype, {
49083  
vendor: 1,204 bytes, lines 49084-49140
49084		wrapAround: {
49085			get: function () {
49086  
49087				console.warn( 'THREE.Material: .wrapAround has been removed.' );
49088  
49089			},
49090			set: function () {
49091  
49092				console.warn( 'THREE.Material: .wrapAround has been removed.' );
49093  
49094			}
49095		},
49096		wrapRGB: {
49097			get: function () {
49098  
49099				console.warn( 'THREE.Material: .wrapRGB has been removed.' );
49100				return new Color();
49101  
49102			}
49103		},
49104  
49105		shading: {
49106			get: function () {
49107  
49108				console.error( 'THREE.' + this.type + ': .shading has been removed. Use the boolean .flatShading instead.' );
49109  
49110			},
49111			set: function ( value ) {
49112  
49113				console.warn( 'THREE.' + this.type + ': .shading has been removed. Use the boolean .flatShading instead.' );
49114				this.flatShading = ( value === FlatShading );
49115  
49116			}
49117		}
49118  
49119	} );
49120  
49121	Object.defineProperties( MeshPhongMaterial.prototype, {
49122  
49123		metal: {
49124			get: function () {
49125  
49126				console.warn( 'THREE.MeshPhongMaterial: .metal has been removed. Use THREE.MeshStandardMaterial instead.' );
49127				return false;
49128  
49129			},
49130			set: function () {
49131  
49132				console.warn( 'THREE.MeshPhongMaterial: .metal has been removed. Use THREE.MeshStandardMaterial instead' );
49133  
49134			}
49135		}
49136  
49137	} );
49138  
49139	Object.defineProperties( ShaderMaterial.prototype, {
49140  
vendor: 4,060 bytes, lines 49141-49280
49141		derivatives: {
49142			get: function () {
49143  
49144				console.warn( 'THREE.ShaderMaterial: .derivatives has been moved to .extensions.derivatives.' );
49145				return this.extensions.derivatives;
49146  
49147			},
49148			set: function ( value ) {
49149  
49150				console.warn( 'THREE. ShaderMaterial: .derivatives has been moved to .extensions.derivatives.' );
49151				this.extensions.derivatives = value;
49152  
49153			}
49154		}
49155  
49156	} );
49157  
49158	//
49159  
49160	Object.assign( WebGLRenderer.prototype, {
49161  
49162		animate: function ( callback ) {
49163  
49164			console.warn( 'THREE.WebGLRenderer: .animate() is now .setAnimationLoop().' );
49165			this.setAnimationLoop( callback );
49166  
49167		},
49168  
49169		getCurrentRenderTarget: function () {
49170  
49171			console.warn( 'THREE.WebGLRenderer: .getCurrentRenderTarget() is now .getRenderTarget().' );
49172			return this.getRenderTarget();
49173  
49174		},
49175  
49176		getMaxAnisotropy: function () {
49177  
49178			console.warn( 'THREE.WebGLRenderer: .getMaxAnisotropy() is now .capabilities.getMaxAnisotropy().' );
49179			return this.capabilities.getMaxAnisotropy();
49180  
49181		},
49182  
49183		getPrecision: function () {
49184  
49185			console.warn( 'THREE.WebGLRenderer: .getPrecision() is now .capabilities.precision.' );
49186			return this.capabilities.precision;
49187  
49188		},
49189  
49190		resetGLState: function () {
49191  
49192			console.warn( 'THREE.WebGLRenderer: .resetGLState() is now .state.reset().' );
49193			return this.state.reset();
49194  
49195		},
49196  
49197		supportsFloatTextures: function () {
49198  
49199			console.warn( 'THREE.WebGLRenderer: .supportsFloatTextures() is now .extensions.get( \'OES_texture_float\' ).' );
49200			return this.extensions.get( 'OES_texture_float' );
49201  
49202		},
49203		supportsHalfFloatTextures: function () {
49204  
49205			console.warn( 'THREE.WebGLRenderer: .supportsHalfFloatTextures() is now .extensions.get( \'OES_texture_half_float\' ).' );
49206			return this.extensions.get( 'OES_texture_half_float' );
49207  
49208		},
49209		supportsStandardDerivatives: function () {
49210  
49211			console.warn( 'THREE.WebGLRenderer: .supportsStandardDerivatives() is now .extensions.get( \'OES_standard_derivatives\' ).' );
49212			return this.extensions.get( 'OES_standard_derivatives' );
49213  
49214		},
49215		supportsCompressedTextureS3TC: function () {
49216  
49217			console.warn( 'THREE.WebGLRenderer: .supportsCompressedTextureS3TC() is now .extensions.get( \'WEBGL_compressed_texture_s3tc\' ).' );
49218			return this.extensions.get( 'WEBGL_compressed_texture_s3tc' );
49219  
49220		},
49221		supportsCompressedTexturePVRTC: function () {
49222  
49223			console.warn( 'THREE.WebGLRenderer: .supportsCompressedTexturePVRTC() is now .extensions.get( \'WEBGL_compressed_texture_pvrtc\' ).' );
49224			return this.extensions.get( 'WEBGL_compressed_texture_pvrtc' );
49225  
49226		},
49227		supportsBlendMinMax: function () {
49228  
49229			console.warn( 'THREE.WebGLRenderer: .supportsBlendMinMax() is now .extensions.get( \'EXT_blend_minmax\' ).' );
49230			return this.extensions.get( 'EXT_blend_minmax' );
49231  
49232		},
49233		supportsVertexTextures: function () {
49234  
49235			console.warn( 'THREE.WebGLRenderer: .supportsVertexTextures() is now .capabilities.vertexTextures.' );
49236			return this.capabilities.vertexTextures;
49237  
49238		},
49239		supportsInstancedArrays: function () {
49240  
49241			console.warn( 'THREE.WebGLRenderer: .supportsInstancedArrays() is now .extensions.get( \'ANGLE_instanced_arrays\' ).' );
49242			return this.extensions.get( 'ANGLE_instanced_arrays' );
49243  
49244		},
49245		enableScissorTest: function ( boolean ) {
49246  
49247			console.warn( 'THREE.WebGLRenderer: .enableScissorTest() is now .setScissorTest().' );
49248			this.setScissorTest( boolean );
49249  
49250		},
49251		initMaterial: function () {
49252  
49253			console.warn( 'THREE.WebGLRenderer: .initMaterial() has been removed.' );
49254  
49255		},
49256		addPrePlugin: function () {
49257  
49258			console.warn( 'THREE.WebGLRenderer: .addPrePlugin() has been removed.' );
49259  
49260		},
49261		addPostPlugin: function () {
49262  
49263			console.warn( 'THREE.WebGLRenderer: .addPostPlugin() has been removed.' );
49264  
49265		},
49266		updateShadowMap: function () {
49267  
49268			console.warn( 'THREE.WebGLRenderer: .updateShadowMap() has been removed.' );
49269  
49270		},
49271		setFaceCulling: function () {
49272  
49273			console.warn( 'THREE.WebGLRenderer: .setFaceCulling() has been removed.' );
49274  
49275		}
49276  
49277	} );
49278  
49279	Object.defineProperties( WebGLRenderer.prototype, {
49280  
49281		shadowMapEnabled: {
49282			get: function () {
49283  
49284				return this.shadowMap.enabled;
49285  
49286			},
49287			set: function ( value ) {
49288  
49289				console.warn( 'THREE.WebGLRenderer: .shadowMapEnabled is now .shadowMap.enabled.' );
49290				this.shadowMap.enabled = value;
49291  
49292			}
49293		},
49294		shadowMapType: {
49295			get: function () {
49296  
49297				return this.shadowMap.type;
49298  
49299			},
49300			set: function ( value ) {
49301  
49302				console.warn( 'THREE.WebGLRenderer: .shadowMapType is now .shadowMap.type.' );
49303				this.shadowMap.type = value;
49304  
49305			}
49306		},
49307		shadowMapCullFace: {
49308			get: function () {
49309  
49310				console.warn( 'THREE.WebGLRenderer: .shadowMapCullFace has been removed. Set Material.shadowSide instead.' );
49311				return undefined;
49312  
49313			},
49314			set: function ( /* value */ ) {
49315  
49316				console.warn( 'THREE.WebGLRenderer: .shadowMapCullFace has been removed. Set Material.shadowSide instead.' );
49317  
49318			}
49319		}
49320	} );
49321  
49322	Object.defineProperties( WebGLShadowMap.prototype, {
49323  
49324		cullFace: {
49325			get: function () {
49326  
49327				console.warn( 'THREE.WebGLRenderer: .shadowMap.cullFace has been removed. Set Material.shadowSide instead.' );
49328				return undefined;
49329  
49330			},
49331			set: function ( /* cullFace */ ) {
49332  
49333				console.warn( 'THREE.WebGLRenderer: .shadowMap.cullFace has been removed. Set Material.shadowSide instead.' );
49334  
49335			}
49336		},
49337		renderReverseSided: {
49338			get: function () {
49339  
49340				console.warn( 'THREE.WebGLRenderer: .shadowMap.renderReverseSided has been removed. Set Material.shadowSide instead.' );
49341				return undefined;
49342  
49343			},
49344			set: function () {
49345  
49346				console.warn( 'THREE.WebGLRenderer: .shadowMap.renderReverseSided has been removed. Set Material.shadowSide instead.' );
49347  
49348			}
49349		},
49350		renderSingleSided: {
49351			get: function () {
49352  
49353				console.warn( 'THREE.WebGLRenderer: .shadowMap.renderSingleSided has been removed. Set Material.shadowSide instead.' );
49354				return undefined;
49355  
49356			},
49357			set: function () {
49358  
49359				console.warn( 'THREE.WebGLRenderer: .shadowMap.renderSingleSided has been removed. Set Material.shadowSide instead.' );
49360  
49361			}
49362		}
49363  
49364	} );
49365  
49366	//
49367  
49368	Object.defineProperties( WebGLRenderTarget.prototype, {
49369  
49370		wrapS: {
49371			get: function () {
49372  
49373				console.warn( 'THREE.WebGLRenderTarget: .wrapS is now .texture.wrapS.' );
49374				return this.texture.wrapS;
49375  
49376			},
49377			set: function ( value ) {
49378  
49379				console.warn( 'THREE.WebGLRenderTarget: .wrapS is now .texture.wrapS.' );
49380				this.texture.wrapS = value;
49381  
49382			}
49383		},
49384		wrapT: {
49385			get: function () {
49386  
49387				console.warn( 'THREE.WebGLRenderTarget: .wrapT is now .texture.wrapT.' );
49388				return this.texture.wrapT;
49389  
49390			},
49391			set: function ( value ) {
49392  
49393				console.warn( 'THREE.WebGLRenderTarget: .wrapT is now .texture.wrapT.' );
49394				this.texture.wrapT = value;
49395  
49396			}
49397		},
49398		magFilter: {
49399			get: function () {
49400  
49401				console.warn( 'THREE.WebGLRenderTarget: .magFilter is now .texture.magFilter.' );
49402				return this.texture.magFilter;
49403  
49404			},
49405			set: function ( value ) {
49406  
49407				console.warn( 'THREE.WebGLRenderTarget: .magFilter is now .texture.magFilter.' );
49408				this.texture.magFilter = value;
49409  
49410			}
49411		},
49412		minFilter: {
49413			get: function () {
49414  
49415				console.warn( 'THREE.WebGLRenderTarget: .minFilter is now .texture.minFilter.' );
49416				return this.texture.minFilter;
49417  
49418			},
49419			set: function ( value ) {
49420  
49421				console.warn( 'THREE.WebGLRenderTarget: .minFilter is now .texture.minFilter.' );
49422				this.texture.minFilter = value;
49423  
49424			}
49425		},
49426		anisotropy: {
49427			get: function () {
49428  
49429				console.warn( 'THREE.WebGLRenderTarget: .anisotropy is now .texture.anisotropy.' );
49430				return this.texture.anisotropy;
49431  
49432			},
49433			set: function ( value ) {
49434  
49435				console.warn( 'THREE.WebGLRenderTarget: .anisotropy is now .texture.anisotropy.' );
49436				this.texture.anisotropy = value;
49437  
49438			}
49439		},
49440		offset: {
49441			get: function () {
49442  
49443				console.warn( 'THREE.WebGLRenderTarget: .offset is now .texture.offset.' );
49444				return this.texture.offset;
49445  
49446			},
49447			set: function ( value ) {
49448  
49449				console.warn( 'THREE.WebGLRenderTarget: .offset is now .texture.offset.' );
49450				this.texture.offset = value;
49451  
49452			}
49453		},
49454		repeat: {
49455			get: function () {
49456  
49457				console.warn( 'THREE.WebGLRenderTarget: .repeat is now .texture.repeat.' );
49458				return this.texture.repeat;
49459  
49460			},
49461			set: function ( value ) {
49462  
49463				console.warn( 'THREE.WebGLRenderTarget: .repeat is now .texture.repeat.' );
49464				this.texture.repeat = value;
49465  
49466			}
49467		},
49468		format: {
49469			get: function () {
49470  
49471				console.warn( 'THREE.WebGLRenderTarget: .format is now .texture.format.' );
49472				return this.texture.format;
49473  
49474			},
49475			set: function ( value ) {
49476  
49477				console.warn( 'THREE.WebGLRenderTarget: .format is now .texture.format.' );
49478				this.texture.format = value;
49479  
49480			}
49481		},
49482		type: {
49483			get: function () {
49484  
49485				console.warn( 'THREE.WebGLRenderTarget: .type is now .texture.type.' );
49486				return this.texture.type;
49487  
49488			},
49489			set: function ( value ) {
49490  
49491				console.warn( 'THREE.WebGLRenderTarget: .type is now .texture.type.' );
49492				this.texture.type = value;
49493  
49494			}
49495		},
49496		generateMipmaps: {
49497			get: function () {
49498  
49499				console.warn( 'THREE.WebGLRenderTarget: .generateMipmaps is now .texture.generateMipmaps.' );
49500				return this.texture.generateMipmaps;
49501  
49502			},
49503			set: function ( value ) {
49504  
49505				console.warn( 'THREE.WebGLRenderTarget: .generateMipmaps is now .texture.generateMipmaps.' );
49506				this.texture.generateMipmaps = value;
49507  
49508			}
49509		}
49510  
49511	} );
49512  
49513	//
49514  
49515	Object.defineProperties( WebVRManager.prototype, {
49516  
vendor: 4,336 bytes, lines 49517-49744
49517		standing: {
49518			set: function ( /* value */ ) {
49519  
49520				console.warn( 'THREE.WebVRManager: .standing has been removed.' );
49521  
49522			}
49523		}
49524  
49525	} );
49526  
49527	//
49528  
49529	Audio.prototype.load = function ( file ) {
49530  
49531		console.warn( 'THREE.Audio: .load has been deprecated. Use THREE.AudioLoader instead.' );
49532		var scope = this;
49533		var audioLoader = new AudioLoader();
49534		audioLoader.load( file, function ( buffer ) {
49535  
49536			scope.setBuffer( buffer );
49537  
49538		} );
49539		return this;
49540  
49541	};
49542  
49543	AudioAnalyser.prototype.getData = function () {
49544  
49545		console.warn( 'THREE.AudioAnalyser: .getData() is now .getFrequencyData().' );
49546		return this.getFrequencyData();
49547  
49548	};
49549  
49550	//
49551  
49552	CubeCamera.prototype.updateCubeMap = function ( renderer, scene ) {
49553  
49554		console.warn( 'THREE.CubeCamera: .updateCubeMap() is now .update().' );
49555		return this.update( renderer, scene );
49556  
49557	};
49558  
49559	/**
49560	 * @author dmarcos / https://github.com/dmarcos
49561	 * @author mrdoob / http://mrdoob.com
49562	 */
49563	var VRControls = function ( object, onError ) {
49564  
49565		var scope = this;
49566  
49567		var vrDisplay, vrDisplays;
49568  
49569		var standingMatrix = new Matrix4();
49570  
49571		var frameData = null;
49572  
49573		if ( 'VRFrameData' in window ) {
49574  
49575			frameData = new VRFrameData();
49576  
49577		}
49578  
49579		function gotVRDisplays( displays ) {
49580  
49581			vrDisplays = displays;
49582  
49583			if ( displays.length > 0 ) {
49584  
49585				vrDisplay = displays[ 0 ];
49586  
49587			} else {
49588  
49589				if ( onError ) onError( 'VR input not available.' );
49590  
49591			}
49592  
49593		}
49594  
49595		if ( navigator.getVRDisplays ) {
49596  
49597			navigator.getVRDisplays().then( gotVRDisplays ).catch( function () {
49598  
49599				console.warn( 'VRControls: Unable to get VR Displays' );
49600  
49601			} );
49602  
49603		}
49604  
49605		// the Rift SDK returns the position in meters
49606		// this scale factor allows the user to define how meters
49607		// are converted to scene units.
49608  
49609		this.scale = 1;
49610  
49611		// If true will use "standing space" coordinate system where y=0 is the
49612		// floor and x=0, z=0 is the center of the room.
49613		this.standing = false;
49614  
49615		// Distance from the users eyes to the floor in meters. Used when
49616		// standing=true but the VRDisplay doesn't provide stageParameters.
49617		this.userHeight = 1.6;
49618  
49619		this.getVRDisplay = function () {
49620  
49621			return vrDisplay;
49622  
49623		};
49624  
49625		this.setVRDisplay = function ( value ) {
49626  
49627			vrDisplay = value;
49628  
49629		};
49630  
49631		this.getVRDisplays = function () {
49632  
49633			console.warn( 'VRControls: getVRDisplays() is being deprecated.' );
49634			return vrDisplays;
49635  
49636		};
49637  
49638		this.getStandingMatrix = function () {
49639  
49640			return standingMatrix;
49641  
49642		};
49643  
49644		this.update = function () {
49645  
49646			if ( vrDisplay ) {
49647  
49648				var pose;
49649  
49650				if ( vrDisplay.getFrameData ) {
49651  
49652					vrDisplay.getFrameData( frameData );
49653					pose = frameData.pose;
49654  
49655				} else if ( vrDisplay.getPose ) {
49656  
49657					pose = vrDisplay.getPose();
49658  
49659				}
49660  
49661				if ( pose.orientation !== null ) {
49662  
49663					object.quaternion.fromArray( pose.orientation );
49664  
49665				}
49666  
49667				if ( pose.position !== null ) {
49668  
49669					object.position.fromArray( pose.position );
49670  
49671				} else {
49672  
49673					object.position.set( 0, 0, 0 );
49674  
49675				}
49676  
49677				if ( this.standing ) {
49678  
49679					if ( vrDisplay.stageParameters ) {
49680  
49681						object.updateMatrix();
49682  
49683						standingMatrix.fromArray( vrDisplay.stageParameters.sittingToStandingTransform );
49684						object.applyMatrix( standingMatrix );
49685  
49686					} else {
49687  
49688						object.position.setY( object.position.y + this.userHeight );
49689  
49690					}
49691  
49692				}
49693  
49694				object.position.multiplyScalar( scope.scale );
49695  
49696			}
49697  
49698		};
49699  
49700		this.dispose = function () {
49701  
49702			vrDisplay = null;
49703  
49704		};
49705  
49706	};
49707  
49708	/**
49709	 * @author dmarcos / https://github.com/dmarcos
49710	 * @author mrdoob / http://mrdoob.com
49711	 *
49712	 * WebVR Spec: http://mozvr.github.io/webvr-spec/webvr.html
49713	 *
49714	 * Firefox: http://mozvr.com/downloads/
49715	 * Chromium: https://webvr.info/get-chrome
49716	 */
49717	var VREffect = function ( renderer, onError ) {
49718  
49719		var vrDisplay, vrDisplays;
49720		var eyeTranslationL = new Vector3();
49721		var eyeTranslationR = new Vector3();
49722		var renderRectL, renderRectR;
49723		var headMatrix = new Matrix4();
49724		var eyeMatrixL = new Matrix4();
49725		var eyeMatrixR = new Matrix4();
49726  
49727		var frameData = null;
49728  
49729		if ( 'VRFrameData' in window ) {
49730  
49731			frameData = new window.VRFrameData();
49732  
49733		}
49734  
49735		function gotVRDisplays( displays ) {
49736  
49737			vrDisplays = displays;
49738  
49739			if ( displays.length > 0 ) {
49740  
49741				vrDisplay = displays[ 0 ];
49742  
49743			} else {
49744  
vendor: 22,864 bytes, lines 49745-50608
49745				if ( onError ) onError( 'HMD not available' );
49746  
49747			}
49748  
49749		}
49750  
49751		if ( navigator.getVRDisplays ) {
49752  
49753			navigator.getVRDisplays().then( gotVRDisplays ).catch( function () {
49754  
49755				console.warn( 'VREffect: Unable to get VR Displays' );
49756  
49757			} );
49758  
49759		}
49760  
49761		//
49762  
49763		this.isPresenting = false;
49764  
49765		var scope = this;
49766  
49767		var rendererSize = renderer.getSize();
49768		var rendererUpdateStyle = false;
49769		var rendererPixelRatio = renderer.getPixelRatio();
49770  
49771		this.getVRDisplay = function () {
49772  
49773			return vrDisplay;
49774  
49775		};
49776  
49777		this.setVRDisplay = function ( value ) {
49778  
49779			vrDisplay = value;
49780  
49781		};
49782  
49783		this.getVRDisplays = function () {
49784  
49785			console.warn( 'VREffect: getVRDisplays() is being deprecated.' );
49786			return vrDisplays;
49787  
49788		};
49789  
49790		this.setSize = function ( width, height, updateStyle ) {
49791  
49792			rendererSize = { width: width, height: height };
49793			rendererUpdateStyle = updateStyle;
49794  
49795			if ( scope.isPresenting ) {
49796  
49797				var eyeParamsL = vrDisplay.getEyeParameters( 'left' );
49798				renderer.setPixelRatio( 1 );
49799				renderer.setSize( eyeParamsL.renderWidth * 2, eyeParamsL.renderHeight, false );
49800  
49801			} else {
49802  
49803				renderer.setPixelRatio( rendererPixelRatio );
49804				renderer.setSize( width, height, updateStyle );
49805  
49806			}
49807  
49808		};
49809  
49810		// VR presentation
49811  
49812		var canvas = renderer.domElement;
49813		var defaultLeftBounds = [ 0.0, 0.0, 0.5, 1.0 ];
49814		var defaultRightBounds = [ 0.5, 0.0, 0.5, 1.0 ];
49815  
49816		function onVRDisplayPresentChange() {
49817  
49818			var wasPresenting = scope.isPresenting;
49819			scope.isPresenting = vrDisplay !== undefined && vrDisplay.isPresenting;
49820  
49821			if ( scope.isPresenting ) {
49822  
49823				var eyeParamsL = vrDisplay.getEyeParameters( 'left' );
49824				var eyeWidth = eyeParamsL.renderWidth;
49825				var eyeHeight = eyeParamsL.renderHeight;
49826  
49827				if ( ! wasPresenting ) {
49828  
49829					rendererPixelRatio = renderer.getPixelRatio();
49830					rendererSize = renderer.getSize();
49831  
49832					renderer.setPixelRatio( 1 );
49833					renderer.setSize( eyeWidth * 2, eyeHeight, false );
49834  
49835				}
49836  
49837			} else if ( wasPresenting ) {
49838  
49839				renderer.setPixelRatio( rendererPixelRatio );
49840				renderer.setSize( rendererSize.width, rendererSize.height, rendererUpdateStyle );
49841  
49842			}
49843  
49844		}
49845  
49846		window.addEventListener( 'vrdisplaypresentchange', onVRDisplayPresentChange, false );
49847  
49848		this.setFullScreen = function ( boolean ) {
49849  
49850			return new Promise( function ( resolve, reject ) {
49851  
49852				if ( vrDisplay === undefined ) {
49853  
49854					reject( new Error( 'No VR hardware found.' ) );
49855					return;
49856  
49857				}
49858  
49859				if ( scope.isPresenting === boolean ) {
49860  
49861					resolve();
49862					return;
49863  
49864				}
49865  
49866				if ( boolean ) {
49867  
49868					resolve( vrDisplay.requestPresent( [ { source: canvas } ] ) );
49869  
49870				} else {
49871  
49872					resolve( vrDisplay.exitPresent() );
49873  
49874				}
49875  
49876			} );
49877  
49878		};
49879  
49880		this.requestPresent = function () {
49881  
49882			return this.setFullScreen( true );
49883  
49884		};
49885  
49886		this.exitPresent = function () {
49887  
49888			return this.setFullScreen( false );
49889  
49890		};
49891  
49892		this.requestAnimationFrame = function ( f ) {
49893  
49894			if ( vrDisplay !== undefined ) {
49895  
49896				return vrDisplay.requestAnimationFrame( f );
49897  
49898			} else {
49899  
49900				return window.requestAnimationFrame( f );
49901  
49902			}
49903  
49904		};
49905  
49906		this.cancelAnimationFrame = function ( h ) {
49907  
49908			if ( vrDisplay !== undefined ) {
49909  
49910				vrDisplay.cancelAnimationFrame( h );
49911  
49912			} else {
49913  
49914				window.cancelAnimationFrame( h );
49915  
49916			}
49917  
49918		};
49919  
49920		this.submitFrame = function () {
49921  
49922			if ( vrDisplay !== undefined && scope.isPresenting ) {
49923  
49924				vrDisplay.submitFrame();
49925  
49926			}
49927  
49928		};
49929  
49930		this.autoSubmitFrame = true;
49931  
49932		// render
49933  
49934		var cameraL = new PerspectiveCamera();
49935		cameraL.layers.enable( 1 );
49936  
49937		var cameraR = new PerspectiveCamera();
49938		cameraR.layers.enable( 2 );
49939  
49940		this.render = function ( scene, camera, renderTarget, forceClear ) {
49941  
49942			if ( vrDisplay && scope.isPresenting ) {
49943  
49944				var autoUpdate = scene.autoUpdate;
49945  
49946				if ( autoUpdate ) {
49947  
49948					scene.updateMatrixWorld();
49949					scene.autoUpdate = false;
49950  
49951				}
49952  
49953				if ( Array.isArray( scene ) ) {
49954  
49955					console.warn( 'VREffect.render() no longer supports arrays. Use object.layers instead.' );
49956					scene = scene[ 0 ];
49957  
49958				}
49959  
49960				// When rendering we don't care what the recommended size is, only what the actual size
49961				// of the backbuffer is.
49962				var size = renderer.getSize();
49963				var layers = vrDisplay.getLayers();
49964				var leftBounds;
49965				var rightBounds;
49966  
49967				if ( layers.length ) {
49968  
49969					var layer = layers[ 0 ];
49970  
49971					leftBounds = layer.leftBounds !== null && layer.leftBounds.length === 4 ? layer.leftBounds : defaultLeftBounds;
49972					rightBounds = layer.rightBounds !== null && layer.rightBounds.length === 4 ? layer.rightBounds : defaultRightBounds;
49973  
49974				} else {
49975  
49976					leftBounds = defaultLeftBounds;
49977					rightBounds = defaultRightBounds;
49978  
49979				}
49980  
49981				renderRectL = {
49982					x: Math.round( size.width * leftBounds[ 0 ] ),
49983					y: Math.round( size.height * leftBounds[ 1 ] ),
49984					width: Math.round( size.width * leftBounds[ 2 ] ),
49985					height: Math.round( size.height * leftBounds[ 3 ] )
49986				};
49987				renderRectR = {
49988					x: Math.round( size.width * rightBounds[ 0 ] ),
49989					y: Math.round( size.height * rightBounds[ 1 ] ),
49990					width: Math.round( size.width * rightBounds[ 2 ] ),
49991					height: Math.round( size.height * rightBounds[ 3 ] )
49992				};
49993  
49994				if ( renderTarget ) {
49995  
49996					renderer.setRenderTarget( renderTarget );
49997					renderTarget.scissorTest = true;
49998  
49999				} else {
50000  
50001					renderer.setRenderTarget( null );
50002					renderer.setScissorTest( true );
50003  
50004				}
50005  
50006				if ( renderer.autoClear || forceClear ) renderer.clear();
50007  
50008				if ( camera.parent === null ) camera.updateMatrixWorld();
50009  
50010				camera.matrixWorld.decompose( cameraL.position, cameraL.quaternion, cameraL.scale );
50011  
50012				cameraR.position.copy( cameraL.position );
50013				cameraR.quaternion.copy( cameraL.quaternion );
50014				cameraR.scale.copy( cameraL.scale );
50015  
50016				if ( vrDisplay.getFrameData ) {
50017  
50018					vrDisplay.depthNear = camera.near;
50019					vrDisplay.depthFar = camera.far;
50020  
50021					vrDisplay.getFrameData( frameData );
50022  
50023					cameraL.projectionMatrix.elements = frameData.leftProjectionMatrix;
50024					cameraR.projectionMatrix.elements = frameData.rightProjectionMatrix;
50025  
50026					getEyeMatrices( frameData );
50027  
50028					cameraL.updateMatrix();
50029					cameraL.matrix.multiply( eyeMatrixL );
50030					cameraL.matrix.decompose( cameraL.position, cameraL.quaternion, cameraL.scale );
50031  
50032					cameraR.updateMatrix();
50033					cameraR.matrix.multiply( eyeMatrixR );
50034					cameraR.matrix.decompose( cameraR.position, cameraR.quaternion, cameraR.scale );
50035  
50036				} else {
50037  
50038					var eyeParamsL = vrDisplay.getEyeParameters( 'left' );
50039					var eyeParamsR = vrDisplay.getEyeParameters( 'right' );
50040  
50041					cameraL.projectionMatrix = fovToProjection( eyeParamsL.fieldOfView, true, camera.near, camera.far );
50042					cameraR.projectionMatrix = fovToProjection( eyeParamsR.fieldOfView, true, camera.near, camera.far );
50043  
50044					eyeTranslationL.fromArray( eyeParamsL.offset );
50045					eyeTranslationR.fromArray( eyeParamsR.offset );
50046  
50047					cameraL.translateOnAxis( eyeTranslationL, cameraL.scale.x );
50048					cameraR.translateOnAxis( eyeTranslationR, cameraR.scale.x );
50049  
50050				}
50051  
50052				// render left eye
50053				if ( renderTarget ) {
50054  
50055					renderTarget.viewport.set( renderRectL.x, renderRectL.y, renderRectL.width, renderRectL.height );
50056					renderTarget.scissor.set( renderRectL.x, renderRectL.y, renderRectL.width, renderRectL.height );
50057  
50058				} else {
50059  
50060					renderer.setViewport( renderRectL.x, renderRectL.y, renderRectL.width, renderRectL.height );
50061					renderer.setScissor( renderRectL.x, renderRectL.y, renderRectL.width, renderRectL.height );
50062  
50063				}
50064				renderer.render( scene, cameraL, renderTarget, forceClear );
50065  
50066				// render right eye
50067				if ( renderTarget ) {
50068  
50069					renderTarget.viewport.set( renderRectR.x, renderRectR.y, renderRectR.width, renderRectR.height );
50070					renderTarget.scissor.set( renderRectR.x, renderRectR.y, renderRectR.width, renderRectR.height );
50071  
50072				} else {
50073  
50074					renderer.setViewport( renderRectR.x, renderRectR.y, renderRectR.width, renderRectR.height );
50075					renderer.setScissor( renderRectR.x, renderRectR.y, renderRectR.width, renderRectR.height );
50076  
50077				}
50078				renderer.render( scene, cameraR, renderTarget, forceClear );
50079  
50080				if ( renderTarget ) {
50081  
50082					renderTarget.viewport.set( 0, 0, size.width, size.height );
50083					renderTarget.scissor.set( 0, 0, size.width, size.height );
50084					renderTarget.scissorTest = false;
50085					renderer.setRenderTarget( null );
50086  
50087				} else {
50088  
50089					renderer.setViewport( 0, 0, size.width, size.height );
50090					renderer.setScissorTest( false );
50091  
50092				}
50093  
50094				if ( autoUpdate ) {
50095  
50096					scene.autoUpdate = true;
50097  
50098				}
50099  
50100				if ( scope.autoSubmitFrame ) {
50101  
50102					scope.submitFrame();
50103  
50104				}
50105  
50106				return;
50107  
50108			}
50109  
50110			// Regular render mode if not HMD
50111  
50112			renderer.render( scene, camera, renderTarget, forceClear );
50113  
50114		};
50115  
50116		this.dispose = function () {
50117  
50118			window.removeEventListener( 'vrdisplaypresentchange', onVRDisplayPresentChange, false );
50119  
50120		};
50121  
50122		//
50123  
50124		var poseOrientation = new Quaternion();
50125		var posePosition = new Vector3();
50126  
50127		// Compute model matrices of the eyes with respect to the head.
50128		function getEyeMatrices( frameData ) {
50129  
50130			// Compute the matrix for the position of the head based on the pose
50131			if ( frameData.pose.orientation ) {
50132  
50133				poseOrientation.fromArray( frameData.pose.orientation );
50134				headMatrix.makeRotationFromQuaternion( poseOrientation );
50135  
50136			}	else {
50137  
50138				headMatrix.identity();
50139  
50140			}
50141  
50142			if ( frameData.pose.position ) {
50143  
50144				posePosition.fromArray( frameData.pose.position );
50145				headMatrix.setPosition( posePosition );
50146  
50147			}
50148  
50149			// The view matrix transforms vertices from sitting space to eye space. As such, the view matrix can be thought of as a product of two matrices:
50150			// headToEyeMatrix * sittingToHeadMatrix
50151  
50152			// The headMatrix that we've calculated above is the model matrix of the head in sitting space, which is the inverse of sittingToHeadMatrix.
50153			// So when we multiply the view matrix with headMatrix, we're left with headToEyeMatrix:
50154			// viewMatrix * headMatrix = headToEyeMatrix * sittingToHeadMatrix * headMatrix = headToEyeMatrix
50155  
50156			eyeMatrixL.fromArray( frameData.leftViewMatrix );
50157			eyeMatrixL.multiply( headMatrix );
50158			eyeMatrixR.fromArray( frameData.rightViewMatrix );
50159			eyeMatrixR.multiply( headMatrix );
50160  
50161			// The eye's model matrix in head space is the inverse of headToEyeMatrix we calculated above.
50162  
50163			eyeMatrixL.getInverse( eyeMatrixL );
50164			eyeMatrixR.getInverse( eyeMatrixR );
50165  
50166		}
50167  
50168		function fovToNDCScaleOffset( fov ) {
50169  
50170			var pxscale = 2.0 / ( fov.leftTan + fov.rightTan );
50171			var pxoffset = ( fov.leftTan - fov.rightTan ) * pxscale * 0.5;
50172			var pyscale = 2.0 / ( fov.upTan + fov.downTan );
50173			var pyoffset = ( fov.upTan - fov.downTan ) * pyscale * 0.5;
50174			return { scale: [ pxscale, pyscale ], offset: [ pxoffset, pyoffset ] };
50175  
50176		}
50177  
50178		function fovPortToProjection( fov, rightHanded, zNear, zFar ) {
50179  
50180			rightHanded = rightHanded === undefined ? true : rightHanded;
50181			zNear = zNear === undefined ? 0.01 : zNear;
50182			zFar = zFar === undefined ? 10000.0 : zFar;
50183  
50184			var handednessScale = rightHanded ? - 1.0 : 1.0;
50185  
50186			// start with an identity matrix
50187			var mobj = new Matrix4();
50188			var m = mobj.elements;
50189  
50190			// and with scale/offset info for normalized device coords
50191			var scaleAndOffset = fovToNDCScaleOffset( fov );
50192  
50193			// X result, map clip edges to [-w,+w]
50194			m[ 0 * 4 + 0 ] = scaleAndOffset.scale[ 0 ];
50195			m[ 0 * 4 + 1 ] = 0.0;
50196			m[ 0 * 4 + 2 ] = scaleAndOffset.offset[ 0 ] * handednessScale;
50197			m[ 0 * 4 + 3 ] = 0.0;
50198  
50199			// Y result, map clip edges to [-w,+w]
50200			// Y offset is negated because this proj matrix transforms from world coords with Y=up,
50201			// but the NDC scaling has Y=down (thanks D3D?)
50202			m[ 1 * 4 + 0 ] = 0.0;
50203			m[ 1 * 4 + 1 ] = scaleAndOffset.scale[ 1 ];
50204			m[ 1 * 4 + 2 ] = - scaleAndOffset.offset[ 1 ] * handednessScale;
50205			m[ 1 * 4 + 3 ] = 0.0;
50206  
50207			// Z result (up to the app)
50208			m[ 2 * 4 + 0 ] = 0.0;
50209			m[ 2 * 4 + 1 ] = 0.0;
50210			m[ 2 * 4 + 2 ] = zFar / ( zNear - zFar ) * - handednessScale;
50211			m[ 2 * 4 + 3 ] = ( zFar * zNear ) / ( zNear - zFar );
50212  
50213			// W result (= Z in)
50214			m[ 3 * 4 + 0 ] = 0.0;
50215			m[ 3 * 4 + 1 ] = 0.0;
50216			m[ 3 * 4 + 2 ] = handednessScale;
50217			m[ 3 * 4 + 3 ] = 0.0;
50218  
50219			mobj.transpose();
50220			return mobj;
50221  
50222		}
50223  
50224		function fovToProjection( fov, rightHanded, zNear, zFar ) {
50225  
50226			var DEG2RAD = Math.PI / 180.0;
50227  
50228			var fovPort = {
50229				upTan: Math.tan( fov.upDegrees * DEG2RAD ),
50230				downTan: Math.tan( fov.downDegrees * DEG2RAD ),
50231				leftTan: Math.tan( fov.leftDegrees * DEG2RAD ),
50232				rightTan: Math.tan( fov.rightDegrees * DEG2RAD )
50233			};
50234  
50235			return fovPortToProjection( fovPort, rightHanded, zNear, zFar );
50236  
50237		}
50238  
50239	};
50240  
50241	/**
50242	 * @author qiao / https://github.com/qiao
50243	 * @author mrdoob / http://mrdoob.com
50244	 * @author alteredq / http://alteredqualia.com/
50245	 * @author WestLangley / http://github.com/WestLangley
50246	 * @author erich666 / http://erichaines.com
50247	 */
50248	var OrbitControls = function ( object, domElement ) {
50249  
50250		this.object = object;
50251  
50252		this.domElement = ( domElement !== undefined ) ? domElement : document;
50253  
50254		// Set to false to disable this control
50255		this.enabled = true;
50256  
50257		// "target" sets the location of focus, where the object orbits around
50258		this.target = new Vector3();
50259  
50260		// How far you can dolly in and out ( PerspectiveCamera only )
50261		this.minDistance = 0;
50262		this.maxDistance = Infinity;
50263  
50264		// How far you can zoom in and out ( OrthographicCamera only )
50265		this.minZoom = 0;
50266		this.maxZoom = Infinity;
50267  
50268		// How far you can orbit vertically, upper and lower limits.
50269		// Range is 0 to Math.PI radians.
50270		this.minPolarAngle = 0; // radians
50271		this.maxPolarAngle = Math.PI; // radians
50272  
50273		// How far you can orbit horizontally, upper and lower limits.
50274		// If set, must be a sub-interval of the interval [ - Math.PI, Math.PI ].
50275		this.minAzimuthAngle = - Infinity; // radians
50276		this.maxAzimuthAngle = Infinity; // radians
50277  
50278		// Set to true to enable damping (inertia)
50279		// If damping is enabled, you must call controls.update() in your animation loop
50280		this.enableDamping = false;
50281		this.dampingFactor = 0.25;
50282  
50283		// This option actually enables dollying in and out; left as "zoom" for backwards compatibility.
50284		// Set to false to disable zooming
50285		this.enableZoom = true;
50286		this.zoomSpeed = 1.0;
50287  
50288		// Set to false to disable rotating
50289		this.enableRotate = true;
50290		this.rotateSpeed = 1.0;
50291  
50292		// Set to false to disable panning
50293		this.enablePan = true;
50294		this.panSpeed = 1.0;
50295		this.screenSpacePanning = false; // if true, pan in screen-space
50296		this.keyPanSpeed = 7.0;	// pixels moved per arrow key push
50297  
50298		// Set to true to automatically rotate around the target
50299		// If auto-rotate is enabled, you must call controls.update() in your animation loop
50300		this.autoRotate = false;
50301		this.autoRotateSpeed = 2.0; // 30 seconds per round when fps is 60
50302  
50303		// Set to false to disable use of the keys
50304		this.enableKeys = true;
50305  
50306		// The four arrow keys
50307		this.keys = { LEFT: 37, UP: 38, RIGHT: 39, BOTTOM: 40 };
50308  
50309		// Mouse buttons
50310		this.mouseButtons = { ORBIT: MOUSE.LEFT, ZOOM: MOUSE.MIDDLE, PAN: MOUSE.RIGHT };
50311  
50312		// for reset
50313		this.target0 = this.target.clone();
50314		this.position0 = this.object.position.clone();
50315		this.zoom0 = this.object.zoom;
50316  
50317		//
50318		// public methods
50319		//
50320  
50321		this.getPolarAngle = function () {
50322  
50323			return spherical.phi;
50324  
50325		};
50326  
50327		this.getAzimuthalAngle = function () {
50328  
50329			return spherical.theta;
50330  
50331		};
50332  
50333		this.saveState = function () {
50334  
50335			scope.target0.copy( scope.target );
50336			scope.position0.copy( scope.object.position );
50337			scope.zoom0 = scope.object.zoom;
50338  
50339		};
50340  
50341		this.reset = function () {
50342  
50343			scope.target.copy( scope.target0 );
50344			scope.object.position.copy( scope.position0 );
50345			scope.object.zoom = scope.zoom0;
50346  
50347			scope.object.updateProjectionMatrix();
50348			scope.dispatchEvent( changeEvent );
50349  
50350			scope.update();
50351  
50352			state = STATE.NONE;
50353  
50354		};
50355  
50356		// this method is exposed, but perhaps it would be better if we can make it private...
50357		this.update = function () {
50358  
50359			var offset = new Vector3();
50360  
50361			// so camera.up is the orbit axis
50362			var quat = new Quaternion().setFromUnitVectors( object.up, new Vector3( 0, 1, 0 ) );
50363			var quatInverse = quat.clone().inverse();
50364  
50365			var lastPosition = new Vector3();
50366			var lastQuaternion = new Quaternion();
50367  
50368			return function update() {
50369  
50370				var position = scope.object.position;
50371  
50372				offset.copy( position ).sub( scope.target );
50373  
50374				// rotate offset to "y-axis-is-up" space
50375				offset.applyQuaternion( quat );
50376  
50377				// angle from z-axis around y-axis
50378				spherical.setFromVector3( offset );
50379  
50380				if ( scope.autoRotate && state === STATE.NONE ) {
50381  
50382					scope.rotateLeft( getAutoRotationAngle() );
50383  
50384				}
50385  
50386				spherical.theta += sphericalDelta.theta;
50387				spherical.phi += sphericalDelta.phi;
50388  
50389				// restrict theta to be between desired limits
50390				spherical.theta = Math.max( scope.minAzimuthAngle, Math.min( scope.maxAzimuthAngle, spherical.theta ) );
50391  
50392				// restrict phi to be between desired limits
50393				spherical.phi = Math.max( scope.minPolarAngle, Math.min( scope.maxPolarAngle, spherical.phi ) );
50394  
50395				spherical.makeSafe();
50396  
50397  
50398				spherical.radius *= scale;
50399  
50400				// restrict radius to be between desired limits
50401				spherical.radius = Math.max( scope.minDistance, Math.min( scope.maxDistance, spherical.radius ) );
50402  
50403				// move target to panned location
50404				scope.target.add( panOffset );
50405  
50406				offset.setFromSpherical( spherical );
50407  
50408				// rotate offset back to "camera-up-vector-is-up" space
50409				offset.applyQuaternion( quatInverse );
50410  
50411				position.copy( scope.target ).add( offset );
50412  
50413				scope.object.lookAt( scope.target );
50414  
50415				if ( scope.enableDamping === true ) {
50416  
50417					sphericalDelta.theta *= ( 1 - scope.dampingFactor );
50418					sphericalDelta.phi *= ( 1 - scope.dampingFactor );
50419  
50420					panOffset.multiplyScalar( 1 - scope.dampingFactor );
50421  
50422				} else {
50423  
50424					sphericalDelta.set( 0, 0, 0 );
50425  
50426					panOffset.set( 0, 0, 0 );
50427  
50428				}
50429  
50430				scale = 1;
50431  
50432				// update condition is:
50433				// min(camera displacement, camera rotation in radians)^2 > EPS
50434				// using small-angle approximation cos(x/2) = 1 - x^2 / 8
50435  
50436				if ( zoomChanged ||
50437					lastPosition.distanceToSquared( scope.object.position ) > EPS ||
50438					8 * ( 1 - lastQuaternion.dot( scope.object.quaternion ) ) > EPS ) {
50439  
50440					scope.dispatchEvent( changeEvent );
50441  
50442					lastPosition.copy( scope.object.position );
50443					lastQuaternion.copy( scope.object.quaternion );
50444					zoomChanged = false;
50445  
50446					return true;
50447  
50448				}
50449  
50450				return false;
50451  
50452			};
50453  
50454		}();
50455  
50456		this.dispose = function () {
50457  
50458			scope.domElement.removeEventListener( 'contextmenu', onContextMenu, false );
50459			scope.domElement.removeEventListener( 'mousedown', onMouseDown, false );
50460			scope.domElement.removeEventListener( 'wheel', onMouseWheel, false );
50461  
50462			scope.domElement.removeEventListener( 'touchstart', onTouchStart, false );
50463			scope.domElement.removeEventListener( 'touchend', onTouchEnd, false );
50464			scope.domElement.removeEventListener( 'touchmove', onTouchMove, false );
50465  
50466			document.removeEventListener( 'mousemove', onMouseMove, false );
50467			document.removeEventListener( 'mouseup', onMouseUp, false );
50468  
50469			window.removeEventListener( 'keydown', onKeyDown, false );
50470  
50471			//scope.dispatchEvent( { type: 'dispose' } ); // should this be added here?
50472  
50473		};
50474  
50475		//
50476		// internals
50477		//
50478  
50479		var scope = this;
50480  
50481		var changeEvent = { type: 'change' };
50482		var startEvent = { type: 'start' };
50483		var endEvent = { type: 'end' };
50484  
50485		var STATE = { NONE: - 1, ROTATE: 0, DOLLY: 1, PAN: 2, TOUCH_ROTATE: 3, TOUCH_DOLLY_PAN: 4 };
50486  
50487		var state = STATE.NONE;
50488  
50489		var EPS = 0.000001;
50490  
50491		// current position in spherical coordinates
50492		var spherical = new Spherical();
50493		var sphericalDelta = new Spherical();
50494  
50495		var scale = 1;
50496		var panOffset = new Vector3();
50497		var zoomChanged = false;
50498  
50499		var rotateStart = new Vector2();
50500		var rotateEnd = new Vector2();
50501		var rotateDelta = new Vector2();
50502  
50503		var panStart = new Vector2();
50504		var panEnd = new Vector2();
50505		var panDelta = new Vector2();
50506  
50507		var dollyStart = new Vector2();
50508		var dollyEnd = new Vector2();
50509		var dollyDelta = new Vector2();
50510  
50511		function getAutoRotationAngle() {
50512  
50513			return 2 * Math.PI / 60 / 60 * scope.autoRotateSpeed;
50514  
50515		}
50516  
50517		function getZoomScale() {
50518  
50519			return Math.pow( 0.95, scope.zoomSpeed );
50520  
50521		}
50522  
50523		scope.rotateLeft = function( angle ) {
50524  
50525			sphericalDelta.theta -= angle;
50526  
50527		};
50528  
50529		scope.rotateUp = function( angle ) {
50530  
50531			sphericalDelta.phi -= angle;
50532  
50533		};
50534  
50535		var panLeft = function () {
50536  
50537			var v = new Vector3();
50538  
50539			return function panLeft( distance, objectMatrix ) {
50540  
50541				v.setFromMatrixColumn( objectMatrix, 0 ); // get X column of objectMatrix
50542				v.multiplyScalar( - distance );
50543  
50544				panOffset.add( v );
50545  
50546			};
50547  
50548		}();
50549  
50550		var panUp = function () {
50551  
50552			var v = new Vector3();
50553  
50554			return function panUp( distance, objectMatrix ) {
50555  
50556				if ( scope.screenSpacePanning === true ) {
50557  
50558					v.setFromMatrixColumn( objectMatrix, 1 );
50559  
50560				} else {
50561  
50562					v.setFromMatrixColumn( objectMatrix, 0 );
50563					v.crossVectors( scope.object.up, v );
50564  
50565				}
50566  
50567				v.multiplyScalar( distance );
50568  
50569				panOffset.add( v );
50570  
50571			};
50572  
50573		}();
50574  
50575		// deltaX and deltaY are in pixels; right and down are positive
50576		var pan = function () {
50577  
50578			var offset = new Vector3();
50579  
50580			return function pan( deltaX, deltaY ) {
50581  
50582				var element = scope.domElement === document ? scope.domElement.body : scope.domElement;
50583  
50584				if ( scope.object.isPerspectiveCamera ) {
50585  
50586					// perspective
50587					var position = scope.object.position;
50588					offset.copy( position ).sub( scope.target );
50589					var targetDistance = offset.length();
50590  
50591					// half of the fov is center to top of screen
50592					targetDistance *= Math.tan( ( scope.object.fov / 2 ) * Math.PI / 180.0 );
50593  
50594					// we use only clientHeight here so aspect ratio does not distort speed
50595					panLeft( 2 * deltaX * targetDistance / element.clientHeight, scope.object.matrix );
50596					panUp( 2 * deltaY * targetDistance / element.clientHeight, scope.object.matrix );
50597  
50598				} else if ( scope.object.isOrthographicCamera ) {
50599  
50600					// orthographic
50601					panLeft( deltaX * ( scope.object.right - scope.object.left ) / scope.object.zoom / element.clientWidth, scope.object.matrix );
50602					panUp( deltaY * ( scope.object.top - scope.object.bottom ) / scope.object.zoom / element.clientHeight, scope.object.matrix );
50603  
50604				} else {
50605  
50606					// camera neither orthographic nor perspective
50607					console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - pan disabled.' );
50608					scope.enablePan = false;
50609  
50610				}
50611  
50612			};
50613  
50614		}();
50615  
50616		function dollyIn( dollyScale ) {
50617  
50618			if ( scope.object.isPerspectiveCamera ) {
50619  
50620				scale /= dollyScale;
50621  
50622			} else if ( scope.object.isOrthographicCamera ) {
50623  
50624				scope.object.zoom = Math.max( scope.minZoom, Math.min( scope.maxZoom, scope.object.zoom * dollyScale ) );
50625				scope.object.updateProjectionMatrix();
50626				zoomChanged = true;
50627  
50628			} else {
50629  
50630				console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.' );
50631				scope.enableZoom = false;
50632  
50633			}
50634  
50635		}
50636  
50637		function dollyOut( dollyScale ) {
50638  
50639			if ( scope.object.isPerspectiveCamera ) {
50640  
50641				scale *= dollyScale;
50642  
50643			} else if ( scope.object.isOrthographicCamera ) {
50644  
50645				scope.object.zoom = Math.max( scope.minZoom, Math.min( scope.maxZoom, scope.object.zoom / dollyScale ) );
50646				scope.object.updateProjectionMatrix();
50647				zoomChanged = true;
50648  
50649			} else {
50650  
50651				console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.' );
50652				scope.enableZoom = false;
vendor: 14,089 bytes, lines 50653-51331
50653  
50654			}
50655  
50656		}
50657  
50658		//
50659		// event callbacks - update the object state
50660		//
50661  
50662		function handleMouseDownRotate( event ) {
50663  
50664			//console.log( 'handleMouseDownRotate' );
50665  
50666			rotateStart.set( event.clientX, event.clientY );
50667  
50668		}
50669  
50670		function handleMouseDownDolly( event ) {
50671  
50672			//console.log( 'handleMouseDownDolly' );
50673  
50674			dollyStart.set( event.clientX, event.clientY );
50675  
50676		}
50677  
50678		function handleMouseDownPan( event ) {
50679  
50680			//console.log( 'handleMouseDownPan' );
50681  
50682			panStart.set( event.clientX, event.clientY );
50683  
50684		}
50685  
50686		function handleMouseMoveRotate( event ) {
50687  
50688			//console.log( 'handleMouseMoveRotate' );
50689  
50690			rotateEnd.set( event.clientX, event.clientY );
50691  
50692			rotateDelta.subVectors( rotateEnd, rotateStart ).multiplyScalar( scope.rotateSpeed );
50693  
50694			var element = scope.domElement === document ? scope.domElement.body : scope.domElement;
50695  
50696			scope.rotateLeft( 2 * Math.PI * rotateDelta.x / element.clientHeight ); // yes, height
50697  
50698			scope.rotateUp( 2 * Math.PI * rotateDelta.y / element.clientHeight );
50699  
50700			rotateStart.copy( rotateEnd );
50701  
50702			scope.update();
50703  
50704		}
50705  
50706		function handleMouseMoveDolly( event ) {
50707  
50708			//console.log( 'handleMouseMoveDolly' );
50709  
50710			dollyEnd.set( event.clientX, event.clientY );
50711  
50712			dollyDelta.subVectors( dollyEnd, dollyStart );
50713  
50714			if ( dollyDelta.y > 0 ) {
50715  
50716				dollyIn( getZoomScale() );
50717  
50718			} else if ( dollyDelta.y < 0 ) {
50719  
50720				dollyOut( getZoomScale() );
50721  
50722			}
50723  
50724			dollyStart.copy( dollyEnd );
50725  
50726			scope.update();
50727  
50728		}
50729  
50730		function handleMouseMovePan( event ) {
50731  
50732			//console.log( 'handleMouseMovePan' );
50733  
50734			panEnd.set( event.clientX, event.clientY );
50735  
50736			panDelta.subVectors( panEnd, panStart ).multiplyScalar( scope.panSpeed );
50737  
50738			pan( panDelta.x, panDelta.y );
50739  
50740			panStart.copy( panEnd );
50741  
50742			scope.update();
50743  
50744		}
50745  
50746		function handleMouseWheel( event ) {
50747  
50748			// console.log( 'handleMouseWheel' );
50749  
50750			if ( event.deltaY < 0 ) {
50751  
50752				dollyOut( getZoomScale() );
50753  
50754			} else if ( event.deltaY > 0 ) {
50755  
50756				dollyIn( getZoomScale() );
50757  
50758			}
50759  
50760			scope.update();
50761  
50762		}
50763  
50764		function handleKeyDown( event ) {
50765  
50766			//console.log( 'handleKeyDown' );
50767  
50768			switch ( event.keyCode ) {
50769  
50770				case scope.keys.UP:
50771					pan( 0, scope.keyPanSpeed );
50772					scope.update();
50773					break;
50774  
50775				case scope.keys.BOTTOM:
50776					pan( 0, - scope.keyPanSpeed );
50777					scope.update();
50778					break;
50779  
50780				case scope.keys.LEFT:
50781					pan( scope.keyPanSpeed, 0 );
50782					scope.update();
50783					break;
50784  
50785				case scope.keys.RIGHT:
50786					pan( - scope.keyPanSpeed, 0 );
50787					scope.update();
50788					break;
50789  
50790			}
50791  
50792		}
50793  
50794		function handleTouchStartRotate( event ) {
50795  
50796			//console.log( 'handleTouchStartRotate' );
50797  
50798			rotateStart.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
50799  
50800		}
50801  
50802		function handleTouchStartDollyPan( event ) {
50803  
50804			//console.log( 'handleTouchStartDollyPan' );
50805  
50806			if ( scope.enableZoom ) {
50807  
50808				var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX;
50809				var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY;
50810  
50811				var distance = Math.sqrt( dx * dx + dy * dy );
50812  
50813				dollyStart.set( 0, distance );
50814  
50815			}
50816  
50817			if ( scope.enablePan ) {
50818  
50819				var x = 0.5 * ( event.touches[ 0 ].pageX + event.touches[ 1 ].pageX );
50820				var y = 0.5 * ( event.touches[ 0 ].pageY + event.touches[ 1 ].pageY );
50821  
50822				panStart.set( x, y );
50823  
50824			}
50825  
50826		}
50827  
50828		function handleTouchMoveRotate( event ) {
50829  
50830			//console.log( 'handleTouchMoveRotate' );
50831  
50832			rotateEnd.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
50833  
50834			rotateDelta.subVectors( rotateEnd, rotateStart ).multiplyScalar( scope.rotateSpeed );
50835  
50836			var element = scope.domElement === document ? scope.domElement.body : scope.domElement;
50837  
50838			scope.rotateLeft( 2 * Math.PI * rotateDelta.x / element.clientHeight ); // yes, height
50839  
50840			scope.rotateUp( 2 * Math.PI * rotateDelta.y / element.clientHeight );
50841  
50842			rotateStart.copy( rotateEnd );
50843  
50844			scope.update();
50845  
50846		}
50847  
50848		function handleTouchMoveDollyPan( event ) {
50849  
50850			//console.log( 'handleTouchMoveDollyPan' );
50851  
50852			if ( scope.enableZoom ) {
50853  
50854				var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX;
50855				var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY;
50856  
50857				var distance = Math.sqrt( dx * dx + dy * dy );
50858  
50859				dollyEnd.set( 0, distance );
50860  
50861				dollyDelta.set( 0, Math.pow( dollyEnd.y / dollyStart.y, scope.zoomSpeed ) );
50862  
50863				dollyIn( dollyDelta.y );
50864  
50865				dollyStart.copy( dollyEnd );
50866  
50867			}
50868  
50869			if ( scope.enablePan ) {
50870  
50871				var x = 0.5 * ( event.touches[ 0 ].pageX + event.touches[ 1 ].pageX );
50872				var y = 0.5 * ( event.touches[ 0 ].pageY + event.touches[ 1 ].pageY );
50873  
50874				panEnd.set( x, y );
50875  
50876				panDelta.subVectors( panEnd, panStart ).multiplyScalar( scope.panSpeed );
50877  
50878				pan( panDelta.x, panDelta.y );
50879  
50880				panStart.copy( panEnd );
50881  
50882			}
50883  
50884			scope.update();
50885  
50886		}
50887  
50888		//
50889		// event handlers - FSM: listen for events and reset state
50890		//
50891  
50892		function onMouseDown( event ) {
50893  
50894			if ( scope.enabled === false ) return;
50895  
50896			event.preventDefault();
50897  
50898			switch ( event.button ) {
50899  
50900				case scope.mouseButtons.ORBIT:
50901  
50902					if ( scope.enableRotate === false ) return;
50903  
50904					handleMouseDownRotate( event );
50905  
50906					state = STATE.ROTATE;
50907  
50908					break;
50909  
50910				case scope.mouseButtons.ZOOM:
50911  
50912					if ( scope.enableZoom === false ) return;
50913  
50914					handleMouseDownDolly( event );
50915  
50916					state = STATE.DOLLY;
50917  
50918					break;
50919  
50920				case scope.mouseButtons.PAN:
50921  
50922					if ( scope.enablePan === false ) return;
50923  
50924					handleMouseDownPan( event );
50925  
50926					state = STATE.PAN;
50927  
50928					break;
50929  
50930			}
50931  
50932			if ( state !== STATE.NONE ) {
50933  
50934				document.addEventListener( 'mousemove', onMouseMove, false );
50935				document.addEventListener( 'mouseup', onMouseUp, false );
50936  
50937				scope.dispatchEvent( startEvent );
50938  
50939			}
50940  
50941		}
50942  
50943		function onMouseMove( event ) {
50944  
50945			if ( scope.enabled === false ) return;
50946  
50947			event.preventDefault();
50948  
50949			switch ( state ) {
50950  
50951				case STATE.ROTATE:
50952  
50953					if ( scope.enableRotate === false ) return;
50954  
50955					handleMouseMoveRotate( event );
50956  
50957					break;
50958  
50959				case STATE.DOLLY:
50960  
50961					if ( scope.enableZoom === false ) return;
50962  
50963					handleMouseMoveDolly( event );
50964  
50965					break;
50966  
50967				case STATE.PAN:
50968  
50969					if ( scope.enablePan === false ) return;
50970  
50971					handleMouseMovePan( event );
50972  
50973					break;
50974  
50975			}
50976  
50977		}
50978  
50979		function onMouseUp( event ) {
50980  
50981			if ( scope.enabled === false ) return;
50982  
50983			document.removeEventListener( 'mousemove', onMouseMove, false );
50984			document.removeEventListener( 'mouseup', onMouseUp, false );
50985  
50986			scope.dispatchEvent( endEvent );
50987  
50988			state = STATE.NONE;
50989  
50990		}
50991  
50992		function onMouseWheel( event ) {
50993  
50994			if ( scope.enabled === false || scope.enableZoom === false || ( state !== STATE.NONE && state !== STATE.ROTATE ) ) return;
50995  
50996			event.preventDefault();
50997			event.stopPropagation();
50998  
50999			scope.dispatchEvent( startEvent );
51000  
51001			handleMouseWheel( event );
51002  
51003			scope.dispatchEvent( endEvent );
51004  
51005		}
51006  
51007		function onKeyDown( event ) {
51008  
51009			if ( scope.enabled === false || scope.enableKeys === false || scope.enablePan === false ) return;
51010  
51011			handleKeyDown( event );
51012  
51013		}
51014  
51015		function onTouchStart( event ) {
51016  
51017			if ( scope.enabled === false ) return;
51018  
51019			event.preventDefault();
51020  
51021			switch ( event.touches.length ) {
51022  
51023				case 1:	// one-fingered touch: rotate
51024  
51025					if ( scope.enableRotate === false ) return;
51026  
51027					handleTouchStartRotate( event );
51028  
51029					state = STATE.TOUCH_ROTATE;
51030  
51031					break;
51032  
51033				case 2:	// two-fingered touch: dolly-pan
51034  
51035					if ( scope.enableZoom === false && scope.enablePan === false ) return;
51036  
51037					handleTouchStartDollyPan( event );
51038  
51039					state = STATE.TOUCH_DOLLY_PAN;
51040  
51041					break;
51042  
51043				default:
51044  
51045					state = STATE.NONE;
51046  
51047			}
51048  
51049			if ( state !== STATE.NONE ) {
51050  
51051				scope.dispatchEvent( startEvent );
51052  
51053			}
51054  
51055		}
51056  
51057		function onTouchMove( event ) {
51058  
51059			if ( scope.enabled === false ) return;
51060  
51061			event.preventDefault();
51062			event.stopPropagation();
51063  
51064			switch ( event.touches.length ) {
51065  
51066				case 1: // one-fingered touch: rotate
51067  
51068					if ( scope.enableRotate === false ) return;
51069					if ( state !== STATE.TOUCH_ROTATE ) return; // is this needed?
51070  
51071					handleTouchMoveRotate( event );
51072  
51073					break;
51074  
51075				case 2: // two-fingered touch: dolly-pan
51076  
51077					if ( scope.enableZoom === false && scope.enablePan === false ) return;
51078					if ( state !== STATE.TOUCH_DOLLY_PAN ) return; // is this needed?
51079  
51080					handleTouchMoveDollyPan( event );
51081  
51082					break;
51083  
51084				default:
51085  
51086					state = STATE.NONE;
51087  
51088			}
51089  
51090		}
51091  
51092		function onTouchEnd( event ) {
51093  
51094			if ( scope.enabled === false ) return;
51095  
51096			scope.dispatchEvent( endEvent );
51097  
51098			state = STATE.NONE;
51099  
51100		}
51101  
51102		function onContextMenu( event ) {
51103  
51104			if ( scope.enabled === false ) return;
51105  
51106			event.preventDefault();
51107  
51108		}
51109  
51110		//
51111  
51112		//scope.domElement.addEventListener\( 'contextmenu', onContextMenu, false );
51113  
51114		scope.domElement.addEventListener( 'mousedown', onMouseDown, false );
51115		scope.domElement.addEventListener( 'wheel', onMouseWheel, false );
51116  
51117		scope.domElement.addEventListener( 'touchstart', onTouchStart, false );
51118		scope.domElement.addEventListener( 'touchend', onTouchEnd, false );
51119		scope.domElement.addEventListener( 'touchmove', onTouchMove, false );
51120  
51121		window.addEventListener( 'keydown', onKeyDown, false );
51122  
51123		// force an update at start
51124  
51125		this.update();
51126  
51127	};
51128  
51129	OrbitControls.prototype = Object.create( EventDispatcher.prototype );
51130	OrbitControls.prototype.constructor = OrbitControls;
51131  
51132	Object.defineProperties( OrbitControls.prototype, {
51133  
51134		center: {
51135  
51136			get: function () {
51137  
51138				console.warn( 'OrbitControls: .center has been renamed to .target' );
51139				return this.target;
51140  
51141			}
51142  
51143		},
51144  
51145		// backward compatibility
51146  
51147		noZoom: {
51148  
51149			get: function () {
51150  
51151				console.warn( 'OrbitControls: .noZoom has been deprecated. Use .enableZoom instead.' );
51152				return ! this.enableZoom;
51153  
51154			},
51155  
51156			set: function ( value ) {
51157  
51158				console.warn( 'OrbitControls: .noZoom has been deprecated. Use .enableZoom instead.' );
51159				this.enableZoom = ! value;
51160  
51161			}
51162  
51163		},
51164  
51165		noRotate: {
51166  
51167			get: function () {
51168  
51169				console.warn( 'OrbitControls: .noRotate has been deprecated. Use .enableRotate instead.' );
51170				return ! this.enableRotate;
51171  
51172			},
51173  
51174			set: function ( value ) {
51175  
51176				console.warn( 'OrbitControls: .noRotate has been deprecated. Use .enableRotate instead.' );
51177				this.enableRotate = ! value;
51178  
51179			}
51180  
51181		},
51182  
51183		noPan: {
51184  
51185			get: function () {
51186  
51187				console.warn( 'OrbitControls: .noPan has been deprecated. Use .enablePan instead.' );
51188				return ! this.enablePan;
51189  
51190			},
51191  
51192			set: function ( value ) {
51193  
51194				console.warn( 'OrbitControls: .noPan has been deprecated. Use .enablePan instead.' );
51195				this.enablePan = ! value;
51196  
51197			}
51198  
51199		},
51200  
51201		noKeys: {
51202  
51203			get: function () {
51204  
51205				console.warn( 'OrbitControls: .noKeys has been deprecated. Use .enableKeys instead.' );
51206				return ! this.enableKeys;
51207  
51208			},
51209  
51210			set: function ( value ) {
51211  
51212				console.warn( 'OrbitControls: .noKeys has been deprecated. Use .enableKeys instead.' );
51213				this.enableKeys = ! value;
51214  
51215			}
51216  
51217		},
51218  
51219		staticMoving: {
51220  
51221			get: function () {
51222  
51223				console.warn( 'OrbitControls: .staticMoving has been deprecated. Use .enableDamping instead.' );
51224				return ! this.enableDamping;
51225  
51226			},
51227  
51228			set: function ( value ) {
51229  
51230				console.warn( 'OrbitControls: .staticMoving has been deprecated. Use .enableDamping instead.' );
51231				this.enableDamping = ! value;
51232  
51233			}
51234  
51235		},
51236  
51237		dynamicDampingFactor: {
51238  
51239			get: function () {
51240  
51241				console.warn( 'OrbitControls: .dynamicDampingFactor has been renamed. Use .dampingFactor instead.' );
51242				return this.dampingFactor;
51243  
51244			},
51245  
51246			set: function ( value ) {
51247  
51248				console.warn( 'OrbitControls: .dynamicDampingFactor has been renamed. Use .dampingFactor instead.' );
51249				this.dampingFactor = value;
51250  
51251			}
51252  
51253		}
51254  
51255	} );
51256  
51257	/**
51258	 * @author richt / http://richt.me
51259	 * @author WestLangley / http://github.com/WestLangley
51260	 *
51261	 * W3C Device Orientation control (http://w3c.github.io/deviceorientation/spec-source-orientation.html)
51262	 */
51263	var DeviceOrientationControls = function ( object ) {
51264  
51265		var scope = this;
51266  
51267		this.object = object;
51268		this.object.rotation.reorder( 'YXZ' );
51269  
51270		this.enabled = true;
51271  
51272		this.deviceOrientation = {};
51273		this.screenOrientation = 0;
51274  
51275		this.alphaOffset = 0; // radians
51276  
51277		var onDeviceOrientationChangeEvent = function ( event ) {
51278  
51279			scope.deviceOrientation = event;
51280  
51281		};
51282  
51283		var onScreenOrientationChangeEvent = function () {
51284  
51285			scope.screenOrientation = window.orientation || 0;
51286  
51287		};
51288  
51289		// The angles alpha, beta and gamma form a set of intrinsic Tait-Bryan angles of type Z-X'-Y''
51290  
51291		var setObjectQuaternion = function () {
51292  
51293			var zee = new Vector3( 0, 0, 1 );
51294  
51295			var euler = new Euler();
51296  
51297			var q0 = new Quaternion();
51298  
51299			var q1 = new Quaternion( - Math.sqrt( 0.5 ), 0, 0, Math.sqrt( 0.5 ) ); // - PI/2 around the x-axis
51300  
51301			return function ( quaternion, alpha, beta, gamma, orient ) {
51302  
51303				euler.set( beta, alpha, - gamma, 'YXZ' ); // 'ZXY' for the device, but 'YXZ' for us
51304  
51305				quaternion.setFromEuler( euler ); // orient the device
51306  
51307				quaternion.multiply( q1 ); // camera looks out the back of the device, not the top
51308  
51309				quaternion.multiply( q0.setFromAxisAngle( zee, - orient ) ); // adjust for screen orientation
51310  
51311			};
51312  
51313		}();
51314  
51315		this.connect = function () {
51316  
51317			onScreenOrientationChangeEvent(); // run once on load
51318  
51319			window.addEventListener( 'orientationchange', onScreenOrientationChangeEvent, false );
51320			window.addEventListener( 'deviceorientation', onDeviceOrientationChangeEvent, false );
51321  
51322			scope.enabled = true;
51323  
51324		};
51325  
51326		this.disconnect = function () {
51327  
51328			window.removeEventListener( 'orientationchange', onScreenOrientationChangeEvent, false );
51329			window.removeEventListener( 'deviceorientation', onDeviceOrientationChangeEvent, false );
51330  
51331			scope.enabled = false;
vendor: 1,895 bytes, lines 51332-51415
51332  
51333		};
51334  
51335		this.update = function () {
51336  
51337			if ( scope.enabled === false ) return;
51338  
51339			var device = scope.deviceOrientation;
51340  
51341			if ( device ) {
51342  
51343				var alpha = device.alpha ? _Math.degToRad( device.alpha ) + scope.alphaOffset : 0; // Z
51344  
51345				var beta = device.beta ? _Math.degToRad( device.beta ) : 0; // X'
51346  
51347				var gamma = device.gamma ? _Math.degToRad( device.gamma ) : 0; // Y''
51348  
51349				var orient = scope.screenOrientation ? _Math.degToRad( scope.screenOrientation ) : 0; // O
51350  
51351				setObjectQuaternion( scope.object.quaternion, alpha, beta, gamma, orient );
51352  
51353			}
51354  
51355  
51356		};
51357  
51358		this.dispose = function () {
51359  
51360			scope.disconnect();
51361  
51362		};
51363  
51364		this.connect();
51365  
51366	};
51367  
51368	/**
51369	 * Convert a quaternion to an angle
51370	 *
51371	 * Taken from https://stackoverflow.com/a/35448946
51372	 * Thanks P. Ellul
51373	 */
51374  
51375	function Quat2Angle(x, y, z, w) {
51376	  var test = x * y + z * w; // singularity at north pole
51377  
51378	  if (test > 0.499) {
51379		var _yaw = 2 * Math.atan2(x, w);
51380  
51381		var _pitch = Math.PI / 2;
51382  
51383		var _roll = 0;
51384		return new Vector3(_pitch, _roll, _yaw);
51385	  } // singularity at south pole
51386  
51387  
51388	  if (test < -0.499) {
51389		var _yaw2 = -2 * Math.atan2(x, w);
51390  
51391		var _pitch2 = -Math.PI / 2;
51392  
51393		var _roll2 = 0;
51394		return new Vector3(_pitch2, _roll2, _yaw2);
51395	  }
51396  
51397	  var sqx = x * x;
51398	  var sqy = y * y;
51399	  var sqz = z * z;
51400	  var yaw = Math.atan2(2 * y * w - 2 * x * z, 1 - 2 * sqy - 2 * sqz);
51401	  var pitch = Math.asin(2 * test);
51402	  var roll = Math.atan2(2 * x * w - 2 * y * z, 1 - 2 * sqx - 2 * sqz);
51403	  return new Vector3(pitch, roll, yaw);
51404	}
51405  
51406	var OrbitOrientationControls =
51407	/*#__PURE__*/
51408	function () {
51409	  function OrbitOrientationControls(options) {
51410		this.object = options.camera;
51411		this.domElement = options.canvas;
51412		this.orbit = new OrbitControls(this.object, this.domElement);
51413		this.speed = 0.5;
51414		this.orbit.target.set(0, 0, -1);
51415		this.orbit.enableZoom = false;
51416		this.orbit.enablePan = false;
51417		this.orbit.rotateSpeed = -this.speed; // if orientation is supported
51418  
51419		if (options.orientation) {
51420		  this.orientation = new DeviceOrientationControls(this.object);
51421		} // if projection is not full view
51422		// limit the rotation angle in order to not display back half view
51423  
51424  
51425		if (options.halfView) {
51426		  this.orbit.minAzimuthAngle = -Math.PI / 4;
51427		  this.orbit.maxAzimuthAngle = Math.PI / 4;
51428		}
51429	  }
51430  
51431	  var _proto = OrbitOrientationControls.prototype;
51432  
51433	  _proto.update = function update() {
51434		// orientation updates the camera using quaternions and
51435		// orbit updates the camera using angles. They are incompatible
51436		// and one update overrides the other. So before
51437		// orbit overrides orientation we convert our quaternion changes to
51438		// an angle change. Then save the angle into orbit so that
51439		// it will take those into account when it updates the camera and overrides
51440		// our changes
51441		if (this.orientation) {
51442		  this.orientation.update();
51443		  var quat = this.orientation.object.quaternion;
51444		  var currentAngle = Quat2Angle(quat.x, quat.y, quat.z, quat.w); // we also have to store the last angle since quaternions are b
51445  
51446		  if (typeof this.lastAngle_ === 'undefined') {
51447			this.lastAngle_ = currentAngle;
51448		  }
51449  
51450		  this.orbit.rotateLeft((this.lastAngle_.z - currentAngle.z) * (1 + this.speed));
51451		  this.orbit.rotateUp((this.lastAngle_.y - currentAngle.y) * (1 + this.speed));
51452		  this.lastAngle_ = currentAngle;
51453		}
51454  
51455		this.orbit.update();
51456	  };
51457  
51458	  _proto.dispose = function dispose() {
51459		this.orbit.dispose();
51460  
51461		if (this.orientation) {
51462		  this.orientation.dispose();
51463		}
51464	  };
51465  
51466	  return OrbitOrientationControls;
51467	}();
51468  
51469	var corsSupport = function () {
51470	  var video = document$1.createElement('video');
51471	  video.crossOrigin = 'anonymous';
51472	  return video.hasAttribute('crossorigin');
51473	}();
51474	var validProjections = ['360', '360_LR', '360_TB', '360_CUBE', 'EAC', 'EAC_LR', 'NONE', 'AUTO', 'Sphere', 'Cube', 'equirectangular', '180', '180_LR', '180_MONO'];
51475	var getInternalProjectionName = function getInternalProjectionName(projection) {
51476	  if (!projection) {
51477		return;
51478	  }
51479  
51480	  projection = projection.toString().trim();
51481  
51482	  if (/sphere/i.test(projection)) {
51483		return '360';
51484	  }
51485  
51486	  if (/cube/i.test(projection)) {
51487		return '360_CUBE';
51488	  }
51489  
51490	  if (/equirectangular/i.test(projection)) {
51491		return '360';
51492	  }
51493  
51494	  for (var i = 0; i < validProjections.length; i++) {
51495		if (new RegExp('^' + validProjections[i] + '$', 'i').test(projection)) {
51496		  return validProjections[i];
51497		}
51498	  }
51499	};
51500  
51501	/**
51502	 * This class reacts to interactions with the canvas and
51503	 * triggers appropriate functionality on the player. Right now
51504	 * it does two things:
51505	 *
51506	 * 1. A `mousedown`/`touchstart` followed by `touchend`/`mouseup` without any
51507	 *    `touchmove` or `mousemove` toggles play/pause on the player
51508	 * 2. Only moving on/clicking the control bar or toggling play/pause should
51509	 *    show the control bar. Moving around the scene in the canvas should not.
51510	 */
51511  
51512	var CanvasPlayerControls =
51513	/*#__PURE__*/
51514	function (_videojs$EventTarget) {
51515	  inheritsLoose(CanvasPlayerControls, _videojs$EventTarget);
51516  
51517	  function CanvasPlayerControls(player, canvas) {
51518		var _this;
51519  
51520		_this = _videojs$EventTarget.call(this) || this;
51521		_this.player = player;
51522		_this.canvas = canvas;
51523		_this.onMoveEnd = videojs.bind(assertThisInitialized(_this), _this.onMoveEnd);
51524		_this.onMoveStart = videojs.bind(assertThisInitialized(_this), _this.onMoveStart);
51525		_this.onMove = videojs.bind(assertThisInitialized(_this), _this.onMove);
51526		_this.onControlBarMove = videojs.bind(assertThisInitialized(_this), _this.onControlBarMove);
51527  
51528		_this.player.controlBar.on(['mousedown', 'mousemove', 'mouseup', 'touchstart', 'touchmove', 'touchend'], _this.onControlBarMove); // we have to override these here because
51529		// video.js listens for user activity on the video element
51530		// and makes the user active when the mouse moves.
51531		// We don't want that for 3d videos
51532  
51533  
51534		_this.oldReportUserActivity = _this.player.reportUserActivity;
51535  
51536		_this.player.reportUserActivity = function () {}; // canvas movements
51537  
51538  
51539		_this.canvas.addEventListener('mousedown', _this.onMoveStart);
51540  
51541		_this.canvas.addEventListener('touchstart', _this.onMoveStart);
51542  
51543		_this.canvas.addEventListener('mousemove', _this.onMove);
51544  
51545		_this.canvas.addEventListener('touchmove', _this.onMove);
51546  
51547		_this.canvas.addEventListener('mouseup', _this.onMoveEnd);
51548  
51549		_this.canvas.addEventListener('touchend', _this.onMoveEnd);
51550  
51551		_this.shouldTogglePlay = false;
51552		return _this;
51553	  }
51554  
51555	  var _proto = CanvasPlayerControls.prototype;
51556  
51557	  _proto.togglePlay = function togglePlay() {
51558		if (this.player.paused()) {
51559		  this.player.play();
51560		} else {
51561		  this.player.pause();
51562		}
51563	  };
51564  
51565	  _proto.onMoveStart = function onMoveStart(e) {
51566		// if the player does not have a controlbar or
51567		// the move was a mouse click but not left click do not
51568		// toggle play.
51569		if (!this.player.controls() || e.type === 'mousedown' && !videojs.dom.isSingleLeftClick(e)) {
51570		  this.shouldTogglePlay = false;
51571		  return;
51572		}
51573  
51574		this.shouldTogglePlay = true;
51575		this.touchMoveCount_ = 0;
51576	  };
51577  
51578	  _proto.onMoveEnd = function onMoveEnd(e) {
51579		// We want to have the same behavior in VR360 Player and standard player.
51580		// in touchend we want to know if was a touch click, for a click we show the bar,
51581		// otherwise continue with the mouse logic.
51582		//
51583		// Maximum movement allowed during a touch event to still be considered a tap
51584		// Other popular libs use anywhere from 2 (hammer.js) to 15,
51585		// so 10 seems like a nice, round number.
51586		if (e.type === 'touchend' && this.touchMoveCount_ < 10) {
51587		  if (this.player.userActive() === false) {
51588			this.player.userActive(true);
51589			return;
51590		  }
51591  
51592		  this.player.userActive(false);
51593		  return;
51594		}
51595  
51596		if (!this.shouldTogglePlay) {
51597		  return;
51598		} // We want the same behavior in Desktop for VR360  and standard player
51599  
51600  
51601		if (e.type == 'mouseup') {
51602		  this.togglePlay();
51603		}
51604	  };
51605  
51606	  _proto.onMove = function onMove(e) {
51607		// Increase touchMoveCount_ since Android detects 1 - 6 touches when user click normally
51608		this.touchMoveCount_++;
51609		this.shouldTogglePlay = false;
51610	  };
51611  
51612	  _proto.onControlBarMove = function onControlBarMove(e) {
51613		this.player.userActive(true);
51614	  };
51615  
51616	  _proto.dispose = function dispose() {
51617		this.canvas.removeEventListener('mousedown', this.onMoveStart);
51618		this.canvas.removeEventListener('touchstart', this.onMoveStart);
51619		this.canvas.removeEventListener('mousemove', this.onMove);
51620		this.canvas.removeEventListener('touchmove', this.onMove);
51621		this.canvas.removeEventListener('mouseup', this.onMoveEnd);
51622		this.canvas.removeEventListener('touchend', this.onMoveEnd);
51623		this.player.controlBar.off(['mousedown', 'mousemove', 'mouseup', 'touchstart', 'touchmove', 'touchend'], this.onControlBarMove);
51624		this.player.reportUserActivity = this.oldReportUserActivity;
51625	  };
51626  
51627	  return CanvasPlayerControls;
51628	}(videojs.EventTarget);
51629  
51630	/**
51631	 * This class manages ambisonic decoding and binaural rendering via Omnitone library.
51632	 */
51633  
51634	var OmnitoneController =
51635	/*#__PURE__*/
51636	function (_videojs$EventTarget) {
51637	  inheritsLoose(OmnitoneController, _videojs$EventTarget);
51638  
51639	  /**
51640	   * Omnitone controller class.
51641	   *
51642	   * @class
51643	   * @param {AudioContext} audioContext - associated AudioContext.
51644	   * @param {Omnitone library} omnitone - Omnitone library element.
51645	   * @param {HTMLVideoElement} video - vidoe tag element.
51646	   * @param {Object} options - omnitone options.
51647	   */
51648	  function OmnitoneController(audioContext, omnitone, video, options) {
51649		var _this;
51650  
51651		_this = _videojs$EventTarget.call(this) || this;
51652		var settings = videojs.mergeOptions({
51653		  // Safari uses the different AAC decoder than FFMPEG. The channel order is
51654		  // The default 4ch AAC channel layout for FFMPEG AAC channel ordering.
51655		  channelMap: videojs.browser.IS_SAFARI ? [2, 0, 1, 3] : [0, 1, 2, 3],
51656		  ambisonicOrder: 1
51657		}, options);
51658		_this.videoElementSource = audioContext.createMediaElementSource(video);
51659		_this.foaRenderer = omnitone.createFOARenderer(audioContext, settings);
51660  
51661		_this.foaRenderer.initialize().then(function () {
51662		  if (audioContext.state === 'suspended') {
51663			_this.trigger({
51664			  type: 'audiocontext-suspended'
51665			});
51666		  }
51667  
51668		  _this.videoElementSource.connect(_this.foaRenderer.input);
51669  
51670		  _this.foaRenderer.output.connect(audioContext.destination);
51671  
51672		  _this.initialized = true;
51673  
51674		  _this.trigger({
51675			type: 'omnitone-ready'
51676		  });
51677		}, function (error) {
51678		  videojs.log.warn("videojs-vr: Omnitone initializes failed with the following error: " + error + ")");
51679		});
51680  
51681		return _this;
51682	  }
51683	  /**
51684	   * Updates the rotation of the Omnitone decoder based on three.js camera matrix.
51685	   *
51686	   * @param {Camera} camera Three.js camera object
51687	   */
51688  
51689  
51690	  var _proto = OmnitoneController.prototype;
51691  
51692	  _proto.update = function update(camera) {
51693		if (!this.initialized) {
51694		  return;
51695		}
51696  
51697		this.foaRenderer.setRotationMatrixFromCamera(camera.matrix);
51698	  }
51699	  /**
51700	   * Destroys the controller and does any necessary cleanup.
51701	   */
51702	  ;
51703  
51704	  _proto.dispose = function dispose() {
51705		this.initialized = false;
51706		this.foaRenderer.setRenderingMode('bypass');
51707		this.foaRenderer = null;
51708	  };
51709  
51710	  return OmnitoneController;
51711	}(videojs.EventTarget);
51712  
51713	var Button = videojs.getComponent('Button');
51714  
51715	var CardboardButton =
51716	/*#__PURE__*/
51717	function (_Button) {
51718	  inheritsLoose(CardboardButton, _Button);
51719  
51720	  function CardboardButton(player, options) {
51721		var _this;
51722  
51723		_this = _Button.call(this, player, options) || this;
51724		_this.handleVrDisplayActivate_ = videojs.bind(assertThisInitialized(_this), _this.handleVrDisplayActivate_);
51725		_this.handleVrDisplayDeactivate_ = videojs.bind(assertThisInitialized(_this), _this.handleVrDisplayDeactivate_);
51726		_this.handleVrDisplayPresentChange_ = videojs.bind(assertThisInitialized(_this), _this.handleVrDisplayPresentChange_);
51727		_this.handleOrientationChange_ = videojs.bind(assertThisInitialized(_this), _this.handleOrientationChange_);
51728		window$1.addEventListener('orientationchange', _this.handleOrientationChange_);
51729		window$1.addEventListener('vrdisplayactivate', _this.handleVrDisplayActivate_);
51730		window$1.addEventListener('vrdisplaydeactivate', _this.handleVrDisplayDeactivate_); // vrdisplaypresentchange does not fire activate or deactivate
51731		// and happens when hitting the back button during cardboard mode
51732		// so we need to make sure we stay in the correct state by
51733		// listening to it and checking if we are presenting it or not
51734  
51735		window$1.addEventListener('vrdisplaypresentchange', _this.handleVrDisplayPresentChange_); // we cannot show the cardboard button in fullscreen on
51736		// android as it breaks the controls, and makes it impossible
51737		// to exit cardboard mode
51738  
51739		if (videojs.browser.IS_ANDROID) {
51740		  _this.on(player, 'fullscreenchange', function () {
51741			if (player.isFullscreen()) {
51742			  _this.hide();
51743			} else {
51744			  _this.show();
51745			}
51746		  });
51747		}
51748  
51749		return _this;
51750	  }
51751  
51752	  var _proto = CardboardButton.prototype;
51753  
51754	  _proto.buildCSSClass = function buildCSSClass() {
51755		return "vjs-button-vr " + _Button.prototype.buildCSSClass.call(this);
51756	  };
51757  
51758	  _proto.handleVrDisplayPresentChange_ = function handleVrDisplayPresentChange_() {
51759		if (!this.player_.vr().vrDisplay.isPresenting && this.active_) {
51760		  this.handleVrDisplayDeactivate_();
51761		}
51762  
51763		if (this.player_.vr().vrDisplay.isPresenting && !this.active_) {
51764		  this.handleVrDisplayActivate_();
51765		}
51766	  };
51767  
51768	  _proto.handleOrientationChange_ = function handleOrientationChange_() {
51769		if (this.active_ && videojs.browser.IS_IOS) {
51770		  this.changeSize_();
51771		}
51772	  };
51773  
51774	  _proto.changeSize_ = function changeSize_() {
51775		this.player_.width(window$1.innerWidth);
51776		this.player_.height(window$1.innerHeight);
51777		window$1.dispatchEvent(new window$1.Event('resize'));
51778	  };
51779  
51780	  _proto.handleVrDisplayActivate_ = function handleVrDisplayActivate_() {
51781		// we mimic fullscreen on IOS
51782		if (videojs.browser.IS_IOS) {
51783		  this.oldWidth_ = this.player_.currentWidth();
51784		  this.oldHeight_ = this.player_.currentHeight();
51785		  this.player_.enterFullWindow();
51786		  this.changeSize_();
51787		}
51788  
51789		this.active_ = true;
51790	  };
51791  
51792	  _proto.handleVrDisplayDeactivate_ = function handleVrDisplayDeactivate_() {
51793		// un-mimic fullscreen on iOS
51794		if (videojs.browser.IS_IOS) {
51795		  if (this.oldWidth_) {
51796			this.player_.width(this.oldWidth_);
51797		  }
51798  
51799		  if (this.oldHeight_) {
51800			this.player_.height(this.oldHeight_);
51801		  }
51802  
51803		  this.player_.exitFullWindow();
51804		}
51805  
51806		this.active_ = false;
51807	  };
51808  
51809	  _proto.handleClick = function handleClick(event) {
51810		// if cardboard mode display is not active, activate it
51811		// otherwise deactivate it
51812		if (!this.active_) {
51813		  // This starts playback mode when the cardboard button
51814		  // is clicked on Android. We need to do this as the controls
51815		  // disappear
51816		  if (!this.player_.hasStarted() && videojs.browser.IS_ANDROID) {
51817			this.player_.play();
51818		  }
51819  
51820		  window$1.dispatchEvent(new window$1.Event('vrdisplayactivate'));
51821		} else {
51822		  window$1.dispatchEvent(new window$1.Event('vrdisplaydeactivate'));
51823		}
51824	  };
51825  
51826	  _proto.dispose = function dispose() {
51827		_Button.prototype.dispose.call(this);
51828  
51829		window$1.removeEventListener('vrdisplayactivate', this.handleVrDisplayActivate_);
51830		window$1.removeEventListener('vrdisplaydeactivate', this.handleVrDisplayDeactivate_);
51831		window$1.removeEventListener('vrdisplaypresentchange', this.handleVrDisplayPresentChange_);
51832	  };
51833  
51834	  return CardboardButton;
51835	}(Button);
51836  
51837	videojs.registerComponent('CardboardButton', CardboardButton);
51838  
51839	var BigPlayButton = videojs.getComponent('BigPlayButton');
51840  
51841	var BigVrPlayButton =
51842	/*#__PURE__*/
51843	function (_BigPlayButton) {
51844	  inheritsLoose(BigVrPlayButton, _BigPlayButton);
51845  
51846	  function BigVrPlayButton() {
51847		return _BigPlayButton.apply(this, arguments) || this;
51848	  }
51849  
51850	  var _proto = BigVrPlayButton.prototype;
51851  
51852	  _proto.buildCSSClass = function buildCSSClass() {
51853		return "vjs-big-vr-play-button " + _BigPlayButton.prototype.buildCSSClass.call(this);
51854	  };
51855  
51856	  return BigVrPlayButton;
51857	}(BigPlayButton);
51858  
51859	videojs.registerComponent('BigVrPlayButton', BigVrPlayButton);
51860  
51861	var defaults = {
51862	  debug: false,
51863	  omnitone: false,
51864	  forceCardboard: false,
51865	  omnitoneOptions: {},
51866	  projection: 'AUTO',
51867	  sphereDetail: 32
51868	};
51869	var errors = {
51870	  'web-vr-out-of-date': {
51871		headline: '360 is out of date',
51872		type: '360_OUT_OF_DATE',
51873		message: "Your browser supports 360 but not the latest version. See <a href='http://webvr.info'>http://webvr.info</a> for more info."
51874	  },
51875	  'web-vr-not-supported': {
51876		headline: '360 not supported on this device',
51877		type: '360_NOT_SUPPORTED',
51878		message: "Your browser does not support 360. See <a href='http://webvr.info'>http://webvr.info</a> for assistance."
51879	  },
51880	  'web-vr-hls-cors-not-supported': {
51881		headline: '360 HLS video not supported on this device',
51882		type: '360_NOT_SUPPORTED',
51883		message: "Your browser/device does not support HLS 360 video. See <a href='http://webvr.info'>http://webvr.info</a> for assistance."
51884	  }
51885	};
51886	var Plugin = videojs.getPlugin('plugin');
51887	var Component = videojs.getComponent('Component');
51888  
51889	var VR =
51890	/*#__PURE__*/
51891	function (_Plugin) {
51892	  inheritsLoose(VR, _Plugin);
51893  
51894	  function VR(player, options) {
51895		var _this;
51896  
51897		var settings = videojs.mergeOptions(defaults, options);
51898		_this = _Plugin.call(this, player, settings) || this;
51899		_this.options_ = settings;
51900		_this.player_ = player;
51901		_this.bigPlayButtonIndex_ = player.children().indexOf(player.getChild('BigPlayButton')) || 0; // custom videojs-errors integration boolean
51902  
51903		_this.videojsErrorsSupport_ = !!videojs.errors;
51904  
51905		if (_this.videojsErrorsSupport_) {
51906		  player.errors({
51907			errors: errors
51908		  });
51909		} // IE 11 does not support enough webgl to be supported
51910		// older safari does not support cors, so it wont work
51911  
51912  
51913		if (videojs.browser.IE_VERSION || !corsSupport) {
51914		  // if a player triggers error before 'loadstart' is fired
51915		  // video.js will reset the error overlay
51916		  _this.player_.on('loadstart', function () {
51917			_this.triggerError_({
51918			  code: 'web-vr-not-supported',
51919			  dismiss: false
51920			});
51921		  });
51922  
51923		  return assertThisInitialized(_this);
51924		}
51925  
51926		_this.polyfill_ = new WebVRPolyfill({
51927		  // do not show rotate instructions
51928		  ROTATE_INSTRUCTIONS_DISABLED: true
51929		});
51930		_this.polyfill_ = new WebVRPolyfill();
51931		_this.handleVrDisplayActivate_ = videojs.bind(assertThisInitialized(_this), _this.handleVrDisplayActivate_);
51932		_this.handleVrDisplayDeactivate_ = videojs.bind(assertThisInitialized(_this), _this.handleVrDisplayDeactivate_);
51933		_this.handleResize_ = videojs.bind(assertThisInitialized(_this), _this.handleResize_);
51934		_this.animate_ = videojs.bind(assertThisInitialized(_this), _this.animate_);
51935  
51936		_this.setProjection(_this.options_.projection); // any time the video element is recycled for ads
51937		// we have to reset the vr state and re-init after ad
51938  
51939  
51940		_this.on(player, 'adstart', function () {
51941		  return player.setTimeout(function () {
51942			// if the video element was recycled for this ad
51943			if (!player.ads || !player.ads.videoElementRecycled()) {
51944			  _this.log('video element not recycled for this ad, no need to reset');
51945  
51946			  return;
51947			}
51948  
51949			_this.log('video element recycled for this ad, reseting');
51950  
51951			_this.reset();
51952  
51953			_this.one(player, 'playing', _this.init);
51954		  });
51955		}, 1);
51956  
51957		_this.on(player, 'loadedmetadata', _this.init);
51958  
51959		return _this;
51960	  }
51961  
51962	  var _proto = VR.prototype;
51963  
51964	  _proto.changeProjection_ = function changeProjection_(projection) {
51965		var _this2 = this;
51966  
51967		projection = getInternalProjectionName(projection); // don't change to an invalid projection
51968  
51969		if (!projection) {
51970		  projection = 'NONE';
51971		}
51972  
51973		var position = {
51974		  x: 0,
51975		  y: 0,
51976		  z: 0
51977		};
51978  
51979		if (this.scene) {
51980		  this.scene.remove(this.movieScreen);
51981		}
51982  
51983		if (projection === 'AUTO') {
51984		  // mediainfo cannot be set to auto or we would infinite loop here
51985		  // each source should know whatever they are 360 or not, if using AUTO
51986		  if (this.player_.mediainfo && this.player_.mediainfo.projection && this.player_.mediainfo.projection !== 'AUTO') {
51987			var autoProjection = getInternalProjectionName(this.player_.mediainfo.projection);
51988			return this.changeProjection_(autoProjection);
51989		  }
51990  
51991		  return this.changeProjection_('NONE');
51992		} else if (projection === '360') {
51993		  this.movieGeometry = new SphereBufferGeometry(256, this.options_.sphereDetail, this.options_.sphereDetail);
51994		  this.movieMaterial = new MeshBasicMaterial({
51995			map: this.videoTexture,
51996			overdraw: true,
51997			side: BackSide
51998		  });
51999		  this.movieScreen = new Mesh(this.movieGeometry, this.movieMaterial);
52000		  this.movieScreen.position.set(position.x, position.y, position.z);
52001		  this.movieScreen.scale.x = -1;
52002		  this.movieScreen.quaternion.setFromAxisAngle({
52003			x: 0,
52004			y: 1,
52005			z: 0
52006		  }, -Math.PI / 2);
52007		  this.scene.add(this.movieScreen);
52008		} else if (projection === '360_LR' || projection === '360_TB') {
52009		  // Left eye view
52010		  var geometry = new SphereGeometry(256, this.options_.sphereDetail, this.options_.sphereDetail);
52011		  var uvs = geometry.faceVertexUvs[0];
52012  
52013		  for (var i = 0; i < uvs.length; i++) {
52014			for (var j = 0; j < 3; j++) {
52015			  if (projection === '360_LR') {
52016				uvs[i][j].x *= 0.5;
52017			  } else {
52018				uvs[i][j].y *= 0.5;
52019				uvs[i][j].y += 0.5;
52020			  }
52021			}
52022		  }
52023  
52024		  this.movieGeometry = new BufferGeometry().fromGeometry(geometry);
52025		  this.movieMaterial = new MeshBasicMaterial({
52026			map: this.videoTexture,
52027			overdraw: true,
52028			side: BackSide
52029		  });
52030		  this.movieScreen = new Mesh(this.movieGeometry, this.movieMaterial);
52031		  this.movieScreen.scale.x = -1;
52032		  this.movieScreen.quaternion.setFromAxisAngle({
52033			x: 0,
52034			y: 1,
52035			z: 0
52036		  }, -Math.PI / 2); // display in left eye only
52037  
52038		  this.movieScreen.layers.set(1);
52039		  this.scene.add(this.movieScreen); // Right eye view
52040  
52041		  geometry = new SphereGeometry(256, this.options_.sphereDetail, this.options_.sphereDetail);
52042		  uvs = geometry.faceVertexUvs[0];
52043  
52044		  for (var _i = 0; _i < uvs.length; _i++) {
52045			for (var _j = 0; _j < 3; _j++) {
52046			  if (projection === '360_LR') {
52047				uvs[_i][_j].x *= 0.5;
52048				uvs[_i][_j].x += 0.5;
52049			  } else {
52050				uvs[_i][_j].y *= 0.5;
52051			  }
52052			}
52053		  }
52054  
52055		  this.movieGeometry = new BufferGeometry().fromGeometry(geometry);
52056		  this.movieMaterial = new MeshBasicMaterial({
52057			map: this.videoTexture,
52058			overdraw: true,
52059			side: BackSide
52060		  });
52061		  this.movieScreen = new Mesh(this.movieGeometry, this.movieMaterial);
52062		  this.movieScreen.scale.x = -1;
52063		  this.movieScreen.quaternion.setFromAxisAngle({
52064			x: 0,
52065			y: 1,
52066			z: 0
52067		  }, -Math.PI / 2); // display in right eye only
52068  
52069		  this.movieScreen.layers.set(2);
52070		  this.scene.add(this.movieScreen);
52071		} else if (projection === '360_CUBE') {
52072		  this.movieGeometry = new BoxGeometry(256, 256, 256);
52073		  this.movieMaterial = new MeshBasicMaterial({
52074			map: this.videoTexture,
52075			overdraw: true,
52076			side: BackSide
52077		  });
52078		  var left = [new Vector2(0, 0.5), new Vector2(0.333, 0.5), new Vector2(0.333, 1), new Vector2(0, 1)];
52079		  var right = [new Vector2(0.333, 0.5), new Vector2(0.666, 0.5), new Vector2(0.666, 1), new Vector2(0.333, 1)];
52080		  var top = [new Vector2(0.666, 0.5), new Vector2(1, 0.5), new Vector2(1, 1), new Vector2(0.666, 1)];
52081		  var bottom = [new Vector2(0, 0), new Vector2(0.333, 0), new Vector2(0.333, 0.5), new Vector2(0, 0.5)];
52082		  var front = [new Vector2(0.333, 0), new Vector2(0.666, 0), new Vector2(0.666, 0.5), new Vector2(0.333, 0.5)];
52083		  var back = [new Vector2(0.666, 0), new Vector2(1, 0), new Vector2(1, 0.5), new Vector2(0.666, 0.5)];
52084		  this.movieGeometry.faceVertexUvs[0] = [];
52085		  this.movieGeometry.faceVertexUvs[0][0] = [right[2], right[1], right[3]];
52086		  this.movieGeometry.faceVertexUvs[0][1] = [right[1], right[0], right[3]];
52087		  this.movieGeometry.faceVertexUvs[0][2] = [left[2], left[1], left[3]];
52088		  this.movieGeometry.faceVertexUvs[0][3] = [left[1], left[0], left[3]];
52089		  this.movieGeometry.faceVertexUvs[0][4] = [top[2], top[1], top[3]];
52090		  this.movieGeometry.faceVertexUvs[0][5] = [top[1], top[0], top[3]];
52091		  this.movieGeometry.faceVertexUvs[0][6] = [bottom[2], bottom[1], bottom[3]];
52092		  this.movieGeometry.faceVertexUvs[0][7] = [bottom[1], bottom[0], bottom[3]];
52093		  this.movieGeometry.faceVertexUvs[0][8] = [front[2], front[1], front[3]];
52094		  this.movieGeometry.faceVertexUvs[0][9] = [front[1], front[0], front[3]];
52095		  this.movieGeometry.faceVertexUvs[0][10] = [back[2], back[1], back[3]];
52096		  this.movieGeometry.faceVertexUvs[0][11] = [back[1], back[0], back[3]];
52097		  this.movieScreen = new Mesh(this.movieGeometry, this.movieMaterial);
52098		  this.movieScreen.position.set(position.x, position.y, position.z);
52099		  this.movieScreen.rotation.y = -Math.PI;
52100		  this.scene.add(this.movieScreen);
52101		} else if (projection === '180' || projection === '180_LR' || projection === '180_MONO') {
52102		  var _geometry = new SphereGeometry(256, this.options_.sphereDetail, this.options_.sphereDetail, Math.PI, Math.PI); // Left eye view
52103  
52104  
52105		  _geometry.scale(-1, 1, 1);
52106  
52107		  var _uvs = _geometry.faceVertexUvs[0];
52108  
52109		  if (projection !== '180_MONO') {
52110			for (var _i2 = 0; _i2 < _uvs.length; _i2++) {
52111			  for (var _j2 = 0; _j2 < 3; _j2++) {
52112				_uvs[_i2][_j2].x *= 0.5;
52113			  }
52114			}
52115		  }
52116  
52117		  this.movieGeometry = new BufferGeometry().fromGeometry(_geometry);
52118		  this.movieMaterial = new MeshBasicMaterial({
52119			map: this.videoTexture,
52120			overdraw: true
52121		  });
52122		  this.movieScreen = new Mesh(this.movieGeometry, this.movieMaterial); // display in left eye only
52123  
52124		  this.movieScreen.layers.set(1);
52125		  this.scene.add(this.movieScreen); // Right eye view
52126  
52127		  _geometry = new SphereGeometry(256, this.options_.sphereDetail, this.options_.sphereDetail, Math.PI, Math.PI);
52128  
52129		  _geometry.scale(-1, 1, 1);
52130  
52131		  _uvs = _geometry.faceVertexUvs[0];
52132  
52133		  for (var _i3 = 0; _i3 < _uvs.length; _i3++) {
52134			for (var _j3 = 0; _j3 < 3; _j3++) {
52135			  _uvs[_i3][_j3].x *= 0.5;
52136			  _uvs[_i3][_j3].x += 0.5;
52137			}
52138		  }
52139  
52140		  this.movieGeometry = new BufferGeometry().fromGeometry(_geometry);
52141		  this.movieMaterial = new MeshBasicMaterial({
52142			map: this.videoTexture,
52143			overdraw: true
52144		  });
52145		  this.movieScreen = new Mesh(this.movieGeometry, this.movieMaterial); // display in right eye only
52146  
52147		  this.movieScreen.layers.set(2);
52148		  this.scene.add(this.movieScreen);
52149		} else if (projection === 'EAC' || projection === 'EAC_LR') {
52150		  var makeScreen = function makeScreen(mapMatrix, scaleMatrix) {
52151			// "Continuity correction?": because of discontinuous faces and aliasing,
52152			// we truncate the 2-pixel-wide strips on all discontinuous edges,
52153			var contCorrect = 2;
52154			_this2.movieGeometry = new BoxGeometry(256, 256, 256);
52155			_this2.movieMaterial = new ShaderMaterial({
52156			  overdraw: true,
52157			  side: BackSide,
52158			  uniforms: {
52159				mapped: {
52160				  value: _this2.videoTexture
52161				},
52162				mapMatrix: {
52163				  value: mapMatrix
52164				},
52165				contCorrect: {
52166				  value: contCorrect
52167				},
52168				faceWH: {
52169				  value: new Vector2(1 / 3, 1 / 2).applyMatrix3(scaleMatrix)
52170				},
52171				vidWH: {
52172				  value: new Vector2(_this2.videoTexture.image.videoWidth, _this2.videoTexture.image.videoHeight).applyMatrix3(scaleMatrix)
52173				}
52174			  },
52175			  vertexShader: "\nvarying vec2 vUv;\nuniform mat3 mapMatrix;\n\nvoid main() {\n  vUv = (mapMatrix * vec3(uv, 1.)).xy;\n  gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.);\n}",
52176			  fragmentShader: "\nvarying vec2 vUv;\nuniform sampler2D mapped;\nuniform vec2 faceWH;\nuniform vec2 vidWH;\nuniform float contCorrect;\n\nconst float PI = 3.1415926535897932384626433832795;\n\nvoid main() {\n  vec2 corner = vUv - mod(vUv, faceWH) + vec2(0, c
52176ontCorrect / vidWH.y);\n\n  vec2 faceWHadj = faceWH - vec2(0, contCorrect * 2. / vidWH.y);\n\n  vec2 p = (vUv - corner) / faceWHadj - .5;\n  vec2 q = 2. / PI * atan(2. * p) + .5;\n\n  vec2 eUv = corner + q * faceWHadj;\n\n  gl_FragColor = texture2D(mapped, eUv);\n}"
52177			});
52178			var right = [new Vector2(0, 1 / 2), new Vector2(1 / 3, 1 / 2), new Vector2(1 / 3, 1), new Vector2(0, 1)];
52179			var front = [new Vector2(1 / 3, 1 / 2), new Vector2(2 / 3, 1 / 2), new Vector2(2 / 3, 1), new Vector2(1 / 3, 1)];
52180			var left = [new Vector2(2 / 3, 1 / 2), new Vector2(1, 1 / 2), new Vector2(1, 1), new Vector2(2 / 3, 1)];
52181			var bottom = [new Vector2(1 / 3, 0), new Vector2(1 / 3, 1 / 2), new Vector2(0, 1 / 2), new Vector2(0, 0)];
52182			var back = [new Vector2(1 / 3, 1 / 2), new Vector2(1 / 3, 0), new Vector2(2 / 3, 0), new Vector2(2 / 3, 1 / 2)];
52183			var top = [new Vector2(1, 0), new Vector2(1, 1 / 2), new Vector2(2 / 3, 1 / 2), new Vector2(2 / 3, 0)];
52184  
52185			for (var _i4 = 0, _arr = [right, front, left, bottom, back, top]; _i4 < _arr.length; _i4++) {
52186			  var face = _arr[_i4];
52187			  var height = _this2.videoTexture.image.videoHeight;
52188			  var lowY = 1;
52189			  var highY = 0;
52190  
52191			  for (var _iterator = face, _isArray = Array.isArray(_iterator), _i5 = 0, _iterator = _isArray ? _iterator : _iterator[Symbol.iterator]();;) {
52192				var _ref;
52193  
52194				if (_isArray) {
52195				  if (_i5 >= _iterator.length) break;
52196				  _ref = _iterator[_i5++];
52197				} else {
52198				  _i5 = _iterator.next();
52199				  if (_i5.done) break;
52200				  _ref = _i5.value;
52201				}
52202  
52203				var vector = _ref;
52204  
52205				if (vector.y < lowY) {
52206				  lowY = vector.y;
52207				}
52208  
52209				if (vector.y > highY) {
52210				  highY = vector.y;
52211				}
52212			  }
52213  
52214			  for (var _iterator2 = face, _isArray2 = Array.isArray(_iterator2), _i6 = 0, _iterator2 = _isArray2 ? _iterator2 : _iterator2[Symbol.iterator]();;) {
52215				var _ref2;
52216  
52217				if (_isArray2) {
52218				  if (_i6 >= _iterator2.length) break;
52219				  _ref2 = _iterator2[_i6++];
52220				} else {
52221				  _i6 = _iterator2.next();
52222				  if (_i6.done) break;
52223				  _ref2 = _i6.value;
52224				}
52225  
52226				var _vector = _ref2;
52227  
52228				if (Math.abs(_vector.y - lowY) < Number.EPSILON) {
52229				  _vector.y += contCorrect / height;
52230				}
52231  
52232				if (Math.abs(_vector.y - highY) < Number.EPSILON) {
52233				  _vector.y -= contCorrect / height;
52234				}
52235  
52236				_vector.x = _vector.x / height * (height - contCorrect * 2) + contCorrect / height;
52237			  }
52238			}
52239  
52240			_this2.movieGeometry.faceVertexUvs[0] = [];
52241			_this2.movieGeometry.faceVertexUvs[0][0] = [right[2], right[1], right[3]];
52242			_this2.movieGeometry.faceVertexUvs[0][1] = [right[1], right[0], right[3]];
52243			_this2.movieGeometry.faceVertexUvs[0][2] = [left[2], left[1], left[3]];
52244			_this2.movieGeometry.faceVertexUvs[0][3] = [left[1], left[0], left[3]];
52245			_this2.movieGeometry.faceVertexUvs[0][4] = [top[2], top[1], top[3]];
52246			_this2.movieGeometry.faceVertexUvs[0][5] = [top[1], top[0], top[3]];
52247			_this2.movieGeometry.faceVertexUvs[0][6] = [bottom[2], bottom[1], bottom[3]];
52248			_this2.movieGeometry.faceVertexUvs[0][7] = [bottom[1], bottom[0], bottom[3]];
52249			_this2.movieGeometry.faceVertexUvs[0][8] = [front[2], front[1], front[3]];
52250			_this2.movieGeometry.faceVertexUvs[0][9] = [front[1], front[0], front[3]];
52251			_this2.movieGeometry.faceVertexUvs[0][10] = [back[2], back[1], back[3]];
52252			_this2.movieGeometry.faceVertexUvs[0][11] = [back[1], back[0], back[3]];
52253			_this2.movieScreen = new Mesh(_this2.movieGeometry, _this2.movieMaterial);
52254  
52255			_this2.movieScreen.position.set(position.x, position.y, position.z);
52256  
52257			_this2.movieScreen.rotation.y = -Math.PI;
52258			return _this2.movieScreen;
52259		  };
52260  
52261		  if (projection === 'EAC') {
52262			this.scene.add(makeScreen(new Matrix3(), new Matrix3()));
52263		  } else {
52264			var scaleMatrix = new Matrix3().set(0, 0.5, 0, 1, 0, 0, 0, 0, 1);
52265			makeScreen(new Matrix3().set(0, -0.5, 0.5, 1, 0, 0, 0, 0, 1), scaleMatrix); // display in left eye only
52266  
52267			this.movieScreen.layers.set(1);
52268			this.scene.add(this.movieScreen);
52269			makeScreen(new Matrix3().set(0, -0.5, 1, 1, 0, 0, 0, 0, 1), scaleMatrix); // display in right eye only
52270  
52271			this.movieScreen.layers.set(2);
52272			this.scene.add(this.movieScreen);
52273		  }
52274		}
52275  
52276		this.currentProjection_ = projection;
52277	  };
52278  
52279	  _proto.triggerError_ = function triggerError_(errorObj) {
52280		// if we have videojs-errors use it
52281		if (this.videojsErrorsSupport_) {
52282		  this.player_.error(errorObj); // if we don't have videojs-errors just use a normal player error
52283		} else {
52284		  // strip any html content from the error message
52285		  // as it is not supported outside of videojs-errors
52286		  var div = document$1.createElement('div');
52287		  div.innerHTML = errors[errorObj.code].message;
52288		  var message = div.textContent || div.innerText || '';
52289		  this.player_.error({
52290			code: errorObj.code,
52291			message: message
52292		  });
52293		}
52294	  };
52295  
52296	  _proto.log = function log() {
52297		if (!this.options_.debug) {
52298		  return;
52299		}
52300  
52301		for (var _len = arguments.length, msgs = new Array(_len), _key = 0; _key < _len; _key++) {
52302		  msgs[_key] = arguments[_key];
52303		}
52304  
52305		msgs.forEach(function (msg) {
52306		  videojs.log('VR: ', msg);
52307		});
52308	  };
52309  
52310	  _proto.handleVrDisplayActivate_ = function handleVrDisplayActivate_() {
52311		var _this3 = this;
52312  
52313		if (!this.vrDisplay) {
52314		  return;
52315		}
52316  
52317		this.vrDisplay.requestPresent([{
52318		  source: this.renderedCanvas
52319		}]).then(function () {
52320		  if (!_this3.vrDisplay.cardboardUI_ || !videojs.browser.IS_IOS) {
52321			return;
52322		  } // webvr-polyfill/cardboard ui only watches for click events
52323		  // to tell that the back arrow button is pressed during cardboard vr.
52324		  // but somewhere along the line these events are silenced with preventDefault
52325		  // but only on iOS, so we translate them ourselves here
52326  
52327  
52328		  var touches = [];
52329  
52330		  var iosCardboardTouchStart_ = function iosCardboardTouchStart_(e) {
52331			for (var i = 0; i < e.touches.length; i++) {
52332			  touches.push(e.touches[i]);
52333			}
52334		  };
52335  
52336		  var iosCardboardTouchEnd_ = function iosCardboardTouchEnd_(e) {
52337			if (!touches.length) {
52338			  return;
52339			}
52340  
52341			touches.forEach(function (t) {
52342			  var simulatedClick = new window$1.MouseEvent('click', {
52343				screenX: t.screenX,
52344				screenY: t.screenY,
52345				clientX: t.clientX,
52346				clientY: t.clientY
52347			  });
52348  
52349			  _this3.renderedCanvas.dispatchEvent(simulatedClick);
52350			});
52351			touches = [];
52352		  };
52353  
52354		  _this3.renderedCanvas.addEventListener('touchstart', iosCardboardTouchStart_);
52355  
52356		  _this3.renderedCanvas.addEventListener('touchend', iosCardboardTouchEnd_);
52357  
52358		  _this3.iosRevertTouchToClick_ = function () {
52359			_this3.renderedCanvas.removeEventListener('touchstart', iosCardboardTouchStart_);
52360  
52361			_this3.renderedCanvas.removeEventListener('touchend', iosCardboardTouchEnd_);
52362  
52363			_this3.iosRevertTouchToClick_ = null;
52364		  };
52365		});
52366	  };
52367  
52368	  _proto.handleVrDisplayDeactivate_ = function handleVrDisplayDeactivate_() {
52369		if (!this.vrDisplay || !this.vrDisplay.isPresenting) {
52370		  return;
52371		}
52372  
52373		if (this.iosRevertTouchToClick_) {
52374		  this.iosRevertTouchToClick_();
52375		}
52376  
52377		this.vrDisplay.exitPresent();
52378	  };
52379  
52380	  _proto.requestAnimationFrame = function requestAnimationFrame(fn) {
52381		if (this.vrDisplay) {
52382		  return this.vrDisplay.requestAnimationFrame(fn);
52383		}
52384  
52385		return this.player_.requestAnimationFrame(fn);
52386	  };
52387  
52388	  _proto.cancelAnimationFrame = function cancelAnimationFrame(id) {
52389		if (this.vrDisplay) {
52390		  return this.vrDisplay.cancelAnimationFrame(id);
52391		}
52392  
52393		return this.player_.cancelAnimationFrame(id);
52394	  };
52395  
52396	  _proto.togglePlay_ = function togglePlay_() {
52397		if (this.player_.paused()) {
52398		  this.player_.play();
52399		} else {
52400		  this.player_.pause();
52401		}
52402	  };
52403  
52404	  _proto.animate_ = function animate_() {
52405		if (!this.initialized_) {
52406		  return;
52407		}
52408  
52409		if (this.getVideoEl_().readyState === this.getVideoEl_().HAVE_ENOUGH_DATA) {
52410		  if (this.videoTexture) {
52411			this.videoTexture.needsUpdate = true;
52412		  }
52413		}
52414  
52415		this.controls3d.update();
52416  
52417		if (this.omniController) {
52418		  this.omniController.update(this.camera);
52419		}
52420  
52421		this.effect.render(this.scene, this.camera);
52422  
52423		if (window$1.navigator.getGamepads) {
52424		  // Grab all gamepads
52425		  var gamepads = window$1.navigator.getGamepads();
52426  
52427		  for (var i = 0; i < gamepads.length; ++i) {
52428			var gamepad = gamepads[i]; // Make sure gamepad is defined
52429			// Only take input if state has changed since we checked last
52430  
52431			if (!gamepad || !gamepad.timestamp || gamepad.timestamp === this.prevTimestamps_[i]) {
52432			  continue;
52433			}
52434  
52435			for (var j = 0; j < gamepad.buttons.length; ++j) {
52436			  if (gamepad.buttons[j].pressed) {
52437				this.togglePlay_();
52438				this.prevTimestamps_[i] = gamepad.timestamp;
52439				break;
52440			  }
52441			}
52442		  }
52443		}
52444  
52445		this.camera.getWorldDirection(this.cameraVector);
52446		this.animationFrameId_ = this.requestAnimationFrame(this.animate_);
52447	  };
52448  
52449	  _proto.handleResize_ = function handleResize_() {
52450		var width = this.player_.currentWidth();
52451		var height = this.player_.currentHeight();
52452		this.effect.setSize(width, height, false);
52453		this.camera.aspect = width / height;
52454		this.camera.updateProjectionMatrix();
52455	  };
52456  
52457	  _proto.setProjection = function setProjection(projection) {
52458		if (!getInternalProjectionName(projection)) {
52459		  videojs.log.error('videojs-vr: please pass a valid projection ' + validProjections.join(', '));
52460		  return;
52461		}
52462  
52463		this.currentProjection_ = projection;
52464		this.defaultProjection_ = projection;
52465	  };
52466  
52467	  _proto.init = function init() {
52468		var _this4 = this;
52469  
52470		this.reset();
52471		this.camera = new PerspectiveCamera(75, this.player_.currentWidth() / this.player_.currentHeight(), 1, 1000); // Store vector representing the direction in which the camera is looking, in world space.
52472  
52473		this.cameraVector = new Vector3();
52474  
52475		if (this.currentProjection_ === '360_LR' || this.currentProjection_ === '360_TB' || this.currentProjection_ === '180' || this.currentProjection_ === '180_LR' || this.currentProjection_ === '180_MONO' || this.currentProjection_ === 'EAC_LR') {
52476		  // Render left eye when not in VR mode
52477		  this.camera.layers.enable(1);
52478		}
52479  
52480		this.scene = new Scene();
52481		this.videoTexture = new VideoTexture(this.getVideoEl_()); // shared regardless of wether VideoTexture is used or
52482		// an image canvas is used
52483  
52484		this.videoTexture.generateMipmaps = false;
52485		this.videoTexture.minFilter = LinearFilter;
52486		this.videoTexture.magFilter = LinearFilter;
52487		this.videoTexture.format = RGBFormat;
52488		this.changeProjection_(this.currentProjection_);
52489  
52490		if (this.currentProjection_ === 'NONE') {
52491		  this.log('Projection is NONE, dont init');
52492		  this.reset();
52493		  return;
52494		}
52495  
52496		this.player_.removeChild('BigPlayButton');
52497		this.player_.addChild('BigVrPlayButton', {}, this.bigPlayButtonIndex_);
52498		this.player_.bigPlayButton = this.player_.getChild('BigVrPlayButton'); // mobile devices, or cardboard forced to on
52499  
52500		if (this.options_.forceCardboard || videojs.browser.IS_ANDROID || videojs.browser.IS_IOS) {
52501		  this.addCardboardButton_();
52502		} // if ios remove full screen toggle
52503  
52504  
52505		if (videojs.browser.IS_IOS && this.player_.controlBar && this.player_.controlBar.fullscreenToggle) {
52506		  this.player_.controlBar.fullscreenToggle.hide();
52507		}
52508  
52509		this.camera.position.set(0, 0, 0);
52510		this.renderer = new WebGLRenderer({
52511		  devicePixelRatio: window$1.devicePixelRatio,
52512		  alpha: false,
52513		  clearColor: 0xffffff,
52514		  antialias: true
52515		});
52516		var webglContext = this.renderer.getContext('webgl');
52517		var oldTexImage2D = webglContext.texImage2D;
52518		/* this is a workaround since threejs uses try catch */
52519  
52520		webglContext.texImage2D = function () {
52521		  try {
52522			for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
52523			  args[_key2] = arguments[_key2];
52524			}
52525  
52526			return oldTexImage2D.apply(webglContext, args);
52527		  } catch (e) {
52528			_this4.reset();
52529  
52530			_this4.player_.pause();
52531  
52532			_this4.triggerError_({
52533			  code: 'web-vr-hls-cors-not-supported',
52534			  dismiss: false
52535			});
52536  
52537			throw new Error(e);
52538		  }
52539		};
52540  
52541		this.renderer.setSize(this.player_.currentWidth(), this.player_.currentHeight(), false);
52542		this.effect = new VREffect(this.renderer);
52543		this.effect.setSize(this.player_.currentWidth(), this.player_.currentHeight(), false);
52544		this.vrDisplay = null; // Previous timestamps for gamepad updates
52545  
52546		this.prevTimestamps_ = [];
52547		this.renderedCanvas = this.renderer.domElement;
52548		this.renderedCanvas.setAttribute('style', 'width: 100%; height: 100%; position: absolute; top:0;');
52549		var videoElStyle = this.getVideoEl_().style;
52550		this.player_.el().insertBefore(this.renderedCanvas, this.player_.el().firstChild);
52551		videoElStyle.zIndex = '-1';
52552		videoElStyle.opacity = '0';
52553  
52554		if (window$1.navigator.getVRDisplays) {
52555		  this.log('is supported, getting vr displays');
52556		  window$1.navigator.getVRDisplays().then(function (displays) {
52557			if (displays.length > 0) {
52558			  _this4.log('Displays found', displays);
52559  
52560			  _this4.vrDisplay = displays[0]; // Native WebVR Head Mounted Displays (HMDs) like the HTC Vive
52561			  // also need the cardboard button to enter fully immersive mode
52562			  // so, we want to add the button if we're not polyfilled.
52563  
52564			  if (!_this4.vrDisplay.isPolyfilled) {
52565				_this4.log('Real HMD found using VRControls', _this4.vrDisplay);
52566  
52567				_this4.addCardboardButton_(); // We use VRControls here since we are working with an HMD
52568				// and we only want orientation controls.
52569  
52570  
52571				_this4.controls3d = new VRControls(_this4.camera);
52572			  }
52573			}
52574  
52575			if (!_this4.controls3d) {
52576			  _this4.log('no HMD found Using Orbit & Orientation Controls');
52577  
52578			  var options = {
52579				camera: _this4.camera,
52580				canvas: _this4.renderedCanvas,
52581				// check if its a half sphere view projection
52582				halfView: _this4.currentProjection_.indexOf('180') === 0,
52583				orientation: videojs.browser.IS_IOS || videojs.browser.IS_ANDROID || false
52584			  };
52585  
52586			  if (_this4.options_.motionControls === false) {
52587				options.orientation = false;
52588			  }
52589  
52590			  _this4.controls3d = new OrbitOrientationControls(options);
52591			  _this4.canvasPlayerControls = new CanvasPlayerControls(_this4.player_, _this4.renderedCanvas);
52592			}
52593  
52594			_this4.animationFrameId_ = _this4.requestAnimationFrame(_this4.animate_);
52595		  });
52596		} else if (window$1.navigator.getVRDevices) {
52597		  this.triggerError_({
52598			code: 'web-vr-out-of-date',
52599			dismiss: false
52600		  });
52601		} else {
52602		  this.triggerError_({
52603			code: 'web-vr-not-supported',
52604			dismiss: false
52605		  });
52606		}
52607  
52608		if (this.options_.omnitone) {
52609		  var audiocontext = AudioContext.getContext();
52610		  this.omniController = new OmnitoneController(audiocontext, this.options_.omnitone, this.getVideoEl_(), this.options_.omnitoneOptions);
52611		  this.omniController.one('audiocontext-suspended', function () {
52612			_this4.player.pause();
52613  
52614			_this4.player.one('playing', function () {
52615			  audiocontext.resume();
52616			});
52617		  });
52618		}
52619  
52620		this.on(this.player_, 'fullscreenchange', this.handleResize_);
52621		window$1.addEventListener('vrdisplaypresentchange', this.handleResize_, true);
52622		window$1.addEventListener('resize', this.handleResize_, true);
52623		window$1.addEventListener('vrdisplayactivate', this.handleVrDisplayActivate_, true);
52624		window$1.addEventListener('vrdisplaydeactivate', this.handleVrDisplayDeactivate_, true);
52625		this.initialized_ = true;
52626		this.trigger('initialized');
52627	  };
52628  
52629	  _proto.addCardboardButton_ = function addCardboardButton_() {
52630		if (!this.player_.controlBar.getChild('CardboardButton')) {
52631		  this.player_.controlBar.addChild('CardboardButton', {});
52632		}
52633	  };
52634  
52635	  _proto.getVideoEl_ = function getVideoEl_() {
52636		return this.player_.el().getElementsByTagName('video')[0];
52637	  };
52638  
52639	  _proto.reset = function reset() {
52640		if (!this.initialized_) {
52641		  return;
52642		}
52643  
52644		if (this.omniController) {
52645		  this.omniController.off('audiocontext-suspended');
52646		  this.omniController.dispose();
52647		  this.omniController = undefined;
52648		}
52649  
52650		if (this.controls3d) {
52651		  this.controls3d.dispose();
52652		  this.controls3d = null;
52653		}
52654  
52655		if (this.canvasPlayerControls) {
52656		  this.canvasPlayerControls.dispose();
52657		  this.canvasPlayerControls = null;
52658		}
52659  
52660		if (this.effect) {
52661		  this.effect.dispose();
52662		  this.effect = null;
52663		}
52664  
52665		window$1.removeEventListener('resize', this.handleResize_, true);
52666		window$1.removeEventListener('vrdisplaypresentchange', this.handleResize_, true);
52667		window$1.removeEventListener('vrdisplayactivate', this.handleVrDisplayActivate_, true);
52668		window$1.removeEventListener('vrdisplaydeactivate', this.handleVrDisplayDeactivate_, true); // re-add the big play button to player
52669  
52670		if (!this.player_.getChild('BigPlayButton')) {
52671		  this.player_.addChild('BigPlayButton', {}, this.bigPlayButtonIndex_);
52672		}
52673  
52674		if (this.player_.getChild('BigVrPlayButton')) {
52675		  this.player_.removeChild('BigVrPlayButton');
52676		} // remove the cardboard button
52677  
52678  
52679		if (this.player_.getChild('CardboardButton')) {
52680		  this.player_.controlBar.removeChild('CardboardButton');
52681		} // show the fullscreen again
52682  
52683  
52684		if (videojs.browser.IS_IOS && this.player_.controlBar && this.player_.controlBar.fullscreenToggle) {
52685		  this.player_.controlBar.fullscreenToggle.show();
52686		} // reset the video element style so that it will be displayed
52687  
52688  
52689		var videoElStyle = this.getVideoEl_().style;
52690		videoElStyle.zIndex = '';
52691		videoElStyle.opacity = ''; // set the current projection to the default
52692  
52693		this.currentProjection_ = this.defaultProjection_; // reset the ios touch to click workaround
52694  
52695		if (this.iosRevertTouchToClick_) {
52696		  this.iosRevertTouchToClick_();
52697		} // remove the old canvas
52698  
52699  
52700		if (this.renderedCanvas) {
52701		  this.renderedCanvas.parentNode.removeChild(this.renderedCanvas);
52702		}
52703  
52704		if (this.animationFrameId_) {
52705		  this.cancelAnimationFrame(this.animationFrameId_);
52706		}
52707  
52708		this.initialized_ = false;
52709	  };
52710  
52711	  _proto.dispose = function dispose() {
52712		_Plugin.prototype.dispose.call(this);
52713  
52714		this.reset();
52715	  };
52716  
52717	  _proto.polyfillVersion = function polyfillVersion() {
52718		return WebVRPolyfill.version;
52719	  };
52720  
52721	  return VR;
52722	}(Plugin);
52723  
52724	VR.prototype.setTimeout = Component.prototype.setTimeout;
52725	VR.prototype.clearTimeout = Component.prototype.clearTimeout;
52726	VR.VERSION = version;
52727	videojs.registerPlugin('vr', VR);
52728  
52729	return VR;
52730  
52731  })));

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.