]> git.openstreetmap.org Git - rails.git/blob - vendor/assets/iD/iD/mapillary-js/mapillary.module.js
Merge pull request #3268 from tomhughes/capitalisation
[rails.git] / vendor / assets / iD / iD / mapillary-js / mapillary.module.js
1 /*! *****************************************************************************
2 Copyright (c) Microsoft Corporation.
3
4 Permission to use, copy, modify, and/or distribute this software for any
5 purpose with or without fee is hereby granted.
6
7 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
8 REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
9 AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
10 INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
11 LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
12 OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
13 PERFORMANCE OF THIS SOFTWARE.
14 ***************************************************************************** */
15 /* global Reflect, Promise */
16
17 var extendStatics = function(d, b) {
18     extendStatics = Object.setPrototypeOf ||
19         ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
20         function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
21     return extendStatics(d, b);
22 };
23
24 function __extends(d, b) {
25     extendStatics(d, b);
26     function __() { this.constructor = d; }
27     d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
28 }
29
30 /** PURE_IMPORTS_START  PURE_IMPORTS_END */
31 function isFunction(x) {
32     return typeof x === 'function';
33 }
34
35 /** PURE_IMPORTS_START  PURE_IMPORTS_END */
36 var _enable_super_gross_mode_that_will_cause_bad_things = false;
37 var config = {
38     Promise: undefined,
39     set useDeprecatedSynchronousErrorHandling(value) {
40         if (value) {
41             var error = /*@__PURE__*/ new Error();
42             /*@__PURE__*/ console.warn('DEPRECATED! RxJS was set to use deprecated synchronous error handling behavior by code at: \n' + error.stack);
43         }
44         _enable_super_gross_mode_that_will_cause_bad_things = value;
45     },
46     get useDeprecatedSynchronousErrorHandling() {
47         return _enable_super_gross_mode_that_will_cause_bad_things;
48     },
49 };
50
51 /** PURE_IMPORTS_START  PURE_IMPORTS_END */
52 function hostReportError(err) {
53     setTimeout(function () { throw err; }, 0);
54 }
55
56 /** PURE_IMPORTS_START _config,_util_hostReportError PURE_IMPORTS_END */
57 var empty$1 = {
58     closed: true,
59     next: function (value) { },
60     error: function (err) {
61         if (config.useDeprecatedSynchronousErrorHandling) {
62             throw err;
63         }
64         else {
65             hostReportError(err);
66         }
67     },
68     complete: function () { }
69 };
70
71 /** PURE_IMPORTS_START  PURE_IMPORTS_END */
72 var isArray$1 = /*@__PURE__*/ (function () { return Array.isArray || (function (x) { return x && typeof x.length === 'number'; }); })();
73
74 /** PURE_IMPORTS_START  PURE_IMPORTS_END */
75 function isObject$1(x) {
76     return x !== null && typeof x === 'object';
77 }
78
79 /** PURE_IMPORTS_START  PURE_IMPORTS_END */
80 var UnsubscriptionErrorImpl = /*@__PURE__*/ (function () {
81     function UnsubscriptionErrorImpl(errors) {
82         Error.call(this);
83         this.message = errors ?
84             errors.length + " errors occurred during unsubscription:\n" + errors.map(function (err, i) { return i + 1 + ") " + err.toString(); }).join('\n  ') : '';
85         this.name = 'UnsubscriptionError';
86         this.errors = errors;
87         return this;
88     }
89     UnsubscriptionErrorImpl.prototype = /*@__PURE__*/ Object.create(Error.prototype);
90     return UnsubscriptionErrorImpl;
91 })();
92 var UnsubscriptionError = UnsubscriptionErrorImpl;
93
94 /** PURE_IMPORTS_START _util_isArray,_util_isObject,_util_isFunction,_util_UnsubscriptionError PURE_IMPORTS_END */
95 var Subscription = /*@__PURE__*/ (function () {
96     function Subscription(unsubscribe) {
97         this.closed = false;
98         this._parentOrParents = null;
99         this._subscriptions = null;
100         if (unsubscribe) {
101             this._ctorUnsubscribe = true;
102             this._unsubscribe = unsubscribe;
103         }
104     }
105     Subscription.prototype.unsubscribe = function () {
106         var errors;
107         if (this.closed) {
108             return;
109         }
110         var _a = this, _parentOrParents = _a._parentOrParents, _ctorUnsubscribe = _a._ctorUnsubscribe, _unsubscribe = _a._unsubscribe, _subscriptions = _a._subscriptions;
111         this.closed = true;
112         this._parentOrParents = null;
113         this._subscriptions = null;
114         if (_parentOrParents instanceof Subscription) {
115             _parentOrParents.remove(this);
116         }
117         else if (_parentOrParents !== null) {
118             for (var index = 0; index < _parentOrParents.length; ++index) {
119                 var parent_1 = _parentOrParents[index];
120                 parent_1.remove(this);
121             }
122         }
123         if (isFunction(_unsubscribe)) {
124             if (_ctorUnsubscribe) {
125                 this._unsubscribe = undefined;
126             }
127             try {
128                 _unsubscribe.call(this);
129             }
130             catch (e) {
131                 errors = e instanceof UnsubscriptionError ? flattenUnsubscriptionErrors(e.errors) : [e];
132             }
133         }
134         if (isArray$1(_subscriptions)) {
135             var index = -1;
136             var len = _subscriptions.length;
137             while (++index < len) {
138                 var sub = _subscriptions[index];
139                 if (isObject$1(sub)) {
140                     try {
141                         sub.unsubscribe();
142                     }
143                     catch (e) {
144                         errors = errors || [];
145                         if (e instanceof UnsubscriptionError) {
146                             errors = errors.concat(flattenUnsubscriptionErrors(e.errors));
147                         }
148                         else {
149                             errors.push(e);
150                         }
151                     }
152                 }
153             }
154         }
155         if (errors) {
156             throw new UnsubscriptionError(errors);
157         }
158     };
159     Subscription.prototype.add = function (teardown) {
160         var subscription = teardown;
161         if (!teardown) {
162             return Subscription.EMPTY;
163         }
164         switch (typeof teardown) {
165             case 'function':
166                 subscription = new Subscription(teardown);
167             case 'object':
168                 if (subscription === this || subscription.closed || typeof subscription.unsubscribe !== 'function') {
169                     return subscription;
170                 }
171                 else if (this.closed) {
172                     subscription.unsubscribe();
173                     return subscription;
174                 }
175                 else if (!(subscription instanceof Subscription)) {
176                     var tmp = subscription;
177                     subscription = new Subscription();
178                     subscription._subscriptions = [tmp];
179                 }
180                 break;
181             default: {
182                 throw new Error('unrecognized teardown ' + teardown + ' added to Subscription.');
183             }
184         }
185         var _parentOrParents = subscription._parentOrParents;
186         if (_parentOrParents === null) {
187             subscription._parentOrParents = this;
188         }
189         else if (_parentOrParents instanceof Subscription) {
190             if (_parentOrParents === this) {
191                 return subscription;
192             }
193             subscription._parentOrParents = [_parentOrParents, this];
194         }
195         else if (_parentOrParents.indexOf(this) === -1) {
196             _parentOrParents.push(this);
197         }
198         else {
199             return subscription;
200         }
201         var subscriptions = this._subscriptions;
202         if (subscriptions === null) {
203             this._subscriptions = [subscription];
204         }
205         else {
206             subscriptions.push(subscription);
207         }
208         return subscription;
209     };
210     Subscription.prototype.remove = function (subscription) {
211         var subscriptions = this._subscriptions;
212         if (subscriptions) {
213             var subscriptionIndex = subscriptions.indexOf(subscription);
214             if (subscriptionIndex !== -1) {
215                 subscriptions.splice(subscriptionIndex, 1);
216             }
217         }
218     };
219     Subscription.EMPTY = (function (empty) {
220         empty.closed = true;
221         return empty;
222     }(new Subscription()));
223     return Subscription;
224 }());
225 function flattenUnsubscriptionErrors(errors) {
226     return errors.reduce(function (errs, err) { return errs.concat((err instanceof UnsubscriptionError) ? err.errors : err); }, []);
227 }
228
229 /** PURE_IMPORTS_START  PURE_IMPORTS_END */
230 var rxSubscriber = /*@__PURE__*/ (function () {
231     return typeof Symbol === 'function'
232         ? /*@__PURE__*/ Symbol('rxSubscriber')
233         : '@@rxSubscriber_' + /*@__PURE__*/ Math.random();
234 })();
235
236 /** PURE_IMPORTS_START tslib,_util_isFunction,_Observer,_Subscription,_internal_symbol_rxSubscriber,_config,_util_hostReportError PURE_IMPORTS_END */
237 var Subscriber = /*@__PURE__*/ (function (_super) {
238     __extends(Subscriber, _super);
239     function Subscriber(destinationOrNext, error, complete) {
240         var _this = _super.call(this) || this;
241         _this.syncErrorValue = null;
242         _this.syncErrorThrown = false;
243         _this.syncErrorThrowable = false;
244         _this.isStopped = false;
245         switch (arguments.length) {
246             case 0:
247                 _this.destination = empty$1;
248                 break;
249             case 1:
250                 if (!destinationOrNext) {
251                     _this.destination = empty$1;
252                     break;
253                 }
254                 if (typeof destinationOrNext === 'object') {
255                     if (destinationOrNext instanceof Subscriber) {
256                         _this.syncErrorThrowable = destinationOrNext.syncErrorThrowable;
257                         _this.destination = destinationOrNext;
258                         destinationOrNext.add(_this);
259                     }
260                     else {
261                         _this.syncErrorThrowable = true;
262                         _this.destination = new SafeSubscriber(_this, destinationOrNext);
263                     }
264                     break;
265                 }
266             default:
267                 _this.syncErrorThrowable = true;
268                 _this.destination = new SafeSubscriber(_this, destinationOrNext, error, complete);
269                 break;
270         }
271         return _this;
272     }
273     Subscriber.prototype[rxSubscriber] = function () { return this; };
274     Subscriber.create = function (next, error, complete) {
275         var subscriber = new Subscriber(next, error, complete);
276         subscriber.syncErrorThrowable = false;
277         return subscriber;
278     };
279     Subscriber.prototype.next = function (value) {
280         if (!this.isStopped) {
281             this._next(value);
282         }
283     };
284     Subscriber.prototype.error = function (err) {
285         if (!this.isStopped) {
286             this.isStopped = true;
287             this._error(err);
288         }
289     };
290     Subscriber.prototype.complete = function () {
291         if (!this.isStopped) {
292             this.isStopped = true;
293             this._complete();
294         }
295     };
296     Subscriber.prototype.unsubscribe = function () {
297         if (this.closed) {
298             return;
299         }
300         this.isStopped = true;
301         _super.prototype.unsubscribe.call(this);
302     };
303     Subscriber.prototype._next = function (value) {
304         this.destination.next(value);
305     };
306     Subscriber.prototype._error = function (err) {
307         this.destination.error(err);
308         this.unsubscribe();
309     };
310     Subscriber.prototype._complete = function () {
311         this.destination.complete();
312         this.unsubscribe();
313     };
314     Subscriber.prototype._unsubscribeAndRecycle = function () {
315         var _parentOrParents = this._parentOrParents;
316         this._parentOrParents = null;
317         this.unsubscribe();
318         this.closed = false;
319         this.isStopped = false;
320         this._parentOrParents = _parentOrParents;
321         return this;
322     };
323     return Subscriber;
324 }(Subscription));
325 var SafeSubscriber = /*@__PURE__*/ (function (_super) {
326     __extends(SafeSubscriber, _super);
327     function SafeSubscriber(_parentSubscriber, observerOrNext, error, complete) {
328         var _this = _super.call(this) || this;
329         _this._parentSubscriber = _parentSubscriber;
330         var next;
331         var context = _this;
332         if (isFunction(observerOrNext)) {
333             next = observerOrNext;
334         }
335         else if (observerOrNext) {
336             next = observerOrNext.next;
337             error = observerOrNext.error;
338             complete = observerOrNext.complete;
339             if (observerOrNext !== empty$1) {
340                 context = Object.create(observerOrNext);
341                 if (isFunction(context.unsubscribe)) {
342                     _this.add(context.unsubscribe.bind(context));
343                 }
344                 context.unsubscribe = _this.unsubscribe.bind(_this);
345             }
346         }
347         _this._context = context;
348         _this._next = next;
349         _this._error = error;
350         _this._complete = complete;
351         return _this;
352     }
353     SafeSubscriber.prototype.next = function (value) {
354         if (!this.isStopped && this._next) {
355             var _parentSubscriber = this._parentSubscriber;
356             if (!config.useDeprecatedSynchronousErrorHandling || !_parentSubscriber.syncErrorThrowable) {
357                 this.__tryOrUnsub(this._next, value);
358             }
359             else if (this.__tryOrSetError(_parentSubscriber, this._next, value)) {
360                 this.unsubscribe();
361             }
362         }
363     };
364     SafeSubscriber.prototype.error = function (err) {
365         if (!this.isStopped) {
366             var _parentSubscriber = this._parentSubscriber;
367             var useDeprecatedSynchronousErrorHandling = config.useDeprecatedSynchronousErrorHandling;
368             if (this._error) {
369                 if (!useDeprecatedSynchronousErrorHandling || !_parentSubscriber.syncErrorThrowable) {
370                     this.__tryOrUnsub(this._error, err);
371                     this.unsubscribe();
372                 }
373                 else {
374                     this.__tryOrSetError(_parentSubscriber, this._error, err);
375                     this.unsubscribe();
376                 }
377             }
378             else if (!_parentSubscriber.syncErrorThrowable) {
379                 this.unsubscribe();
380                 if (useDeprecatedSynchronousErrorHandling) {
381                     throw err;
382                 }
383                 hostReportError(err);
384             }
385             else {
386                 if (useDeprecatedSynchronousErrorHandling) {
387                     _parentSubscriber.syncErrorValue = err;
388                     _parentSubscriber.syncErrorThrown = true;
389                 }
390                 else {
391                     hostReportError(err);
392                 }
393                 this.unsubscribe();
394             }
395         }
396     };
397     SafeSubscriber.prototype.complete = function () {
398         var _this = this;
399         if (!this.isStopped) {
400             var _parentSubscriber = this._parentSubscriber;
401             if (this._complete) {
402                 var wrappedComplete = function () { return _this._complete.call(_this._context); };
403                 if (!config.useDeprecatedSynchronousErrorHandling || !_parentSubscriber.syncErrorThrowable) {
404                     this.__tryOrUnsub(wrappedComplete);
405                     this.unsubscribe();
406                 }
407                 else {
408                     this.__tryOrSetError(_parentSubscriber, wrappedComplete);
409                     this.unsubscribe();
410                 }
411             }
412             else {
413                 this.unsubscribe();
414             }
415         }
416     };
417     SafeSubscriber.prototype.__tryOrUnsub = function (fn, value) {
418         try {
419             fn.call(this._context, value);
420         }
421         catch (err) {
422             this.unsubscribe();
423             if (config.useDeprecatedSynchronousErrorHandling) {
424                 throw err;
425             }
426             else {
427                 hostReportError(err);
428             }
429         }
430     };
431     SafeSubscriber.prototype.__tryOrSetError = function (parent, fn, value) {
432         if (!config.useDeprecatedSynchronousErrorHandling) {
433             throw new Error('bad call');
434         }
435         try {
436             fn.call(this._context, value);
437         }
438         catch (err) {
439             if (config.useDeprecatedSynchronousErrorHandling) {
440                 parent.syncErrorValue = err;
441                 parent.syncErrorThrown = true;
442                 return true;
443             }
444             else {
445                 hostReportError(err);
446                 return true;
447             }
448         }
449         return false;
450     };
451     SafeSubscriber.prototype._unsubscribe = function () {
452         var _parentSubscriber = this._parentSubscriber;
453         this._context = null;
454         this._parentSubscriber = null;
455         _parentSubscriber.unsubscribe();
456     };
457     return SafeSubscriber;
458 }(Subscriber));
459
460 /** PURE_IMPORTS_START _Subscriber PURE_IMPORTS_END */
461 function canReportError(observer) {
462     while (observer) {
463         var _a = observer, closed_1 = _a.closed, destination = _a.destination, isStopped = _a.isStopped;
464         if (closed_1 || isStopped) {
465             return false;
466         }
467         else if (destination && destination instanceof Subscriber) {
468             observer = destination;
469         }
470         else {
471             observer = null;
472         }
473     }
474     return true;
475 }
476
477 /** PURE_IMPORTS_START _Subscriber,_symbol_rxSubscriber,_Observer PURE_IMPORTS_END */
478 function toSubscriber(nextOrObserver, error, complete) {
479     if (nextOrObserver) {
480         if (nextOrObserver instanceof Subscriber) {
481             return nextOrObserver;
482         }
483         if (nextOrObserver[rxSubscriber]) {
484             return nextOrObserver[rxSubscriber]();
485         }
486     }
487     if (!nextOrObserver && !error && !complete) {
488         return new Subscriber(empty$1);
489     }
490     return new Subscriber(nextOrObserver, error, complete);
491 }
492
493 /** PURE_IMPORTS_START  PURE_IMPORTS_END */
494 var observable = /*@__PURE__*/ (function () { return typeof Symbol === 'function' && Symbol.observable || '@@observable'; })();
495
496 /** PURE_IMPORTS_START  PURE_IMPORTS_END */
497 function identity(x) {
498     return x;
499 }
500
501 /** PURE_IMPORTS_START _identity PURE_IMPORTS_END */
502 function pipe() {
503     var fns = [];
504     for (var _i = 0; _i < arguments.length; _i++) {
505         fns[_i] = arguments[_i];
506     }
507     return pipeFromArray(fns);
508 }
509 function pipeFromArray(fns) {
510     if (fns.length === 0) {
511         return identity;
512     }
513     if (fns.length === 1) {
514         return fns[0];
515     }
516     return function piped(input) {
517         return fns.reduce(function (prev, fn) { return fn(prev); }, input);
518     };
519 }
520
521 /** PURE_IMPORTS_START _util_canReportError,_util_toSubscriber,_symbol_observable,_util_pipe,_config PURE_IMPORTS_END */
522 var Observable = /*@__PURE__*/ (function () {
523     function Observable(subscribe) {
524         this._isScalar = false;
525         if (subscribe) {
526             this._subscribe = subscribe;
527         }
528     }
529     Observable.prototype.lift = function (operator) {
530         var observable = new Observable();
531         observable.source = this;
532         observable.operator = operator;
533         return observable;
534     };
535     Observable.prototype.subscribe = function (observerOrNext, error, complete) {
536         var operator = this.operator;
537         var sink = toSubscriber(observerOrNext, error, complete);
538         if (operator) {
539             sink.add(operator.call(sink, this.source));
540         }
541         else {
542             sink.add(this.source || (config.useDeprecatedSynchronousErrorHandling && !sink.syncErrorThrowable) ?
543                 this._subscribe(sink) :
544                 this._trySubscribe(sink));
545         }
546         if (config.useDeprecatedSynchronousErrorHandling) {
547             if (sink.syncErrorThrowable) {
548                 sink.syncErrorThrowable = false;
549                 if (sink.syncErrorThrown) {
550                     throw sink.syncErrorValue;
551                 }
552             }
553         }
554         return sink;
555     };
556     Observable.prototype._trySubscribe = function (sink) {
557         try {
558             return this._subscribe(sink);
559         }
560         catch (err) {
561             if (config.useDeprecatedSynchronousErrorHandling) {
562                 sink.syncErrorThrown = true;
563                 sink.syncErrorValue = err;
564             }
565             if (canReportError(sink)) {
566                 sink.error(err);
567             }
568             else {
569                 console.warn(err);
570             }
571         }
572     };
573     Observable.prototype.forEach = function (next, promiseCtor) {
574         var _this = this;
575         promiseCtor = getPromiseCtor(promiseCtor);
576         return new promiseCtor(function (resolve, reject) {
577             var subscription;
578             subscription = _this.subscribe(function (value) {
579                 try {
580                     next(value);
581                 }
582                 catch (err) {
583                     reject(err);
584                     if (subscription) {
585                         subscription.unsubscribe();
586                     }
587                 }
588             }, reject, resolve);
589         });
590     };
591     Observable.prototype._subscribe = function (subscriber) {
592         var source = this.source;
593         return source && source.subscribe(subscriber);
594     };
595     Observable.prototype[observable] = function () {
596         return this;
597     };
598     Observable.prototype.pipe = function () {
599         var operations = [];
600         for (var _i = 0; _i < arguments.length; _i++) {
601             operations[_i] = arguments[_i];
602         }
603         if (operations.length === 0) {
604             return this;
605         }
606         return pipeFromArray(operations)(this);
607     };
608     Observable.prototype.toPromise = function (promiseCtor) {
609         var _this = this;
610         promiseCtor = getPromiseCtor(promiseCtor);
611         return new promiseCtor(function (resolve, reject) {
612             var value;
613             _this.subscribe(function (x) { return value = x; }, function (err) { return reject(err); }, function () { return resolve(value); });
614         });
615     };
616     Observable.create = function (subscribe) {
617         return new Observable(subscribe);
618     };
619     return Observable;
620 }());
621 function getPromiseCtor(promiseCtor) {
622     if (!promiseCtor) {
623         promiseCtor = Promise;
624     }
625     if (!promiseCtor) {
626         throw new Error('no Promise impl found');
627     }
628     return promiseCtor;
629 }
630
631 /** PURE_IMPORTS_START  PURE_IMPORTS_END */
632 var ObjectUnsubscribedErrorImpl = /*@__PURE__*/ (function () {
633     function ObjectUnsubscribedErrorImpl() {
634         Error.call(this);
635         this.message = 'object unsubscribed';
636         this.name = 'ObjectUnsubscribedError';
637         return this;
638     }
639     ObjectUnsubscribedErrorImpl.prototype = /*@__PURE__*/ Object.create(Error.prototype);
640     return ObjectUnsubscribedErrorImpl;
641 })();
642 var ObjectUnsubscribedError = ObjectUnsubscribedErrorImpl;
643
644 /** PURE_IMPORTS_START tslib,_Subscription PURE_IMPORTS_END */
645 var SubjectSubscription = /*@__PURE__*/ (function (_super) {
646     __extends(SubjectSubscription, _super);
647     function SubjectSubscription(subject, subscriber) {
648         var _this = _super.call(this) || this;
649         _this.subject = subject;
650         _this.subscriber = subscriber;
651         _this.closed = false;
652         return _this;
653     }
654     SubjectSubscription.prototype.unsubscribe = function () {
655         if (this.closed) {
656             return;
657         }
658         this.closed = true;
659         var subject = this.subject;
660         var observers = subject.observers;
661         this.subject = null;
662         if (!observers || observers.length === 0 || subject.isStopped || subject.closed) {
663             return;
664         }
665         var subscriberIndex = observers.indexOf(this.subscriber);
666         if (subscriberIndex !== -1) {
667             observers.splice(subscriberIndex, 1);
668         }
669     };
670     return SubjectSubscription;
671 }(Subscription));
672
673 /** PURE_IMPORTS_START tslib,_Observable,_Subscriber,_Subscription,_util_ObjectUnsubscribedError,_SubjectSubscription,_internal_symbol_rxSubscriber PURE_IMPORTS_END */
674 var SubjectSubscriber = /*@__PURE__*/ (function (_super) {
675     __extends(SubjectSubscriber, _super);
676     function SubjectSubscriber(destination) {
677         var _this = _super.call(this, destination) || this;
678         _this.destination = destination;
679         return _this;
680     }
681     return SubjectSubscriber;
682 }(Subscriber));
683 var Subject = /*@__PURE__*/ (function (_super) {
684     __extends(Subject, _super);
685     function Subject() {
686         var _this = _super.call(this) || this;
687         _this.observers = [];
688         _this.closed = false;
689         _this.isStopped = false;
690         _this.hasError = false;
691         _this.thrownError = null;
692         return _this;
693     }
694     Subject.prototype[rxSubscriber] = function () {
695         return new SubjectSubscriber(this);
696     };
697     Subject.prototype.lift = function (operator) {
698         var subject = new AnonymousSubject(this, this);
699         subject.operator = operator;
700         return subject;
701     };
702     Subject.prototype.next = function (value) {
703         if (this.closed) {
704             throw new ObjectUnsubscribedError();
705         }
706         if (!this.isStopped) {
707             var observers = this.observers;
708             var len = observers.length;
709             var copy = observers.slice();
710             for (var i = 0; i < len; i++) {
711                 copy[i].next(value);
712             }
713         }
714     };
715     Subject.prototype.error = function (err) {
716         if (this.closed) {
717             throw new ObjectUnsubscribedError();
718         }
719         this.hasError = true;
720         this.thrownError = err;
721         this.isStopped = true;
722         var observers = this.observers;
723         var len = observers.length;
724         var copy = observers.slice();
725         for (var i = 0; i < len; i++) {
726             copy[i].error(err);
727         }
728         this.observers.length = 0;
729     };
730     Subject.prototype.complete = function () {
731         if (this.closed) {
732             throw new ObjectUnsubscribedError();
733         }
734         this.isStopped = true;
735         var observers = this.observers;
736         var len = observers.length;
737         var copy = observers.slice();
738         for (var i = 0; i < len; i++) {
739             copy[i].complete();
740         }
741         this.observers.length = 0;
742     };
743     Subject.prototype.unsubscribe = function () {
744         this.isStopped = true;
745         this.closed = true;
746         this.observers = null;
747     };
748     Subject.prototype._trySubscribe = function (subscriber) {
749         if (this.closed) {
750             throw new ObjectUnsubscribedError();
751         }
752         else {
753             return _super.prototype._trySubscribe.call(this, subscriber);
754         }
755     };
756     Subject.prototype._subscribe = function (subscriber) {
757         if (this.closed) {
758             throw new ObjectUnsubscribedError();
759         }
760         else if (this.hasError) {
761             subscriber.error(this.thrownError);
762             return Subscription.EMPTY;
763         }
764         else if (this.isStopped) {
765             subscriber.complete();
766             return Subscription.EMPTY;
767         }
768         else {
769             this.observers.push(subscriber);
770             return new SubjectSubscription(this, subscriber);
771         }
772     };
773     Subject.prototype.asObservable = function () {
774         var observable = new Observable();
775         observable.source = this;
776         return observable;
777     };
778     Subject.create = function (destination, source) {
779         return new AnonymousSubject(destination, source);
780     };
781     return Subject;
782 }(Observable));
783 var AnonymousSubject = /*@__PURE__*/ (function (_super) {
784     __extends(AnonymousSubject, _super);
785     function AnonymousSubject(destination, source) {
786         var _this = _super.call(this) || this;
787         _this.destination = destination;
788         _this.source = source;
789         return _this;
790     }
791     AnonymousSubject.prototype.next = function (value) {
792         var destination = this.destination;
793         if (destination && destination.next) {
794             destination.next(value);
795         }
796     };
797     AnonymousSubject.prototype.error = function (err) {
798         var destination = this.destination;
799         if (destination && destination.error) {
800             this.destination.error(err);
801         }
802     };
803     AnonymousSubject.prototype.complete = function () {
804         var destination = this.destination;
805         if (destination && destination.complete) {
806             this.destination.complete();
807         }
808     };
809     AnonymousSubject.prototype._subscribe = function (subscriber) {
810         var source = this.source;
811         if (source) {
812             return this.source.subscribe(subscriber);
813         }
814         else {
815             return Subscription.EMPTY;
816         }
817     };
818     return AnonymousSubject;
819 }(Subject));
820
821 /** PURE_IMPORTS_START tslib,_Subscriber PURE_IMPORTS_END */
822 function refCount() {
823     return function refCountOperatorFunction(source) {
824         return source.lift(new RefCountOperator(source));
825     };
826 }
827 var RefCountOperator = /*@__PURE__*/ (function () {
828     function RefCountOperator(connectable) {
829         this.connectable = connectable;
830     }
831     RefCountOperator.prototype.call = function (subscriber, source) {
832         var connectable = this.connectable;
833         connectable._refCount++;
834         var refCounter = new RefCountSubscriber(subscriber, connectable);
835         var subscription = source.subscribe(refCounter);
836         if (!refCounter.closed) {
837             refCounter.connection = connectable.connect();
838         }
839         return subscription;
840     };
841     return RefCountOperator;
842 }());
843 var RefCountSubscriber = /*@__PURE__*/ (function (_super) {
844     __extends(RefCountSubscriber, _super);
845     function RefCountSubscriber(destination, connectable) {
846         var _this = _super.call(this, destination) || this;
847         _this.connectable = connectable;
848         return _this;
849     }
850     RefCountSubscriber.prototype._unsubscribe = function () {
851         var connectable = this.connectable;
852         if (!connectable) {
853             this.connection = null;
854             return;
855         }
856         this.connectable = null;
857         var refCount = connectable._refCount;
858         if (refCount <= 0) {
859             this.connection = null;
860             return;
861         }
862         connectable._refCount = refCount - 1;
863         if (refCount > 1) {
864             this.connection = null;
865             return;
866         }
867         var connection = this.connection;
868         var sharedConnection = connectable._connection;
869         this.connection = null;
870         if (sharedConnection && (!connection || sharedConnection === connection)) {
871             sharedConnection.unsubscribe();
872         }
873     };
874     return RefCountSubscriber;
875 }(Subscriber));
876
877 /** PURE_IMPORTS_START tslib,_Subject,_Observable,_Subscriber,_Subscription,_operators_refCount PURE_IMPORTS_END */
878 var ConnectableObservable = /*@__PURE__*/ (function (_super) {
879     __extends(ConnectableObservable, _super);
880     function ConnectableObservable(source, subjectFactory) {
881         var _this = _super.call(this) || this;
882         _this.source = source;
883         _this.subjectFactory = subjectFactory;
884         _this._refCount = 0;
885         _this._isComplete = false;
886         return _this;
887     }
888     ConnectableObservable.prototype._subscribe = function (subscriber) {
889         return this.getSubject().subscribe(subscriber);
890     };
891     ConnectableObservable.prototype.getSubject = function () {
892         var subject = this._subject;
893         if (!subject || subject.isStopped) {
894             this._subject = this.subjectFactory();
895         }
896         return this._subject;
897     };
898     ConnectableObservable.prototype.connect = function () {
899         var connection = this._connection;
900         if (!connection) {
901             this._isComplete = false;
902             connection = this._connection = new Subscription();
903             connection.add(this.source
904                 .subscribe(new ConnectableSubscriber(this.getSubject(), this)));
905             if (connection.closed) {
906                 this._connection = null;
907                 connection = Subscription.EMPTY;
908             }
909         }
910         return connection;
911     };
912     ConnectableObservable.prototype.refCount = function () {
913         return refCount()(this);
914     };
915     return ConnectableObservable;
916 }(Observable));
917 var connectableObservableDescriptor = /*@__PURE__*/ (function () {
918     var connectableProto = ConnectableObservable.prototype;
919     return {
920         operator: { value: null },
921         _refCount: { value: 0, writable: true },
922         _subject: { value: null, writable: true },
923         _connection: { value: null, writable: true },
924         _subscribe: { value: connectableProto._subscribe },
925         _isComplete: { value: connectableProto._isComplete, writable: true },
926         getSubject: { value: connectableProto.getSubject },
927         connect: { value: connectableProto.connect },
928         refCount: { value: connectableProto.refCount }
929     };
930 })();
931 var ConnectableSubscriber = /*@__PURE__*/ (function (_super) {
932     __extends(ConnectableSubscriber, _super);
933     function ConnectableSubscriber(destination, connectable) {
934         var _this = _super.call(this, destination) || this;
935         _this.connectable = connectable;
936         return _this;
937     }
938     ConnectableSubscriber.prototype._error = function (err) {
939         this._unsubscribe();
940         _super.prototype._error.call(this, err);
941     };
942     ConnectableSubscriber.prototype._complete = function () {
943         this.connectable._isComplete = true;
944         this._unsubscribe();
945         _super.prototype._complete.call(this);
946     };
947     ConnectableSubscriber.prototype._unsubscribe = function () {
948         var connectable = this.connectable;
949         if (connectable) {
950             this.connectable = null;
951             var connection = connectable._connection;
952             connectable._refCount = 0;
953             connectable._subject = null;
954             connectable._connection = null;
955             if (connection) {
956                 connection.unsubscribe();
957             }
958         }
959     };
960     return ConnectableSubscriber;
961 }(SubjectSubscriber));
962
963 /** PURE_IMPORTS_START tslib,_Subject,_util_ObjectUnsubscribedError PURE_IMPORTS_END */
964 var BehaviorSubject = /*@__PURE__*/ (function (_super) {
965     __extends(BehaviorSubject, _super);
966     function BehaviorSubject(_value) {
967         var _this = _super.call(this) || this;
968         _this._value = _value;
969         return _this;
970     }
971     Object.defineProperty(BehaviorSubject.prototype, "value", {
972         get: function () {
973             return this.getValue();
974         },
975         enumerable: true,
976         configurable: true
977     });
978     BehaviorSubject.prototype._subscribe = function (subscriber) {
979         var subscription = _super.prototype._subscribe.call(this, subscriber);
980         if (subscription && !subscription.closed) {
981             subscriber.next(this._value);
982         }
983         return subscription;
984     };
985     BehaviorSubject.prototype.getValue = function () {
986         if (this.hasError) {
987             throw this.thrownError;
988         }
989         else if (this.closed) {
990             throw new ObjectUnsubscribedError();
991         }
992         else {
993             return this._value;
994         }
995     };
996     BehaviorSubject.prototype.next = function (value) {
997         _super.prototype.next.call(this, this._value = value);
998     };
999     return BehaviorSubject;
1000 }(Subject));
1001
1002 /** PURE_IMPORTS_START tslib,_Subscription PURE_IMPORTS_END */
1003 var Action = /*@__PURE__*/ (function (_super) {
1004     __extends(Action, _super);
1005     function Action(scheduler, work) {
1006         return _super.call(this) || this;
1007     }
1008     Action.prototype.schedule = function (state, delay) {
1009         return this;
1010     };
1011     return Action;
1012 }(Subscription));
1013
1014 /** PURE_IMPORTS_START tslib,_Action PURE_IMPORTS_END */
1015 var AsyncAction = /*@__PURE__*/ (function (_super) {
1016     __extends(AsyncAction, _super);
1017     function AsyncAction(scheduler, work) {
1018         var _this = _super.call(this, scheduler, work) || this;
1019         _this.scheduler = scheduler;
1020         _this.work = work;
1021         _this.pending = false;
1022         return _this;
1023     }
1024     AsyncAction.prototype.schedule = function (state, delay) {
1025         if (delay === void 0) {
1026             delay = 0;
1027         }
1028         if (this.closed) {
1029             return this;
1030         }
1031         this.state = state;
1032         var id = this.id;
1033         var scheduler = this.scheduler;
1034         if (id != null) {
1035             this.id = this.recycleAsyncId(scheduler, id, delay);
1036         }
1037         this.pending = true;
1038         this.delay = delay;
1039         this.id = this.id || this.requestAsyncId(scheduler, this.id, delay);
1040         return this;
1041     };
1042     AsyncAction.prototype.requestAsyncId = function (scheduler, id, delay) {
1043         if (delay === void 0) {
1044             delay = 0;
1045         }
1046         return setInterval(scheduler.flush.bind(scheduler, this), delay);
1047     };
1048     AsyncAction.prototype.recycleAsyncId = function (scheduler, id, delay) {
1049         if (delay === void 0) {
1050             delay = 0;
1051         }
1052         if (delay !== null && this.delay === delay && this.pending === false) {
1053             return id;
1054         }
1055         clearInterval(id);
1056         return undefined;
1057     };
1058     AsyncAction.prototype.execute = function (state, delay) {
1059         if (this.closed) {
1060             return new Error('executing a cancelled action');
1061         }
1062         this.pending = false;
1063         var error = this._execute(state, delay);
1064         if (error) {
1065             return error;
1066         }
1067         else if (this.pending === false && this.id != null) {
1068             this.id = this.recycleAsyncId(this.scheduler, this.id, null);
1069         }
1070     };
1071     AsyncAction.prototype._execute = function (state, delay) {
1072         var errored = false;
1073         var errorValue = undefined;
1074         try {
1075             this.work(state);
1076         }
1077         catch (e) {
1078             errored = true;
1079             errorValue = !!e && e || new Error(e);
1080         }
1081         if (errored) {
1082             this.unsubscribe();
1083             return errorValue;
1084         }
1085     };
1086     AsyncAction.prototype._unsubscribe = function () {
1087         var id = this.id;
1088         var scheduler = this.scheduler;
1089         var actions = scheduler.actions;
1090         var index = actions.indexOf(this);
1091         this.work = null;
1092         this.state = null;
1093         this.pending = false;
1094         this.scheduler = null;
1095         if (index !== -1) {
1096             actions.splice(index, 1);
1097         }
1098         if (id != null) {
1099             this.id = this.recycleAsyncId(scheduler, id, null);
1100         }
1101         this.delay = null;
1102     };
1103     return AsyncAction;
1104 }(Action));
1105
1106 /** PURE_IMPORTS_START tslib,_AsyncAction PURE_IMPORTS_END */
1107 var QueueAction = /*@__PURE__*/ (function (_super) {
1108     __extends(QueueAction, _super);
1109     function QueueAction(scheduler, work) {
1110         var _this = _super.call(this, scheduler, work) || this;
1111         _this.scheduler = scheduler;
1112         _this.work = work;
1113         return _this;
1114     }
1115     QueueAction.prototype.schedule = function (state, delay) {
1116         if (delay === void 0) {
1117             delay = 0;
1118         }
1119         if (delay > 0) {
1120             return _super.prototype.schedule.call(this, state, delay);
1121         }
1122         this.delay = delay;
1123         this.state = state;
1124         this.scheduler.flush(this);
1125         return this;
1126     };
1127     QueueAction.prototype.execute = function (state, delay) {
1128         return (delay > 0 || this.closed) ?
1129             _super.prototype.execute.call(this, state, delay) :
1130             this._execute(state, delay);
1131     };
1132     QueueAction.prototype.requestAsyncId = function (scheduler, id, delay) {
1133         if (delay === void 0) {
1134             delay = 0;
1135         }
1136         if ((delay !== null && delay > 0) || (delay === null && this.delay > 0)) {
1137             return _super.prototype.requestAsyncId.call(this, scheduler, id, delay);
1138         }
1139         return scheduler.flush(this);
1140     };
1141     return QueueAction;
1142 }(AsyncAction));
1143
1144 var Scheduler = /*@__PURE__*/ (function () {
1145     function Scheduler(SchedulerAction, now) {
1146         if (now === void 0) {
1147             now = Scheduler.now;
1148         }
1149         this.SchedulerAction = SchedulerAction;
1150         this.now = now;
1151     }
1152     Scheduler.prototype.schedule = function (work, delay, state) {
1153         if (delay === void 0) {
1154             delay = 0;
1155         }
1156         return new this.SchedulerAction(this, work).schedule(state, delay);
1157     };
1158     Scheduler.now = function () { return Date.now(); };
1159     return Scheduler;
1160 }());
1161
1162 /** PURE_IMPORTS_START tslib,_Scheduler PURE_IMPORTS_END */
1163 var AsyncScheduler = /*@__PURE__*/ (function (_super) {
1164     __extends(AsyncScheduler, _super);
1165     function AsyncScheduler(SchedulerAction, now) {
1166         if (now === void 0) {
1167             now = Scheduler.now;
1168         }
1169         var _this = _super.call(this, SchedulerAction, function () {
1170             if (AsyncScheduler.delegate && AsyncScheduler.delegate !== _this) {
1171                 return AsyncScheduler.delegate.now();
1172             }
1173             else {
1174                 return now();
1175             }
1176         }) || this;
1177         _this.actions = [];
1178         _this.active = false;
1179         _this.scheduled = undefined;
1180         return _this;
1181     }
1182     AsyncScheduler.prototype.schedule = function (work, delay, state) {
1183         if (delay === void 0) {
1184             delay = 0;
1185         }
1186         if (AsyncScheduler.delegate && AsyncScheduler.delegate !== this) {
1187             return AsyncScheduler.delegate.schedule(work, delay, state);
1188         }
1189         else {
1190             return _super.prototype.schedule.call(this, work, delay, state);
1191         }
1192     };
1193     AsyncScheduler.prototype.flush = function (action) {
1194         var actions = this.actions;
1195         if (this.active) {
1196             actions.push(action);
1197             return;
1198         }
1199         var error;
1200         this.active = true;
1201         do {
1202             if (error = action.execute(action.state, action.delay)) {
1203                 break;
1204             }
1205         } while (action = actions.shift());
1206         this.active = false;
1207         if (error) {
1208             while (action = actions.shift()) {
1209                 action.unsubscribe();
1210             }
1211             throw error;
1212         }
1213     };
1214     return AsyncScheduler;
1215 }(Scheduler));
1216
1217 /** PURE_IMPORTS_START tslib,_AsyncScheduler PURE_IMPORTS_END */
1218 var QueueScheduler = /*@__PURE__*/ (function (_super) {
1219     __extends(QueueScheduler, _super);
1220     function QueueScheduler() {
1221         return _super !== null && _super.apply(this, arguments) || this;
1222     }
1223     return QueueScheduler;
1224 }(AsyncScheduler));
1225
1226 /** PURE_IMPORTS_START _QueueAction,_QueueScheduler PURE_IMPORTS_END */
1227 var queueScheduler = /*@__PURE__*/ new QueueScheduler(QueueAction);
1228 var queue = queueScheduler;
1229
1230 /** PURE_IMPORTS_START _Observable PURE_IMPORTS_END */
1231 var EMPTY$1 = /*@__PURE__*/ new Observable(function (subscriber) { return subscriber.complete(); });
1232 function empty(scheduler) {
1233     return scheduler ? emptyScheduled(scheduler) : EMPTY$1;
1234 }
1235 function emptyScheduled(scheduler) {
1236     return new Observable(function (subscriber) { return scheduler.schedule(function () { return subscriber.complete(); }); });
1237 }
1238
1239 /** PURE_IMPORTS_START  PURE_IMPORTS_END */
1240 function isScheduler(value) {
1241     return value && typeof value.schedule === 'function';
1242 }
1243
1244 /** PURE_IMPORTS_START  PURE_IMPORTS_END */
1245 var subscribeToArray = function (array) {
1246     return function (subscriber) {
1247         for (var i = 0, len = array.length; i < len && !subscriber.closed; i++) {
1248             subscriber.next(array[i]);
1249         }
1250         subscriber.complete();
1251     };
1252 };
1253
1254 /** PURE_IMPORTS_START _Observable,_Subscription PURE_IMPORTS_END */
1255 function scheduleArray(input, scheduler) {
1256     return new Observable(function (subscriber) {
1257         var sub = new Subscription();
1258         var i = 0;
1259         sub.add(scheduler.schedule(function () {
1260             if (i === input.length) {
1261                 subscriber.complete();
1262                 return;
1263             }
1264             subscriber.next(input[i++]);
1265             if (!subscriber.closed) {
1266                 sub.add(this.schedule());
1267             }
1268         }));
1269         return sub;
1270     });
1271 }
1272
1273 /** PURE_IMPORTS_START _Observable,_util_subscribeToArray,_scheduled_scheduleArray PURE_IMPORTS_END */
1274 function fromArray(input, scheduler) {
1275     if (!scheduler) {
1276         return new Observable(subscribeToArray(input));
1277     }
1278     else {
1279         return scheduleArray(input, scheduler);
1280     }
1281 }
1282
1283 /** PURE_IMPORTS_START _util_isScheduler,_fromArray,_scheduled_scheduleArray PURE_IMPORTS_END */
1284 function of() {
1285     var args = [];
1286     for (var _i = 0; _i < arguments.length; _i++) {
1287         args[_i] = arguments[_i];
1288     }
1289     var scheduler = args[args.length - 1];
1290     if (isScheduler(scheduler)) {
1291         args.pop();
1292         return scheduleArray(args, scheduler);
1293     }
1294     else {
1295         return fromArray(args);
1296     }
1297 }
1298
1299 /** PURE_IMPORTS_START _Observable PURE_IMPORTS_END */
1300 function throwError(error, scheduler) {
1301     if (!scheduler) {
1302         return new Observable(function (subscriber) { return subscriber.error(error); });
1303     }
1304     else {
1305         return new Observable(function (subscriber) { return scheduler.schedule(dispatch$1, 0, { error: error, subscriber: subscriber }); });
1306     }
1307 }
1308 function dispatch$1(_a) {
1309     var error = _a.error, subscriber = _a.subscriber;
1310     subscriber.error(error);
1311 }
1312
1313 /** PURE_IMPORTS_START _observable_empty,_observable_of,_observable_throwError PURE_IMPORTS_END */
1314 var Notification = /*@__PURE__*/ (function () {
1315     function Notification(kind, value, error) {
1316         this.kind = kind;
1317         this.value = value;
1318         this.error = error;
1319         this.hasValue = kind === 'N';
1320     }
1321     Notification.prototype.observe = function (observer) {
1322         switch (this.kind) {
1323             case 'N':
1324                 return observer.next && observer.next(this.value);
1325             case 'E':
1326                 return observer.error && observer.error(this.error);
1327             case 'C':
1328                 return observer.complete && observer.complete();
1329         }
1330     };
1331     Notification.prototype.do = function (next, error, complete) {
1332         var kind = this.kind;
1333         switch (kind) {
1334             case 'N':
1335                 return next && next(this.value);
1336             case 'E':
1337                 return error && error(this.error);
1338             case 'C':
1339                 return complete && complete();
1340         }
1341     };
1342     Notification.prototype.accept = function (nextOrObserver, error, complete) {
1343         if (nextOrObserver && typeof nextOrObserver.next === 'function') {
1344             return this.observe(nextOrObserver);
1345         }
1346         else {
1347             return this.do(nextOrObserver, error, complete);
1348         }
1349     };
1350     Notification.prototype.toObservable = function () {
1351         var kind = this.kind;
1352         switch (kind) {
1353             case 'N':
1354                 return of(this.value);
1355             case 'E':
1356                 return throwError(this.error);
1357             case 'C':
1358                 return empty();
1359         }
1360         throw new Error('unexpected notification kind value');
1361     };
1362     Notification.createNext = function (value) {
1363         if (typeof value !== 'undefined') {
1364             return new Notification('N', value);
1365         }
1366         return Notification.undefinedValueNotification;
1367     };
1368     Notification.createError = function (err) {
1369         return new Notification('E', undefined, err);
1370     };
1371     Notification.createComplete = function () {
1372         return Notification.completeNotification;
1373     };
1374     Notification.completeNotification = new Notification('C');
1375     Notification.undefinedValueNotification = new Notification('N', undefined);
1376     return Notification;
1377 }());
1378
1379 /** PURE_IMPORTS_START tslib,_Subscriber,_Notification PURE_IMPORTS_END */
1380 var ObserveOnSubscriber = /*@__PURE__*/ (function (_super) {
1381     __extends(ObserveOnSubscriber, _super);
1382     function ObserveOnSubscriber(destination, scheduler, delay) {
1383         if (delay === void 0) {
1384             delay = 0;
1385         }
1386         var _this = _super.call(this, destination) || this;
1387         _this.scheduler = scheduler;
1388         _this.delay = delay;
1389         return _this;
1390     }
1391     ObserveOnSubscriber.dispatch = function (arg) {
1392         var notification = arg.notification, destination = arg.destination;
1393         notification.observe(destination);
1394         this.unsubscribe();
1395     };
1396     ObserveOnSubscriber.prototype.scheduleMessage = function (notification) {
1397         var destination = this.destination;
1398         destination.add(this.scheduler.schedule(ObserveOnSubscriber.dispatch, this.delay, new ObserveOnMessage(notification, this.destination)));
1399     };
1400     ObserveOnSubscriber.prototype._next = function (value) {
1401         this.scheduleMessage(Notification.createNext(value));
1402     };
1403     ObserveOnSubscriber.prototype._error = function (err) {
1404         this.scheduleMessage(Notification.createError(err));
1405         this.unsubscribe();
1406     };
1407     ObserveOnSubscriber.prototype._complete = function () {
1408         this.scheduleMessage(Notification.createComplete());
1409         this.unsubscribe();
1410     };
1411     return ObserveOnSubscriber;
1412 }(Subscriber));
1413 var ObserveOnMessage = /*@__PURE__*/ (function () {
1414     function ObserveOnMessage(notification, destination) {
1415         this.notification = notification;
1416         this.destination = destination;
1417     }
1418     return ObserveOnMessage;
1419 }());
1420
1421 /** PURE_IMPORTS_START tslib,_Subject,_scheduler_queue,_Subscription,_operators_observeOn,_util_ObjectUnsubscribedError,_SubjectSubscription PURE_IMPORTS_END */
1422 var ReplaySubject = /*@__PURE__*/ (function (_super) {
1423     __extends(ReplaySubject, _super);
1424     function ReplaySubject(bufferSize, windowTime, scheduler) {
1425         if (bufferSize === void 0) {
1426             bufferSize = Number.POSITIVE_INFINITY;
1427         }
1428         if (windowTime === void 0) {
1429             windowTime = Number.POSITIVE_INFINITY;
1430         }
1431         var _this = _super.call(this) || this;
1432         _this.scheduler = scheduler;
1433         _this._events = [];
1434         _this._infiniteTimeWindow = false;
1435         _this._bufferSize = bufferSize < 1 ? 1 : bufferSize;
1436         _this._windowTime = windowTime < 1 ? 1 : windowTime;
1437         if (windowTime === Number.POSITIVE_INFINITY) {
1438             _this._infiniteTimeWindow = true;
1439             _this.next = _this.nextInfiniteTimeWindow;
1440         }
1441         else {
1442             _this.next = _this.nextTimeWindow;
1443         }
1444         return _this;
1445     }
1446     ReplaySubject.prototype.nextInfiniteTimeWindow = function (value) {
1447         if (!this.isStopped) {
1448             var _events = this._events;
1449             _events.push(value);
1450             if (_events.length > this._bufferSize) {
1451                 _events.shift();
1452             }
1453         }
1454         _super.prototype.next.call(this, value);
1455     };
1456     ReplaySubject.prototype.nextTimeWindow = function (value) {
1457         if (!this.isStopped) {
1458             this._events.push(new ReplayEvent(this._getNow(), value));
1459             this._trimBufferThenGetEvents();
1460         }
1461         _super.prototype.next.call(this, value);
1462     };
1463     ReplaySubject.prototype._subscribe = function (subscriber) {
1464         var _infiniteTimeWindow = this._infiniteTimeWindow;
1465         var _events = _infiniteTimeWindow ? this._events : this._trimBufferThenGetEvents();
1466         var scheduler = this.scheduler;
1467         var len = _events.length;
1468         var subscription;
1469         if (this.closed) {
1470             throw new ObjectUnsubscribedError();
1471         }
1472         else if (this.isStopped || this.hasError) {
1473             subscription = Subscription.EMPTY;
1474         }
1475         else {
1476             this.observers.push(subscriber);
1477             subscription = new SubjectSubscription(this, subscriber);
1478         }
1479         if (scheduler) {
1480             subscriber.add(subscriber = new ObserveOnSubscriber(subscriber, scheduler));
1481         }
1482         if (_infiniteTimeWindow) {
1483             for (var i = 0; i < len && !subscriber.closed; i++) {
1484                 subscriber.next(_events[i]);
1485             }
1486         }
1487         else {
1488             for (var i = 0; i < len && !subscriber.closed; i++) {
1489                 subscriber.next(_events[i].value);
1490             }
1491         }
1492         if (this.hasError) {
1493             subscriber.error(this.thrownError);
1494         }
1495         else if (this.isStopped) {
1496             subscriber.complete();
1497         }
1498         return subscription;
1499     };
1500     ReplaySubject.prototype._getNow = function () {
1501         return (this.scheduler || queue).now();
1502     };
1503     ReplaySubject.prototype._trimBufferThenGetEvents = function () {
1504         var now = this._getNow();
1505         var _bufferSize = this._bufferSize;
1506         var _windowTime = this._windowTime;
1507         var _events = this._events;
1508         var eventsCount = _events.length;
1509         var spliceCount = 0;
1510         while (spliceCount < eventsCount) {
1511             if ((now - _events[spliceCount].time) < _windowTime) {
1512                 break;
1513             }
1514             spliceCount++;
1515         }
1516         if (eventsCount > _bufferSize) {
1517             spliceCount = Math.max(spliceCount, eventsCount - _bufferSize);
1518         }
1519         if (spliceCount > 0) {
1520             _events.splice(0, spliceCount);
1521         }
1522         return _events;
1523     };
1524     return ReplaySubject;
1525 }(Subject));
1526 var ReplayEvent = /*@__PURE__*/ (function () {
1527     function ReplayEvent(time, value) {
1528         this.time = time;
1529         this.value = value;
1530     }
1531     return ReplayEvent;
1532 }());
1533
1534 /** PURE_IMPORTS_START _AsyncAction,_AsyncScheduler PURE_IMPORTS_END */
1535 var asyncScheduler = /*@__PURE__*/ new AsyncScheduler(AsyncAction);
1536 var async = asyncScheduler;
1537
1538 /** PURE_IMPORTS_START  PURE_IMPORTS_END */
1539 function noop() { }
1540
1541 /** PURE_IMPORTS_START  PURE_IMPORTS_END */
1542 var ArgumentOutOfRangeErrorImpl = /*@__PURE__*/ (function () {
1543     function ArgumentOutOfRangeErrorImpl() {
1544         Error.call(this);
1545         this.message = 'argument out of range';
1546         this.name = 'ArgumentOutOfRangeError';
1547         return this;
1548     }
1549     ArgumentOutOfRangeErrorImpl.prototype = /*@__PURE__*/ Object.create(Error.prototype);
1550     return ArgumentOutOfRangeErrorImpl;
1551 })();
1552 var ArgumentOutOfRangeError = ArgumentOutOfRangeErrorImpl;
1553
1554 /** PURE_IMPORTS_START  PURE_IMPORTS_END */
1555 var EmptyErrorImpl = /*@__PURE__*/ (function () {
1556     function EmptyErrorImpl() {
1557         Error.call(this);
1558         this.message = 'no elements in sequence';
1559         this.name = 'EmptyError';
1560         return this;
1561     }
1562     EmptyErrorImpl.prototype = /*@__PURE__*/ Object.create(Error.prototype);
1563     return EmptyErrorImpl;
1564 })();
1565 var EmptyError = EmptyErrorImpl;
1566
1567 /** PURE_IMPORTS_START  PURE_IMPORTS_END */
1568 var TimeoutErrorImpl = /*@__PURE__*/ (function () {
1569     function TimeoutErrorImpl() {
1570         Error.call(this);
1571         this.message = 'Timeout has occurred';
1572         this.name = 'TimeoutError';
1573         return this;
1574     }
1575     TimeoutErrorImpl.prototype = /*@__PURE__*/ Object.create(Error.prototype);
1576     return TimeoutErrorImpl;
1577 })();
1578 var TimeoutError = TimeoutErrorImpl;
1579
1580 /** PURE_IMPORTS_START tslib,_Subscriber PURE_IMPORTS_END */
1581 function map(project, thisArg) {
1582     return function mapOperation(source) {
1583         if (typeof project !== 'function') {
1584             throw new TypeError('argument is not a function. Are you looking for `mapTo()`?');
1585         }
1586         return source.lift(new MapOperator(project, thisArg));
1587     };
1588 }
1589 var MapOperator = /*@__PURE__*/ (function () {
1590     function MapOperator(project, thisArg) {
1591         this.project = project;
1592         this.thisArg = thisArg;
1593     }
1594     MapOperator.prototype.call = function (subscriber, source) {
1595         return source.subscribe(new MapSubscriber(subscriber, this.project, this.thisArg));
1596     };
1597     return MapOperator;
1598 }());
1599 var MapSubscriber = /*@__PURE__*/ (function (_super) {
1600     __extends(MapSubscriber, _super);
1601     function MapSubscriber(destination, project, thisArg) {
1602         var _this = _super.call(this, destination) || this;
1603         _this.project = project;
1604         _this.count = 0;
1605         _this.thisArg = thisArg || _this;
1606         return _this;
1607     }
1608     MapSubscriber.prototype._next = function (value) {
1609         var result;
1610         try {
1611             result = this.project.call(this.thisArg, value, this.count++);
1612         }
1613         catch (err) {
1614             this.destination.error(err);
1615             return;
1616         }
1617         this.destination.next(result);
1618     };
1619     return MapSubscriber;
1620 }(Subscriber));
1621
1622 /** PURE_IMPORTS_START tslib,_Subscriber PURE_IMPORTS_END */
1623 var OuterSubscriber = /*@__PURE__*/ (function (_super) {
1624     __extends(OuterSubscriber, _super);
1625     function OuterSubscriber() {
1626         return _super !== null && _super.apply(this, arguments) || this;
1627     }
1628     OuterSubscriber.prototype.notifyNext = function (outerValue, innerValue, outerIndex, innerIndex, innerSub) {
1629         this.destination.next(innerValue);
1630     };
1631     OuterSubscriber.prototype.notifyError = function (error, innerSub) {
1632         this.destination.error(error);
1633     };
1634     OuterSubscriber.prototype.notifyComplete = function (innerSub) {
1635         this.destination.complete();
1636     };
1637     return OuterSubscriber;
1638 }(Subscriber));
1639
1640 /** PURE_IMPORTS_START tslib,_Subscriber PURE_IMPORTS_END */
1641 var InnerSubscriber = /*@__PURE__*/ (function (_super) {
1642     __extends(InnerSubscriber, _super);
1643     function InnerSubscriber(parent, outerValue, outerIndex) {
1644         var _this = _super.call(this) || this;
1645         _this.parent = parent;
1646         _this.outerValue = outerValue;
1647         _this.outerIndex = outerIndex;
1648         _this.index = 0;
1649         return _this;
1650     }
1651     InnerSubscriber.prototype._next = function (value) {
1652         this.parent.notifyNext(this.outerValue, value, this.outerIndex, this.index++, this);
1653     };
1654     InnerSubscriber.prototype._error = function (error) {
1655         this.parent.notifyError(error, this);
1656         this.unsubscribe();
1657     };
1658     InnerSubscriber.prototype._complete = function () {
1659         this.parent.notifyComplete(this);
1660         this.unsubscribe();
1661     };
1662     return InnerSubscriber;
1663 }(Subscriber));
1664
1665 /** PURE_IMPORTS_START _hostReportError PURE_IMPORTS_END */
1666 var subscribeToPromise = function (promise) {
1667     return function (subscriber) {
1668         promise.then(function (value) {
1669             if (!subscriber.closed) {
1670                 subscriber.next(value);
1671                 subscriber.complete();
1672             }
1673         }, function (err) { return subscriber.error(err); })
1674             .then(null, hostReportError);
1675         return subscriber;
1676     };
1677 };
1678
1679 /** PURE_IMPORTS_START  PURE_IMPORTS_END */
1680 function getSymbolIterator() {
1681     if (typeof Symbol !== 'function' || !Symbol.iterator) {
1682         return '@@iterator';
1683     }
1684     return Symbol.iterator;
1685 }
1686 var iterator = /*@__PURE__*/ getSymbolIterator();
1687
1688 /** PURE_IMPORTS_START _symbol_iterator PURE_IMPORTS_END */
1689 var subscribeToIterable = function (iterable) {
1690     return function (subscriber) {
1691         var iterator$1 = iterable[iterator]();
1692         do {
1693             var item = void 0;
1694             try {
1695                 item = iterator$1.next();
1696             }
1697             catch (err) {
1698                 subscriber.error(err);
1699                 return subscriber;
1700             }
1701             if (item.done) {
1702                 subscriber.complete();
1703                 break;
1704             }
1705             subscriber.next(item.value);
1706             if (subscriber.closed) {
1707                 break;
1708             }
1709         } while (true);
1710         if (typeof iterator$1.return === 'function') {
1711             subscriber.add(function () {
1712                 if (iterator$1.return) {
1713                     iterator$1.return();
1714                 }
1715             });
1716         }
1717         return subscriber;
1718     };
1719 };
1720
1721 /** PURE_IMPORTS_START _symbol_observable PURE_IMPORTS_END */
1722 var subscribeToObservable = function (obj) {
1723     return function (subscriber) {
1724         var obs = obj[observable]();
1725         if (typeof obs.subscribe !== 'function') {
1726             throw new TypeError('Provided object does not correctly implement Symbol.observable');
1727         }
1728         else {
1729             return obs.subscribe(subscriber);
1730         }
1731     };
1732 };
1733
1734 /** PURE_IMPORTS_START  PURE_IMPORTS_END */
1735 var isArrayLike = (function (x) { return x && typeof x.length === 'number' && typeof x !== 'function'; });
1736
1737 /** PURE_IMPORTS_START  PURE_IMPORTS_END */
1738 function isPromise(value) {
1739     return !!value && typeof value.subscribe !== 'function' && typeof value.then === 'function';
1740 }
1741
1742 /** PURE_IMPORTS_START _subscribeToArray,_subscribeToPromise,_subscribeToIterable,_subscribeToObservable,_isArrayLike,_isPromise,_isObject,_symbol_iterator,_symbol_observable PURE_IMPORTS_END */
1743 var subscribeTo = function (result) {
1744     if (!!result && typeof result[observable] === 'function') {
1745         return subscribeToObservable(result);
1746     }
1747     else if (isArrayLike(result)) {
1748         return subscribeToArray(result);
1749     }
1750     else if (isPromise(result)) {
1751         return subscribeToPromise(result);
1752     }
1753     else if (!!result && typeof result[iterator] === 'function') {
1754         return subscribeToIterable(result);
1755     }
1756     else {
1757         var value = isObject$1(result) ? 'an invalid object' : "'" + result + "'";
1758         var msg = "You provided " + value + " where a stream was expected."
1759             + ' You can provide an Observable, Promise, Array, or Iterable.';
1760         throw new TypeError(msg);
1761     }
1762 };
1763
1764 /** PURE_IMPORTS_START _InnerSubscriber,_subscribeTo,_Observable PURE_IMPORTS_END */
1765 function subscribeToResult(outerSubscriber, result, outerValue, outerIndex, innerSubscriber) {
1766     if (innerSubscriber === void 0) {
1767         innerSubscriber = new InnerSubscriber(outerSubscriber, outerValue, outerIndex);
1768     }
1769     if (innerSubscriber.closed) {
1770         return undefined;
1771     }
1772     if (result instanceof Observable) {
1773         return result.subscribe(innerSubscriber);
1774     }
1775     return subscribeTo(result)(innerSubscriber);
1776 }
1777
1778 /** PURE_IMPORTS_START tslib,_util_isScheduler,_util_isArray,_OuterSubscriber,_util_subscribeToResult,_fromArray PURE_IMPORTS_END */
1779 var NONE = {};
1780 function combineLatest() {
1781     var observables = [];
1782     for (var _i = 0; _i < arguments.length; _i++) {
1783         observables[_i] = arguments[_i];
1784     }
1785     var resultSelector = undefined;
1786     var scheduler = undefined;
1787     if (isScheduler(observables[observables.length - 1])) {
1788         scheduler = observables.pop();
1789     }
1790     if (typeof observables[observables.length - 1] === 'function') {
1791         resultSelector = observables.pop();
1792     }
1793     if (observables.length === 1 && isArray$1(observables[0])) {
1794         observables = observables[0];
1795     }
1796     return fromArray(observables, scheduler).lift(new CombineLatestOperator(resultSelector));
1797 }
1798 var CombineLatestOperator = /*@__PURE__*/ (function () {
1799     function CombineLatestOperator(resultSelector) {
1800         this.resultSelector = resultSelector;
1801     }
1802     CombineLatestOperator.prototype.call = function (subscriber, source) {
1803         return source.subscribe(new CombineLatestSubscriber(subscriber, this.resultSelector));
1804     };
1805     return CombineLatestOperator;
1806 }());
1807 var CombineLatestSubscriber = /*@__PURE__*/ (function (_super) {
1808     __extends(CombineLatestSubscriber, _super);
1809     function CombineLatestSubscriber(destination, resultSelector) {
1810         var _this = _super.call(this, destination) || this;
1811         _this.resultSelector = resultSelector;
1812         _this.active = 0;
1813         _this.values = [];
1814         _this.observables = [];
1815         return _this;
1816     }
1817     CombineLatestSubscriber.prototype._next = function (observable) {
1818         this.values.push(NONE);
1819         this.observables.push(observable);
1820     };
1821     CombineLatestSubscriber.prototype._complete = function () {
1822         var observables = this.observables;
1823         var len = observables.length;
1824         if (len === 0) {
1825             this.destination.complete();
1826         }
1827         else {
1828             this.active = len;
1829             this.toRespond = len;
1830             for (var i = 0; i < len; i++) {
1831                 var observable = observables[i];
1832                 this.add(subscribeToResult(this, observable, undefined, i));
1833             }
1834         }
1835     };
1836     CombineLatestSubscriber.prototype.notifyComplete = function (unused) {
1837         if ((this.active -= 1) === 0) {
1838             this.destination.complete();
1839         }
1840     };
1841     CombineLatestSubscriber.prototype.notifyNext = function (_outerValue, innerValue, outerIndex) {
1842         var values = this.values;
1843         var oldVal = values[outerIndex];
1844         var toRespond = !this.toRespond
1845             ? 0
1846             : oldVal === NONE ? --this.toRespond : this.toRespond;
1847         values[outerIndex] = innerValue;
1848         if (toRespond === 0) {
1849             if (this.resultSelector) {
1850                 this._tryResultSelector(values);
1851             }
1852             else {
1853                 this.destination.next(values.slice());
1854             }
1855         }
1856     };
1857     CombineLatestSubscriber.prototype._tryResultSelector = function (values) {
1858         var result;
1859         try {
1860             result = this.resultSelector.apply(this, values);
1861         }
1862         catch (err) {
1863             this.destination.error(err);
1864             return;
1865         }
1866         this.destination.next(result);
1867     };
1868     return CombineLatestSubscriber;
1869 }(OuterSubscriber));
1870
1871 /** PURE_IMPORTS_START _Observable,_Subscription,_symbol_observable PURE_IMPORTS_END */
1872 function scheduleObservable(input, scheduler) {
1873     return new Observable(function (subscriber) {
1874         var sub = new Subscription();
1875         sub.add(scheduler.schedule(function () {
1876             var observable$1 = input[observable]();
1877             sub.add(observable$1.subscribe({
1878                 next: function (value) { sub.add(scheduler.schedule(function () { return subscriber.next(value); })); },
1879                 error: function (err) { sub.add(scheduler.schedule(function () { return subscriber.error(err); })); },
1880                 complete: function () { sub.add(scheduler.schedule(function () { return subscriber.complete(); })); },
1881             }));
1882         }));
1883         return sub;
1884     });
1885 }
1886
1887 /** PURE_IMPORTS_START _Observable,_Subscription PURE_IMPORTS_END */
1888 function schedulePromise(input, scheduler) {
1889     return new Observable(function (subscriber) {
1890         var sub = new Subscription();
1891         sub.add(scheduler.schedule(function () {
1892             return input.then(function (value) {
1893                 sub.add(scheduler.schedule(function () {
1894                     subscriber.next(value);
1895                     sub.add(scheduler.schedule(function () { return subscriber.complete(); }));
1896                 }));
1897             }, function (err) {
1898                 sub.add(scheduler.schedule(function () { return subscriber.error(err); }));
1899             });
1900         }));
1901         return sub;
1902     });
1903 }
1904
1905 /** PURE_IMPORTS_START _Observable,_Subscription,_symbol_iterator PURE_IMPORTS_END */
1906 function scheduleIterable(input, scheduler) {
1907     if (!input) {
1908         throw new Error('Iterable cannot be null');
1909     }
1910     return new Observable(function (subscriber) {
1911         var sub = new Subscription();
1912         var iterator$1;
1913         sub.add(function () {
1914             if (iterator$1 && typeof iterator$1.return === 'function') {
1915                 iterator$1.return();
1916             }
1917         });
1918         sub.add(scheduler.schedule(function () {
1919             iterator$1 = input[iterator]();
1920             sub.add(scheduler.schedule(function () {
1921                 if (subscriber.closed) {
1922                     return;
1923                 }
1924                 var value;
1925                 var done;
1926                 try {
1927                     var result = iterator$1.next();
1928                     value = result.value;
1929                     done = result.done;
1930                 }
1931                 catch (err) {
1932                     subscriber.error(err);
1933                     return;
1934                 }
1935                 if (done) {
1936                     subscriber.complete();
1937                 }
1938                 else {
1939                     subscriber.next(value);
1940                     this.schedule();
1941                 }
1942             }));
1943         }));
1944         return sub;
1945     });
1946 }
1947
1948 /** PURE_IMPORTS_START _symbol_observable PURE_IMPORTS_END */
1949 function isInteropObservable(input) {
1950     return input && typeof input[observable] === 'function';
1951 }
1952
1953 /** PURE_IMPORTS_START _symbol_iterator PURE_IMPORTS_END */
1954 function isIterable(input) {
1955     return input && typeof input[iterator] === 'function';
1956 }
1957
1958 /** PURE_IMPORTS_START _scheduleObservable,_schedulePromise,_scheduleArray,_scheduleIterable,_util_isInteropObservable,_util_isPromise,_util_isArrayLike,_util_isIterable PURE_IMPORTS_END */
1959 function scheduled(input, scheduler) {
1960     if (input != null) {
1961         if (isInteropObservable(input)) {
1962             return scheduleObservable(input, scheduler);
1963         }
1964         else if (isPromise(input)) {
1965             return schedulePromise(input, scheduler);
1966         }
1967         else if (isArrayLike(input)) {
1968             return scheduleArray(input, scheduler);
1969         }
1970         else if (isIterable(input) || typeof input === 'string') {
1971             return scheduleIterable(input, scheduler);
1972         }
1973     }
1974     throw new TypeError((input !== null && typeof input || input) + ' is not observable');
1975 }
1976
1977 /** PURE_IMPORTS_START _Observable,_util_subscribeTo,_scheduled_scheduled PURE_IMPORTS_END */
1978 function from(input, scheduler) {
1979     if (!scheduler) {
1980         if (input instanceof Observable) {
1981             return input;
1982         }
1983         return new Observable(subscribeTo(input));
1984     }
1985     else {
1986         return scheduled(input, scheduler);
1987     }
1988 }
1989
1990 /** PURE_IMPORTS_START tslib,_Subscriber,_Observable,_util_subscribeTo PURE_IMPORTS_END */
1991 var SimpleInnerSubscriber = /*@__PURE__*/ (function (_super) {
1992     __extends(SimpleInnerSubscriber, _super);
1993     function SimpleInnerSubscriber(parent) {
1994         var _this = _super.call(this) || this;
1995         _this.parent = parent;
1996         return _this;
1997     }
1998     SimpleInnerSubscriber.prototype._next = function (value) {
1999         this.parent.notifyNext(value);
2000     };
2001     SimpleInnerSubscriber.prototype._error = function (error) {
2002         this.parent.notifyError(error);
2003         this.unsubscribe();
2004     };
2005     SimpleInnerSubscriber.prototype._complete = function () {
2006         this.parent.notifyComplete();
2007         this.unsubscribe();
2008     };
2009     return SimpleInnerSubscriber;
2010 }(Subscriber));
2011 var SimpleOuterSubscriber = /*@__PURE__*/ (function (_super) {
2012     __extends(SimpleOuterSubscriber, _super);
2013     function SimpleOuterSubscriber() {
2014         return _super !== null && _super.apply(this, arguments) || this;
2015     }
2016     SimpleOuterSubscriber.prototype.notifyNext = function (innerValue) {
2017         this.destination.next(innerValue);
2018     };
2019     SimpleOuterSubscriber.prototype.notifyError = function (err) {
2020         this.destination.error(err);
2021     };
2022     SimpleOuterSubscriber.prototype.notifyComplete = function () {
2023         this.destination.complete();
2024     };
2025     return SimpleOuterSubscriber;
2026 }(Subscriber));
2027 function innerSubscribe(result, innerSubscriber) {
2028     if (innerSubscriber.closed) {
2029         return undefined;
2030     }
2031     if (result instanceof Observable) {
2032         return result.subscribe(innerSubscriber);
2033     }
2034     return subscribeTo(result)(innerSubscriber);
2035 }
2036
2037 /** PURE_IMPORTS_START tslib,_map,_observable_from,_innerSubscribe PURE_IMPORTS_END */
2038 function mergeMap(project, resultSelector, concurrent) {
2039     if (concurrent === void 0) {
2040         concurrent = Number.POSITIVE_INFINITY;
2041     }
2042     if (typeof resultSelector === 'function') {
2043         return function (source) { return source.pipe(mergeMap(function (a, i) { return from(project(a, i)).pipe(map(function (b, ii) { return resultSelector(a, b, i, ii); })); }, concurrent)); };
2044     }
2045     else if (typeof resultSelector === 'number') {
2046         concurrent = resultSelector;
2047     }
2048     return function (source) { return source.lift(new MergeMapOperator(project, concurrent)); };
2049 }
2050 var MergeMapOperator = /*@__PURE__*/ (function () {
2051     function MergeMapOperator(project, concurrent) {
2052         if (concurrent === void 0) {
2053             concurrent = Number.POSITIVE_INFINITY;
2054         }
2055         this.project = project;
2056         this.concurrent = concurrent;
2057     }
2058     MergeMapOperator.prototype.call = function (observer, source) {
2059         return source.subscribe(new MergeMapSubscriber(observer, this.project, this.concurrent));
2060     };
2061     return MergeMapOperator;
2062 }());
2063 var MergeMapSubscriber = /*@__PURE__*/ (function (_super) {
2064     __extends(MergeMapSubscriber, _super);
2065     function MergeMapSubscriber(destination, project, concurrent) {
2066         if (concurrent === void 0) {
2067             concurrent = Number.POSITIVE_INFINITY;
2068         }
2069         var _this = _super.call(this, destination) || this;
2070         _this.project = project;
2071         _this.concurrent = concurrent;
2072         _this.hasCompleted = false;
2073         _this.buffer = [];
2074         _this.active = 0;
2075         _this.index = 0;
2076         return _this;
2077     }
2078     MergeMapSubscriber.prototype._next = function (value) {
2079         if (this.active < this.concurrent) {
2080             this._tryNext(value);
2081         }
2082         else {
2083             this.buffer.push(value);
2084         }
2085     };
2086     MergeMapSubscriber.prototype._tryNext = function (value) {
2087         var result;
2088         var index = this.index++;
2089         try {
2090             result = this.project(value, index);
2091         }
2092         catch (err) {
2093             this.destination.error(err);
2094             return;
2095         }
2096         this.active++;
2097         this._innerSub(result);
2098     };
2099     MergeMapSubscriber.prototype._innerSub = function (ish) {
2100         var innerSubscriber = new SimpleInnerSubscriber(this);
2101         var destination = this.destination;
2102         destination.add(innerSubscriber);
2103         var innerSubscription = innerSubscribe(ish, innerSubscriber);
2104         if (innerSubscription !== innerSubscriber) {
2105             destination.add(innerSubscription);
2106         }
2107     };
2108     MergeMapSubscriber.prototype._complete = function () {
2109         this.hasCompleted = true;
2110         if (this.active === 0 && this.buffer.length === 0) {
2111             this.destination.complete();
2112         }
2113         this.unsubscribe();
2114     };
2115     MergeMapSubscriber.prototype.notifyNext = function (innerValue) {
2116         this.destination.next(innerValue);
2117     };
2118     MergeMapSubscriber.prototype.notifyComplete = function () {
2119         var buffer = this.buffer;
2120         this.active--;
2121         if (buffer.length > 0) {
2122             this._next(buffer.shift());
2123         }
2124         else if (this.active === 0 && this.hasCompleted) {
2125             this.destination.complete();
2126         }
2127     };
2128     return MergeMapSubscriber;
2129 }(SimpleOuterSubscriber));
2130
2131 /** PURE_IMPORTS_START _mergeMap,_util_identity PURE_IMPORTS_END */
2132 function mergeAll(concurrent) {
2133     if (concurrent === void 0) {
2134         concurrent = Number.POSITIVE_INFINITY;
2135     }
2136     return mergeMap(identity, concurrent);
2137 }
2138
2139 /** PURE_IMPORTS_START _mergeAll PURE_IMPORTS_END */
2140 function concatAll() {
2141     return mergeAll(1);
2142 }
2143
2144 /** PURE_IMPORTS_START _of,_operators_concatAll PURE_IMPORTS_END */
2145 function concat() {
2146     var observables = [];
2147     for (var _i = 0; _i < arguments.length; _i++) {
2148         observables[_i] = arguments[_i];
2149     }
2150     return concatAll()(of.apply(void 0, observables));
2151 }
2152
2153 /** PURE_IMPORTS_START _Observable,_util_isArray,_util_isFunction,_operators_map PURE_IMPORTS_END */
2154 function fromEvent(target, eventName, options, resultSelector) {
2155     if (isFunction(options)) {
2156         resultSelector = options;
2157         options = undefined;
2158     }
2159     if (resultSelector) {
2160         return fromEvent(target, eventName, options).pipe(map(function (args) { return isArray$1(args) ? resultSelector.apply(void 0, args) : resultSelector(args); }));
2161     }
2162     return new Observable(function (subscriber) {
2163         function handler(e) {
2164             if (arguments.length > 1) {
2165                 subscriber.next(Array.prototype.slice.call(arguments));
2166             }
2167             else {
2168                 subscriber.next(e);
2169             }
2170         }
2171         setupSubscription(target, eventName, handler, subscriber, options);
2172     });
2173 }
2174 function setupSubscription(sourceObj, eventName, handler, subscriber, options) {
2175     var unsubscribe;
2176     if (isEventTarget(sourceObj)) {
2177         var source_1 = sourceObj;
2178         sourceObj.addEventListener(eventName, handler, options);
2179         unsubscribe = function () { return source_1.removeEventListener(eventName, handler, options); };
2180     }
2181     else if (isJQueryStyleEventEmitter(sourceObj)) {
2182         var source_2 = sourceObj;
2183         sourceObj.on(eventName, handler);
2184         unsubscribe = function () { return source_2.off(eventName, handler); };
2185     }
2186     else if (isNodeStyleEventEmitter(sourceObj)) {
2187         var source_3 = sourceObj;
2188         sourceObj.addListener(eventName, handler);
2189         unsubscribe = function () { return source_3.removeListener(eventName, handler); };
2190     }
2191     else if (sourceObj && sourceObj.length) {
2192         for (var i = 0, len = sourceObj.length; i < len; i++) {
2193             setupSubscription(sourceObj[i], eventName, handler, subscriber, options);
2194         }
2195     }
2196     else {
2197         throw new TypeError('Invalid event target');
2198     }
2199     subscriber.add(unsubscribe);
2200 }
2201 function isNodeStyleEventEmitter(sourceObj) {
2202     return sourceObj && typeof sourceObj.addListener === 'function' && typeof sourceObj.removeListener === 'function';
2203 }
2204 function isJQueryStyleEventEmitter(sourceObj) {
2205     return sourceObj && typeof sourceObj.on === 'function' && typeof sourceObj.off === 'function';
2206 }
2207 function isEventTarget(sourceObj) {
2208     return sourceObj && typeof sourceObj.addEventListener === 'function' && typeof sourceObj.removeEventListener === 'function';
2209 }
2210
2211 /** PURE_IMPORTS_START _isArray PURE_IMPORTS_END */
2212 function isNumeric(val) {
2213     return !isArray$1(val) && (val - parseFloat(val) + 1) >= 0;
2214 }
2215
2216 /** PURE_IMPORTS_START _Observable,_util_isScheduler,_operators_mergeAll,_fromArray PURE_IMPORTS_END */
2217 function merge() {
2218     var observables = [];
2219     for (var _i = 0; _i < arguments.length; _i++) {
2220         observables[_i] = arguments[_i];
2221     }
2222     var concurrent = Number.POSITIVE_INFINITY;
2223     var scheduler = null;
2224     var last = observables[observables.length - 1];
2225     if (isScheduler(last)) {
2226         scheduler = observables.pop();
2227         if (observables.length > 1 && typeof observables[observables.length - 1] === 'number') {
2228             concurrent = observables.pop();
2229         }
2230     }
2231     else if (typeof last === 'number') {
2232         concurrent = observables.pop();
2233     }
2234     if (scheduler === null && observables.length === 1 && observables[0] instanceof Observable) {
2235         return observables[0];
2236     }
2237     return mergeAll(concurrent)(fromArray(observables, scheduler));
2238 }
2239
2240 /** PURE_IMPORTS_START tslib,_Subscriber PURE_IMPORTS_END */
2241 function filter(predicate, thisArg) {
2242     return function filterOperatorFunction(source) {
2243         return source.lift(new FilterOperator(predicate, thisArg));
2244     };
2245 }
2246 var FilterOperator = /*@__PURE__*/ (function () {
2247     function FilterOperator(predicate, thisArg) {
2248         this.predicate = predicate;
2249         this.thisArg = thisArg;
2250     }
2251     FilterOperator.prototype.call = function (subscriber, source) {
2252         return source.subscribe(new FilterSubscriber(subscriber, this.predicate, this.thisArg));
2253     };
2254     return FilterOperator;
2255 }());
2256 var FilterSubscriber = /*@__PURE__*/ (function (_super) {
2257     __extends(FilterSubscriber, _super);
2258     function FilterSubscriber(destination, predicate, thisArg) {
2259         var _this = _super.call(this, destination) || this;
2260         _this.predicate = predicate;
2261         _this.thisArg = thisArg;
2262         _this.count = 0;
2263         return _this;
2264     }
2265     FilterSubscriber.prototype._next = function (value) {
2266         var result;
2267         try {
2268             result = this.predicate.call(this.thisArg, value, this.count++);
2269         }
2270         catch (err) {
2271             this.destination.error(err);
2272             return;
2273         }
2274         if (result) {
2275             this.destination.next(value);
2276         }
2277     };
2278     return FilterSubscriber;
2279 }(Subscriber));
2280
2281 /** PURE_IMPORTS_START _Observable,_scheduler_async,_util_isNumeric,_util_isScheduler PURE_IMPORTS_END */
2282 function timer(dueTime, periodOrScheduler, scheduler) {
2283     if (dueTime === void 0) {
2284         dueTime = 0;
2285     }
2286     var period = -1;
2287     if (isNumeric(periodOrScheduler)) {
2288         period = Number(periodOrScheduler) < 1 && 1 || Number(periodOrScheduler);
2289     }
2290     else if (isScheduler(periodOrScheduler)) {
2291         scheduler = periodOrScheduler;
2292     }
2293     if (!isScheduler(scheduler)) {
2294         scheduler = async;
2295     }
2296     return new Observable(function (subscriber) {
2297         var due = isNumeric(dueTime)
2298             ? dueTime
2299             : (+dueTime - scheduler.now());
2300         return scheduler.schedule(dispatch, due, {
2301             index: 0, period: period, subscriber: subscriber
2302         });
2303     });
2304 }
2305 function dispatch(state) {
2306     var index = state.index, period = state.period, subscriber = state.subscriber;
2307     subscriber.next(index);
2308     if (subscriber.closed) {
2309         return;
2310     }
2311     else if (period === -1) {
2312         return subscriber.complete();
2313     }
2314     state.index = index + 1;
2315     this.schedule(state, period);
2316 }
2317
2318 /** PURE_IMPORTS_START tslib,_fromArray,_util_isArray,_Subscriber,_.._internal_symbol_iterator,_innerSubscribe PURE_IMPORTS_END */
2319 function zip() {
2320     var observables = [];
2321     for (var _i = 0; _i < arguments.length; _i++) {
2322         observables[_i] = arguments[_i];
2323     }
2324     var resultSelector = observables[observables.length - 1];
2325     if (typeof resultSelector === 'function') {
2326         observables.pop();
2327     }
2328     return fromArray(observables, undefined).lift(new ZipOperator(resultSelector));
2329 }
2330 var ZipOperator = /*@__PURE__*/ (function () {
2331     function ZipOperator(resultSelector) {
2332         this.resultSelector = resultSelector;
2333     }
2334     ZipOperator.prototype.call = function (subscriber, source) {
2335         return source.subscribe(new ZipSubscriber(subscriber, this.resultSelector));
2336     };
2337     return ZipOperator;
2338 }());
2339 var ZipSubscriber = /*@__PURE__*/ (function (_super) {
2340     __extends(ZipSubscriber, _super);
2341     function ZipSubscriber(destination, resultSelector, values) {
2342         var _this = _super.call(this, destination) || this;
2343         _this.resultSelector = resultSelector;
2344         _this.iterators = [];
2345         _this.active = 0;
2346         _this.resultSelector = (typeof resultSelector === 'function') ? resultSelector : undefined;
2347         return _this;
2348     }
2349     ZipSubscriber.prototype._next = function (value) {
2350         var iterators = this.iterators;
2351         if (isArray$1(value)) {
2352             iterators.push(new StaticArrayIterator(value));
2353         }
2354         else if (typeof value[iterator] === 'function') {
2355             iterators.push(new StaticIterator(value[iterator]()));
2356         }
2357         else {
2358             iterators.push(new ZipBufferIterator(this.destination, this, value));
2359         }
2360     };
2361     ZipSubscriber.prototype._complete = function () {
2362         var iterators = this.iterators;
2363         var len = iterators.length;
2364         this.unsubscribe();
2365         if (len === 0) {
2366             this.destination.complete();
2367             return;
2368         }
2369         this.active = len;
2370         for (var i = 0; i < len; i++) {
2371             var iterator = iterators[i];
2372             if (iterator.stillUnsubscribed) {
2373                 var destination = this.destination;
2374                 destination.add(iterator.subscribe());
2375             }
2376             else {
2377                 this.active--;
2378             }
2379         }
2380     };
2381     ZipSubscriber.prototype.notifyInactive = function () {
2382         this.active--;
2383         if (this.active === 0) {
2384             this.destination.complete();
2385         }
2386     };
2387     ZipSubscriber.prototype.checkIterators = function () {
2388         var iterators = this.iterators;
2389         var len = iterators.length;
2390         var destination = this.destination;
2391         for (var i = 0; i < len; i++) {
2392             var iterator = iterators[i];
2393             if (typeof iterator.hasValue === 'function' && !iterator.hasValue()) {
2394                 return;
2395             }
2396         }
2397         var shouldComplete = false;
2398         var args = [];
2399         for (var i = 0; i < len; i++) {
2400             var iterator = iterators[i];
2401             var result = iterator.next();
2402             if (iterator.hasCompleted()) {
2403                 shouldComplete = true;
2404             }
2405             if (result.done) {
2406                 destination.complete();
2407                 return;
2408             }
2409             args.push(result.value);
2410         }
2411         if (this.resultSelector) {
2412             this._tryresultSelector(args);
2413         }
2414         else {
2415             destination.next(args);
2416         }
2417         if (shouldComplete) {
2418             destination.complete();
2419         }
2420     };
2421     ZipSubscriber.prototype._tryresultSelector = function (args) {
2422         var result;
2423         try {
2424             result = this.resultSelector.apply(this, args);
2425         }
2426         catch (err) {
2427             this.destination.error(err);
2428             return;
2429         }
2430         this.destination.next(result);
2431     };
2432     return ZipSubscriber;
2433 }(Subscriber));
2434 var StaticIterator = /*@__PURE__*/ (function () {
2435     function StaticIterator(iterator) {
2436         this.iterator = iterator;
2437         this.nextResult = iterator.next();
2438     }
2439     StaticIterator.prototype.hasValue = function () {
2440         return true;
2441     };
2442     StaticIterator.prototype.next = function () {
2443         var result = this.nextResult;
2444         this.nextResult = this.iterator.next();
2445         return result;
2446     };
2447     StaticIterator.prototype.hasCompleted = function () {
2448         var nextResult = this.nextResult;
2449         return Boolean(nextResult && nextResult.done);
2450     };
2451     return StaticIterator;
2452 }());
2453 var StaticArrayIterator = /*@__PURE__*/ (function () {
2454     function StaticArrayIterator(array) {
2455         this.array = array;
2456         this.index = 0;
2457         this.length = 0;
2458         this.length = array.length;
2459     }
2460     StaticArrayIterator.prototype[iterator] = function () {
2461         return this;
2462     };
2463     StaticArrayIterator.prototype.next = function (value) {
2464         var i = this.index++;
2465         var array = this.array;
2466         return i < this.length ? { value: array[i], done: false } : { value: null, done: true };
2467     };
2468     StaticArrayIterator.prototype.hasValue = function () {
2469         return this.array.length > this.index;
2470     };
2471     StaticArrayIterator.prototype.hasCompleted = function () {
2472         return this.array.length === this.index;
2473     };
2474     return StaticArrayIterator;
2475 }());
2476 var ZipBufferIterator = /*@__PURE__*/ (function (_super) {
2477     __extends(ZipBufferIterator, _super);
2478     function ZipBufferIterator(destination, parent, observable) {
2479         var _this = _super.call(this, destination) || this;
2480         _this.parent = parent;
2481         _this.observable = observable;
2482         _this.stillUnsubscribed = true;
2483         _this.buffer = [];
2484         _this.isComplete = false;
2485         return _this;
2486     }
2487     ZipBufferIterator.prototype[iterator] = function () {
2488         return this;
2489     };
2490     ZipBufferIterator.prototype.next = function () {
2491         var buffer = this.buffer;
2492         if (buffer.length === 0 && this.isComplete) {
2493             return { value: null, done: true };
2494         }
2495         else {
2496             return { value: buffer.shift(), done: false };
2497         }
2498     };
2499     ZipBufferIterator.prototype.hasValue = function () {
2500         return this.buffer.length > 0;
2501     };
2502     ZipBufferIterator.prototype.hasCompleted = function () {
2503         return this.buffer.length === 0 && this.isComplete;
2504     };
2505     ZipBufferIterator.prototype.notifyComplete = function () {
2506         if (this.buffer.length > 0) {
2507             this.isComplete = true;
2508             this.parent.notifyInactive();
2509         }
2510         else {
2511             this.destination.complete();
2512         }
2513     };
2514     ZipBufferIterator.prototype.notifyNext = function (innerValue) {
2515         this.buffer.push(innerValue);
2516         this.parent.checkIterators();
2517     };
2518     ZipBufferIterator.prototype.subscribe = function () {
2519         return innerSubscribe(this.observable, new SimpleInnerSubscriber(this));
2520     };
2521     return ZipBufferIterator;
2522 }(SimpleOuterSubscriber));
2523
2524 /** PURE_IMPORTS_START tslib,_innerSubscribe PURE_IMPORTS_END */
2525 function audit(durationSelector) {
2526     return function auditOperatorFunction(source) {
2527         return source.lift(new AuditOperator(durationSelector));
2528     };
2529 }
2530 var AuditOperator = /*@__PURE__*/ (function () {
2531     function AuditOperator(durationSelector) {
2532         this.durationSelector = durationSelector;
2533     }
2534     AuditOperator.prototype.call = function (subscriber, source) {
2535         return source.subscribe(new AuditSubscriber(subscriber, this.durationSelector));
2536     };
2537     return AuditOperator;
2538 }());
2539 var AuditSubscriber = /*@__PURE__*/ (function (_super) {
2540     __extends(AuditSubscriber, _super);
2541     function AuditSubscriber(destination, durationSelector) {
2542         var _this = _super.call(this, destination) || this;
2543         _this.durationSelector = durationSelector;
2544         _this.hasValue = false;
2545         return _this;
2546     }
2547     AuditSubscriber.prototype._next = function (value) {
2548         this.value = value;
2549         this.hasValue = true;
2550         if (!this.throttled) {
2551             var duration = void 0;
2552             try {
2553                 var durationSelector = this.durationSelector;
2554                 duration = durationSelector(value);
2555             }
2556             catch (err) {
2557                 return this.destination.error(err);
2558             }
2559             var innerSubscription = innerSubscribe(duration, new SimpleInnerSubscriber(this));
2560             if (!innerSubscription || innerSubscription.closed) {
2561                 this.clearThrottle();
2562             }
2563             else {
2564                 this.add(this.throttled = innerSubscription);
2565             }
2566         }
2567     };
2568     AuditSubscriber.prototype.clearThrottle = function () {
2569         var _a = this, value = _a.value, hasValue = _a.hasValue, throttled = _a.throttled;
2570         if (throttled) {
2571             this.remove(throttled);
2572             this.throttled = undefined;
2573             throttled.unsubscribe();
2574         }
2575         if (hasValue) {
2576             this.value = undefined;
2577             this.hasValue = false;
2578             this.destination.next(value);
2579         }
2580     };
2581     AuditSubscriber.prototype.notifyNext = function () {
2582         this.clearThrottle();
2583     };
2584     AuditSubscriber.prototype.notifyComplete = function () {
2585         this.clearThrottle();
2586     };
2587     return AuditSubscriber;
2588 }(SimpleOuterSubscriber));
2589
2590 /** PURE_IMPORTS_START _scheduler_async,_audit,_observable_timer PURE_IMPORTS_END */
2591 function auditTime(duration, scheduler) {
2592     if (scheduler === void 0) {
2593         scheduler = async;
2594     }
2595     return audit(function () { return timer(duration, scheduler); });
2596 }
2597
2598 /** PURE_IMPORTS_START tslib,_Subscriber PURE_IMPORTS_END */
2599 function bufferCount(bufferSize, startBufferEvery) {
2600     if (startBufferEvery === void 0) {
2601         startBufferEvery = null;
2602     }
2603     return function bufferCountOperatorFunction(source) {
2604         return source.lift(new BufferCountOperator(bufferSize, startBufferEvery));
2605     };
2606 }
2607 var BufferCountOperator = /*@__PURE__*/ (function () {
2608     function BufferCountOperator(bufferSize, startBufferEvery) {
2609         this.bufferSize = bufferSize;
2610         this.startBufferEvery = startBufferEvery;
2611         if (!startBufferEvery || bufferSize === startBufferEvery) {
2612             this.subscriberClass = BufferCountSubscriber;
2613         }
2614         else {
2615             this.subscriberClass = BufferSkipCountSubscriber;
2616         }
2617     }
2618     BufferCountOperator.prototype.call = function (subscriber, source) {
2619         return source.subscribe(new this.subscriberClass(subscriber, this.bufferSize, this.startBufferEvery));
2620     };
2621     return BufferCountOperator;
2622 }());
2623 var BufferCountSubscriber = /*@__PURE__*/ (function (_super) {
2624     __extends(BufferCountSubscriber, _super);
2625     function BufferCountSubscriber(destination, bufferSize) {
2626         var _this = _super.call(this, destination) || this;
2627         _this.bufferSize = bufferSize;
2628         _this.buffer = [];
2629         return _this;
2630     }
2631     BufferCountSubscriber.prototype._next = function (value) {
2632         var buffer = this.buffer;
2633         buffer.push(value);
2634         if (buffer.length == this.bufferSize) {
2635             this.destination.next(buffer);
2636             this.buffer = [];
2637         }
2638     };
2639     BufferCountSubscriber.prototype._complete = function () {
2640         var buffer = this.buffer;
2641         if (buffer.length > 0) {
2642             this.destination.next(buffer);
2643         }
2644         _super.prototype._complete.call(this);
2645     };
2646     return BufferCountSubscriber;
2647 }(Subscriber));
2648 var BufferSkipCountSubscriber = /*@__PURE__*/ (function (_super) {
2649     __extends(BufferSkipCountSubscriber, _super);
2650     function BufferSkipCountSubscriber(destination, bufferSize, startBufferEvery) {
2651         var _this = _super.call(this, destination) || this;
2652         _this.bufferSize = bufferSize;
2653         _this.startBufferEvery = startBufferEvery;
2654         _this.buffers = [];
2655         _this.count = 0;
2656         return _this;
2657     }
2658     BufferSkipCountSubscriber.prototype._next = function (value) {
2659         var _a = this, bufferSize = _a.bufferSize, startBufferEvery = _a.startBufferEvery, buffers = _a.buffers, count = _a.count;
2660         this.count++;
2661         if (count % startBufferEvery === 0) {
2662             buffers.push([]);
2663         }
2664         for (var i = buffers.length; i--;) {
2665             var buffer = buffers[i];
2666             buffer.push(value);
2667             if (buffer.length === bufferSize) {
2668                 buffers.splice(i, 1);
2669                 this.destination.next(buffer);
2670             }
2671         }
2672     };
2673     BufferSkipCountSubscriber.prototype._complete = function () {
2674         var _a = this, buffers = _a.buffers, destination = _a.destination;
2675         while (buffers.length > 0) {
2676             var buffer = buffers.shift();
2677             if (buffer.length > 0) {
2678                 destination.next(buffer);
2679             }
2680         }
2681         _super.prototype._complete.call(this);
2682     };
2683     return BufferSkipCountSubscriber;
2684 }(Subscriber));
2685
2686 /** PURE_IMPORTS_START tslib,_Subscription,_innerSubscribe PURE_IMPORTS_END */
2687 function bufferWhen(closingSelector) {
2688     return function (source) {
2689         return source.lift(new BufferWhenOperator(closingSelector));
2690     };
2691 }
2692 var BufferWhenOperator = /*@__PURE__*/ (function () {
2693     function BufferWhenOperator(closingSelector) {
2694         this.closingSelector = closingSelector;
2695     }
2696     BufferWhenOperator.prototype.call = function (subscriber, source) {
2697         return source.subscribe(new BufferWhenSubscriber(subscriber, this.closingSelector));
2698     };
2699     return BufferWhenOperator;
2700 }());
2701 var BufferWhenSubscriber = /*@__PURE__*/ (function (_super) {
2702     __extends(BufferWhenSubscriber, _super);
2703     function BufferWhenSubscriber(destination, closingSelector) {
2704         var _this = _super.call(this, destination) || this;
2705         _this.closingSelector = closingSelector;
2706         _this.subscribing = false;
2707         _this.openBuffer();
2708         return _this;
2709     }
2710     BufferWhenSubscriber.prototype._next = function (value) {
2711         this.buffer.push(value);
2712     };
2713     BufferWhenSubscriber.prototype._complete = function () {
2714         var buffer = this.buffer;
2715         if (buffer) {
2716             this.destination.next(buffer);
2717         }
2718         _super.prototype._complete.call(this);
2719     };
2720     BufferWhenSubscriber.prototype._unsubscribe = function () {
2721         this.buffer = undefined;
2722         this.subscribing = false;
2723     };
2724     BufferWhenSubscriber.prototype.notifyNext = function () {
2725         this.openBuffer();
2726     };
2727     BufferWhenSubscriber.prototype.notifyComplete = function () {
2728         if (this.subscribing) {
2729             this.complete();
2730         }
2731         else {
2732             this.openBuffer();
2733         }
2734     };
2735     BufferWhenSubscriber.prototype.openBuffer = function () {
2736         var closingSubscription = this.closingSubscription;
2737         if (closingSubscription) {
2738             this.remove(closingSubscription);
2739             closingSubscription.unsubscribe();
2740         }
2741         var buffer = this.buffer;
2742         if (this.buffer) {
2743             this.destination.next(buffer);
2744         }
2745         this.buffer = [];
2746         var closingNotifier;
2747         try {
2748             var closingSelector = this.closingSelector;
2749             closingNotifier = closingSelector();
2750         }
2751         catch (err) {
2752             return this.error(err);
2753         }
2754         closingSubscription = new Subscription();
2755         this.closingSubscription = closingSubscription;
2756         this.add(closingSubscription);
2757         this.subscribing = true;
2758         closingSubscription.add(innerSubscribe(closingNotifier, new SimpleInnerSubscriber(this)));
2759         this.subscribing = false;
2760     };
2761     return BufferWhenSubscriber;
2762 }(SimpleOuterSubscriber));
2763
2764 /** PURE_IMPORTS_START tslib,_innerSubscribe PURE_IMPORTS_END */
2765 function catchError(selector) {
2766     return function catchErrorOperatorFunction(source) {
2767         var operator = new CatchOperator(selector);
2768         var caught = source.lift(operator);
2769         return (operator.caught = caught);
2770     };
2771 }
2772 var CatchOperator = /*@__PURE__*/ (function () {
2773     function CatchOperator(selector) {
2774         this.selector = selector;
2775     }
2776     CatchOperator.prototype.call = function (subscriber, source) {
2777         return source.subscribe(new CatchSubscriber(subscriber, this.selector, this.caught));
2778     };
2779     return CatchOperator;
2780 }());
2781 var CatchSubscriber = /*@__PURE__*/ (function (_super) {
2782     __extends(CatchSubscriber, _super);
2783     function CatchSubscriber(destination, selector, caught) {
2784         var _this = _super.call(this, destination) || this;
2785         _this.selector = selector;
2786         _this.caught = caught;
2787         return _this;
2788     }
2789     CatchSubscriber.prototype.error = function (err) {
2790         if (!this.isStopped) {
2791             var result = void 0;
2792             try {
2793                 result = this.selector(err, this.caught);
2794             }
2795             catch (err2) {
2796                 _super.prototype.error.call(this, err2);
2797                 return;
2798             }
2799             this._unsubscribeAndRecycle();
2800             var innerSubscriber = new SimpleInnerSubscriber(this);
2801             this.add(innerSubscriber);
2802             var innerSubscription = innerSubscribe(result, innerSubscriber);
2803             if (innerSubscription !== innerSubscriber) {
2804                 this.add(innerSubscription);
2805             }
2806         }
2807     };
2808     return CatchSubscriber;
2809 }(SimpleOuterSubscriber));
2810
2811 /** PURE_IMPORTS_START _mergeMap PURE_IMPORTS_END */
2812 function concatMap(project, resultSelector) {
2813     return mergeMap(project, resultSelector, 1);
2814 }
2815
2816 /** PURE_IMPORTS_START tslib,_Subscriber,_scheduler_async PURE_IMPORTS_END */
2817 function debounceTime(dueTime, scheduler) {
2818     if (scheduler === void 0) {
2819         scheduler = async;
2820     }
2821     return function (source) { return source.lift(new DebounceTimeOperator(dueTime, scheduler)); };
2822 }
2823 var DebounceTimeOperator = /*@__PURE__*/ (function () {
2824     function DebounceTimeOperator(dueTime, scheduler) {
2825         this.dueTime = dueTime;
2826         this.scheduler = scheduler;
2827     }
2828     DebounceTimeOperator.prototype.call = function (subscriber, source) {
2829         return source.subscribe(new DebounceTimeSubscriber(subscriber, this.dueTime, this.scheduler));
2830     };
2831     return DebounceTimeOperator;
2832 }());
2833 var DebounceTimeSubscriber = /*@__PURE__*/ (function (_super) {
2834     __extends(DebounceTimeSubscriber, _super);
2835     function DebounceTimeSubscriber(destination, dueTime, scheduler) {
2836         var _this = _super.call(this, destination) || this;
2837         _this.dueTime = dueTime;
2838         _this.scheduler = scheduler;
2839         _this.debouncedSubscription = null;
2840         _this.lastValue = null;
2841         _this.hasValue = false;
2842         return _this;
2843     }
2844     DebounceTimeSubscriber.prototype._next = function (value) {
2845         this.clearDebounce();
2846         this.lastValue = value;
2847         this.hasValue = true;
2848         this.add(this.debouncedSubscription = this.scheduler.schedule(dispatchNext, this.dueTime, this));
2849     };
2850     DebounceTimeSubscriber.prototype._complete = function () {
2851         this.debouncedNext();
2852         this.destination.complete();
2853     };
2854     DebounceTimeSubscriber.prototype.debouncedNext = function () {
2855         this.clearDebounce();
2856         if (this.hasValue) {
2857             var lastValue = this.lastValue;
2858             this.lastValue = null;
2859             this.hasValue = false;
2860             this.destination.next(lastValue);
2861         }
2862     };
2863     DebounceTimeSubscriber.prototype.clearDebounce = function () {
2864         var debouncedSubscription = this.debouncedSubscription;
2865         if (debouncedSubscription !== null) {
2866             this.remove(debouncedSubscription);
2867             debouncedSubscription.unsubscribe();
2868             this.debouncedSubscription = null;
2869         }
2870     };
2871     return DebounceTimeSubscriber;
2872 }(Subscriber));
2873 function dispatchNext(subscriber) {
2874     subscriber.debouncedNext();
2875 }
2876
2877 /** PURE_IMPORTS_START tslib,_Subscriber PURE_IMPORTS_END */
2878 function defaultIfEmpty(defaultValue) {
2879     if (defaultValue === void 0) {
2880         defaultValue = null;
2881     }
2882     return function (source) { return source.lift(new DefaultIfEmptyOperator(defaultValue)); };
2883 }
2884 var DefaultIfEmptyOperator = /*@__PURE__*/ (function () {
2885     function DefaultIfEmptyOperator(defaultValue) {
2886         this.defaultValue = defaultValue;
2887     }
2888     DefaultIfEmptyOperator.prototype.call = function (subscriber, source) {
2889         return source.subscribe(new DefaultIfEmptySubscriber(subscriber, this.defaultValue));
2890     };
2891     return DefaultIfEmptyOperator;
2892 }());
2893 var DefaultIfEmptySubscriber = /*@__PURE__*/ (function (_super) {
2894     __extends(DefaultIfEmptySubscriber, _super);
2895     function DefaultIfEmptySubscriber(destination, defaultValue) {
2896         var _this = _super.call(this, destination) || this;
2897         _this.defaultValue = defaultValue;
2898         _this.isEmpty = true;
2899         return _this;
2900     }
2901     DefaultIfEmptySubscriber.prototype._next = function (value) {
2902         this.isEmpty = false;
2903         this.destination.next(value);
2904     };
2905     DefaultIfEmptySubscriber.prototype._complete = function () {
2906         if (this.isEmpty) {
2907             this.destination.next(this.defaultValue);
2908         }
2909         this.destination.complete();
2910     };
2911     return DefaultIfEmptySubscriber;
2912 }(Subscriber));
2913
2914 /** PURE_IMPORTS_START  PURE_IMPORTS_END */
2915 function isDate(value) {
2916     return value instanceof Date && !isNaN(+value);
2917 }
2918
2919 /** PURE_IMPORTS_START tslib,_Subscriber PURE_IMPORTS_END */
2920 function distinctUntilChanged(compare, keySelector) {
2921     return function (source) { return source.lift(new DistinctUntilChangedOperator(compare, keySelector)); };
2922 }
2923 var DistinctUntilChangedOperator = /*@__PURE__*/ (function () {
2924     function DistinctUntilChangedOperator(compare, keySelector) {
2925         this.compare = compare;
2926         this.keySelector = keySelector;
2927     }
2928     DistinctUntilChangedOperator.prototype.call = function (subscriber, source) {
2929         return source.subscribe(new DistinctUntilChangedSubscriber(subscriber, this.compare, this.keySelector));
2930     };
2931     return DistinctUntilChangedOperator;
2932 }());
2933 var DistinctUntilChangedSubscriber = /*@__PURE__*/ (function (_super) {
2934     __extends(DistinctUntilChangedSubscriber, _super);
2935     function DistinctUntilChangedSubscriber(destination, compare, keySelector) {
2936         var _this = _super.call(this, destination) || this;
2937         _this.keySelector = keySelector;
2938         _this.hasKey = false;
2939         if (typeof compare === 'function') {
2940             _this.compare = compare;
2941         }
2942         return _this;
2943     }
2944     DistinctUntilChangedSubscriber.prototype.compare = function (x, y) {
2945         return x === y;
2946     };
2947     DistinctUntilChangedSubscriber.prototype._next = function (value) {
2948         var key;
2949         try {
2950             var keySelector = this.keySelector;
2951             key = keySelector ? keySelector(value) : value;
2952         }
2953         catch (err) {
2954             return this.destination.error(err);
2955         }
2956         var result = false;
2957         if (this.hasKey) {
2958             try {
2959                 var compare = this.compare;
2960                 result = compare(this.key, key);
2961             }
2962             catch (err) {
2963                 return this.destination.error(err);
2964             }
2965         }
2966         else {
2967             this.hasKey = true;
2968         }
2969         if (!result) {
2970             this.key = key;
2971             this.destination.next(value);
2972         }
2973     };
2974     return DistinctUntilChangedSubscriber;
2975 }(Subscriber));
2976
2977 /** PURE_IMPORTS_START tslib,_util_EmptyError,_Subscriber PURE_IMPORTS_END */
2978 function throwIfEmpty(errorFactory) {
2979     if (errorFactory === void 0) {
2980         errorFactory = defaultErrorFactory;
2981     }
2982     return function (source) {
2983         return source.lift(new ThrowIfEmptyOperator(errorFactory));
2984     };
2985 }
2986 var ThrowIfEmptyOperator = /*@__PURE__*/ (function () {
2987     function ThrowIfEmptyOperator(errorFactory) {
2988         this.errorFactory = errorFactory;
2989     }
2990     ThrowIfEmptyOperator.prototype.call = function (subscriber, source) {
2991         return source.subscribe(new ThrowIfEmptySubscriber(subscriber, this.errorFactory));
2992     };
2993     return ThrowIfEmptyOperator;
2994 }());
2995 var ThrowIfEmptySubscriber = /*@__PURE__*/ (function (_super) {
2996     __extends(ThrowIfEmptySubscriber, _super);
2997     function ThrowIfEmptySubscriber(destination, errorFactory) {
2998         var _this = _super.call(this, destination) || this;
2999         _this.errorFactory = errorFactory;
3000         _this.hasValue = false;
3001         return _this;
3002     }
3003     ThrowIfEmptySubscriber.prototype._next = function (value) {
3004         this.hasValue = true;
3005         this.destination.next(value);
3006     };
3007     ThrowIfEmptySubscriber.prototype._complete = function () {
3008         if (!this.hasValue) {
3009             var err = void 0;
3010             try {
3011                 err = this.errorFactory();
3012             }
3013             catch (e) {
3014                 err = e;
3015             }
3016             this.destination.error(err);
3017         }
3018         else {
3019             return this.destination.complete();
3020         }
3021     };
3022     return ThrowIfEmptySubscriber;
3023 }(Subscriber));
3024 function defaultErrorFactory() {
3025     return new EmptyError();
3026 }
3027
3028 /** PURE_IMPORTS_START tslib,_Subscriber,_util_ArgumentOutOfRangeError,_observable_empty PURE_IMPORTS_END */
3029 function take(count) {
3030     return function (source) {
3031         if (count === 0) {
3032             return empty();
3033         }
3034         else {
3035             return source.lift(new TakeOperator(count));
3036         }
3037     };
3038 }
3039 var TakeOperator = /*@__PURE__*/ (function () {
3040     function TakeOperator(total) {
3041         this.total = total;
3042         if (this.total < 0) {
3043             throw new ArgumentOutOfRangeError;
3044         }
3045     }
3046     TakeOperator.prototype.call = function (subscriber, source) {
3047         return source.subscribe(new TakeSubscriber(subscriber, this.total));
3048     };
3049     return TakeOperator;
3050 }());
3051 var TakeSubscriber = /*@__PURE__*/ (function (_super) {
3052     __extends(TakeSubscriber, _super);
3053     function TakeSubscriber(destination, total) {
3054         var _this = _super.call(this, destination) || this;
3055         _this.total = total;
3056         _this.count = 0;
3057         return _this;
3058     }
3059     TakeSubscriber.prototype._next = function (value) {
3060         var total = this.total;
3061         var count = ++this.count;
3062         if (count <= total) {
3063             this.destination.next(value);
3064             if (count === total) {
3065                 this.destination.complete();
3066                 this.unsubscribe();
3067             }
3068         }
3069     };
3070     return TakeSubscriber;
3071 }(Subscriber));
3072
3073 /** PURE_IMPORTS_START tslib,_innerSubscribe PURE_IMPORTS_END */
3074 function expand(project, concurrent, scheduler) {
3075     if (concurrent === void 0) {
3076         concurrent = Number.POSITIVE_INFINITY;
3077     }
3078     concurrent = (concurrent || 0) < 1 ? Number.POSITIVE_INFINITY : concurrent;
3079     return function (source) { return source.lift(new ExpandOperator(project, concurrent, scheduler)); };
3080 }
3081 var ExpandOperator = /*@__PURE__*/ (function () {
3082     function ExpandOperator(project, concurrent, scheduler) {
3083         this.project = project;
3084         this.concurrent = concurrent;
3085         this.scheduler = scheduler;
3086     }
3087     ExpandOperator.prototype.call = function (subscriber, source) {
3088         return source.subscribe(new ExpandSubscriber(subscriber, this.project, this.concurrent, this.scheduler));
3089     };
3090     return ExpandOperator;
3091 }());
3092 var ExpandSubscriber = /*@__PURE__*/ (function (_super) {
3093     __extends(ExpandSubscriber, _super);
3094     function ExpandSubscriber(destination, project, concurrent, scheduler) {
3095         var _this = _super.call(this, destination) || this;
3096         _this.project = project;
3097         _this.concurrent = concurrent;
3098         _this.scheduler = scheduler;
3099         _this.index = 0;
3100         _this.active = 0;
3101         _this.hasCompleted = false;
3102         if (concurrent < Number.POSITIVE_INFINITY) {
3103             _this.buffer = [];
3104         }
3105         return _this;
3106     }
3107     ExpandSubscriber.dispatch = function (arg) {
3108         var subscriber = arg.subscriber, result = arg.result, value = arg.value, index = arg.index;
3109         subscriber.subscribeToProjection(result, value, index);
3110     };
3111     ExpandSubscriber.prototype._next = function (value) {
3112         var destination = this.destination;
3113         if (destination.closed) {
3114             this._complete();
3115             return;
3116         }
3117         var index = this.index++;
3118         if (this.active < this.concurrent) {
3119             destination.next(value);
3120             try {
3121                 var project = this.project;
3122                 var result = project(value, index);
3123                 if (!this.scheduler) {
3124                     this.subscribeToProjection(result, value, index);
3125                 }
3126                 else {
3127                     var state = { subscriber: this, result: result, value: value, index: index };
3128                     var destination_1 = this.destination;
3129                     destination_1.add(this.scheduler.schedule(ExpandSubscriber.dispatch, 0, state));
3130                 }
3131             }
3132             catch (e) {
3133                 destination.error(e);
3134             }
3135         }
3136         else {
3137             this.buffer.push(value);
3138         }
3139     };
3140     ExpandSubscriber.prototype.subscribeToProjection = function (result, value, index) {
3141         this.active++;
3142         var destination = this.destination;
3143         destination.add(innerSubscribe(result, new SimpleInnerSubscriber(this)));
3144     };
3145     ExpandSubscriber.prototype._complete = function () {
3146         this.hasCompleted = true;
3147         if (this.hasCompleted && this.active === 0) {
3148             this.destination.complete();
3149         }
3150         this.unsubscribe();
3151     };
3152     ExpandSubscriber.prototype.notifyNext = function (innerValue) {
3153         this._next(innerValue);
3154     };
3155     ExpandSubscriber.prototype.notifyComplete = function () {
3156         var buffer = this.buffer;
3157         this.active--;
3158         if (buffer && buffer.length > 0) {
3159             this._next(buffer.shift());
3160         }
3161         if (this.hasCompleted && this.active === 0) {
3162             this.destination.complete();
3163         }
3164     };
3165     return ExpandSubscriber;
3166 }(SimpleOuterSubscriber));
3167
3168 /** PURE_IMPORTS_START tslib,_Subscriber,_Subscription PURE_IMPORTS_END */
3169 function finalize(callback) {
3170     return function (source) { return source.lift(new FinallyOperator(callback)); };
3171 }
3172 var FinallyOperator = /*@__PURE__*/ (function () {
3173     function FinallyOperator(callback) {
3174         this.callback = callback;
3175     }
3176     FinallyOperator.prototype.call = function (subscriber, source) {
3177         return source.subscribe(new FinallySubscriber(subscriber, this.callback));
3178     };
3179     return FinallyOperator;
3180 }());
3181 var FinallySubscriber = /*@__PURE__*/ (function (_super) {
3182     __extends(FinallySubscriber, _super);
3183     function FinallySubscriber(destination, callback) {
3184         var _this = _super.call(this, destination) || this;
3185         _this.add(new Subscription(callback));
3186         return _this;
3187     }
3188     return FinallySubscriber;
3189 }(Subscriber));
3190
3191 /** PURE_IMPORTS_START _util_EmptyError,_filter,_take,_defaultIfEmpty,_throwIfEmpty,_util_identity PURE_IMPORTS_END */
3192 function first(predicate, defaultValue) {
3193     var hasDefaultValue = arguments.length >= 2;
3194     return function (source) { return source.pipe(predicate ? filter(function (v, i) { return predicate(v, i, source); }) : identity, take(1), hasDefaultValue ? defaultIfEmpty(defaultValue) : throwIfEmpty(function () { return new EmptyError(); })); };
3195 }
3196
3197 /** PURE_IMPORTS_START tslib,_Subscriber,_util_ArgumentOutOfRangeError,_observable_empty PURE_IMPORTS_END */
3198 function takeLast(count) {
3199     return function takeLastOperatorFunction(source) {
3200         if (count === 0) {
3201             return empty();
3202         }
3203         else {
3204             return source.lift(new TakeLastOperator(count));
3205         }
3206     };
3207 }
3208 var TakeLastOperator = /*@__PURE__*/ (function () {
3209     function TakeLastOperator(total) {
3210         this.total = total;
3211         if (this.total < 0) {
3212             throw new ArgumentOutOfRangeError;
3213         }
3214     }
3215     TakeLastOperator.prototype.call = function (subscriber, source) {
3216         return source.subscribe(new TakeLastSubscriber(subscriber, this.total));
3217     };
3218     return TakeLastOperator;
3219 }());
3220 var TakeLastSubscriber = /*@__PURE__*/ (function (_super) {
3221     __extends(TakeLastSubscriber, _super);
3222     function TakeLastSubscriber(destination, total) {
3223         var _this = _super.call(this, destination) || this;
3224         _this.total = total;
3225         _this.ring = new Array();
3226         _this.count = 0;
3227         return _this;
3228     }
3229     TakeLastSubscriber.prototype._next = function (value) {
3230         var ring = this.ring;
3231         var total = this.total;
3232         var count = this.count++;
3233         if (ring.length < total) {
3234             ring.push(value);
3235         }
3236         else {
3237             var index = count % total;
3238             ring[index] = value;
3239         }
3240     };
3241     TakeLastSubscriber.prototype._complete = function () {
3242         var destination = this.destination;
3243         var count = this.count;
3244         if (count > 0) {
3245             var total = this.count >= this.total ? this.total : this.count;
3246             var ring = this.ring;
3247             for (var i = 0; i < total; i++) {
3248                 var idx = (count++) % total;
3249                 destination.next(ring[idx]);
3250             }
3251         }
3252         destination.complete();
3253     };
3254     return TakeLastSubscriber;
3255 }(Subscriber));
3256
3257 /** PURE_IMPORTS_START _util_EmptyError,_filter,_takeLast,_throwIfEmpty,_defaultIfEmpty,_util_identity PURE_IMPORTS_END */
3258 function last(predicate, defaultValue) {
3259     var hasDefaultValue = arguments.length >= 2;
3260     return function (source) { return source.pipe(predicate ? filter(function (v, i) { return predicate(v, i, source); }) : identity, takeLast(1), hasDefaultValue ? defaultIfEmpty(defaultValue) : throwIfEmpty(function () { return new EmptyError(); })); };
3261 }
3262
3263 /** PURE_IMPORTS_START tslib,_Subscriber PURE_IMPORTS_END */
3264 function scan(accumulator, seed) {
3265     var hasSeed = false;
3266     if (arguments.length >= 2) {
3267         hasSeed = true;
3268     }
3269     return function scanOperatorFunction(source) {
3270         return source.lift(new ScanOperator(accumulator, seed, hasSeed));
3271     };
3272 }
3273 var ScanOperator = /*@__PURE__*/ (function () {
3274     function ScanOperator(accumulator, seed, hasSeed) {
3275         if (hasSeed === void 0) {
3276             hasSeed = false;
3277         }
3278         this.accumulator = accumulator;
3279         this.seed = seed;
3280         this.hasSeed = hasSeed;
3281     }
3282     ScanOperator.prototype.call = function (subscriber, source) {
3283         return source.subscribe(new ScanSubscriber(subscriber, this.accumulator, this.seed, this.hasSeed));
3284     };
3285     return ScanOperator;
3286 }());
3287 var ScanSubscriber = /*@__PURE__*/ (function (_super) {
3288     __extends(ScanSubscriber, _super);
3289     function ScanSubscriber(destination, accumulator, _seed, hasSeed) {
3290         var _this = _super.call(this, destination) || this;
3291         _this.accumulator = accumulator;
3292         _this._seed = _seed;
3293         _this.hasSeed = hasSeed;
3294         _this.index = 0;
3295         return _this;
3296     }
3297     Object.defineProperty(ScanSubscriber.prototype, "seed", {
3298         get: function () {
3299             return this._seed;
3300         },
3301         set: function (value) {
3302             this.hasSeed = true;
3303             this._seed = value;
3304         },
3305         enumerable: true,
3306         configurable: true
3307     });
3308     ScanSubscriber.prototype._next = function (value) {
3309         if (!this.hasSeed) {
3310             this.seed = value;
3311             this.destination.next(value);
3312         }
3313         else {
3314             return this._tryNext(value);
3315         }
3316     };
3317     ScanSubscriber.prototype._tryNext = function (value) {
3318         var index = this.index++;
3319         var result;
3320         try {
3321             result = this.accumulator(this.seed, value, index);
3322         }
3323         catch (err) {
3324             this.destination.error(err);
3325         }
3326         this.seed = result;
3327         this.destination.next(result);
3328     };
3329     return ScanSubscriber;
3330 }(Subscriber));
3331
3332 /** PURE_IMPORTS_START _scan,_takeLast,_defaultIfEmpty,_util_pipe PURE_IMPORTS_END */
3333 function reduce(accumulator, seed) {
3334     if (arguments.length >= 2) {
3335         return function reduceOperatorFunctionWithSeed(source) {
3336             return pipe(scan(accumulator, seed), takeLast(1), defaultIfEmpty(seed))(source);
3337         };
3338     }
3339     return function reduceOperatorFunction(source) {
3340         return pipe(scan(function (acc, value, index) { return accumulator(acc, value, index + 1); }), takeLast(1))(source);
3341     };
3342 }
3343
3344 /** PURE_IMPORTS_START _observable_ConnectableObservable PURE_IMPORTS_END */
3345 function multicast(subjectOrSubjectFactory, selector) {
3346     return function multicastOperatorFunction(source) {
3347         var subjectFactory;
3348         if (typeof subjectOrSubjectFactory === 'function') {
3349             subjectFactory = subjectOrSubjectFactory;
3350         }
3351         else {
3352             subjectFactory = function subjectFactory() {
3353                 return subjectOrSubjectFactory;
3354             };
3355         }
3356         if (typeof selector === 'function') {
3357             return source.lift(new MulticastOperator(subjectFactory, selector));
3358         }
3359         var connectable = Object.create(source, connectableObservableDescriptor);
3360         connectable.source = source;
3361         connectable.subjectFactory = subjectFactory;
3362         return connectable;
3363     };
3364 }
3365 var MulticastOperator = /*@__PURE__*/ (function () {
3366     function MulticastOperator(subjectFactory, selector) {
3367         this.subjectFactory = subjectFactory;
3368         this.selector = selector;
3369     }
3370     MulticastOperator.prototype.call = function (subscriber, source) {
3371         var selector = this.selector;
3372         var subject = this.subjectFactory();
3373         var subscription = selector(subject).subscribe(subscriber);
3374         subscription.add(source.subscribe(subject));
3375         return subscription;
3376     };
3377     return MulticastOperator;
3378 }());
3379
3380 /** PURE_IMPORTS_START tslib,_Subscriber PURE_IMPORTS_END */
3381 function pairwise() {
3382     return function (source) { return source.lift(new PairwiseOperator()); };
3383 }
3384 var PairwiseOperator = /*@__PURE__*/ (function () {
3385     function PairwiseOperator() {
3386     }
3387     PairwiseOperator.prototype.call = function (subscriber, source) {
3388         return source.subscribe(new PairwiseSubscriber(subscriber));
3389     };
3390     return PairwiseOperator;
3391 }());
3392 var PairwiseSubscriber = /*@__PURE__*/ (function (_super) {
3393     __extends(PairwiseSubscriber, _super);
3394     function PairwiseSubscriber(destination) {
3395         var _this = _super.call(this, destination) || this;
3396         _this.hasPrev = false;
3397         return _this;
3398     }
3399     PairwiseSubscriber.prototype._next = function (value) {
3400         var pair;
3401         if (this.hasPrev) {
3402             pair = [this.prev, value];
3403         }
3404         else {
3405             this.hasPrev = true;
3406         }
3407         this.prev = value;
3408         if (pair) {
3409             this.destination.next(pair);
3410         }
3411     };
3412     return PairwiseSubscriber;
3413 }(Subscriber));
3414
3415 /** PURE_IMPORTS_START _map PURE_IMPORTS_END */
3416 function pluck() {
3417     var properties = [];
3418     for (var _i = 0; _i < arguments.length; _i++) {
3419         properties[_i] = arguments[_i];
3420     }
3421     var length = properties.length;
3422     if (length === 0) {
3423         throw new Error('list of properties cannot be empty.');
3424     }
3425     return function (source) { return map(plucker(properties, length))(source); };
3426 }
3427 function plucker(props, length) {
3428     var mapper = function (x) {
3429         var currentProp = x;
3430         for (var i = 0; i < length; i++) {
3431             var p = currentProp != null ? currentProp[props[i]] : undefined;
3432             if (p !== void 0) {
3433                 currentProp = p;
3434             }
3435             else {
3436                 return undefined;
3437             }
3438         }
3439         return currentProp;
3440     };
3441     return mapper;
3442 }
3443
3444 /** PURE_IMPORTS_START _Subject,_multicast PURE_IMPORTS_END */
3445 function publish(selector) {
3446     return selector ?
3447         multicast(function () { return new Subject(); }, selector) :
3448         multicast(new Subject());
3449 }
3450
3451 /** PURE_IMPORTS_START _ReplaySubject,_multicast PURE_IMPORTS_END */
3452 function publishReplay(bufferSize, windowTime, selectorOrScheduler, scheduler) {
3453     if (selectorOrScheduler && typeof selectorOrScheduler !== 'function') {
3454         scheduler = selectorOrScheduler;
3455     }
3456     var selector = typeof selectorOrScheduler === 'function' ? selectorOrScheduler : undefined;
3457     var subject = new ReplaySubject(bufferSize, windowTime, scheduler);
3458     return function (source) { return multicast(function () { return subject; }, selector)(source); };
3459 }
3460
3461 /** PURE_IMPORTS_START tslib,_Subscriber PURE_IMPORTS_END */
3462 function retry(count) {
3463     if (count === void 0) {
3464         count = -1;
3465     }
3466     return function (source) { return source.lift(new RetryOperator(count, source)); };
3467 }
3468 var RetryOperator = /*@__PURE__*/ (function () {
3469     function RetryOperator(count, source) {
3470         this.count = count;
3471         this.source = source;
3472     }
3473     RetryOperator.prototype.call = function (subscriber, source) {
3474         return source.subscribe(new RetrySubscriber(subscriber, this.count, this.source));
3475     };
3476     return RetryOperator;
3477 }());
3478 var RetrySubscriber = /*@__PURE__*/ (function (_super) {
3479     __extends(RetrySubscriber, _super);
3480     function RetrySubscriber(destination, count, source) {
3481         var _this = _super.call(this, destination) || this;
3482         _this.count = count;
3483         _this.source = source;
3484         return _this;
3485     }
3486     RetrySubscriber.prototype.error = function (err) {
3487         if (!this.isStopped) {
3488             var _a = this, source = _a.source, count = _a.count;
3489             if (count === 0) {
3490                 return _super.prototype.error.call(this, err);
3491             }
3492             else if (count > -1) {
3493                 this.count = count - 1;
3494             }
3495             source.subscribe(this._unsubscribeAndRecycle());
3496         }
3497     };
3498     return RetrySubscriber;
3499 }(Subscriber));
3500
3501 /** PURE_IMPORTS_START tslib,_innerSubscribe PURE_IMPORTS_END */
3502 function sample(notifier) {
3503     return function (source) { return source.lift(new SampleOperator(notifier)); };
3504 }
3505 var SampleOperator = /*@__PURE__*/ (function () {
3506     function SampleOperator(notifier) {
3507         this.notifier = notifier;
3508     }
3509     SampleOperator.prototype.call = function (subscriber, source) {
3510         var sampleSubscriber = new SampleSubscriber(subscriber);
3511         var subscription = source.subscribe(sampleSubscriber);
3512         subscription.add(innerSubscribe(this.notifier, new SimpleInnerSubscriber(sampleSubscriber)));
3513         return subscription;
3514     };
3515     return SampleOperator;
3516 }());
3517 var SampleSubscriber = /*@__PURE__*/ (function (_super) {
3518     __extends(SampleSubscriber, _super);
3519     function SampleSubscriber() {
3520         var _this = _super !== null && _super.apply(this, arguments) || this;
3521         _this.hasValue = false;
3522         return _this;
3523     }
3524     SampleSubscriber.prototype._next = function (value) {
3525         this.value = value;
3526         this.hasValue = true;
3527     };
3528     SampleSubscriber.prototype.notifyNext = function () {
3529         this.emitValue();
3530     };
3531     SampleSubscriber.prototype.notifyComplete = function () {
3532         this.emitValue();
3533     };
3534     SampleSubscriber.prototype.emitValue = function () {
3535         if (this.hasValue) {
3536             this.hasValue = false;
3537             this.destination.next(this.value);
3538         }
3539     };
3540     return SampleSubscriber;
3541 }(SimpleOuterSubscriber));
3542
3543 /** PURE_IMPORTS_START _multicast,_refCount,_Subject PURE_IMPORTS_END */
3544 function shareSubjectFactory() {
3545     return new Subject();
3546 }
3547 function share() {
3548     return function (source) { return refCount()(multicast(shareSubjectFactory)(source)); };
3549 }
3550
3551 /** PURE_IMPORTS_START tslib,_Subscriber PURE_IMPORTS_END */
3552 function skip(count) {
3553     return function (source) { return source.lift(new SkipOperator(count)); };
3554 }
3555 var SkipOperator = /*@__PURE__*/ (function () {
3556     function SkipOperator(total) {
3557         this.total = total;
3558     }
3559     SkipOperator.prototype.call = function (subscriber, source) {
3560         return source.subscribe(new SkipSubscriber(subscriber, this.total));
3561     };
3562     return SkipOperator;
3563 }());
3564 var SkipSubscriber = /*@__PURE__*/ (function (_super) {
3565     __extends(SkipSubscriber, _super);
3566     function SkipSubscriber(destination, total) {
3567         var _this = _super.call(this, destination) || this;
3568         _this.total = total;
3569         _this.count = 0;
3570         return _this;
3571     }
3572     SkipSubscriber.prototype._next = function (x) {
3573         if (++this.count > this.total) {
3574             this.destination.next(x);
3575         }
3576     };
3577     return SkipSubscriber;
3578 }(Subscriber));
3579
3580 /** PURE_IMPORTS_START tslib,_Subscriber PURE_IMPORTS_END */
3581 function skipWhile(predicate) {
3582     return function (source) { return source.lift(new SkipWhileOperator(predicate)); };
3583 }
3584 var SkipWhileOperator = /*@__PURE__*/ (function () {
3585     function SkipWhileOperator(predicate) {
3586         this.predicate = predicate;
3587     }
3588     SkipWhileOperator.prototype.call = function (subscriber, source) {
3589         return source.subscribe(new SkipWhileSubscriber(subscriber, this.predicate));
3590     };
3591     return SkipWhileOperator;
3592 }());
3593 var SkipWhileSubscriber = /*@__PURE__*/ (function (_super) {
3594     __extends(SkipWhileSubscriber, _super);
3595     function SkipWhileSubscriber(destination, predicate) {
3596         var _this = _super.call(this, destination) || this;
3597         _this.predicate = predicate;
3598         _this.skipping = true;
3599         _this.index = 0;
3600         return _this;
3601     }
3602     SkipWhileSubscriber.prototype._next = function (value) {
3603         var destination = this.destination;
3604         if (this.skipping) {
3605             this.tryCallPredicate(value);
3606         }
3607         if (!this.skipping) {
3608             destination.next(value);
3609         }
3610     };
3611     SkipWhileSubscriber.prototype.tryCallPredicate = function (value) {
3612         try {
3613             var result = this.predicate(value, this.index++);
3614             this.skipping = Boolean(result);
3615         }
3616         catch (err) {
3617             this.destination.error(err);
3618         }
3619     };
3620     return SkipWhileSubscriber;
3621 }(Subscriber));
3622
3623 /** PURE_IMPORTS_START _observable_concat,_util_isScheduler PURE_IMPORTS_END */
3624 function startWith() {
3625     var array = [];
3626     for (var _i = 0; _i < arguments.length; _i++) {
3627         array[_i] = arguments[_i];
3628     }
3629     var scheduler = array[array.length - 1];
3630     if (isScheduler(scheduler)) {
3631         array.pop();
3632         return function (source) { return concat(array, source, scheduler); };
3633     }
3634     else {
3635         return function (source) { return concat(array, source); };
3636     }
3637 }
3638
3639 /** PURE_IMPORTS_START tslib,_map,_observable_from,_innerSubscribe PURE_IMPORTS_END */
3640 function switchMap(project, resultSelector) {
3641     if (typeof resultSelector === 'function') {
3642         return function (source) { return source.pipe(switchMap(function (a, i) { return from(project(a, i)).pipe(map(function (b, ii) { return resultSelector(a, b, i, ii); })); })); };
3643     }
3644     return function (source) { return source.lift(new SwitchMapOperator(project)); };
3645 }
3646 var SwitchMapOperator = /*@__PURE__*/ (function () {
3647     function SwitchMapOperator(project) {
3648         this.project = project;
3649     }
3650     SwitchMapOperator.prototype.call = function (subscriber, source) {
3651         return source.subscribe(new SwitchMapSubscriber(subscriber, this.project));
3652     };
3653     return SwitchMapOperator;
3654 }());
3655 var SwitchMapSubscriber = /*@__PURE__*/ (function (_super) {
3656     __extends(SwitchMapSubscriber, _super);
3657     function SwitchMapSubscriber(destination, project) {
3658         var _this = _super.call(this, destination) || this;
3659         _this.project = project;
3660         _this.index = 0;
3661         return _this;
3662     }
3663     SwitchMapSubscriber.prototype._next = function (value) {
3664         var result;
3665         var index = this.index++;
3666         try {
3667             result = this.project(value, index);
3668         }
3669         catch (error) {
3670             this.destination.error(error);
3671             return;
3672         }
3673         this._innerSub(result);
3674     };
3675     SwitchMapSubscriber.prototype._innerSub = function (result) {
3676         var innerSubscription = this.innerSubscription;
3677         if (innerSubscription) {
3678             innerSubscription.unsubscribe();
3679         }
3680         var innerSubscriber = new SimpleInnerSubscriber(this);
3681         var destination = this.destination;
3682         destination.add(innerSubscriber);
3683         this.innerSubscription = innerSubscribe(result, innerSubscriber);
3684         if (this.innerSubscription !== innerSubscriber) {
3685             destination.add(this.innerSubscription);
3686         }
3687     };
3688     SwitchMapSubscriber.prototype._complete = function () {
3689         var innerSubscription = this.innerSubscription;
3690         if (!innerSubscription || innerSubscription.closed) {
3691             _super.prototype._complete.call(this);
3692         }
3693         this.unsubscribe();
3694     };
3695     SwitchMapSubscriber.prototype._unsubscribe = function () {
3696         this.innerSubscription = undefined;
3697     };
3698     SwitchMapSubscriber.prototype.notifyComplete = function () {
3699         this.innerSubscription = undefined;
3700         if (this.isStopped) {
3701             _super.prototype._complete.call(this);
3702         }
3703     };
3704     SwitchMapSubscriber.prototype.notifyNext = function (innerValue) {
3705         this.destination.next(innerValue);
3706     };
3707     return SwitchMapSubscriber;
3708 }(SimpleOuterSubscriber));
3709
3710 /** PURE_IMPORTS_START tslib,_innerSubscribe PURE_IMPORTS_END */
3711 function takeUntil(notifier) {
3712     return function (source) { return source.lift(new TakeUntilOperator(notifier)); };
3713 }
3714 var TakeUntilOperator = /*@__PURE__*/ (function () {
3715     function TakeUntilOperator(notifier) {
3716         this.notifier = notifier;
3717     }
3718     TakeUntilOperator.prototype.call = function (subscriber, source) {
3719         var takeUntilSubscriber = new TakeUntilSubscriber(subscriber);
3720         var notifierSubscription = innerSubscribe(this.notifier, new SimpleInnerSubscriber(takeUntilSubscriber));
3721         if (notifierSubscription && !takeUntilSubscriber.seenValue) {
3722             takeUntilSubscriber.add(notifierSubscription);
3723             return source.subscribe(takeUntilSubscriber);
3724         }
3725         return takeUntilSubscriber;
3726     };
3727     return TakeUntilOperator;
3728 }());
3729 var TakeUntilSubscriber = /*@__PURE__*/ (function (_super) {
3730     __extends(TakeUntilSubscriber, _super);
3731     function TakeUntilSubscriber(destination) {
3732         var _this = _super.call(this, destination) || this;
3733         _this.seenValue = false;
3734         return _this;
3735     }
3736     TakeUntilSubscriber.prototype.notifyNext = function () {
3737         this.seenValue = true;
3738         this.complete();
3739     };
3740     TakeUntilSubscriber.prototype.notifyComplete = function () {
3741     };
3742     return TakeUntilSubscriber;
3743 }(SimpleOuterSubscriber));
3744
3745 /** PURE_IMPORTS_START tslib,_Subscriber PURE_IMPORTS_END */
3746 function takeWhile(predicate, inclusive) {
3747     if (inclusive === void 0) {
3748         inclusive = false;
3749     }
3750     return function (source) {
3751         return source.lift(new TakeWhileOperator(predicate, inclusive));
3752     };
3753 }
3754 var TakeWhileOperator = /*@__PURE__*/ (function () {
3755     function TakeWhileOperator(predicate, inclusive) {
3756         this.predicate = predicate;
3757         this.inclusive = inclusive;
3758     }
3759     TakeWhileOperator.prototype.call = function (subscriber, source) {
3760         return source.subscribe(new TakeWhileSubscriber(subscriber, this.predicate, this.inclusive));
3761     };
3762     return TakeWhileOperator;
3763 }());
3764 var TakeWhileSubscriber = /*@__PURE__*/ (function (_super) {
3765     __extends(TakeWhileSubscriber, _super);
3766     function TakeWhileSubscriber(destination, predicate, inclusive) {
3767         var _this = _super.call(this, destination) || this;
3768         _this.predicate = predicate;
3769         _this.inclusive = inclusive;
3770         _this.index = 0;
3771         return _this;
3772     }
3773     TakeWhileSubscriber.prototype._next = function (value) {
3774         var destination = this.destination;
3775         var result;
3776         try {
3777             result = this.predicate(value, this.index++);
3778         }
3779         catch (err) {
3780             destination.error(err);
3781             return;
3782         }
3783         this.nextOrComplete(value, result);
3784     };
3785     TakeWhileSubscriber.prototype.nextOrComplete = function (value, predicateResult) {
3786         var destination = this.destination;
3787         if (Boolean(predicateResult)) {
3788             destination.next(value);
3789         }
3790         else {
3791             if (this.inclusive) {
3792                 destination.next(value);
3793             }
3794             destination.complete();
3795         }
3796     };
3797     return TakeWhileSubscriber;
3798 }(Subscriber));
3799
3800 /** PURE_IMPORTS_START tslib,_Subscriber,_util_noop,_util_isFunction PURE_IMPORTS_END */
3801 function tap(nextOrObserver, error, complete) {
3802     return function tapOperatorFunction(source) {
3803         return source.lift(new DoOperator(nextOrObserver, error, complete));
3804     };
3805 }
3806 var DoOperator = /*@__PURE__*/ (function () {
3807     function DoOperator(nextOrObserver, error, complete) {
3808         this.nextOrObserver = nextOrObserver;
3809         this.error = error;
3810         this.complete = complete;
3811     }
3812     DoOperator.prototype.call = function (subscriber, source) {
3813         return source.subscribe(new TapSubscriber(subscriber, this.nextOrObserver, this.error, this.complete));
3814     };
3815     return DoOperator;
3816 }());
3817 var TapSubscriber = /*@__PURE__*/ (function (_super) {
3818     __extends(TapSubscriber, _super);
3819     function TapSubscriber(destination, observerOrNext, error, complete) {
3820         var _this = _super.call(this, destination) || this;
3821         _this._tapNext = noop;
3822         _this._tapError = noop;
3823         _this._tapComplete = noop;
3824         _this._tapError = error || noop;
3825         _this._tapComplete = complete || noop;
3826         if (isFunction(observerOrNext)) {
3827             _this._context = _this;
3828             _this._tapNext = observerOrNext;
3829         }
3830         else if (observerOrNext) {
3831             _this._context = observerOrNext;
3832             _this._tapNext = observerOrNext.next || noop;
3833             _this._tapError = observerOrNext.error || noop;
3834             _this._tapComplete = observerOrNext.complete || noop;
3835         }
3836         return _this;
3837     }
3838     TapSubscriber.prototype._next = function (value) {
3839         try {
3840             this._tapNext.call(this._context, value);
3841         }
3842         catch (err) {
3843             this.destination.error(err);
3844             return;
3845         }
3846         this.destination.next(value);
3847     };
3848     TapSubscriber.prototype._error = function (err) {
3849         try {
3850             this._tapError.call(this._context, err);
3851         }
3852         catch (err) {
3853             this.destination.error(err);
3854             return;
3855         }
3856         this.destination.error(err);
3857     };
3858     TapSubscriber.prototype._complete = function () {
3859         try {
3860             this._tapComplete.call(this._context);
3861         }
3862         catch (err) {
3863             this.destination.error(err);
3864             return;
3865         }
3866         return this.destination.complete();
3867     };
3868     return TapSubscriber;
3869 }(Subscriber));
3870
3871 /** PURE_IMPORTS_START tslib,_scheduler_async,_util_isDate,_innerSubscribe PURE_IMPORTS_END */
3872 function timeoutWith(due, withObservable, scheduler) {
3873     if (scheduler === void 0) {
3874         scheduler = async;
3875     }
3876     return function (source) {
3877         var absoluteTimeout = isDate(due);
3878         var waitFor = absoluteTimeout ? (+due - scheduler.now()) : Math.abs(due);
3879         return source.lift(new TimeoutWithOperator(waitFor, absoluteTimeout, withObservable, scheduler));
3880     };
3881 }
3882 var TimeoutWithOperator = /*@__PURE__*/ (function () {
3883     function TimeoutWithOperator(waitFor, absoluteTimeout, withObservable, scheduler) {
3884         this.waitFor = waitFor;
3885         this.absoluteTimeout = absoluteTimeout;
3886         this.withObservable = withObservable;
3887         this.scheduler = scheduler;
3888     }
3889     TimeoutWithOperator.prototype.call = function (subscriber, source) {
3890         return source.subscribe(new TimeoutWithSubscriber(subscriber, this.absoluteTimeout, this.waitFor, this.withObservable, this.scheduler));
3891     };
3892     return TimeoutWithOperator;
3893 }());
3894 var TimeoutWithSubscriber = /*@__PURE__*/ (function (_super) {
3895     __extends(TimeoutWithSubscriber, _super);
3896     function TimeoutWithSubscriber(destination, absoluteTimeout, waitFor, withObservable, scheduler) {
3897         var _this = _super.call(this, destination) || this;
3898         _this.absoluteTimeout = absoluteTimeout;
3899         _this.waitFor = waitFor;
3900         _this.withObservable = withObservable;
3901         _this.scheduler = scheduler;
3902         _this.scheduleTimeout();
3903         return _this;
3904     }
3905     TimeoutWithSubscriber.dispatchTimeout = function (subscriber) {
3906         var withObservable = subscriber.withObservable;
3907         subscriber._unsubscribeAndRecycle();
3908         subscriber.add(innerSubscribe(withObservable, new SimpleInnerSubscriber(subscriber)));
3909     };
3910     TimeoutWithSubscriber.prototype.scheduleTimeout = function () {
3911         var action = this.action;
3912         if (action) {
3913             this.action = action.schedule(this, this.waitFor);
3914         }
3915         else {
3916             this.add(this.action = this.scheduler.schedule(TimeoutWithSubscriber.dispatchTimeout, this.waitFor, this));
3917         }
3918     };
3919     TimeoutWithSubscriber.prototype._next = function (value) {
3920         if (!this.absoluteTimeout) {
3921             this.scheduleTimeout();
3922         }
3923         _super.prototype._next.call(this, value);
3924     };
3925     TimeoutWithSubscriber.prototype._unsubscribe = function () {
3926         this.action = undefined;
3927         this.scheduler = null;
3928         this.withObservable = null;
3929     };
3930     return TimeoutWithSubscriber;
3931 }(SimpleOuterSubscriber));
3932
3933 /** PURE_IMPORTS_START _scheduler_async,_util_TimeoutError,_timeoutWith,_observable_throwError PURE_IMPORTS_END */
3934 function timeout(due, scheduler) {
3935     if (scheduler === void 0) {
3936         scheduler = async;
3937     }
3938     return timeoutWith(due, throwError(new TimeoutError()), scheduler);
3939 }
3940
3941 /** PURE_IMPORTS_START tslib,_OuterSubscriber,_util_subscribeToResult PURE_IMPORTS_END */
3942 function withLatestFrom() {
3943     var args = [];
3944     for (var _i = 0; _i < arguments.length; _i++) {
3945         args[_i] = arguments[_i];
3946     }
3947     return function (source) {
3948         var project;
3949         if (typeof args[args.length - 1] === 'function') {
3950             project = args.pop();
3951         }
3952         var observables = args;
3953         return source.lift(new WithLatestFromOperator(observables, project));
3954     };
3955 }
3956 var WithLatestFromOperator = /*@__PURE__*/ (function () {
3957     function WithLatestFromOperator(observables, project) {
3958         this.observables = observables;
3959         this.project = project;
3960     }
3961     WithLatestFromOperator.prototype.call = function (subscriber, source) {
3962         return source.subscribe(new WithLatestFromSubscriber(subscriber, this.observables, this.project));
3963     };
3964     return WithLatestFromOperator;
3965 }());
3966 var WithLatestFromSubscriber = /*@__PURE__*/ (function (_super) {
3967     __extends(WithLatestFromSubscriber, _super);
3968     function WithLatestFromSubscriber(destination, observables, project) {
3969         var _this = _super.call(this, destination) || this;
3970         _this.observables = observables;
3971         _this.project = project;
3972         _this.toRespond = [];
3973         var len = observables.length;
3974         _this.values = new Array(len);
3975         for (var i = 0; i < len; i++) {
3976             _this.toRespond.push(i);
3977         }
3978         for (var i = 0; i < len; i++) {
3979             var observable = observables[i];
3980             _this.add(subscribeToResult(_this, observable, undefined, i));
3981         }
3982         return _this;
3983     }
3984     WithLatestFromSubscriber.prototype.notifyNext = function (_outerValue, innerValue, outerIndex) {
3985         this.values[outerIndex] = innerValue;
3986         var toRespond = this.toRespond;
3987         if (toRespond.length > 0) {
3988             var found = toRespond.indexOf(outerIndex);
3989             if (found !== -1) {
3990                 toRespond.splice(found, 1);
3991             }
3992         }
3993     };
3994     WithLatestFromSubscriber.prototype.notifyComplete = function () {
3995     };
3996     WithLatestFromSubscriber.prototype._next = function (value) {
3997         if (this.toRespond.length === 0) {
3998             var args = [value].concat(this.values);
3999             if (this.project) {
4000                 this._tryProject(args);
4001             }
4002             else {
4003                 this.destination.next(args);
4004             }
4005         }
4006     };
4007     WithLatestFromSubscriber.prototype._tryProject = function (args) {
4008         var result;
4009         try {
4010             result = this.project.apply(this, args);
4011         }
4012         catch (err) {
4013             this.destination.error(err);
4014             return;
4015         }
4016         this.destination.next(result);
4017     };
4018     return WithLatestFromSubscriber;
4019 }(OuterSubscriber));
4020
4021 /**
4022  * @class Filter
4023  *
4024  * @classdesc Represents a class for creating image filters. Implementation and
4025  * definitions based on https://github.com/mapbox/feature-filter.
4026  */
4027 class FilterCreator {
4028     /**
4029      * Create a filter from a filter expression.
4030      *
4031      * @description The following filters are supported:
4032      *
4033      * Comparison
4034      * `==`
4035      * `!=`
4036      * `<`
4037      * `<=`
4038      * `>`
4039      * `>=`
4040      *
4041      * Set membership
4042      * `in`
4043      * `!in`
4044      *
4045      * Combining
4046      * `all`
4047      *
4048      * @param {FilterExpression} filter - Comparison, set membership or combinding filter
4049      * expression.
4050      * @returns {FilterFunction} Function taking a image and returning a boolean that
4051      * indicates whether the image passed the test or not.
4052      */
4053     createFilter(filter) {
4054         return new Function("node", "return " + this._compile(filter) + ";");
4055     }
4056     _compile(filter) {
4057         if (filter == null || filter.length <= 1) {
4058             return "true";
4059         }
4060         const operator = filter[0];
4061         const operation = operator === "==" ? this._compileComparisonOp("===", filter[1], filter[2], false) :
4062             operator === "!=" ? this._compileComparisonOp("!==", filter[1], filter[2], false) :
4063                 operator === ">" ||
4064                     operator === ">=" ||
4065                     operator === "<" ||
4066                     operator === "<=" ? this._compileComparisonOp(operator, filter[1], filter[2], true) :
4067                     operator === "in" ?
4068                         this._compileInOp(filter[1], filter.slice(2)) :
4069                         operator === "!in" ?
4070                             this._compileNegation(this._compileInOp(filter[1], filter.slice(2))) :
4071                             operator === "all" ? this._compileLogicalOp(filter.slice(1), "&&") :
4072                                 "true";
4073         return "(" + operation + ")";
4074     }
4075     _compare(a, b) {
4076         return a < b ? -1 : a > b ? 1 : 0;
4077     }
4078     _compileComparisonOp(operator, property, value, checkType) {
4079         const left = this._compilePropertyReference(property);
4080         const right = JSON.stringify(value);
4081         return (checkType ? "typeof " + left + "===typeof " + right + "&&" : "") + left + operator + right;
4082     }
4083     _compileInOp(property, values) {
4084         const compare = this._compare;
4085         const left = JSON.stringify(values.sort(compare));
4086         const right = this._compilePropertyReference(property);
4087         return left + ".indexOf(" + right + ")!==-1";
4088     }
4089     _compileLogicalOp(filters, operator) {
4090         const compile = this._compile.bind(this);
4091         return filters.map(compile).join(operator);
4092     }
4093     _compileNegation(expression) {
4094         return "!(" + expression + ")";
4095     }
4096     _compilePropertyReference(property) {
4097         return "node[" + JSON.stringify(property) + "]";
4098     }
4099 }
4100
4101 // threejs.org/license
4102 const REVISION = '125';
4103 const CullFaceNone = 0;
4104 const CullFaceBack = 1;
4105 const CullFaceFront = 2;
4106 const PCFShadowMap = 1;
4107 const PCFSoftShadowMap = 2;
4108 const VSMShadowMap = 3;
4109 const FrontSide = 0;
4110 const BackSide = 1;
4111 const DoubleSide = 2;
4112 const FlatShading = 1;
4113 const NoBlending = 0;
4114 const NormalBlending = 1;
4115 const AdditiveBlending = 2;
4116 const SubtractiveBlending = 3;
4117 const MultiplyBlending = 4;
4118 const CustomBlending = 5;
4119 const AddEquation = 100;
4120 const SubtractEquation = 101;
4121 const ReverseSubtractEquation = 102;
4122 const MinEquation = 103;
4123 const MaxEquation = 104;
4124 const ZeroFactor = 200;
4125 const OneFactor = 201;
4126 const SrcColorFactor = 202;
4127 const OneMinusSrcColorFactor = 203;
4128 const SrcAlphaFactor = 204;
4129 const OneMinusSrcAlphaFactor = 205;
4130 const DstAlphaFactor = 206;
4131 const OneMinusDstAlphaFactor = 207;
4132 const DstColorFactor = 208;
4133 const OneMinusDstColorFactor = 209;
4134 const SrcAlphaSaturateFactor = 210;
4135 const NeverDepth = 0;
4136 const AlwaysDepth = 1;
4137 const LessDepth = 2;
4138 const LessEqualDepth = 3;
4139 const EqualDepth = 4;
4140 const GreaterEqualDepth = 5;
4141 const GreaterDepth = 6;
4142 const NotEqualDepth = 7;
4143 const MultiplyOperation = 0;
4144 const MixOperation = 1;
4145 const AddOperation = 2;
4146 const NoToneMapping = 0;
4147 const LinearToneMapping = 1;
4148 const ReinhardToneMapping = 2;
4149 const CineonToneMapping = 3;
4150 const ACESFilmicToneMapping = 4;
4151 const CustomToneMapping = 5;
4152
4153 const UVMapping = 300;
4154 const CubeReflectionMapping = 301;
4155 const CubeRefractionMapping = 302;
4156 const EquirectangularReflectionMapping = 303;
4157 const EquirectangularRefractionMapping = 304;
4158 const CubeUVReflectionMapping = 306;
4159 const CubeUVRefractionMapping = 307;
4160 const RepeatWrapping = 1000;
4161 const ClampToEdgeWrapping = 1001;
4162 const MirroredRepeatWrapping = 1002;
4163 const NearestFilter = 1003;
4164 const NearestMipmapNearestFilter = 1004;
4165 const NearestMipmapLinearFilter = 1005;
4166 const LinearFilter = 1006;
4167 const LinearMipmapNearestFilter = 1007;
4168 const LinearMipmapLinearFilter = 1008;
4169 const UnsignedByteType = 1009;
4170 const ByteType = 1010;
4171 const ShortType = 1011;
4172 const UnsignedShortType = 1012;
4173 const IntType = 1013;
4174 const UnsignedIntType = 1014;
4175 const FloatType = 1015;
4176 const HalfFloatType = 1016;
4177 const UnsignedShort4444Type = 1017;
4178 const UnsignedShort5551Type = 1018;
4179 const UnsignedShort565Type = 1019;
4180 const UnsignedInt248Type = 1020;
4181 const AlphaFormat = 1021;
4182 const RGBFormat = 1022;
4183 const RGBAFormat = 1023;
4184 const LuminanceFormat = 1024;
4185 const LuminanceAlphaFormat = 1025;
4186 const DepthFormat = 1026;
4187 const DepthStencilFormat = 1027;
4188 const RedFormat = 1028;
4189 const RedIntegerFormat = 1029;
4190 const RGFormat = 1030;
4191 const RGIntegerFormat = 1031;
4192 const RGBIntegerFormat = 1032;
4193 const RGBAIntegerFormat = 1033;
4194
4195 const RGB_S3TC_DXT1_Format = 33776;
4196 const RGBA_S3TC_DXT1_Format = 33777;
4197 const RGBA_S3TC_DXT3_Format = 33778;
4198 const RGBA_S3TC_DXT5_Format = 33779;
4199 const RGB_PVRTC_4BPPV1_Format = 35840;
4200 const RGB_PVRTC_2BPPV1_Format = 35841;
4201 const RGBA_PVRTC_4BPPV1_Format = 35842;
4202 const RGBA_PVRTC_2BPPV1_Format = 35843;
4203 const RGB_ETC1_Format = 36196;
4204 const RGB_ETC2_Format = 37492;
4205 const RGBA_ETC2_EAC_Format = 37496;
4206 const RGBA_ASTC_4x4_Format = 37808;
4207 const RGBA_ASTC_5x4_Format = 37809;
4208 const RGBA_ASTC_5x5_Format = 37810;
4209 const RGBA_ASTC_6x5_Format = 37811;
4210 const RGBA_ASTC_6x6_Format = 37812;
4211 const RGBA_ASTC_8x5_Format = 37813;
4212 const RGBA_ASTC_8x6_Format = 37814;
4213 const RGBA_ASTC_8x8_Format = 37815;
4214 const RGBA_ASTC_10x5_Format = 37816;
4215 const RGBA_ASTC_10x6_Format = 37817;
4216 const RGBA_ASTC_10x8_Format = 37818;
4217 const RGBA_ASTC_10x10_Format = 37819;
4218 const RGBA_ASTC_12x10_Format = 37820;
4219 const RGBA_ASTC_12x12_Format = 37821;
4220 const RGBA_BPTC_Format = 36492;
4221 const SRGB8_ALPHA8_ASTC_4x4_Format = 37840;
4222 const SRGB8_ALPHA8_ASTC_5x4_Format = 37841;
4223 const SRGB8_ALPHA8_ASTC_5x5_Format = 37842;
4224 const SRGB8_ALPHA8_ASTC_6x5_Format = 37843;
4225 const SRGB8_ALPHA8_ASTC_6x6_Format = 37844;
4226 const SRGB8_ALPHA8_ASTC_8x5_Format = 37845;
4227 const SRGB8_ALPHA8_ASTC_8x6_Format = 37846;
4228 const SRGB8_ALPHA8_ASTC_8x8_Format = 37847;
4229 const SRGB8_ALPHA8_ASTC_10x5_Format = 37848;
4230 const SRGB8_ALPHA8_ASTC_10x6_Format = 37849;
4231 const SRGB8_ALPHA8_ASTC_10x8_Format = 37850;
4232 const SRGB8_ALPHA8_ASTC_10x10_Format = 37851;
4233 const SRGB8_ALPHA8_ASTC_12x10_Format = 37852;
4234 const SRGB8_ALPHA8_ASTC_12x12_Format = 37853;
4235 const LoopOnce = 2200;
4236 const LoopRepeat = 2201;
4237 const LoopPingPong = 2202;
4238 const InterpolateDiscrete = 2300;
4239 const InterpolateLinear = 2301;
4240 const InterpolateSmooth = 2302;
4241 const ZeroCurvatureEnding = 2400;
4242 const ZeroSlopeEnding = 2401;
4243 const WrapAroundEnding = 2402;
4244 const NormalAnimationBlendMode = 2500;
4245 const AdditiveAnimationBlendMode = 2501;
4246 const TrianglesDrawMode = 0;
4247 const LinearEncoding = 3000;
4248 const sRGBEncoding = 3001;
4249 const GammaEncoding = 3007;
4250 const RGBEEncoding = 3002;
4251 const LogLuvEncoding = 3003;
4252 const RGBM7Encoding = 3004;
4253 const RGBM16Encoding = 3005;
4254 const RGBDEncoding = 3006;
4255 const BasicDepthPacking = 3200;
4256 const RGBADepthPacking = 3201;
4257 const TangentSpaceNormalMap = 0;
4258 const ObjectSpaceNormalMap = 1;
4259 const KeepStencilOp = 7680;
4260 const AlwaysStencilFunc = 519;
4261
4262 const StaticDrawUsage = 35044;
4263 const DynamicDrawUsage = 35048;
4264 const GLSL3 = '300 es';
4265
4266 /**
4267  * https://github.com/mrdoob/eventdispatcher.js/
4268  */
4269
4270 function EventDispatcher() {}
4271
4272 Object.assign( EventDispatcher.prototype, {
4273
4274         addEventListener: function ( type, listener ) {
4275
4276                 if ( this._listeners === undefined ) this._listeners = {};
4277
4278                 const listeners = this._listeners;
4279
4280                 if ( listeners[ type ] === undefined ) {
4281
4282                         listeners[ type ] = [];
4283
4284                 }
4285
4286                 if ( listeners[ type ].indexOf( listener ) === - 1 ) {
4287
4288                         listeners[ type ].push( listener );
4289
4290                 }
4291
4292         },
4293
4294         hasEventListener: function ( type, listener ) {
4295
4296                 if ( this._listeners === undefined ) return false;
4297
4298                 const listeners = this._listeners;
4299
4300                 return listeners[ type ] !== undefined && listeners[ type ].indexOf( listener ) !== - 1;
4301
4302         },
4303
4304         removeEventListener: function ( type, listener ) {
4305
4306                 if ( this._listeners === undefined ) return;
4307
4308                 const listeners = this._listeners;
4309                 const listenerArray = listeners[ type ];
4310
4311                 if ( listenerArray !== undefined ) {
4312
4313                         const index = listenerArray.indexOf( listener );
4314
4315                         if ( index !== - 1 ) {
4316
4317                                 listenerArray.splice( index, 1 );
4318
4319                         }
4320
4321                 }
4322
4323         },
4324
4325         dispatchEvent: function ( event ) {
4326
4327                 if ( this._listeners === undefined ) return;
4328
4329                 const listeners = this._listeners;
4330                 const listenerArray = listeners[ event.type ];
4331
4332                 if ( listenerArray !== undefined ) {
4333
4334                         event.target = this;
4335
4336                         // Make a copy, in case listeners are removed while iterating.
4337                         const array = listenerArray.slice( 0 );
4338
4339                         for ( let i = 0, l = array.length; i < l; i ++ ) {
4340
4341                                 array[ i ].call( this, event );
4342
4343                         }
4344
4345                 }
4346
4347         }
4348
4349 } );
4350
4351 const _lut = [];
4352
4353 for ( let i = 0; i < 256; i ++ ) {
4354
4355         _lut[ i ] = ( i < 16 ? '0' : '' ) + ( i ).toString( 16 );
4356
4357 }
4358
4359 let _seed = 1234567;
4360
4361 const MathUtils = {
4362
4363         DEG2RAD: Math.PI / 180,
4364         RAD2DEG: 180 / Math.PI,
4365
4366         generateUUID: function () {
4367
4368                 // http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript/21963136#21963136
4369
4370                 const d0 = Math.random() * 0xffffffff | 0;
4371                 const d1 = Math.random() * 0xffffffff | 0;
4372                 const d2 = Math.random() * 0xffffffff | 0;
4373                 const d3 = Math.random() * 0xffffffff | 0;
4374                 const uuid = _lut[ d0 & 0xff ] + _lut[ d0 >> 8 & 0xff ] + _lut[ d0 >> 16 & 0xff ] + _lut[ d0 >> 24 & 0xff ] + '-' +
4375                         _lut[ d1 & 0xff ] + _lut[ d1 >> 8 & 0xff ] + '-' + _lut[ d1 >> 16 & 0x0f | 0x40 ] + _lut[ d1 >> 24 & 0xff ] + '-' +
4376                         _lut[ d2 & 0x3f | 0x80 ] + _lut[ d2 >> 8 & 0xff ] + '-' + _lut[ d2 >> 16 & 0xff ] + _lut[ d2 >> 24 & 0xff ] +
4377                         _lut[ d3 & 0xff ] + _lut[ d3 >> 8 & 0xff ] + _lut[ d3 >> 16 & 0xff ] + _lut[ d3 >> 24 & 0xff ];
4378
4379                 // .toUpperCase() here flattens concatenated strings to save heap memory space.
4380                 return uuid.toUpperCase();
4381
4382         },
4383
4384         clamp: function ( value, min, max ) {
4385
4386                 return Math.max( min, Math.min( max, value ) );
4387
4388         },
4389
4390         // compute euclidian modulo of m % n
4391         // https://en.wikipedia.org/wiki/Modulo_operation
4392
4393         euclideanModulo: function ( n, m ) {
4394
4395                 return ( ( n % m ) + m ) % m;
4396
4397         },
4398
4399         // Linear mapping from range <a1, a2> to range <b1, b2>
4400
4401         mapLinear: function ( x, a1, a2, b1, b2 ) {
4402
4403                 return b1 + ( x - a1 ) * ( b2 - b1 ) / ( a2 - a1 );
4404
4405         },
4406
4407         // https://en.wikipedia.org/wiki/Linear_interpolation
4408
4409         lerp: function ( x, y, t ) {
4410
4411                 return ( 1 - t ) * x + t * y;
4412
4413         },
4414
4415         // http://www.rorydriscoll.com/2016/03/07/frame-rate-independent-damping-using-lerp/
4416
4417         damp: function ( x, y, lambda, dt ) {
4418
4419                 return MathUtils.lerp( x, y, 1 - Math.exp( - lambda * dt ) );
4420
4421         },
4422
4423         // https://www.desmos.com/calculator/vcsjnyz7x4
4424
4425         pingpong: function ( x, length = 1 ) {
4426
4427                 return length - Math.abs( MathUtils.euclideanModulo( x, length * 2 ) - length );
4428
4429         },
4430
4431         // http://en.wikipedia.org/wiki/Smoothstep
4432
4433         smoothstep: function ( x, min, max ) {
4434
4435                 if ( x <= min ) return 0;
4436                 if ( x >= max ) return 1;
4437
4438                 x = ( x - min ) / ( max - min );
4439
4440                 return x * x * ( 3 - 2 * x );
4441
4442         },
4443
4444         smootherstep: function ( x, min, max ) {
4445
4446                 if ( x <= min ) return 0;
4447                 if ( x >= max ) return 1;
4448
4449                 x = ( x - min ) / ( max - min );
4450
4451                 return x * x * x * ( x * ( x * 6 - 15 ) + 10 );
4452
4453         },
4454
4455         // Random integer from <low, high> interval
4456
4457         randInt: function ( low, high ) {
4458
4459                 return low + Math.floor( Math.random() * ( high - low + 1 ) );
4460
4461         },
4462
4463         // Random float from <low, high> interval
4464
4465         randFloat: function ( low, high ) {
4466
4467                 return low + Math.random() * ( high - low );
4468
4469         },
4470
4471         // Random float from <-range/2, range/2> interval
4472
4473         randFloatSpread: function ( range ) {
4474
4475                 return range * ( 0.5 - Math.random() );
4476
4477         },
4478
4479         // Deterministic pseudo-random float in the interval [ 0, 1 ]
4480
4481         seededRandom: function ( s ) {
4482
4483                 if ( s !== undefined ) _seed = s % 2147483647;
4484
4485                 // Park-Miller algorithm
4486
4487                 _seed = _seed * 16807 % 2147483647;
4488
4489                 return ( _seed - 1 ) / 2147483646;
4490
4491         },
4492
4493         degToRad: function ( degrees ) {
4494
4495                 return degrees * MathUtils.DEG2RAD;
4496
4497         },
4498
4499         radToDeg: function ( radians ) {
4500
4501                 return radians * MathUtils.RAD2DEG;
4502
4503         },
4504
4505         isPowerOfTwo: function ( value ) {
4506
4507                 return ( value & ( value - 1 ) ) === 0 && value !== 0;
4508
4509         },
4510
4511         ceilPowerOfTwo: function ( value ) {
4512
4513                 return Math.pow( 2, Math.ceil( Math.log( value ) / Math.LN2 ) );
4514
4515         },
4516
4517         floorPowerOfTwo: function ( value ) {
4518
4519                 return Math.pow( 2, Math.floor( Math.log( value ) / Math.LN2 ) );
4520
4521         },
4522
4523         setQuaternionFromProperEuler: function ( q, a, b, c, order ) {
4524
4525                 // Intrinsic Proper Euler Angles - see https://en.wikipedia.org/wiki/Euler_angles
4526
4527                 // rotations are applied to the axes in the order specified by 'order'
4528                 // rotation by angle 'a' is applied first, then by angle 'b', then by angle 'c'
4529                 // angles are in radians
4530
4531                 const cos = Math.cos;
4532                 const sin = Math.sin;
4533
4534                 const c2 = cos( b / 2 );
4535                 const s2 = sin( b / 2 );
4536
4537                 const c13 = cos( ( a + c ) / 2 );
4538                 const s13 = sin( ( a + c ) / 2 );
4539
4540                 const c1_3 = cos( ( a - c ) / 2 );
4541                 const s1_3 = sin( ( a - c ) / 2 );
4542
4543                 const c3_1 = cos( ( c - a ) / 2 );
4544                 const s3_1 = sin( ( c - a ) / 2 );
4545
4546                 switch ( order ) {
4547
4548                         case 'XYX':
4549                                 q.set( c2 * s13, s2 * c1_3, s2 * s1_3, c2 * c13 );
4550                                 break;
4551
4552                         case 'YZY':
4553                                 q.set( s2 * s1_3, c2 * s13, s2 * c1_3, c2 * c13 );
4554                                 break;
4555
4556                         case 'ZXZ':
4557                                 q.set( s2 * c1_3, s2 * s1_3, c2 * s13, c2 * c13 );
4558                                 break;
4559
4560                         case 'XZX':
4561                                 q.set( c2 * s13, s2 * s3_1, s2 * c3_1, c2 * c13 );
4562                                 break;
4563
4564                         case 'YXY':
4565                                 q.set( s2 * c3_1, c2 * s13, s2 * s3_1, c2 * c13 );
4566                                 break;
4567
4568                         case 'ZYZ':
4569                                 q.set( s2 * s3_1, s2 * c3_1, c2 * s13, c2 * c13 );
4570                                 break;
4571
4572                         default:
4573                                 console.warn( 'THREE.MathUtils: .setQuaternionFromProperEuler() encountered an unknown order: ' + order );
4574
4575                 }
4576
4577         }
4578
4579 };
4580
4581 class Vector2 {
4582
4583         constructor( x = 0, y = 0 ) {
4584
4585                 Object.defineProperty( this, 'isVector2', { value: true } );
4586
4587                 this.x = x;
4588                 this.y = y;
4589
4590         }
4591
4592         get width() {
4593
4594                 return this.x;
4595
4596         }
4597
4598         set width( value ) {
4599
4600                 this.x = value;
4601
4602         }
4603
4604         get height() {
4605
4606                 return this.y;
4607
4608         }
4609
4610         set height( value ) {
4611
4612                 this.y = value;
4613
4614         }
4615
4616         set( x, y ) {
4617
4618                 this.x = x;
4619                 this.y = y;
4620
4621                 return this;
4622
4623         }
4624
4625         setScalar( scalar ) {
4626
4627                 this.x = scalar;
4628                 this.y = scalar;
4629
4630                 return this;
4631
4632         }
4633
4634         setX( x ) {
4635
4636                 this.x = x;
4637
4638                 return this;
4639
4640         }
4641
4642         setY( y ) {
4643
4644                 this.y = y;
4645
4646                 return this;
4647
4648         }
4649
4650         setComponent( index, value ) {
4651
4652                 switch ( index ) {
4653
4654                         case 0: this.x = value; break;
4655                         case 1: this.y = value; break;
4656                         default: throw new Error( 'index is out of range: ' + index );
4657
4658                 }
4659
4660                 return this;
4661
4662         }
4663
4664         getComponent( index ) {
4665
4666                 switch ( index ) {
4667
4668                         case 0: return this.x;
4669                         case 1: return this.y;
4670                         default: throw new Error( 'index is out of range: ' + index );
4671
4672                 }
4673
4674         }
4675
4676         clone() {
4677
4678                 return new this.constructor( this.x, this.y );
4679
4680         }
4681
4682         copy( v ) {
4683
4684                 this.x = v.x;
4685                 this.y = v.y;
4686
4687                 return this;
4688
4689         }
4690
4691         add( v, w ) {
4692
4693                 if ( w !== undefined ) {
4694
4695                         console.warn( 'THREE.Vector2: .add() now only accepts one argument. Use .addVectors( a, b ) instead.' );
4696                         return this.addVectors( v, w );
4697
4698                 }
4699
4700                 this.x += v.x;
4701                 this.y += v.y;
4702
4703                 return this;
4704
4705         }
4706
4707         addScalar( s ) {
4708
4709                 this.x += s;
4710                 this.y += s;
4711
4712                 return this;
4713
4714         }
4715
4716         addVectors( a, b ) {
4717
4718                 this.x = a.x + b.x;
4719                 this.y = a.y + b.y;
4720
4721                 return this;
4722
4723         }
4724
4725         addScaledVector( v, s ) {
4726
4727                 this.x += v.x * s;
4728                 this.y += v.y * s;
4729
4730                 return this;
4731
4732         }
4733
4734         sub( v, w ) {
4735
4736                 if ( w !== undefined ) {
4737
4738                         console.warn( 'THREE.Vector2: .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' );
4739                         return this.subVectors( v, w );
4740
4741                 }
4742
4743                 this.x -= v.x;
4744                 this.y -= v.y;
4745
4746                 return this;
4747
4748         }
4749
4750         subScalar( s ) {
4751
4752                 this.x -= s;
4753                 this.y -= s;
4754
4755                 return this;
4756
4757         }
4758
4759         subVectors( a, b ) {
4760
4761                 this.x = a.x - b.x;
4762                 this.y = a.y - b.y;
4763
4764                 return this;
4765
4766         }
4767
4768         multiply( v ) {
4769
4770                 this.x *= v.x;
4771                 this.y *= v.y;
4772
4773                 return this;
4774
4775         }
4776
4777         multiplyScalar( scalar ) {
4778
4779                 this.x *= scalar;
4780                 this.y *= scalar;
4781
4782                 return this;
4783
4784         }
4785
4786         divide( v ) {
4787
4788                 this.x /= v.x;
4789                 this.y /= v.y;
4790
4791                 return this;
4792
4793         }
4794
4795         divideScalar( scalar ) {
4796
4797                 return this.multiplyScalar( 1 / scalar );
4798
4799         }
4800
4801         applyMatrix3( m ) {
4802
4803                 const x = this.x, y = this.y;
4804                 const e = m.elements;
4805
4806                 this.x = e[ 0 ] * x + e[ 3 ] * y + e[ 6 ];
4807                 this.y = e[ 1 ] * x + e[ 4 ] * y + e[ 7 ];
4808
4809                 return this;
4810
4811         }
4812
4813         min( v ) {
4814
4815                 this.x = Math.min( this.x, v.x );
4816                 this.y = Math.min( this.y, v.y );
4817
4818                 return this;
4819
4820         }
4821
4822         max( v ) {
4823
4824                 this.x = Math.max( this.x, v.x );
4825                 this.y = Math.max( this.y, v.y );
4826
4827                 return this;
4828
4829         }
4830
4831         clamp( min, max ) {
4832
4833                 // assumes min < max, componentwise
4834
4835                 this.x = Math.max( min.x, Math.min( max.x, this.x ) );
4836                 this.y = Math.max( min.y, Math.min( max.y, this.y ) );
4837
4838                 return this;
4839
4840         }
4841
4842         clampScalar( minVal, maxVal ) {
4843
4844                 this.x = Math.max( minVal, Math.min( maxVal, this.x ) );
4845                 this.y = Math.max( minVal, Math.min( maxVal, this.y ) );
4846
4847                 return this;
4848
4849         }
4850
4851         clampLength( min, max ) {
4852
4853                 const length = this.length();
4854
4855                 return this.divideScalar( length || 1 ).multiplyScalar( Math.max( min, Math.min( max, length ) ) );
4856
4857         }
4858
4859         floor() {
4860
4861                 this.x = Math.floor( this.x );
4862                 this.y = Math.floor( this.y );
4863
4864                 return this;
4865
4866         }
4867
4868         ceil() {
4869
4870                 this.x = Math.ceil( this.x );
4871                 this.y = Math.ceil( this.y );
4872
4873                 return this;
4874
4875         }
4876
4877         round() {
4878
4879                 this.x = Math.round( this.x );
4880                 this.y = Math.round( this.y );
4881
4882                 return this;
4883
4884         }
4885
4886         roundToZero() {
4887
4888                 this.x = ( this.x < 0 ) ? Math.ceil( this.x ) : Math.floor( this.x );
4889                 this.y = ( this.y < 0 ) ? Math.ceil( this.y ) : Math.floor( this.y );
4890
4891                 return this;
4892
4893         }
4894
4895         negate() {
4896
4897                 this.x = - this.x;
4898                 this.y = - this.y;
4899
4900                 return this;
4901
4902         }
4903
4904         dot( v ) {
4905
4906                 return this.x * v.x + this.y * v.y;
4907
4908         }
4909
4910         cross( v ) {
4911
4912                 return this.x * v.y - this.y * v.x;
4913
4914         }
4915
4916         lengthSq() {
4917
4918                 return this.x * this.x + this.y * this.y;
4919
4920         }
4921
4922         length() {
4923
4924                 return Math.sqrt( this.x * this.x + this.y * this.y );
4925
4926         }
4927
4928         manhattanLength() {
4929
4930                 return Math.abs( this.x ) + Math.abs( this.y );
4931
4932         }
4933
4934         normalize() {
4935
4936                 return this.divideScalar( this.length() || 1 );
4937
4938         }
4939
4940         angle() {
4941
4942                 // computes the angle in radians with respect to the positive x-axis
4943
4944                 const angle = Math.atan2( - this.y, - this.x ) + Math.PI;
4945
4946                 return angle;
4947
4948         }
4949
4950         distanceTo( v ) {
4951
4952                 return Math.sqrt( this.distanceToSquared( v ) );
4953
4954         }
4955
4956         distanceToSquared( v ) {
4957
4958                 const dx = this.x - v.x, dy = this.y - v.y;
4959                 return dx * dx + dy * dy;
4960
4961         }
4962
4963         manhattanDistanceTo( v ) {
4964
4965                 return Math.abs( this.x - v.x ) + Math.abs( this.y - v.y );
4966
4967         }
4968
4969         setLength( length ) {
4970
4971                 return this.normalize().multiplyScalar( length );
4972
4973         }
4974
4975         lerp( v, alpha ) {
4976
4977                 this.x += ( v.x - this.x ) * alpha;
4978                 this.y += ( v.y - this.y ) * alpha;
4979
4980                 return this;
4981
4982         }
4983
4984         lerpVectors( v1, v2, alpha ) {
4985
4986                 this.x = v1.x + ( v2.x - v1.x ) * alpha;
4987                 this.y = v1.y + ( v2.y - v1.y ) * alpha;
4988
4989                 return this;
4990
4991         }
4992
4993         equals( v ) {
4994
4995                 return ( ( v.x === this.x ) && ( v.y === this.y ) );
4996
4997         }
4998
4999         fromArray( array, offset = 0 ) {
5000
5001                 this.x = array[ offset ];
5002                 this.y = array[ offset + 1 ];
5003
5004                 return this;
5005
5006         }
5007
5008         toArray( array = [], offset = 0 ) {
5009
5010                 array[ offset ] = this.x;
5011                 array[ offset + 1 ] = this.y;
5012
5013                 return array;
5014
5015         }
5016
5017         fromBufferAttribute( attribute, index, offset ) {
5018
5019                 if ( offset !== undefined ) {
5020
5021                         console.warn( 'THREE.Vector2: offset has been removed from .fromBufferAttribute().' );
5022
5023                 }
5024
5025                 this.x = attribute.getX( index );
5026                 this.y = attribute.getY( index );
5027
5028                 return this;
5029
5030         }
5031
5032         rotateAround( center, angle ) {
5033
5034                 const c = Math.cos( angle ), s = Math.sin( angle );
5035
5036                 const x = this.x - center.x;
5037                 const y = this.y - center.y;
5038
5039                 this.x = x * c - y * s + center.x;
5040                 this.y = x * s + y * c + center.y;
5041
5042                 return this;
5043
5044         }
5045
5046         random() {
5047
5048                 this.x = Math.random();
5049                 this.y = Math.random();
5050
5051                 return this;
5052
5053         }
5054
5055 }
5056
5057 class Matrix3 {
5058
5059         constructor() {
5060
5061                 Object.defineProperty( this, 'isMatrix3', { value: true } );
5062
5063                 this.elements = [
5064
5065                         1, 0, 0,
5066                         0, 1, 0,
5067                         0, 0, 1
5068
5069                 ];
5070
5071                 if ( arguments.length > 0 ) {
5072
5073                         console.error( 'THREE.Matrix3: the constructor no longer reads arguments. use .set() instead.' );
5074
5075                 }
5076
5077         }
5078
5079         set( n11, n12, n13, n21, n22, n23, n31, n32, n33 ) {
5080
5081                 const te = this.elements;
5082
5083                 te[ 0 ] = n11; te[ 1 ] = n21; te[ 2 ] = n31;
5084                 te[ 3 ] = n12; te[ 4 ] = n22; te[ 5 ] = n32;
5085                 te[ 6 ] = n13; te[ 7 ] = n23; te[ 8 ] = n33;
5086
5087                 return this;
5088
5089         }
5090
5091         identity() {
5092
5093                 this.set(
5094
5095                         1, 0, 0,
5096                         0, 1, 0,
5097                         0, 0, 1
5098
5099                 );
5100
5101                 return this;
5102
5103         }
5104
5105         clone() {
5106
5107                 return new this.constructor().fromArray( this.elements );
5108
5109         }
5110
5111         copy( m ) {
5112
5113                 const te = this.elements;
5114                 const me = m.elements;
5115
5116                 te[ 0 ] = me[ 0 ]; te[ 1 ] = me[ 1 ]; te[ 2 ] = me[ 2 ];
5117                 te[ 3 ] = me[ 3 ]; te[ 4 ] = me[ 4 ]; te[ 5 ] = me[ 5 ];
5118                 te[ 6 ] = me[ 6 ]; te[ 7 ] = me[ 7 ]; te[ 8 ] = me[ 8 ];
5119
5120                 return this;
5121
5122         }
5123
5124         extractBasis( xAxis, yAxis, zAxis ) {
5125
5126                 xAxis.setFromMatrix3Column( this, 0 );
5127                 yAxis.setFromMatrix3Column( this, 1 );
5128                 zAxis.setFromMatrix3Column( this, 2 );
5129
5130                 return this;
5131
5132         }
5133
5134         setFromMatrix4( m ) {
5135
5136                 const me = m.elements;
5137
5138                 this.set(
5139
5140                         me[ 0 ], me[ 4 ], me[ 8 ],
5141                         me[ 1 ], me[ 5 ], me[ 9 ],
5142                         me[ 2 ], me[ 6 ], me[ 10 ]
5143
5144                 );
5145
5146                 return this;
5147
5148         }
5149
5150         multiply( m ) {
5151
5152                 return this.multiplyMatrices( this, m );
5153
5154         }
5155
5156         premultiply( m ) {
5157
5158                 return this.multiplyMatrices( m, this );
5159
5160         }
5161
5162         multiplyMatrices( a, b ) {
5163
5164                 const ae = a.elements;
5165                 const be = b.elements;
5166                 const te = this.elements;
5167
5168                 const a11 = ae[ 0 ], a12 = ae[ 3 ], a13 = ae[ 6 ];
5169                 const a21 = ae[ 1 ], a22 = ae[ 4 ], a23 = ae[ 7 ];
5170                 const a31 = ae[ 2 ], a32 = ae[ 5 ], a33 = ae[ 8 ];
5171
5172                 const b11 = be[ 0 ], b12 = be[ 3 ], b13 = be[ 6 ];
5173                 const b21 = be[ 1 ], b22 = be[ 4 ], b23 = be[ 7 ];
5174                 const b31 = be[ 2 ], b32 = be[ 5 ], b33 = be[ 8 ];
5175
5176                 te[ 0 ] = a11 * b11 + a12 * b21 + a13 * b31;
5177                 te[ 3 ] = a11 * b12 + a12 * b22 + a13 * b32;
5178                 te[ 6 ] = a11 * b13 + a12 * b23 + a13 * b33;
5179
5180                 te[ 1 ] = a21 * b11 + a22 * b21 + a23 * b31;
5181                 te[ 4 ] = a21 * b12 + a22 * b22 + a23 * b32;
5182                 te[ 7 ] = a21 * b13 + a22 * b23 + a23 * b33;
5183
5184                 te[ 2 ] = a31 * b11 + a32 * b21 + a33 * b31;
5185                 te[ 5 ] = a31 * b12 + a32 * b22 + a33 * b32;
5186                 te[ 8 ] = a31 * b13 + a32 * b23 + a33 * b33;
5187
5188                 return this;
5189
5190         }
5191
5192         multiplyScalar( s ) {
5193
5194                 const te = this.elements;
5195
5196                 te[ 0 ] *= s; te[ 3 ] *= s; te[ 6 ] *= s;
5197                 te[ 1 ] *= s; te[ 4 ] *= s; te[ 7 ] *= s;
5198                 te[ 2 ] *= s; te[ 5 ] *= s; te[ 8 ] *= s;
5199
5200                 return this;
5201
5202         }
5203
5204         determinant() {
5205
5206                 const te = this.elements;
5207
5208                 const a = te[ 0 ], b = te[ 1 ], c = te[ 2 ],
5209                         d = te[ 3 ], e = te[ 4 ], f = te[ 5 ],
5210                         g = te[ 6 ], h = te[ 7 ], i = te[ 8 ];
5211
5212                 return a * e * i - a * f * h - b * d * i + b * f * g + c * d * h - c * e * g;
5213
5214         }
5215
5216         invert() {
5217
5218                 const te = this.elements,
5219
5220                         n11 = te[ 0 ], n21 = te[ 1 ], n31 = te[ 2 ],
5221                         n12 = te[ 3 ], n22 = te[ 4 ], n32 = te[ 5 ],
5222                         n13 = te[ 6 ], n23 = te[ 7 ], n33 = te[ 8 ],
5223
5224                         t11 = n33 * n22 - n32 * n23,
5225                         t12 = n32 * n13 - n33 * n12,
5226                         t13 = n23 * n12 - n22 * n13,
5227
5228                         det = n11 * t11 + n21 * t12 + n31 * t13;
5229
5230                 if ( det === 0 ) return this.set( 0, 0, 0, 0, 0, 0, 0, 0, 0 );
5231
5232                 const detInv = 1 / det;
5233
5234                 te[ 0 ] = t11 * detInv;
5235                 te[ 1 ] = ( n31 * n23 - n33 * n21 ) * detInv;
5236                 te[ 2 ] = ( n32 * n21 - n31 * n22 ) * detInv;
5237
5238                 te[ 3 ] = t12 * detInv;
5239                 te[ 4 ] = ( n33 * n11 - n31 * n13 ) * detInv;
5240                 te[ 5 ] = ( n31 * n12 - n32 * n11 ) * detInv;
5241
5242                 te[ 6 ] = t13 * detInv;
5243                 te[ 7 ] = ( n21 * n13 - n23 * n11 ) * detInv;
5244                 te[ 8 ] = ( n22 * n11 - n21 * n12 ) * detInv;
5245
5246                 return this;
5247
5248         }
5249
5250         transpose() {
5251
5252                 let tmp;
5253                 const m = this.elements;
5254
5255                 tmp = m[ 1 ]; m[ 1 ] = m[ 3 ]; m[ 3 ] = tmp;
5256                 tmp = m[ 2 ]; m[ 2 ] = m[ 6 ]; m[ 6 ] = tmp;
5257                 tmp = m[ 5 ]; m[ 5 ] = m[ 7 ]; m[ 7 ] = tmp;
5258
5259                 return this;
5260
5261         }
5262
5263         getNormalMatrix( matrix4 ) {
5264
5265                 return this.setFromMatrix4( matrix4 ).copy( this ).invert().transpose();
5266
5267         }
5268
5269         transposeIntoArray( r ) {
5270
5271                 const m = this.elements;
5272
5273                 r[ 0 ] = m[ 0 ];
5274                 r[ 1 ] = m[ 3 ];
5275                 r[ 2 ] = m[ 6 ];
5276                 r[ 3 ] = m[ 1 ];
5277                 r[ 4 ] = m[ 4 ];
5278                 r[ 5 ] = m[ 7 ];
5279                 r[ 6 ] = m[ 2 ];
5280                 r[ 7 ] = m[ 5 ];
5281                 r[ 8 ] = m[ 8 ];
5282
5283                 return this;
5284
5285         }
5286
5287         setUvTransform( tx, ty, sx, sy, rotation, cx, cy ) {
5288
5289                 const c = Math.cos( rotation );
5290                 const s = Math.sin( rotation );
5291
5292                 this.set(
5293                         sx * c, sx * s, - sx * ( c * cx + s * cy ) + cx + tx,
5294                         - sy * s, sy * c, - sy * ( - s * cx + c * cy ) + cy + ty,
5295                         0, 0, 1
5296                 );
5297
5298                 return this;
5299
5300         }
5301
5302         scale( sx, sy ) {
5303
5304                 const te = this.elements;
5305
5306                 te[ 0 ] *= sx; te[ 3 ] *= sx; te[ 6 ] *= sx;
5307                 te[ 1 ] *= sy; te[ 4 ] *= sy; te[ 7 ] *= sy;
5308
5309                 return this;
5310
5311         }
5312
5313         rotate( theta ) {
5314
5315                 const c = Math.cos( theta );
5316                 const s = Math.sin( theta );
5317
5318                 const te = this.elements;
5319
5320                 const a11 = te[ 0 ], a12 = te[ 3 ], a13 = te[ 6 ];
5321                 const a21 = te[ 1 ], a22 = te[ 4 ], a23 = te[ 7 ];
5322
5323                 te[ 0 ] = c * a11 + s * a21;
5324                 te[ 3 ] = c * a12 + s * a22;
5325                 te[ 6 ] = c * a13 + s * a23;
5326
5327                 te[ 1 ] = - s * a11 + c * a21;
5328                 te[ 4 ] = - s * a12 + c * a22;
5329                 te[ 7 ] = - s * a13 + c * a23;
5330
5331                 return this;
5332
5333         }
5334
5335         translate( tx, ty ) {
5336
5337                 const te = this.elements;
5338
5339                 te[ 0 ] += tx * te[ 2 ]; te[ 3 ] += tx * te[ 5 ]; te[ 6 ] += tx * te[ 8 ];
5340                 te[ 1 ] += ty * te[ 2 ]; te[ 4 ] += ty * te[ 5 ]; te[ 7 ] += ty * te[ 8 ];
5341
5342                 return this;
5343
5344         }
5345
5346         equals( matrix ) {
5347
5348                 const te = this.elements;
5349                 const me = matrix.elements;
5350
5351                 for ( let i = 0; i < 9; i ++ ) {
5352
5353                         if ( te[ i ] !== me[ i ] ) return false;
5354
5355                 }
5356
5357                 return true;
5358
5359         }
5360
5361         fromArray( array, offset = 0 ) {
5362
5363                 for ( let i = 0; i < 9; i ++ ) {
5364
5365                         this.elements[ i ] = array[ i + offset ];
5366
5367                 }
5368
5369                 return this;
5370
5371         }
5372
5373         toArray( array = [], offset = 0 ) {
5374
5375                 const te = this.elements;
5376
5377                 array[ offset ] = te[ 0 ];
5378                 array[ offset + 1 ] = te[ 1 ];
5379                 array[ offset + 2 ] = te[ 2 ];
5380
5381                 array[ offset + 3 ] = te[ 3 ];
5382                 array[ offset + 4 ] = te[ 4 ];
5383                 array[ offset + 5 ] = te[ 5 ];
5384
5385                 array[ offset + 6 ] = te[ 6 ];
5386                 array[ offset + 7 ] = te[ 7 ];
5387                 array[ offset + 8 ] = te[ 8 ];
5388
5389                 return array;
5390
5391         }
5392
5393 }
5394
5395 let _canvas;
5396
5397 const ImageUtils = {
5398
5399         getDataURL: function ( image ) {
5400
5401                 if ( /^data:/i.test( image.src ) ) {
5402
5403                         return image.src;
5404
5405                 }
5406
5407                 if ( typeof HTMLCanvasElement == 'undefined' ) {
5408
5409                         return image.src;
5410
5411                 }
5412
5413                 let canvas;
5414
5415                 if ( image instanceof HTMLCanvasElement ) {
5416
5417                         canvas = image;
5418
5419                 } else {
5420
5421                         if ( _canvas === undefined ) _canvas = document.createElementNS( 'http://www.w3.org/1999/xhtml', 'canvas' );
5422
5423                         _canvas.width = image.width;
5424                         _canvas.height = image.height;
5425
5426                         const context = _canvas.getContext( '2d' );
5427
5428                         if ( image instanceof ImageData ) {
5429
5430                                 context.putImageData( image, 0, 0 );
5431
5432                         } else {
5433
5434                                 context.drawImage( image, 0, 0, image.width, image.height );
5435
5436                         }
5437
5438                         canvas = _canvas;
5439
5440                 }
5441
5442                 if ( canvas.width > 2048 || canvas.height > 2048 ) {
5443
5444                         return canvas.toDataURL( 'image/jpeg', 0.6 );
5445
5446                 } else {
5447
5448                         return canvas.toDataURL( 'image/png' );
5449
5450                 }
5451
5452         }
5453
5454 };
5455
5456 let textureId = 0;
5457
5458 function Texture( image = Texture.DEFAULT_IMAGE, mapping = Texture.DEFAULT_MAPPING, wrapS = ClampToEdgeWrapping, wrapT = ClampToEdgeWrapping, magFilter = LinearFilter, minFilter = LinearMipmapLinearFilter, format = RGBAFormat, type = UnsignedByteType, anisotropy = 1, encoding = LinearEncoding ) {
5459
5460         Object.defineProperty( this, 'id', { value: textureId ++ } );
5461
5462         this.uuid = MathUtils.generateUUID();
5463
5464         this.name = '';
5465
5466         this.image = image;
5467         this.mipmaps = [];
5468
5469         this.mapping = mapping;
5470
5471         this.wrapS = wrapS;
5472         this.wrapT = wrapT;
5473
5474         this.magFilter = magFilter;
5475         this.minFilter = minFilter;
5476
5477         this.anisotropy = anisotropy;
5478
5479         this.format = format;
5480         this.internalFormat = null;
5481         this.type = type;
5482
5483         this.offset = new Vector2( 0, 0 );
5484         this.repeat = new Vector2( 1, 1 );
5485         this.center = new Vector2( 0, 0 );
5486         this.rotation = 0;
5487
5488         this.matrixAutoUpdate = true;
5489         this.matrix = new Matrix3();
5490
5491         this.generateMipmaps = true;
5492         this.premultiplyAlpha = false;
5493         this.flipY = true;
5494         this.unpackAlignment = 4;       // valid values: 1, 2, 4, 8 (see http://www.khronos.org/opengles/sdk/docs/man/xhtml/glPixelStorei.xml)
5495
5496         // Values of encoding !== THREE.LinearEncoding only supported on map, envMap and emissiveMap.
5497         //
5498         // Also changing the encoding after already used by a Material will not automatically make the Material
5499         // update. You need to explicitly call Material.needsUpdate to trigger it to recompile.
5500         this.encoding = encoding;
5501
5502         this.version = 0;
5503         this.onUpdate = null;
5504
5505 }
5506
5507 Texture.DEFAULT_IMAGE = undefined;
5508 Texture.DEFAULT_MAPPING = UVMapping;
5509
5510 Texture.prototype = Object.assign( Object.create( EventDispatcher.prototype ), {
5511
5512         constructor: Texture,
5513
5514         isTexture: true,
5515
5516         updateMatrix: function () {
5517
5518                 this.matrix.setUvTransform( this.offset.x, this.offset.y, this.repeat.x, this.repeat.y, this.rotation, this.center.x, this.center.y );
5519
5520         },
5521
5522         clone: function () {
5523
5524                 return new this.constructor().copy( this );
5525
5526         },
5527
5528         copy: function ( source ) {
5529
5530                 this.name = source.name;
5531
5532                 this.image = source.image;
5533                 this.mipmaps = source.mipmaps.slice( 0 );
5534
5535                 this.mapping = source.mapping;
5536
5537                 this.wrapS = source.wrapS;
5538                 this.wrapT = source.wrapT;
5539
5540                 this.magFilter = source.magFilter;
5541                 this.minFilter = source.minFilter;
5542
5543                 this.anisotropy = source.anisotropy;
5544
5545                 this.format = source.format;
5546                 this.internalFormat = source.internalFormat;
5547                 this.type = source.type;
5548
5549                 this.offset.copy( source.offset );
5550                 this.repeat.copy( source.repeat );
5551                 this.center.copy( source.center );
5552                 this.rotation = source.rotation;
5553
5554                 this.matrixAutoUpdate = source.matrixAutoUpdate;
5555                 this.matrix.copy( source.matrix );
5556
5557                 this.generateMipmaps = source.generateMipmaps;
5558                 this.premultiplyAlpha = source.premultiplyAlpha;
5559                 this.flipY = source.flipY;
5560                 this.unpackAlignment = source.unpackAlignment;
5561                 this.encoding = source.encoding;
5562
5563                 return this;
5564
5565         },
5566
5567         toJSON: function ( meta ) {
5568
5569                 const isRootObject = ( meta === undefined || typeof meta === 'string' );
5570
5571                 if ( ! isRootObject && meta.textures[ this.uuid ] !== undefined ) {
5572
5573                         return meta.textures[ this.uuid ];
5574
5575                 }
5576
5577                 const output = {
5578
5579                         metadata: {
5580                                 version: 4.5,
5581                                 type: 'Texture',
5582                                 generator: 'Texture.toJSON'
5583                         },
5584
5585                         uuid: this.uuid,
5586                         name: this.name,
5587
5588                         mapping: this.mapping,
5589
5590                         repeat: [ this.repeat.x, this.repeat.y ],
5591                         offset: [ this.offset.x, this.offset.y ],
5592                         center: [ this.center.x, this.center.y ],
5593                         rotation: this.rotation,
5594
5595                         wrap: [ this.wrapS, this.wrapT ],
5596
5597                         format: this.format,
5598                         type: this.type,
5599                         encoding: this.encoding,
5600
5601                         minFilter: this.minFilter,
5602                         magFilter: this.magFilter,
5603                         anisotropy: this.anisotropy,
5604
5605                         flipY: this.flipY,
5606
5607                         premultiplyAlpha: this.premultiplyAlpha,
5608                         unpackAlignment: this.unpackAlignment
5609
5610                 };
5611
5612                 if ( this.image !== undefined ) {
5613
5614                         // TODO: Move to THREE.Image
5615
5616                         const image = this.image;
5617
5618                         if ( image.uuid === undefined ) {
5619
5620                                 image.uuid = MathUtils.generateUUID(); // UGH
5621
5622                         }
5623
5624                         if ( ! isRootObject && meta.images[ image.uuid ] === undefined ) {
5625
5626                                 let url;
5627
5628                                 if ( Array.isArray( image ) ) {
5629
5630                                         // process array of images e.g. CubeTexture
5631
5632                                         url = [];
5633
5634                                         for ( let i = 0, l = image.length; i < l; i ++ ) {
5635
5636                                                 // check cube texture with data textures
5637
5638                                                 if ( image[ i ].isDataTexture ) {
5639
5640                                                         url.push( serializeImage( image[ i ].image ) );
5641
5642                                                 } else {
5643
5644                                                         url.push( serializeImage( image[ i ] ) );
5645
5646                                                 }
5647
5648                                         }
5649
5650                                 } else {
5651
5652                                         // process single image
5653
5654                                         url = serializeImage( image );
5655
5656                                 }
5657
5658                                 meta.images[ image.uuid ] = {
5659                                         uuid: image.uuid,
5660                                         url: url
5661                                 };
5662
5663                         }
5664
5665                         output.image = image.uuid;
5666
5667                 }
5668
5669                 if ( ! isRootObject ) {
5670
5671                         meta.textures[ this.uuid ] = output;
5672
5673                 }
5674
5675                 return output;
5676
5677         },
5678
5679         dispose: function () {
5680
5681                 this.dispatchEvent( { type: 'dispose' } );
5682
5683         },
5684
5685         transformUv: function ( uv ) {
5686
5687                 if ( this.mapping !== UVMapping ) return uv;
5688
5689                 uv.applyMatrix3( this.matrix );
5690
5691                 if ( uv.x < 0 || uv.x > 1 ) {
5692
5693                         switch ( this.wrapS ) {
5694
5695                                 case RepeatWrapping:
5696
5697                                         uv.x = uv.x - Math.floor( uv.x );
5698                                         break;
5699
5700                                 case ClampToEdgeWrapping:
5701
5702                                         uv.x = uv.x < 0 ? 0 : 1;
5703                                         break;
5704
5705                                 case MirroredRepeatWrapping:
5706
5707                                         if ( Math.abs( Math.floor( uv.x ) % 2 ) === 1 ) {
5708
5709                                                 uv.x = Math.ceil( uv.x ) - uv.x;
5710
5711                                         } else {
5712
5713                                                 uv.x = uv.x - Math.floor( uv.x );
5714
5715                                         }
5716
5717                                         break;
5718
5719                         }
5720
5721                 }
5722
5723                 if ( uv.y < 0 || uv.y > 1 ) {
5724
5725                         switch ( this.wrapT ) {
5726
5727                                 case RepeatWrapping:
5728
5729                                         uv.y = uv.y - Math.floor( uv.y );
5730                                         break;
5731
5732                                 case ClampToEdgeWrapping:
5733
5734                                         uv.y = uv.y < 0 ? 0 : 1;
5735                                         break;
5736
5737                                 case MirroredRepeatWrapping:
5738
5739                                         if ( Math.abs( Math.floor( uv.y ) % 2 ) === 1 ) {
5740
5741                                                 uv.y = Math.ceil( uv.y ) - uv.y;
5742
5743                                         } else {
5744
5745                                                 uv.y = uv.y - Math.floor( uv.y );
5746
5747                                         }
5748
5749                                         break;
5750
5751                         }
5752
5753                 }
5754
5755                 if ( this.flipY ) {
5756
5757                         uv.y = 1 - uv.y;
5758
5759                 }
5760
5761                 return uv;
5762
5763         }
5764
5765 } );
5766
5767 Object.defineProperty( Texture.prototype, 'needsUpdate', {
5768
5769         set: function ( value ) {
5770
5771                 if ( value === true ) this.version ++;
5772
5773         }
5774
5775 } );
5776
5777 function serializeImage( image ) {
5778
5779         if ( ( typeof HTMLImageElement !== 'undefined' && image instanceof HTMLImageElement ) ||
5780                 ( typeof HTMLCanvasElement !== 'undefined' && image instanceof HTMLCanvasElement ) ||
5781                 ( typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap ) ) {
5782
5783                 // default images
5784
5785                 return ImageUtils.getDataURL( image );
5786
5787         } else {
5788
5789                 if ( image.data ) {
5790
5791                         // images of DataTexture
5792
5793                         return {
5794                                 data: Array.prototype.slice.call( image.data ),
5795                                 width: image.width,
5796                                 height: image.height,
5797                                 type: image.data.constructor.name
5798                         };
5799
5800                 } else {
5801
5802                         console.warn( 'THREE.Texture: Unable to serialize Texture.' );
5803                         return {};
5804
5805                 }
5806
5807         }
5808
5809 }
5810
5811 class Vector4 {
5812
5813         constructor( x = 0, y = 0, z = 0, w = 1 ) {
5814
5815                 Object.defineProperty( this, 'isVector4', { value: true } );
5816
5817                 this.x = x;
5818                 this.y = y;
5819                 this.z = z;
5820                 this.w = w;
5821
5822         }
5823
5824         get width() {
5825
5826                 return this.z;
5827
5828         }
5829
5830         set width( value ) {
5831
5832                 this.z = value;
5833
5834         }
5835
5836         get height() {
5837
5838                 return this.w;
5839
5840         }
5841
5842         set height( value ) {
5843
5844                 this.w = value;
5845
5846         }
5847
5848         set( x, y, z, w ) {
5849
5850                 this.x = x;
5851                 this.y = y;
5852                 this.z = z;
5853                 this.w = w;
5854
5855                 return this;
5856
5857         }
5858
5859         setScalar( scalar ) {
5860
5861                 this.x = scalar;
5862                 this.y = scalar;
5863                 this.z = scalar;
5864                 this.w = scalar;
5865
5866                 return this;
5867
5868         }
5869
5870         setX( x ) {
5871
5872                 this.x = x;
5873
5874                 return this;
5875
5876         }
5877
5878         setY( y ) {
5879
5880                 this.y = y;
5881
5882                 return this;
5883
5884         }
5885
5886         setZ( z ) {
5887
5888                 this.z = z;
5889
5890                 return this;
5891
5892         }
5893
5894         setW( w ) {
5895
5896                 this.w = w;
5897
5898                 return this;
5899
5900         }
5901
5902         setComponent( index, value ) {
5903
5904                 switch ( index ) {
5905
5906                         case 0: this.x = value; break;
5907                         case 1: this.y = value; break;
5908                         case 2: this.z = value; break;
5909                         case 3: this.w = value; break;
5910                         default: throw new Error( 'index is out of range: ' + index );
5911
5912                 }
5913
5914                 return this;
5915
5916         }
5917
5918         getComponent( index ) {
5919
5920                 switch ( index ) {
5921
5922                         case 0: return this.x;
5923                         case 1: return this.y;
5924                         case 2: return this.z;
5925                         case 3: return this.w;
5926                         default: throw new Error( 'index is out of range: ' + index );
5927
5928                 }
5929
5930         }
5931
5932         clone() {
5933
5934                 return new this.constructor( this.x, this.y, this.z, this.w );
5935
5936         }
5937
5938         copy( v ) {
5939
5940                 this.x = v.x;
5941                 this.y = v.y;
5942                 this.z = v.z;
5943                 this.w = ( v.w !== undefined ) ? v.w : 1;
5944
5945                 return this;
5946
5947         }
5948
5949         add( v, w ) {
5950
5951                 if ( w !== undefined ) {
5952
5953                         console.warn( 'THREE.Vector4: .add() now only accepts one argument. Use .addVectors( a, b ) instead.' );
5954                         return this.addVectors( v, w );
5955
5956                 }
5957
5958                 this.x += v.x;
5959                 this.y += v.y;
5960                 this.z += v.z;
5961                 this.w += v.w;
5962
5963                 return this;
5964
5965         }
5966
5967         addScalar( s ) {
5968
5969                 this.x += s;
5970                 this.y += s;
5971                 this.z += s;
5972                 this.w += s;
5973
5974                 return this;
5975
5976         }
5977
5978         addVectors( a, b ) {
5979
5980                 this.x = a.x + b.x;
5981                 this.y = a.y + b.y;
5982                 this.z = a.z + b.z;
5983                 this.w = a.w + b.w;
5984
5985                 return this;
5986
5987         }
5988
5989         addScaledVector( v, s ) {
5990
5991                 this.x += v.x * s;
5992                 this.y += v.y * s;
5993                 this.z += v.z * s;
5994                 this.w += v.w * s;
5995
5996                 return this;
5997
5998         }
5999
6000         sub( v, w ) {
6001
6002                 if ( w !== undefined ) {
6003
6004                         console.warn( 'THREE.Vector4: .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' );
6005                         return this.subVectors( v, w );
6006
6007                 }
6008
6009                 this.x -= v.x;
6010                 this.y -= v.y;
6011                 this.z -= v.z;
6012                 this.w -= v.w;
6013
6014                 return this;
6015
6016         }
6017
6018         subScalar( s ) {
6019
6020                 this.x -= s;
6021                 this.y -= s;
6022                 this.z -= s;
6023                 this.w -= s;
6024
6025                 return this;
6026
6027         }
6028
6029         subVectors( a, b ) {
6030
6031                 this.x = a.x - b.x;
6032                 this.y = a.y - b.y;
6033                 this.z = a.z - b.z;
6034                 this.w = a.w - b.w;
6035
6036                 return this;
6037
6038         }
6039
6040         multiply( v ) {
6041
6042                 this.x *= v.x;
6043                 this.y *= v.y;
6044                 this.z *= v.z;
6045                 this.w *= v.w;
6046
6047                 return this;
6048
6049         }
6050
6051         multiplyScalar( scalar ) {
6052
6053                 this.x *= scalar;
6054                 this.y *= scalar;
6055                 this.z *= scalar;
6056                 this.w *= scalar;
6057
6058                 return this;
6059
6060         }
6061
6062         applyMatrix4( m ) {
6063
6064                 const x = this.x, y = this.y, z = this.z, w = this.w;
6065                 const e = m.elements;
6066
6067                 this.x = e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z + e[ 12 ] * w;
6068                 this.y = e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z + e[ 13 ] * w;
6069                 this.z = e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z + e[ 14 ] * w;
6070                 this.w = e[ 3 ] * x + e[ 7 ] * y + e[ 11 ] * z + e[ 15 ] * w;
6071
6072                 return this;
6073
6074         }
6075
6076         divideScalar( scalar ) {
6077
6078                 return this.multiplyScalar( 1 / scalar );
6079
6080         }
6081
6082         setAxisAngleFromQuaternion( q ) {
6083
6084                 // http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToAngle/index.htm
6085
6086                 // q is assumed to be normalized
6087
6088                 this.w = 2 * Math.acos( q.w );
6089
6090                 const s = Math.sqrt( 1 - q.w * q.w );
6091
6092                 if ( s < 0.0001 ) {
6093
6094                         this.x = 1;
6095                         this.y = 0;
6096                         this.z = 0;
6097
6098                 } else {
6099
6100                         this.x = q.x / s;
6101                         this.y = q.y / s;
6102                         this.z = q.z / s;
6103
6104                 }
6105
6106                 return this;
6107
6108         }
6109
6110         setAxisAngleFromRotationMatrix( m ) {
6111
6112                 // http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToAngle/index.htm
6113
6114                 // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)
6115
6116                 let angle, x, y, z; // variables for result
6117                 const epsilon = 0.01,           // margin to allow for rounding errors
6118                         epsilon2 = 0.1,         // margin to distinguish between 0 and 180 degrees
6119
6120                         te = m.elements,
6121
6122                         m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ],
6123                         m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ],
6124                         m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ];
6125
6126                 if ( ( Math.abs( m12 - m21 ) < epsilon ) &&
6127                      ( Math.abs( m13 - m31 ) < epsilon ) &&
6128                      ( Math.abs( m23 - m32 ) < epsilon ) ) {
6129
6130                         // singularity found
6131                         // first check for identity matrix which must have +1 for all terms
6132                         // in leading diagonal and zero in other terms
6133
6134                         if ( ( Math.abs( m12 + m21 ) < epsilon2 ) &&
6135                              ( Math.abs( m13 + m31 ) < epsilon2 ) &&
6136                              ( Math.abs( m23 + m32 ) < epsilon2 ) &&
6137                              ( Math.abs( m11 + m22 + m33 - 3 ) < epsilon2 ) ) {
6138
6139                                 // this singularity is identity matrix so angle = 0
6140
6141                                 this.set( 1, 0, 0, 0 );
6142
6143                                 return this; // zero angle, arbitrary axis
6144
6145                         }
6146
6147                         // otherwise this singularity is angle = 180
6148
6149                         angle = Math.PI;
6150
6151                         const xx = ( m11 + 1 ) / 2;
6152                         const yy = ( m22 + 1 ) / 2;
6153                         const zz = ( m33 + 1 ) / 2;
6154                         const xy = ( m12 + m21 ) / 4;
6155                         const xz = ( m13 + m31 ) / 4;
6156                         const yz = ( m23 + m32 ) / 4;
6157
6158                         if ( ( xx > yy ) && ( xx > zz ) ) {
6159
6160                                 // m11 is the largest diagonal term
6161
6162                                 if ( xx < epsilon ) {
6163
6164                                         x = 0;
6165                                         y = 0.707106781;
6166                                         z = 0.707106781;
6167
6168                                 } else {
6169
6170                                         x = Math.sqrt( xx );
6171                                         y = xy / x;
6172                                         z = xz / x;
6173
6174                                 }
6175
6176                         } else if ( yy > zz ) {
6177
6178                                 // m22 is the largest diagonal term
6179
6180                                 if ( yy < epsilon ) {
6181
6182                                         x = 0.707106781;
6183                                         y = 0;
6184                                         z = 0.707106781;
6185
6186                                 } else {
6187
6188                                         y = Math.sqrt( yy );
6189                                         x = xy / y;
6190                                         z = yz / y;
6191
6192                                 }
6193
6194                         } else {
6195
6196                                 // m33 is the largest diagonal term so base result on this
6197
6198                                 if ( zz < epsilon ) {
6199
6200                                         x = 0.707106781;
6201                                         y = 0.707106781;
6202                                         z = 0;
6203
6204                                 } else {
6205
6206                                         z = Math.sqrt( zz );
6207                                         x = xz / z;
6208                                         y = yz / z;
6209
6210                                 }
6211
6212                         }
6213
6214                         this.set( x, y, z, angle );
6215
6216                         return this; // return 180 deg rotation
6217
6218                 }
6219
6220                 // as we have reached here there are no singularities so we can handle normally
6221
6222                 let s = Math.sqrt( ( m32 - m23 ) * ( m32 - m23 ) +
6223                         ( m13 - m31 ) * ( m13 - m31 ) +
6224                         ( m21 - m12 ) * ( m21 - m12 ) ); // used to normalize
6225
6226                 if ( Math.abs( s ) < 0.001 ) s = 1;
6227
6228                 // prevent divide by zero, should not happen if matrix is orthogonal and should be
6229                 // caught by singularity test above, but I've left it in just in case
6230
6231                 this.x = ( m32 - m23 ) / s;
6232                 this.y = ( m13 - m31 ) / s;
6233                 this.z = ( m21 - m12 ) / s;
6234                 this.w = Math.acos( ( m11 + m22 + m33 - 1 ) / 2 );
6235
6236                 return this;
6237
6238         }
6239
6240         min( v ) {
6241
6242                 this.x = Math.min( this.x, v.x );
6243                 this.y = Math.min( this.y, v.y );
6244                 this.z = Math.min( this.z, v.z );
6245                 this.w = Math.min( this.w, v.w );
6246
6247                 return this;
6248
6249         }
6250
6251         max( v ) {
6252
6253                 this.x = Math.max( this.x, v.x );
6254                 this.y = Math.max( this.y, v.y );
6255                 this.z = Math.max( this.z, v.z );
6256                 this.w = Math.max( this.w, v.w );
6257
6258                 return this;
6259
6260         }
6261
6262         clamp( min, max ) {
6263
6264                 // assumes min < max, componentwise
6265
6266                 this.x = Math.max( min.x, Math.min( max.x, this.x ) );
6267                 this.y = Math.max( min.y, Math.min( max.y, this.y ) );
6268                 this.z = Math.max( min.z, Math.min( max.z, this.z ) );
6269                 this.w = Math.max( min.w, Math.min( max.w, this.w ) );
6270
6271                 return this;
6272
6273         }
6274
6275         clampScalar( minVal, maxVal ) {
6276
6277                 this.x = Math.max( minVal, Math.min( maxVal, this.x ) );
6278                 this.y = Math.max( minVal, Math.min( maxVal, this.y ) );
6279                 this.z = Math.max( minVal, Math.min( maxVal, this.z ) );
6280                 this.w = Math.max( minVal, Math.min( maxVal, this.w ) );
6281
6282                 return this;
6283
6284         }
6285
6286         clampLength( min, max ) {
6287
6288                 const length = this.length();
6289
6290                 return this.divideScalar( length || 1 ).multiplyScalar( Math.max( min, Math.min( max, length ) ) );
6291
6292         }
6293
6294         floor() {
6295
6296                 this.x = Math.floor( this.x );
6297                 this.y = Math.floor( this.y );
6298                 this.z = Math.floor( this.z );
6299                 this.w = Math.floor( this.w );
6300
6301                 return this;
6302
6303         }
6304
6305         ceil() {
6306
6307                 this.x = Math.ceil( this.x );
6308                 this.y = Math.ceil( this.y );
6309                 this.z = Math.ceil( this.z );
6310                 this.w = Math.ceil( this.w );
6311
6312                 return this;
6313
6314         }
6315
6316         round() {
6317
6318                 this.x = Math.round( this.x );
6319                 this.y = Math.round( this.y );
6320                 this.z = Math.round( this.z );
6321                 this.w = Math.round( this.w );
6322
6323                 return this;
6324
6325         }
6326
6327         roundToZero() {
6328
6329                 this.x = ( this.x < 0 ) ? Math.ceil( this.x ) : Math.floor( this.x );
6330                 this.y = ( this.y < 0 ) ? Math.ceil( this.y ) : Math.floor( this.y );
6331                 this.z = ( this.z < 0 ) ? Math.ceil( this.z ) : Math.floor( this.z );
6332                 this.w = ( this.w < 0 ) ? Math.ceil( this.w ) : Math.floor( this.w );
6333
6334                 return this;
6335
6336         }
6337
6338         negate() {
6339
6340                 this.x = - this.x;
6341                 this.y = - this.y;
6342                 this.z = - this.z;
6343                 this.w = - this.w;
6344
6345                 return this;
6346
6347         }
6348
6349         dot( v ) {
6350
6351                 return this.x * v.x + this.y * v.y + this.z * v.z + this.w * v.w;
6352
6353         }
6354
6355         lengthSq() {
6356
6357                 return this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w;
6358
6359         }
6360
6361         length() {
6362
6363                 return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w );
6364
6365         }
6366
6367         manhattanLength() {
6368
6369                 return Math.abs( this.x ) + Math.abs( this.y ) + Math.abs( this.z ) + Math.abs( this.w );
6370
6371         }
6372
6373         normalize() {
6374
6375                 return this.divideScalar( this.length() || 1 );
6376
6377         }
6378
6379         setLength( length ) {
6380
6381                 return this.normalize().multiplyScalar( length );
6382
6383         }
6384
6385         lerp( v, alpha ) {
6386
6387                 this.x += ( v.x - this.x ) * alpha;
6388                 this.y += ( v.y - this.y ) * alpha;
6389                 this.z += ( v.z - this.z ) * alpha;
6390                 this.w += ( v.w - this.w ) * alpha;
6391
6392                 return this;
6393
6394         }
6395
6396         lerpVectors( v1, v2, alpha ) {
6397
6398                 this.x = v1.x + ( v2.x - v1.x ) * alpha;
6399                 this.y = v1.y + ( v2.y - v1.y ) * alpha;
6400                 this.z = v1.z + ( v2.z - v1.z ) * alpha;
6401                 this.w = v1.w + ( v2.w - v1.w ) * alpha;
6402
6403                 return this;
6404
6405         }
6406
6407         equals( v ) {
6408
6409                 return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) && ( v.w === this.w ) );
6410
6411         }
6412
6413         fromArray( array, offset = 0 ) {
6414
6415                 this.x = array[ offset ];
6416                 this.y = array[ offset + 1 ];
6417                 this.z = array[ offset + 2 ];
6418                 this.w = array[ offset + 3 ];
6419
6420                 return this;
6421
6422         }
6423
6424         toArray( array = [], offset = 0 ) {
6425
6426                 array[ offset ] = this.x;
6427                 array[ offset + 1 ] = this.y;
6428                 array[ offset + 2 ] = this.z;
6429                 array[ offset + 3 ] = this.w;
6430
6431                 return array;
6432
6433         }
6434
6435         fromBufferAttribute( attribute, index, offset ) {
6436
6437                 if ( offset !== undefined ) {
6438
6439                         console.warn( 'THREE.Vector4: offset has been removed from .fromBufferAttribute().' );
6440
6441                 }
6442
6443                 this.x = attribute.getX( index );
6444                 this.y = attribute.getY( index );
6445                 this.z = attribute.getZ( index );
6446                 this.w = attribute.getW( index );
6447
6448                 return this;
6449
6450         }
6451
6452         random() {
6453
6454                 this.x = Math.random();
6455                 this.y = Math.random();
6456                 this.z = Math.random();
6457                 this.w = Math.random();
6458
6459                 return this;
6460
6461         }
6462
6463 }
6464
6465 /*
6466  In options, we can specify:
6467  * Texture parameters for an auto-generated target texture
6468  * depthBuffer/stencilBuffer: Booleans to indicate if we should generate these buffers
6469 */
6470 class WebGLRenderTarget extends EventDispatcher {
6471
6472         constructor( width, height, options ) {
6473
6474                 super();
6475
6476                 Object.defineProperty( this, 'isWebGLRenderTarget', { value: true } );
6477
6478                 this.width = width;
6479                 this.height = height;
6480
6481                 this.scissor = new Vector4( 0, 0, width, height );
6482                 this.scissorTest = false;
6483
6484                 this.viewport = new Vector4( 0, 0, width, height );
6485
6486                 options = options || {};
6487
6488                 this.texture = new Texture( undefined, options.mapping, options.wrapS, options.wrapT, options.magFilter, options.minFilter, options.format, options.type, options.anisotropy, options.encoding );
6489
6490                 this.texture.image = {};
6491                 this.texture.image.width = width;
6492                 this.texture.image.height = height;
6493
6494                 this.texture.generateMipmaps = options.generateMipmaps !== undefined ? options.generateMipmaps : false;
6495                 this.texture.minFilter = options.minFilter !== undefined ? options.minFilter : LinearFilter;
6496
6497                 this.depthBuffer = options.depthBuffer !== undefined ? options.depthBuffer : true;
6498                 this.stencilBuffer = options.stencilBuffer !== undefined ? options.stencilBuffer : false;
6499                 this.depthTexture = options.depthTexture !== undefined ? options.depthTexture : null;
6500
6501         }
6502
6503         setSize( width, height ) {
6504
6505                 if ( this.width !== width || this.height !== height ) {
6506
6507                         this.width = width;
6508                         this.height = height;
6509
6510                         this.texture.image.width = width;
6511                         this.texture.image.height = height;
6512
6513                         this.dispose();
6514
6515                 }
6516
6517                 this.viewport.set( 0, 0, width, height );
6518                 this.scissor.set( 0, 0, width, height );
6519
6520         }
6521
6522         clone() {
6523
6524                 return new this.constructor().copy( this );
6525
6526         }
6527
6528         copy( source ) {
6529
6530                 this.width = source.width;
6531                 this.height = source.height;
6532
6533                 this.viewport.copy( source.viewport );
6534
6535                 this.texture = source.texture.clone();
6536
6537                 this.depthBuffer = source.depthBuffer;
6538                 this.stencilBuffer = source.stencilBuffer;
6539                 this.depthTexture = source.depthTexture;
6540
6541                 return this;
6542
6543         }
6544
6545         dispose() {
6546
6547                 this.dispatchEvent( { type: 'dispose' } );
6548
6549         }
6550
6551 }
6552
6553 class Quaternion {
6554
6555         constructor( x = 0, y = 0, z = 0, w = 1 ) {
6556
6557                 Object.defineProperty( this, 'isQuaternion', { value: true } );
6558
6559                 this._x = x;
6560                 this._y = y;
6561                 this._z = z;
6562                 this._w = w;
6563
6564         }
6565
6566         static slerp( qa, qb, qm, t ) {
6567
6568                 return qm.copy( qa ).slerp( qb, t );
6569
6570         }
6571
6572         static slerpFlat( dst, dstOffset, src0, srcOffset0, src1, srcOffset1, t ) {
6573
6574                 // fuzz-free, array-based Quaternion SLERP operation
6575
6576                 let x0 = src0[ srcOffset0 + 0 ],
6577                         y0 = src0[ srcOffset0 + 1 ],
6578                         z0 = src0[ srcOffset0 + 2 ],
6579                         w0 = src0[ srcOffset0 + 3 ];
6580
6581                 const x1 = src1[ srcOffset1 + 0 ],
6582                         y1 = src1[ srcOffset1 + 1 ],
6583                         z1 = src1[ srcOffset1 + 2 ],
6584                         w1 = src1[ srcOffset1 + 3 ];
6585
6586                 if ( w0 !== w1 || x0 !== x1 || y0 !== y1 || z0 !== z1 ) {
6587
6588                         let s = 1 - t;
6589                         const cos = x0 * x1 + y0 * y1 + z0 * z1 + w0 * w1,
6590                                 dir = ( cos >= 0 ? 1 : - 1 ),
6591                                 sqrSin = 1 - cos * cos;
6592
6593                         // Skip the Slerp for tiny steps to avoid numeric problems:
6594                         if ( sqrSin > Number.EPSILON ) {
6595
6596                                 const sin = Math.sqrt( sqrSin ),
6597                                         len = Math.atan2( sin, cos * dir );
6598
6599                                 s = Math.sin( s * len ) / sin;
6600                                 t = Math.sin( t * len ) / sin;
6601
6602                         }
6603
6604                         const tDir = t * dir;
6605
6606                         x0 = x0 * s + x1 * tDir;
6607                         y0 = y0 * s + y1 * tDir;
6608                         z0 = z0 * s + z1 * tDir;
6609                         w0 = w0 * s + w1 * tDir;
6610
6611                         // Normalize in case we just did a lerp:
6612                         if ( s === 1 - t ) {
6613
6614                                 const f = 1 / Math.sqrt( x0 * x0 + y0 * y0 + z0 * z0 + w0 * w0 );
6615
6616                                 x0 *= f;
6617                                 y0 *= f;
6618                                 z0 *= f;
6619                                 w0 *= f;
6620
6621                         }
6622
6623                 }
6624
6625                 dst[ dstOffset ] = x0;
6626                 dst[ dstOffset + 1 ] = y0;
6627                 dst[ dstOffset + 2 ] = z0;
6628                 dst[ dstOffset + 3 ] = w0;
6629
6630         }
6631
6632         static multiplyQuaternionsFlat( dst, dstOffset, src0, srcOffset0, src1, srcOffset1 ) {
6633
6634                 const x0 = src0[ srcOffset0 ];
6635                 const y0 = src0[ srcOffset0 + 1 ];
6636                 const z0 = src0[ srcOffset0 + 2 ];
6637                 const w0 = src0[ srcOffset0 + 3 ];
6638
6639                 const x1 = src1[ srcOffset1 ];
6640                 const y1 = src1[ srcOffset1 + 1 ];
6641                 const z1 = src1[ srcOffset1 + 2 ];
6642                 const w1 = src1[ srcOffset1 + 3 ];
6643
6644                 dst[ dstOffset ] = x0 * w1 + w0 * x1 + y0 * z1 - z0 * y1;
6645                 dst[ dstOffset + 1 ] = y0 * w1 + w0 * y1 + z0 * x1 - x0 * z1;
6646                 dst[ dstOffset + 2 ] = z0 * w1 + w0 * z1 + x0 * y1 - y0 * x1;
6647                 dst[ dstOffset + 3 ] = w0 * w1 - x0 * x1 - y0 * y1 - z0 * z1;
6648
6649                 return dst;
6650
6651         }
6652
6653         get x() {
6654
6655                 return this._x;
6656
6657         }
6658
6659         set x( value ) {
6660
6661                 this._x = value;
6662                 this._onChangeCallback();
6663
6664         }
6665
6666         get y() {
6667
6668                 return this._y;
6669
6670         }
6671
6672         set y( value ) {
6673
6674                 this._y = value;
6675                 this._onChangeCallback();
6676
6677         }
6678
6679         get z() {
6680
6681                 return this._z;
6682
6683         }
6684
6685         set z( value ) {
6686
6687                 this._z = value;
6688                 this._onChangeCallback();
6689
6690         }
6691
6692         get w() {
6693
6694                 return this._w;
6695
6696         }
6697
6698         set w( value ) {
6699
6700                 this._w = value;
6701                 this._onChangeCallback();
6702
6703         }
6704
6705         set( x, y, z, w ) {
6706
6707                 this._x = x;
6708                 this._y = y;
6709                 this._z = z;
6710                 this._w = w;
6711
6712                 this._onChangeCallback();
6713
6714                 return this;
6715
6716         }
6717
6718         clone() {
6719
6720                 return new this.constructor( this._x, this._y, this._z, this._w );
6721
6722         }
6723
6724         copy( quaternion ) {
6725
6726                 this._x = quaternion.x;
6727                 this._y = quaternion.y;
6728                 this._z = quaternion.z;
6729                 this._w = quaternion.w;
6730
6731                 this._onChangeCallback();
6732
6733                 return this;
6734
6735         }
6736
6737         setFromEuler( euler, update ) {
6738
6739                 if ( ! ( euler && euler.isEuler ) ) {
6740
6741                         throw new Error( 'THREE.Quaternion: .setFromEuler() now expects an Euler rotation rather than a Vector3 and order.' );
6742
6743                 }
6744
6745                 const x = euler._x, y = euler._y, z = euler._z, order = euler._order;
6746
6747                 // http://www.mathworks.com/matlabcentral/fileexchange/
6748                 //      20696-function-to-convert-between-dcm-euler-angles-quaternions-and-euler-vectors/
6749                 //      content/SpinCalc.m
6750
6751                 const cos = Math.cos;
6752                 const sin = Math.sin;
6753
6754                 const c1 = cos( x / 2 );
6755                 const c2 = cos( y / 2 );
6756                 const c3 = cos( z / 2 );
6757
6758                 const s1 = sin( x / 2 );
6759                 const s2 = sin( y / 2 );
6760                 const s3 = sin( z / 2 );
6761
6762                 switch ( order ) {
6763
6764                         case 'XYZ':
6765                                 this._x = s1 * c2 * c3 + c1 * s2 * s3;
6766                                 this._y = c1 * s2 * c3 - s1 * c2 * s3;
6767                                 this._z = c1 * c2 * s3 + s1 * s2 * c3;
6768                                 this._w = c1 * c2 * c3 - s1 * s2 * s3;
6769                                 break;
6770
6771                         case 'YXZ':
6772                                 this._x = s1 * c2 * c3 + c1 * s2 * s3;
6773                                 this._y = c1 * s2 * c3 - s1 * c2 * s3;
6774                                 this._z = c1 * c2 * s3 - s1 * s2 * c3;
6775                                 this._w = c1 * c2 * c3 + s1 * s2 * s3;
6776                                 break;
6777
6778                         case 'ZXY':
6779                                 this._x = s1 * c2 * c3 - c1 * s2 * s3;
6780                                 this._y = c1 * s2 * c3 + s1 * c2 * s3;
6781                                 this._z = c1 * c2 * s3 + s1 * s2 * c3;
6782                                 this._w = c1 * c2 * c3 - s1 * s2 * s3;
6783                                 break;
6784
6785                         case 'ZYX':
6786                                 this._x = s1 * c2 * c3 - c1 * s2 * s3;
6787                                 this._y = c1 * s2 * c3 + s1 * c2 * s3;
6788                                 this._z = c1 * c2 * s3 - s1 * s2 * c3;
6789                                 this._w = c1 * c2 * c3 + s1 * s2 * s3;
6790                                 break;
6791
6792                         case 'YZX':
6793                                 this._x = s1 * c2 * c3 + c1 * s2 * s3;
6794                                 this._y = c1 * s2 * c3 + s1 * c2 * s3;
6795                                 this._z = c1 * c2 * s3 - s1 * s2 * c3;
6796                                 this._w = c1 * c2 * c3 - s1 * s2 * s3;
6797                                 break;
6798
6799                         case 'XZY':
6800                                 this._x = s1 * c2 * c3 - c1 * s2 * s3;
6801                                 this._y = c1 * s2 * c3 - s1 * c2 * s3;
6802                                 this._z = c1 * c2 * s3 + s1 * s2 * c3;
6803                                 this._w = c1 * c2 * c3 + s1 * s2 * s3;
6804                                 break;
6805
6806                         default:
6807                                 console.warn( 'THREE.Quaternion: .setFromEuler() encountered an unknown order: ' + order );
6808
6809                 }
6810
6811                 if ( update !== false ) this._onChangeCallback();
6812
6813                 return this;
6814
6815         }
6816
6817         setFromAxisAngle( axis, angle ) {
6818
6819                 // http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToQuaternion/index.htm
6820
6821                 // assumes axis is normalized
6822
6823                 const halfAngle = angle / 2, s = Math.sin( halfAngle );
6824
6825                 this._x = axis.x * s;
6826                 this._y = axis.y * s;
6827                 this._z = axis.z * s;
6828                 this._w = Math.cos( halfAngle );
6829
6830                 this._onChangeCallback();
6831
6832                 return this;
6833
6834         }
6835
6836         setFromRotationMatrix( m ) {
6837
6838                 // http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm
6839
6840                 // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)
6841
6842                 const te = m.elements,
6843
6844                         m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ],
6845                         m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ],
6846                         m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ],
6847
6848                         trace = m11 + m22 + m33;
6849
6850                 if ( trace > 0 ) {
6851
6852                         const s = 0.5 / Math.sqrt( trace + 1.0 );
6853
6854                         this._w = 0.25 / s;
6855                         this._x = ( m32 - m23 ) * s;
6856                         this._y = ( m13 - m31 ) * s;
6857                         this._z = ( m21 - m12 ) * s;
6858
6859                 } else if ( m11 > m22 && m11 > m33 ) {
6860
6861                         const s = 2.0 * Math.sqrt( 1.0 + m11 - m22 - m33 );
6862
6863                         this._w = ( m32 - m23 ) / s;
6864                         this._x = 0.25 * s;
6865                         this._y = ( m12 + m21 ) / s;
6866                         this._z = ( m13 + m31 ) / s;
6867
6868                 } else if ( m22 > m33 ) {
6869
6870                         const s = 2.0 * Math.sqrt( 1.0 + m22 - m11 - m33 );
6871
6872                         this._w = ( m13 - m31 ) / s;
6873                         this._x = ( m12 + m21 ) / s;
6874                         this._y = 0.25 * s;
6875                         this._z = ( m23 + m32 ) / s;
6876
6877                 } else {
6878
6879                         const s = 2.0 * Math.sqrt( 1.0 + m33 - m11 - m22 );
6880
6881                         this._w = ( m21 - m12 ) / s;
6882                         this._x = ( m13 + m31 ) / s;
6883                         this._y = ( m23 + m32 ) / s;
6884                         this._z = 0.25 * s;
6885
6886                 }
6887
6888                 this._onChangeCallback();
6889
6890                 return this;
6891
6892         }
6893
6894         setFromUnitVectors( vFrom, vTo ) {
6895
6896                 // assumes direction vectors vFrom and vTo are normalized
6897
6898                 const EPS = 0.000001;
6899
6900                 let r = vFrom.dot( vTo ) + 1;
6901
6902                 if ( r < EPS ) {
6903
6904                         r = 0;
6905
6906                         if ( Math.abs( vFrom.x ) > Math.abs( vFrom.z ) ) {
6907
6908                                 this._x = - vFrom.y;
6909                                 this._y = vFrom.x;
6910                                 this._z = 0;
6911                                 this._w = r;
6912
6913                         } else {
6914
6915                                 this._x = 0;
6916                                 this._y = - vFrom.z;
6917                                 this._z = vFrom.y;
6918                                 this._w = r;
6919
6920                         }
6921
6922                 } else {
6923
6924                         // crossVectors( vFrom, vTo ); // inlined to avoid cyclic dependency on Vector3
6925
6926                         this._x = vFrom.y * vTo.z - vFrom.z * vTo.y;
6927                         this._y = vFrom.z * vTo.x - vFrom.x * vTo.z;
6928                         this._z = vFrom.x * vTo.y - vFrom.y * vTo.x;
6929                         this._w = r;
6930
6931                 }
6932
6933                 return this.normalize();
6934
6935         }
6936
6937         angleTo( q ) {
6938
6939                 return 2 * Math.acos( Math.abs( MathUtils.clamp( this.dot( q ), - 1, 1 ) ) );
6940
6941         }
6942
6943         rotateTowards( q, step ) {
6944
6945                 const angle = this.angleTo( q );
6946
6947                 if ( angle === 0 ) return this;
6948
6949                 const t = Math.min( 1, step / angle );
6950
6951                 this.slerp( q, t );
6952
6953                 return this;
6954
6955         }
6956
6957         identity() {
6958
6959                 return this.set( 0, 0, 0, 1 );
6960
6961         }
6962
6963         invert() {
6964
6965                 // quaternion is assumed to have unit length
6966
6967                 return this.conjugate();
6968
6969         }
6970
6971         conjugate() {
6972
6973                 this._x *= - 1;
6974                 this._y *= - 1;
6975                 this._z *= - 1;
6976
6977                 this._onChangeCallback();
6978
6979                 return this;
6980
6981         }
6982
6983         dot( v ) {
6984
6985                 return this._x * v._x + this._y * v._y + this._z * v._z + this._w * v._w;
6986
6987         }
6988
6989         lengthSq() {
6990
6991                 return this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w;
6992
6993         }
6994
6995         length() {
6996
6997                 return Math.sqrt( this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w );
6998
6999         }
7000
7001         normalize() {
7002
7003                 let l = this.length();
7004
7005                 if ( l === 0 ) {
7006
7007                         this._x = 0;
7008                         this._y = 0;
7009                         this._z = 0;
7010                         this._w = 1;
7011
7012                 } else {
7013
7014                         l = 1 / l;
7015
7016                         this._x = this._x * l;
7017                         this._y = this._y * l;
7018                         this._z = this._z * l;
7019                         this._w = this._w * l;
7020
7021                 }
7022
7023                 this._onChangeCallback();
7024
7025                 return this;
7026
7027         }
7028
7029         multiply( q, p ) {
7030
7031                 if ( p !== undefined ) {
7032
7033                         console.warn( 'THREE.Quaternion: .multiply() now only accepts one argument. Use .multiplyQuaternions( a, b ) instead.' );
7034                         return this.multiplyQuaternions( q, p );
7035
7036                 }
7037
7038                 return this.multiplyQuaternions( this, q );
7039
7040         }
7041
7042         premultiply( q ) {
7043
7044                 return this.multiplyQuaternions( q, this );
7045
7046         }
7047
7048         multiplyQuaternions( a, b ) {
7049
7050                 // from http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/code/index.htm
7051
7052                 const qax = a._x, qay = a._y, qaz = a._z, qaw = a._w;
7053                 const qbx = b._x, qby = b._y, qbz = b._z, qbw = b._w;
7054
7055                 this._x = qax * qbw + qaw * qbx + qay * qbz - qaz * qby;
7056                 this._y = qay * qbw + qaw * qby + qaz * qbx - qax * qbz;
7057                 this._z = qaz * qbw + qaw * qbz + qax * qby - qay * qbx;
7058                 this._w = qaw * qbw - qax * qbx - qay * qby - qaz * qbz;
7059
7060                 this._onChangeCallback();
7061
7062                 return this;
7063
7064         }
7065
7066         slerp( qb, t ) {
7067
7068                 if ( t === 0 ) return this;
7069                 if ( t === 1 ) return this.copy( qb );
7070
7071                 const x = this._x, y = this._y, z = this._z, w = this._w;
7072
7073                 // http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/slerp/
7074
7075                 let cosHalfTheta = w * qb._w + x * qb._x + y * qb._y + z * qb._z;
7076
7077                 if ( cosHalfTheta < 0 ) {
7078
7079                         this._w = - qb._w;
7080                         this._x = - qb._x;
7081                         this._y = - qb._y;
7082                         this._z = - qb._z;
7083
7084                         cosHalfTheta = - cosHalfTheta;
7085
7086                 } else {
7087
7088                         this.copy( qb );
7089
7090                 }
7091
7092                 if ( cosHalfTheta >= 1.0 ) {
7093
7094                         this._w = w;
7095                         this._x = x;
7096                         this._y = y;
7097                         this._z = z;
7098
7099                         return this;
7100
7101                 }
7102
7103                 const sqrSinHalfTheta = 1.0 - cosHalfTheta * cosHalfTheta;
7104
7105                 if ( sqrSinHalfTheta <= Number.EPSILON ) {
7106
7107                         const s = 1 - t;
7108                         this._w = s * w + t * this._w;
7109                         this._x = s * x + t * this._x;
7110                         this._y = s * y + t * this._y;
7111                         this._z = s * z + t * this._z;
7112
7113                         this.normalize();
7114                         this._onChangeCallback();
7115
7116                         return this;
7117
7118                 }
7119
7120                 const sinHalfTheta = Math.sqrt( sqrSinHalfTheta );
7121                 const halfTheta = Math.atan2( sinHalfTheta, cosHalfTheta );
7122                 const ratioA = Math.sin( ( 1 - t ) * halfTheta ) / sinHalfTheta,
7123                         ratioB = Math.sin( t * halfTheta ) / sinHalfTheta;
7124
7125                 this._w = ( w * ratioA + this._w * ratioB );
7126                 this._x = ( x * ratioA + this._x * ratioB );
7127                 this._y = ( y * ratioA + this._y * ratioB );
7128                 this._z = ( z * ratioA + this._z * ratioB );
7129
7130                 this._onChangeCallback();
7131
7132                 return this;
7133
7134         }
7135
7136         equals( quaternion ) {
7137
7138                 return ( quaternion._x === this._x ) && ( quaternion._y === this._y ) && ( quaternion._z === this._z ) && ( quaternion._w === this._w );
7139
7140         }
7141
7142         fromArray( array, offset = 0 ) {
7143
7144                 this._x = array[ offset ];
7145                 this._y = array[ offset + 1 ];
7146                 this._z = array[ offset + 2 ];
7147                 this._w = array[ offset + 3 ];
7148
7149                 this._onChangeCallback();
7150
7151                 return this;
7152
7153         }
7154
7155         toArray( array = [], offset = 0 ) {
7156
7157                 array[ offset ] = this._x;
7158                 array[ offset + 1 ] = this._y;
7159                 array[ offset + 2 ] = this._z;
7160                 array[ offset + 3 ] = this._w;
7161
7162                 return array;
7163
7164         }
7165
7166         fromBufferAttribute( attribute, index ) {
7167
7168                 this._x = attribute.getX( index );
7169                 this._y = attribute.getY( index );
7170                 this._z = attribute.getZ( index );
7171                 this._w = attribute.getW( index );
7172
7173                 return this;
7174
7175         }
7176
7177         _onChange( callback ) {
7178
7179                 this._onChangeCallback = callback;
7180
7181                 return this;
7182
7183         }
7184
7185         _onChangeCallback() {}
7186
7187 }
7188
7189 class Vector3 {
7190
7191         constructor( x = 0, y = 0, z = 0 ) {
7192
7193                 Object.defineProperty( this, 'isVector3', { value: true } );
7194
7195                 this.x = x;
7196                 this.y = y;
7197                 this.z = z;
7198
7199         }
7200
7201         set( x, y, z ) {
7202
7203                 if ( z === undefined ) z = this.z; // sprite.scale.set(x,y)
7204
7205                 this.x = x;
7206                 this.y = y;
7207                 this.z = z;
7208
7209                 return this;
7210
7211         }
7212
7213         setScalar( scalar ) {
7214
7215                 this.x = scalar;
7216                 this.y = scalar;
7217                 this.z = scalar;
7218
7219                 return this;
7220
7221         }
7222
7223         setX( x ) {
7224
7225                 this.x = x;
7226
7227                 return this;
7228
7229         }
7230
7231         setY( y ) {
7232
7233                 this.y = y;
7234
7235                 return this;
7236
7237         }
7238
7239         setZ( z ) {
7240
7241                 this.z = z;
7242
7243                 return this;
7244
7245         }
7246
7247         setComponent( index, value ) {
7248
7249                 switch ( index ) {
7250
7251                         case 0: this.x = value; break;
7252                         case 1: this.y = value; break;
7253                         case 2: this.z = value; break;
7254                         default: throw new Error( 'index is out of range: ' + index );
7255
7256                 }
7257
7258                 return this;
7259
7260         }
7261
7262         getComponent( index ) {
7263
7264                 switch ( index ) {
7265
7266                         case 0: return this.x;
7267                         case 1: return this.y;
7268                         case 2: return this.z;
7269                         default: throw new Error( 'index is out of range: ' + index );
7270
7271                 }
7272
7273         }
7274
7275         clone() {
7276
7277                 return new this.constructor( this.x, this.y, this.z );
7278
7279         }
7280
7281         copy( v ) {
7282
7283                 this.x = v.x;
7284                 this.y = v.y;
7285                 this.z = v.z;
7286
7287                 return this;
7288
7289         }
7290
7291         add( v, w ) {
7292
7293                 if ( w !== undefined ) {
7294
7295                         console.warn( 'THREE.Vector3: .add() now only accepts one argument. Use .addVectors( a, b ) instead.' );
7296                         return this.addVectors( v, w );
7297
7298                 }
7299
7300                 this.x += v.x;
7301                 this.y += v.y;
7302                 this.z += v.z;
7303
7304                 return this;
7305
7306         }
7307
7308         addScalar( s ) {
7309
7310                 this.x += s;
7311                 this.y += s;
7312                 this.z += s;
7313
7314                 return this;
7315
7316         }
7317
7318         addVectors( a, b ) {
7319
7320                 this.x = a.x + b.x;
7321                 this.y = a.y + b.y;
7322                 this.z = a.z + b.z;
7323
7324                 return this;
7325
7326         }
7327
7328         addScaledVector( v, s ) {
7329
7330                 this.x += v.x * s;
7331                 this.y += v.y * s;
7332                 this.z += v.z * s;
7333
7334                 return this;
7335
7336         }
7337
7338         sub( v, w ) {
7339
7340                 if ( w !== undefined ) {
7341
7342                         console.warn( 'THREE.Vector3: .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' );
7343                         return this.subVectors( v, w );
7344
7345                 }
7346
7347                 this.x -= v.x;
7348                 this.y -= v.y;
7349                 this.z -= v.z;
7350
7351                 return this;
7352
7353         }
7354
7355         subScalar( s ) {
7356
7357                 this.x -= s;
7358                 this.y -= s;
7359                 this.z -= s;
7360
7361                 return this;
7362
7363         }
7364
7365         subVectors( a, b ) {
7366
7367                 this.x = a.x - b.x;
7368                 this.y = a.y - b.y;
7369                 this.z = a.z - b.z;
7370
7371                 return this;
7372
7373         }
7374
7375         multiply( v, w ) {
7376
7377                 if ( w !== undefined ) {
7378
7379                         console.warn( 'THREE.Vector3: .multiply() now only accepts one argument. Use .multiplyVectors( a, b ) instead.' );
7380                         return this.multiplyVectors( v, w );
7381
7382                 }
7383
7384                 this.x *= v.x;
7385                 this.y *= v.y;
7386                 this.z *= v.z;
7387
7388                 return this;
7389
7390         }
7391
7392         multiplyScalar( scalar ) {
7393
7394                 this.x *= scalar;
7395                 this.y *= scalar;
7396                 this.z *= scalar;
7397
7398                 return this;
7399
7400         }
7401
7402         multiplyVectors( a, b ) {
7403
7404                 this.x = a.x * b.x;
7405                 this.y = a.y * b.y;
7406                 this.z = a.z * b.z;
7407
7408                 return this;
7409
7410         }
7411
7412         applyEuler( euler ) {
7413
7414                 if ( ! ( euler && euler.isEuler ) ) {
7415
7416                         console.error( 'THREE.Vector3: .applyEuler() now expects an Euler rotation rather than a Vector3 and order.' );
7417
7418                 }
7419
7420                 return this.applyQuaternion( _quaternion.setFromEuler( euler ) );
7421
7422         }
7423
7424         applyAxisAngle( axis, angle ) {
7425
7426                 return this.applyQuaternion( _quaternion.setFromAxisAngle( axis, angle ) );
7427
7428         }
7429
7430         applyMatrix3( m ) {
7431
7432                 const x = this.x, y = this.y, z = this.z;
7433                 const e = m.elements;
7434
7435                 this.x = e[ 0 ] * x + e[ 3 ] * y + e[ 6 ] * z;
7436                 this.y = e[ 1 ] * x + e[ 4 ] * y + e[ 7 ] * z;
7437                 this.z = e[ 2 ] * x + e[ 5 ] * y + e[ 8 ] * z;
7438
7439                 return this;
7440
7441         }
7442
7443         applyNormalMatrix( m ) {
7444
7445                 return this.applyMatrix3( m ).normalize();
7446
7447         }
7448
7449         applyMatrix4( m ) {
7450
7451                 const x = this.x, y = this.y, z = this.z;
7452                 const e = m.elements;
7453
7454                 const w = 1 / ( e[ 3 ] * x + e[ 7 ] * y + e[ 11 ] * z + e[ 15 ] );
7455
7456                 this.x = ( e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z + e[ 12 ] ) * w;
7457                 this.y = ( e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z + e[ 13 ] ) * w;
7458                 this.z = ( e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z + e[ 14 ] ) * w;
7459
7460                 return this;
7461
7462         }
7463
7464         applyQuaternion( q ) {
7465
7466                 const x = this.x, y = this.y, z = this.z;
7467                 const qx = q.x, qy = q.y, qz = q.z, qw = q.w;
7468
7469                 // calculate quat * vector
7470
7471                 const ix = qw * x + qy * z - qz * y;
7472                 const iy = qw * y + qz * x - qx * z;
7473                 const iz = qw * z + qx * y - qy * x;
7474                 const iw = - qx * x - qy * y - qz * z;
7475
7476                 // calculate result * inverse quat
7477
7478                 this.x = ix * qw + iw * - qx + iy * - qz - iz * - qy;
7479                 this.y = iy * qw + iw * - qy + iz * - qx - ix * - qz;
7480                 this.z = iz * qw + iw * - qz + ix * - qy - iy * - qx;
7481
7482                 return this;
7483
7484         }
7485
7486         project( camera ) {
7487
7488                 return this.applyMatrix4( camera.matrixWorldInverse ).applyMatrix4( camera.projectionMatrix );
7489
7490         }
7491
7492         unproject( camera ) {
7493
7494                 return this.applyMatrix4( camera.projectionMatrixInverse ).applyMatrix4( camera.matrixWorld );
7495
7496         }
7497
7498         transformDirection( m ) {
7499
7500                 // input: THREE.Matrix4 affine matrix
7501                 // vector interpreted as a direction
7502
7503                 const x = this.x, y = this.y, z = this.z;
7504                 const e = m.elements;
7505
7506                 this.x = e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z;
7507                 this.y = e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z;
7508                 this.z = e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z;
7509
7510                 return this.normalize();
7511
7512         }
7513
7514         divide( v ) {
7515
7516                 this.x /= v.x;
7517                 this.y /= v.y;
7518                 this.z /= v.z;
7519
7520                 return this;
7521
7522         }
7523
7524         divideScalar( scalar ) {
7525
7526                 return this.multiplyScalar( 1 / scalar );
7527
7528         }
7529
7530         min( v ) {
7531
7532                 this.x = Math.min( this.x, v.x );
7533                 this.y = Math.min( this.y, v.y );
7534                 this.z = Math.min( this.z, v.z );
7535
7536                 return this;
7537
7538         }
7539
7540         max( v ) {
7541
7542                 this.x = Math.max( this.x, v.x );
7543                 this.y = Math.max( this.y, v.y );
7544                 this.z = Math.max( this.z, v.z );
7545
7546                 return this;
7547
7548         }
7549
7550         clamp( min, max ) {
7551
7552                 // assumes min < max, componentwise
7553
7554                 this.x = Math.max( min.x, Math.min( max.x, this.x ) );
7555                 this.y = Math.max( min.y, Math.min( max.y, this.y ) );
7556                 this.z = Math.max( min.z, Math.min( max.z, this.z ) );
7557
7558                 return this;
7559
7560         }
7561
7562         clampScalar( minVal, maxVal ) {
7563
7564                 this.x = Math.max( minVal, Math.min( maxVal, this.x ) );
7565                 this.y = Math.max( minVal, Math.min( maxVal, this.y ) );
7566                 this.z = Math.max( minVal, Math.min( maxVal, this.z ) );
7567
7568                 return this;
7569
7570         }
7571
7572         clampLength( min, max ) {
7573
7574                 const length = this.length();
7575
7576                 return this.divideScalar( length || 1 ).multiplyScalar( Math.max( min, Math.min( max, length ) ) );
7577
7578         }
7579
7580         floor() {
7581
7582                 this.x = Math.floor( this.x );
7583                 this.y = Math.floor( this.y );
7584                 this.z = Math.floor( this.z );
7585
7586                 return this;
7587
7588         }
7589
7590         ceil() {
7591
7592                 this.x = Math.ceil( this.x );
7593                 this.y = Math.ceil( this.y );
7594                 this.z = Math.ceil( this.z );
7595
7596                 return this;
7597
7598         }
7599
7600         round() {
7601
7602                 this.x = Math.round( this.x );
7603                 this.y = Math.round( this.y );
7604                 this.z = Math.round( this.z );
7605
7606                 return this;
7607
7608         }
7609
7610         roundToZero() {
7611
7612                 this.x = ( this.x < 0 ) ? Math.ceil( this.x ) : Math.floor( this.x );
7613                 this.y = ( this.y < 0 ) ? Math.ceil( this.y ) : Math.floor( this.y );
7614                 this.z = ( this.z < 0 ) ? Math.ceil( this.z ) : Math.floor( this.z );
7615
7616                 return this;
7617
7618         }
7619
7620         negate() {
7621
7622                 this.x = - this.x;
7623                 this.y = - this.y;
7624                 this.z = - this.z;
7625
7626                 return this;
7627
7628         }
7629
7630         dot( v ) {
7631
7632                 return this.x * v.x + this.y * v.y + this.z * v.z;
7633
7634         }
7635
7636         // TODO lengthSquared?
7637
7638         lengthSq() {
7639
7640                 return this.x * this.x + this.y * this.y + this.z * this.z;
7641
7642         }
7643
7644         length() {
7645
7646                 return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z );
7647
7648         }
7649
7650         manhattanLength() {
7651
7652                 return Math.abs( this.x ) + Math.abs( this.y ) + Math.abs( this.z );
7653
7654         }
7655
7656         normalize() {
7657
7658                 return this.divideScalar( this.length() || 1 );
7659
7660         }
7661
7662         setLength( length ) {
7663
7664                 return this.normalize().multiplyScalar( length );
7665
7666         }
7667
7668         lerp( v, alpha ) {
7669
7670                 this.x += ( v.x - this.x ) * alpha;
7671                 this.y += ( v.y - this.y ) * alpha;
7672                 this.z += ( v.z - this.z ) * alpha;
7673
7674                 return this;
7675
7676         }
7677
7678         lerpVectors( v1, v2, alpha ) {
7679
7680                 this.x = v1.x + ( v2.x - v1.x ) * alpha;
7681                 this.y = v1.y + ( v2.y - v1.y ) * alpha;
7682                 this.z = v1.z + ( v2.z - v1.z ) * alpha;
7683
7684                 return this;
7685
7686         }
7687
7688         cross( v, w ) {
7689
7690                 if ( w !== undefined ) {
7691
7692                         console.warn( 'THREE.Vector3: .cross() now only accepts one argument. Use .crossVectors( a, b ) instead.' );
7693                         return this.crossVectors( v, w );
7694
7695                 }
7696
7697                 return this.crossVectors( this, v );
7698
7699         }
7700
7701         crossVectors( a, b ) {
7702
7703                 const ax = a.x, ay = a.y, az = a.z;
7704                 const bx = b.x, by = b.y, bz = b.z;
7705
7706                 this.x = ay * bz - az * by;
7707                 this.y = az * bx - ax * bz;
7708                 this.z = ax * by - ay * bx;
7709
7710                 return this;
7711
7712         }
7713
7714         projectOnVector( v ) {
7715
7716                 const denominator = v.lengthSq();
7717
7718                 if ( denominator === 0 ) return this.set( 0, 0, 0 );
7719
7720                 const scalar = v.dot( this ) / denominator;
7721
7722                 return this.copy( v ).multiplyScalar( scalar );
7723
7724         }
7725
7726         projectOnPlane( planeNormal ) {
7727
7728                 _vector.copy( this ).projectOnVector( planeNormal );
7729
7730                 return this.sub( _vector );
7731
7732         }
7733
7734         reflect( normal ) {
7735
7736                 // reflect incident vector off plane orthogonal to normal
7737                 // normal is assumed to have unit length
7738
7739                 return this.sub( _vector.copy( normal ).multiplyScalar( 2 * this.dot( normal ) ) );
7740
7741         }
7742
7743         angleTo( v ) {
7744
7745                 const denominator = Math.sqrt( this.lengthSq() * v.lengthSq() );
7746
7747                 if ( denominator === 0 ) return Math.PI / 2;
7748
7749                 const theta = this.dot( v ) / denominator;
7750
7751                 // clamp, to handle numerical problems
7752
7753                 return Math.acos( MathUtils.clamp( theta, - 1, 1 ) );
7754
7755         }
7756
7757         distanceTo( v ) {
7758
7759                 return Math.sqrt( this.distanceToSquared( v ) );
7760
7761         }
7762
7763         distanceToSquared( v ) {
7764
7765                 const dx = this.x - v.x, dy = this.y - v.y, dz = this.z - v.z;
7766
7767                 return dx * dx + dy * dy + dz * dz;
7768
7769         }
7770
7771         manhattanDistanceTo( v ) {
7772
7773                 return Math.abs( this.x - v.x ) + Math.abs( this.y - v.y ) + Math.abs( this.z - v.z );
7774
7775         }
7776
7777         setFromSpherical( s ) {
7778
7779                 return this.setFromSphericalCoords( s.radius, s.phi, s.theta );
7780
7781         }
7782
7783         setFromSphericalCoords( radius, phi, theta ) {
7784
7785                 const sinPhiRadius = Math.sin( phi ) * radius;
7786
7787                 this.x = sinPhiRadius * Math.sin( theta );
7788                 this.y = Math.cos( phi ) * radius;
7789                 this.z = sinPhiRadius * Math.cos( theta );
7790
7791                 return this;
7792
7793         }
7794
7795         setFromCylindrical( c ) {
7796
7797                 return this.setFromCylindricalCoords( c.radius, c.theta, c.y );
7798
7799         }
7800
7801         setFromCylindricalCoords( radius, theta, y ) {
7802
7803                 this.x = radius * Math.sin( theta );
7804                 this.y = y;
7805                 this.z = radius * Math.cos( theta );
7806
7807                 return this;
7808
7809         }
7810
7811         setFromMatrixPosition( m ) {
7812
7813                 const e = m.elements;
7814
7815                 this.x = e[ 12 ];
7816                 this.y = e[ 13 ];
7817                 this.z = e[ 14 ];
7818
7819                 return this;
7820
7821         }
7822
7823         setFromMatrixScale( m ) {
7824
7825                 const sx = this.setFromMatrixColumn( m, 0 ).length();
7826                 const sy = this.setFromMatrixColumn( m, 1 ).length();
7827                 const sz = this.setFromMatrixColumn( m, 2 ).length();
7828
7829                 this.x = sx;
7830                 this.y = sy;
7831                 this.z = sz;
7832
7833                 return this;
7834
7835         }
7836
7837         setFromMatrixColumn( m, index ) {
7838
7839                 return this.fromArray( m.elements, index * 4 );
7840
7841         }
7842
7843         setFromMatrix3Column( m, index ) {
7844
7845                 return this.fromArray( m.elements, index * 3 );
7846
7847         }
7848
7849         equals( v ) {
7850
7851                 return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) );
7852
7853         }
7854
7855         fromArray( array, offset = 0 ) {
7856
7857                 this.x = array[ offset ];
7858                 this.y = array[ offset + 1 ];
7859                 this.z = array[ offset + 2 ];
7860
7861                 return this;
7862
7863         }
7864
7865         toArray( array = [], offset = 0 ) {
7866
7867                 array[ offset ] = this.x;
7868                 array[ offset + 1 ] = this.y;
7869                 array[ offset + 2 ] = this.z;
7870
7871                 return array;
7872
7873         }
7874
7875         fromBufferAttribute( attribute, index, offset ) {
7876
7877                 if ( offset !== undefined ) {
7878
7879                         console.warn( 'THREE.Vector3: offset has been removed from .fromBufferAttribute().' );
7880
7881                 }
7882
7883                 this.x = attribute.getX( index );
7884                 this.y = attribute.getY( index );
7885                 this.z = attribute.getZ( index );
7886
7887                 return this;
7888
7889         }
7890
7891         random() {
7892
7893                 this.x = Math.random();
7894                 this.y = Math.random();
7895                 this.z = Math.random();
7896
7897                 return this;
7898
7899         }
7900
7901 }
7902
7903 const _vector = /*@__PURE__*/ new Vector3();
7904 const _quaternion = /*@__PURE__*/ new Quaternion();
7905
7906 class Box3 {
7907
7908         constructor( min, max ) {
7909
7910                 Object.defineProperty( this, 'isBox3', { value: true } );
7911
7912                 this.min = ( min !== undefined ) ? min : new Vector3( + Infinity, + Infinity, + Infinity );
7913                 this.max = ( max !== undefined ) ? max : new Vector3( - Infinity, - Infinity, - Infinity );
7914
7915         }
7916
7917         set( min, max ) {
7918
7919                 this.min.copy( min );
7920                 this.max.copy( max );
7921
7922                 return this;
7923
7924         }
7925
7926         setFromArray( array ) {
7927
7928                 let minX = + Infinity;
7929                 let minY = + Infinity;
7930                 let minZ = + Infinity;
7931
7932                 let maxX = - Infinity;
7933                 let maxY = - Infinity;
7934                 let maxZ = - Infinity;
7935
7936                 for ( let i = 0, l = array.length; i < l; i += 3 ) {
7937
7938                         const x = array[ i ];
7939                         const y = array[ i + 1 ];
7940                         const z = array[ i + 2 ];
7941
7942                         if ( x < minX ) minX = x;
7943                         if ( y < minY ) minY = y;
7944                         if ( z < minZ ) minZ = z;
7945
7946                         if ( x > maxX ) maxX = x;
7947                         if ( y > maxY ) maxY = y;
7948                         if ( z > maxZ ) maxZ = z;
7949
7950                 }
7951
7952                 this.min.set( minX, minY, minZ );
7953                 this.max.set( maxX, maxY, maxZ );
7954
7955                 return this;
7956
7957         }
7958
7959         setFromBufferAttribute( attribute ) {
7960
7961                 let minX = + Infinity;
7962                 let minY = + Infinity;
7963                 let minZ = + Infinity;
7964
7965                 let maxX = - Infinity;
7966                 let maxY = - Infinity;
7967                 let maxZ = - Infinity;
7968
7969                 for ( let i = 0, l = attribute.count; i < l; i ++ ) {
7970
7971                         const x = attribute.getX( i );
7972                         const y = attribute.getY( i );
7973                         const z = attribute.getZ( i );
7974
7975                         if ( x < minX ) minX = x;
7976                         if ( y < minY ) minY = y;
7977                         if ( z < minZ ) minZ = z;
7978
7979                         if ( x > maxX ) maxX = x;
7980                         if ( y > maxY ) maxY = y;
7981                         if ( z > maxZ ) maxZ = z;
7982
7983                 }
7984
7985                 this.min.set( minX, minY, minZ );
7986                 this.max.set( maxX, maxY, maxZ );
7987
7988                 return this;
7989
7990         }
7991
7992         setFromPoints( points ) {
7993
7994                 this.makeEmpty();
7995
7996                 for ( let i = 0, il = points.length; i < il; i ++ ) {
7997
7998                         this.expandByPoint( points[ i ] );
7999
8000                 }
8001
8002                 return this;
8003
8004         }
8005
8006         setFromCenterAndSize( center, size ) {
8007
8008                 const halfSize = _vector$1.copy( size ).multiplyScalar( 0.5 );
8009
8010                 this.min.copy( center ).sub( halfSize );
8011                 this.max.copy( center ).add( halfSize );
8012
8013                 return this;
8014
8015         }
8016
8017         setFromObject( object ) {
8018
8019                 this.makeEmpty();
8020
8021                 return this.expandByObject( object );
8022
8023         }
8024
8025         clone() {
8026
8027                 return new this.constructor().copy( this );
8028
8029         }
8030
8031         copy( box ) {
8032
8033                 this.min.copy( box.min );
8034                 this.max.copy( box.max );
8035
8036                 return this;
8037
8038         }
8039
8040         makeEmpty() {
8041
8042                 this.min.x = this.min.y = this.min.z = + Infinity;
8043                 this.max.x = this.max.y = this.max.z = - Infinity;
8044
8045                 return this;
8046
8047         }
8048
8049         isEmpty() {
8050
8051                 // this is a more robust check for empty than ( volume <= 0 ) because volume can get positive with two negative axes
8052
8053                 return ( this.max.x < this.min.x ) || ( this.max.y < this.min.y ) || ( this.max.z < this.min.z );
8054
8055         }
8056
8057         getCenter( target ) {
8058
8059                 if ( target === undefined ) {
8060
8061                         console.warn( 'THREE.Box3: .getCenter() target is now required' );
8062                         target = new Vector3();
8063
8064                 }
8065
8066                 return this.isEmpty() ? target.set( 0, 0, 0 ) : target.addVectors( this.min, this.max ).multiplyScalar( 0.5 );
8067
8068         }
8069
8070         getSize( target ) {
8071
8072                 if ( target === undefined ) {
8073
8074                         console.warn( 'THREE.Box3: .getSize() target is now required' );
8075                         target = new Vector3();
8076
8077                 }
8078
8079                 return this.isEmpty() ? target.set( 0, 0, 0 ) : target.subVectors( this.max, this.min );
8080
8081         }
8082
8083         expandByPoint( point ) {
8084
8085                 this.min.min( point );
8086                 this.max.max( point );
8087
8088                 return this;
8089
8090         }
8091
8092         expandByVector( vector ) {
8093
8094                 this.min.sub( vector );
8095                 this.max.add( vector );
8096
8097                 return this;
8098
8099         }
8100
8101         expandByScalar( scalar ) {
8102
8103                 this.min.addScalar( - scalar );
8104                 this.max.addScalar( scalar );
8105
8106                 return this;
8107
8108         }
8109
8110         expandByObject( object ) {
8111
8112                 // Computes the world-axis-aligned bounding box of an object (including its children),
8113                 // accounting for both the object's, and children's, world transforms
8114
8115                 object.updateWorldMatrix( false, false );
8116
8117                 const geometry = object.geometry;
8118
8119                 if ( geometry !== undefined ) {
8120
8121                         if ( geometry.boundingBox === null ) {
8122
8123                                 geometry.computeBoundingBox();
8124
8125                         }
8126
8127                         _box.copy( geometry.boundingBox );
8128                         _box.applyMatrix4( object.matrixWorld );
8129
8130                         this.union( _box );
8131
8132                 }
8133
8134                 const children = object.children;
8135
8136                 for ( let i = 0, l = children.length; i < l; i ++ ) {
8137
8138                         this.expandByObject( children[ i ] );
8139
8140                 }
8141
8142                 return this;
8143
8144         }
8145
8146         containsPoint( point ) {
8147
8148                 return point.x < this.min.x || point.x > this.max.x ||
8149                         point.y < this.min.y || point.y > this.max.y ||
8150                         point.z < this.min.z || point.z > this.max.z ? false : true;
8151
8152         }
8153
8154         containsBox( box ) {
8155
8156                 return this.min.x <= box.min.x && box.max.x <= this.max.x &&
8157                         this.min.y <= box.min.y && box.max.y <= this.max.y &&
8158                         this.min.z <= box.min.z && box.max.z <= this.max.z;
8159
8160         }
8161
8162         getParameter( point, target ) {
8163
8164                 // This can potentially have a divide by zero if the box
8165                 // has a size dimension of 0.
8166
8167                 if ( target === undefined ) {
8168
8169                         console.warn( 'THREE.Box3: .getParameter() target is now required' );
8170                         target = new Vector3();
8171
8172                 }
8173
8174                 return target.set(
8175                         ( point.x - this.min.x ) / ( this.max.x - this.min.x ),
8176                         ( point.y - this.min.y ) / ( this.max.y - this.min.y ),
8177                         ( point.z - this.min.z ) / ( this.max.z - this.min.z )
8178                 );
8179
8180         }
8181
8182         intersectsBox( box ) {
8183
8184                 // using 6 splitting planes to rule out intersections.
8185                 return box.max.x < this.min.x || box.min.x > this.max.x ||
8186                         box.max.y < this.min.y || box.min.y > this.max.y ||
8187                         box.max.z < this.min.z || box.min.z > this.max.z ? false : true;
8188
8189         }
8190
8191         intersectsSphere( sphere ) {
8192
8193                 // Find the point on the AABB closest to the sphere center.
8194                 this.clampPoint( sphere.center, _vector$1 );
8195
8196                 // If that point is inside the sphere, the AABB and sphere intersect.
8197                 return _vector$1.distanceToSquared( sphere.center ) <= ( sphere.radius * sphere.radius );
8198
8199         }
8200
8201         intersectsPlane( plane ) {
8202
8203                 // We compute the minimum and maximum dot product values. If those values
8204                 // are on the same side (back or front) of the plane, then there is no intersection.
8205
8206                 let min, max;
8207
8208                 if ( plane.normal.x > 0 ) {
8209
8210                         min = plane.normal.x * this.min.x;
8211                         max = plane.normal.x * this.max.x;
8212
8213                 } else {
8214
8215                         min = plane.normal.x * this.max.x;
8216                         max = plane.normal.x * this.min.x;
8217
8218                 }
8219
8220                 if ( plane.normal.y > 0 ) {
8221
8222                         min += plane.normal.y * this.min.y;
8223                         max += plane.normal.y * this.max.y;
8224
8225                 } else {
8226
8227                         min += plane.normal.y * this.max.y;
8228                         max += plane.normal.y * this.min.y;
8229
8230                 }
8231
8232                 if ( plane.normal.z > 0 ) {
8233
8234                         min += plane.normal.z * this.min.z;
8235                         max += plane.normal.z * this.max.z;
8236
8237                 } else {
8238
8239                         min += plane.normal.z * this.max.z;
8240                         max += plane.normal.z * this.min.z;
8241
8242                 }
8243
8244                 return ( min <= - plane.constant && max >= - plane.constant );
8245
8246         }
8247
8248         intersectsTriangle( triangle ) {
8249
8250                 if ( this.isEmpty() ) {
8251
8252                         return false;
8253
8254                 }
8255
8256                 // compute box center and extents
8257                 this.getCenter( _center );
8258                 _extents.subVectors( this.max, _center );
8259
8260                 // translate triangle to aabb origin
8261                 _v0.subVectors( triangle.a, _center );
8262                 _v1.subVectors( triangle.b, _center );
8263                 _v2.subVectors( triangle.c, _center );
8264
8265                 // compute edge vectors for triangle
8266                 _f0.subVectors( _v1, _v0 );
8267                 _f1.subVectors( _v2, _v1 );
8268                 _f2.subVectors( _v0, _v2 );
8269
8270                 // test against axes that are given by cross product combinations of the edges of the triangle and the edges of the aabb
8271                 // 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
8272                 // axis_ij = u_i x f_j (u0, u1, u2 = face normals of aabb = x,y,z axes vectors since aabb is axis aligned)
8273                 let axes = [
8274                         0, - _f0.z, _f0.y, 0, - _f1.z, _f1.y, 0, - _f2.z, _f2.y,
8275                         _f0.z, 0, - _f0.x, _f1.z, 0, - _f1.x, _f2.z, 0, - _f2.x,
8276                         - _f0.y, _f0.x, 0, - _f1.y, _f1.x, 0, - _f2.y, _f2.x, 0
8277                 ];
8278                 if ( ! satForAxes( axes, _v0, _v1, _v2, _extents ) ) {
8279
8280                         return false;
8281
8282                 }
8283
8284                 // test 3 face normals from the aabb
8285                 axes = [ 1, 0, 0, 0, 1, 0, 0, 0, 1 ];
8286                 if ( ! satForAxes( axes, _v0, _v1, _v2, _extents ) ) {
8287
8288                         return false;
8289
8290                 }
8291
8292                 // finally testing the face normal of the triangle
8293                 // use already existing triangle edge vectors here
8294                 _triangleNormal.crossVectors( _f0, _f1 );
8295                 axes = [ _triangleNormal.x, _triangleNormal.y, _triangleNormal.z ];
8296
8297                 return satForAxes( axes, _v0, _v1, _v2, _extents );
8298
8299         }
8300
8301         clampPoint( point, target ) {
8302
8303                 if ( target === undefined ) {
8304
8305                         console.warn( 'THREE.Box3: .clampPoint() target is now required' );
8306                         target = new Vector3();
8307
8308                 }
8309
8310                 return target.copy( point ).clamp( this.min, this.max );
8311
8312         }
8313
8314         distanceToPoint( point ) {
8315
8316                 const clampedPoint = _vector$1.copy( point ).clamp( this.min, this.max );
8317
8318                 return clampedPoint.sub( point ).length();
8319
8320         }
8321
8322         getBoundingSphere( target ) {
8323
8324                 if ( target === undefined ) {
8325
8326                         console.error( 'THREE.Box3: .getBoundingSphere() target is now required' );
8327                         //target = new Sphere(); // removed to avoid cyclic dependency
8328
8329                 }
8330
8331                 this.getCenter( target.center );
8332
8333                 target.radius = this.getSize( _vector$1 ).length() * 0.5;
8334
8335                 return target;
8336
8337         }
8338
8339         intersect( box ) {
8340
8341                 this.min.max( box.min );
8342                 this.max.min( box.max );
8343
8344                 // 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.
8345                 if ( this.isEmpty() ) this.makeEmpty();
8346
8347                 return this;
8348
8349         }
8350
8351         union( box ) {
8352
8353                 this.min.min( box.min );
8354                 this.max.max( box.max );
8355
8356                 return this;
8357
8358         }
8359
8360         applyMatrix4( matrix ) {
8361
8362                 // transform of empty box is an empty box.
8363                 if ( this.isEmpty() ) return this;
8364
8365                 // NOTE: I am using a binary pattern to specify all 2^3 combinations below
8366                 _points[ 0 ].set( this.min.x, this.min.y, this.min.z ).applyMatrix4( matrix ); // 000
8367                 _points[ 1 ].set( this.min.x, this.min.y, this.max.z ).applyMatrix4( matrix ); // 001
8368                 _points[ 2 ].set( this.min.x, this.max.y, this.min.z ).applyMatrix4( matrix ); // 010
8369                 _points[ 3 ].set( this.min.x, this.max.y, this.max.z ).applyMatrix4( matrix ); // 011
8370                 _points[ 4 ].set( this.max.x, this.min.y, this.min.z ).applyMatrix4( matrix ); // 100
8371                 _points[ 5 ].set( this.max.x, this.min.y, this.max.z ).applyMatrix4( matrix ); // 101
8372                 _points[ 6 ].set( this.max.x, this.max.y, this.min.z ).applyMatrix4( matrix ); // 110
8373                 _points[ 7 ].set( this.max.x, this.max.y, this.max.z ).applyMatrix4( matrix ); // 111
8374
8375                 this.setFromPoints( _points );
8376
8377                 return this;
8378
8379         }
8380
8381         translate( offset ) {
8382
8383                 this.min.add( offset );
8384                 this.max.add( offset );
8385
8386                 return this;
8387
8388         }
8389
8390         equals( box ) {
8391
8392                 return box.min.equals( this.min ) && box.max.equals( this.max );
8393
8394         }
8395
8396 }
8397
8398 function satForAxes( axes, v0, v1, v2, extents ) {
8399
8400         for ( let i = 0, j = axes.length - 3; i <= j; i += 3 ) {
8401
8402                 _testAxis.fromArray( axes, i );
8403                 // project the aabb onto the seperating axis
8404                 const r = extents.x * Math.abs( _testAxis.x ) + extents.y * Math.abs( _testAxis.y ) + extents.z * Math.abs( _testAxis.z );
8405                 // project all 3 vertices of the triangle onto the seperating axis
8406                 const p0 = v0.dot( _testAxis );
8407                 const p1 = v1.dot( _testAxis );
8408                 const p2 = v2.dot( _testAxis );
8409                 // actual test, basically see if either of the most extreme of the triangle points intersects r
8410                 if ( Math.max( - Math.max( p0, p1, p2 ), Math.min( p0, p1, p2 ) ) > r ) {
8411
8412                         // points of the projected triangle are outside the projected half-length of the aabb
8413                         // the axis is seperating and we can exit
8414                         return false;
8415
8416                 }
8417
8418         }
8419
8420         return true;
8421
8422 }
8423
8424 const _points = [
8425         /*@__PURE__*/ new Vector3(),
8426         /*@__PURE__*/ new Vector3(),
8427         /*@__PURE__*/ new Vector3(),
8428         /*@__PURE__*/ new Vector3(),
8429         /*@__PURE__*/ new Vector3(),
8430         /*@__PURE__*/ new Vector3(),
8431         /*@__PURE__*/ new Vector3(),
8432         /*@__PURE__*/ new Vector3()
8433 ];
8434
8435 const _vector$1 = /*@__PURE__*/ new Vector3();
8436
8437 const _box = /*@__PURE__*/ new Box3();
8438
8439 // triangle centered vertices
8440
8441 const _v0 = /*@__PURE__*/ new Vector3();
8442 const _v1 = /*@__PURE__*/ new Vector3();
8443 const _v2 = /*@__PURE__*/ new Vector3();
8444
8445 // triangle edge vectors
8446
8447 const _f0 = /*@__PURE__*/ new Vector3();
8448 const _f1 = /*@__PURE__*/ new Vector3();
8449 const _f2 = /*@__PURE__*/ new Vector3();
8450
8451 const _center = /*@__PURE__*/ new Vector3();
8452 const _extents = /*@__PURE__*/ new Vector3();
8453 const _triangleNormal = /*@__PURE__*/ new Vector3();
8454 const _testAxis = /*@__PURE__*/ new Vector3();
8455
8456 const _box$1 = /*@__PURE__*/ new Box3();
8457
8458 class Sphere {
8459
8460         constructor( center, radius ) {
8461
8462                 this.center = ( center !== undefined ) ? center : new Vector3();
8463                 this.radius = ( radius !== undefined ) ? radius : - 1;
8464
8465         }
8466
8467         set( center, radius ) {
8468
8469                 this.center.copy( center );
8470                 this.radius = radius;
8471
8472                 return this;
8473
8474         }
8475
8476         setFromPoints( points, optionalCenter ) {
8477
8478                 const center = this.center;
8479
8480                 if ( optionalCenter !== undefined ) {
8481
8482                         center.copy( optionalCenter );
8483
8484                 } else {
8485
8486                         _box$1.setFromPoints( points ).getCenter( center );
8487
8488                 }
8489
8490                 let maxRadiusSq = 0;
8491
8492                 for ( let i = 0, il = points.length; i < il; i ++ ) {
8493
8494                         maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( points[ i ] ) );
8495
8496                 }
8497
8498                 this.radius = Math.sqrt( maxRadiusSq );
8499
8500                 return this;
8501
8502         }
8503
8504         clone() {
8505
8506                 return new this.constructor().copy( this );
8507
8508         }
8509
8510         copy( sphere ) {
8511
8512                 this.center.copy( sphere.center );
8513                 this.radius = sphere.radius;
8514
8515                 return this;
8516
8517         }
8518
8519         isEmpty() {
8520
8521                 return ( this.radius < 0 );
8522
8523         }
8524
8525         makeEmpty() {
8526
8527                 this.center.set( 0, 0, 0 );
8528                 this.radius = - 1;
8529
8530                 return this;
8531
8532         }
8533
8534         containsPoint( point ) {
8535
8536                 return ( point.distanceToSquared( this.center ) <= ( this.radius * this.radius ) );
8537
8538         }
8539
8540         distanceToPoint( point ) {
8541
8542                 return ( point.distanceTo( this.center ) - this.radius );
8543
8544         }
8545
8546         intersectsSphere( sphere ) {
8547
8548                 const radiusSum = this.radius + sphere.radius;
8549
8550                 return sphere.center.distanceToSquared( this.center ) <= ( radiusSum * radiusSum );
8551
8552         }
8553
8554         intersectsBox( box ) {
8555
8556                 return box.intersectsSphere( this );
8557
8558         }
8559
8560         intersectsPlane( plane ) {
8561
8562                 return Math.abs( plane.distanceToPoint( this.center ) ) <= this.radius;
8563
8564         }
8565
8566         clampPoint( point, target ) {
8567
8568                 const deltaLengthSq = this.center.distanceToSquared( point );
8569
8570                 if ( target === undefined ) {
8571
8572                         console.warn( 'THREE.Sphere: .clampPoint() target is now required' );
8573                         target = new Vector3();
8574
8575                 }
8576
8577                 target.copy( point );
8578
8579                 if ( deltaLengthSq > ( this.radius * this.radius ) ) {
8580
8581                         target.sub( this.center ).normalize();
8582                         target.multiplyScalar( this.radius ).add( this.center );
8583
8584                 }
8585
8586                 return target;
8587
8588         }
8589
8590         getBoundingBox( target ) {
8591
8592                 if ( target === undefined ) {
8593
8594                         console.warn( 'THREE.Sphere: .getBoundingBox() target is now required' );
8595                         target = new Box3();
8596
8597                 }
8598
8599                 if ( this.isEmpty() ) {
8600
8601                         // Empty sphere produces empty bounding box
8602                         target.makeEmpty();
8603                         return target;
8604
8605                 }
8606
8607                 target.set( this.center, this.center );
8608                 target.expandByScalar( this.radius );
8609
8610                 return target;
8611
8612         }
8613
8614         applyMatrix4( matrix ) {
8615
8616                 this.center.applyMatrix4( matrix );
8617                 this.radius = this.radius * matrix.getMaxScaleOnAxis();
8618
8619                 return this;
8620
8621         }
8622
8623         translate( offset ) {
8624
8625                 this.center.add( offset );
8626
8627                 return this;
8628
8629         }
8630
8631         equals( sphere ) {
8632
8633                 return sphere.center.equals( this.center ) && ( sphere.radius === this.radius );
8634
8635         }
8636
8637 }
8638
8639 const _vector$2 = /*@__PURE__*/ new Vector3();
8640 const _segCenter = /*@__PURE__*/ new Vector3();
8641 const _segDir = /*@__PURE__*/ new Vector3();
8642 const _diff = /*@__PURE__*/ new Vector3();
8643
8644 const _edge1 = /*@__PURE__*/ new Vector3();
8645 const _edge2 = /*@__PURE__*/ new Vector3();
8646 const _normal = /*@__PURE__*/ new Vector3();
8647
8648 class Ray {
8649
8650         constructor( origin, direction ) {
8651
8652                 this.origin = ( origin !== undefined ) ? origin : new Vector3();
8653                 this.direction = ( direction !== undefined ) ? direction : new Vector3( 0, 0, - 1 );
8654
8655         }
8656
8657         set( origin, direction ) {
8658
8659                 this.origin.copy( origin );
8660                 this.direction.copy( direction );
8661
8662                 return this;
8663
8664         }
8665
8666         clone() {
8667
8668                 return new this.constructor().copy( this );
8669
8670         }
8671
8672         copy( ray ) {
8673
8674                 this.origin.copy( ray.origin );
8675                 this.direction.copy( ray.direction );
8676
8677                 return this;
8678
8679         }
8680
8681         at( t, target ) {
8682
8683                 if ( target === undefined ) {
8684
8685                         console.warn( 'THREE.Ray: .at() target is now required' );
8686                         target = new Vector3();
8687
8688                 }
8689
8690                 return target.copy( this.direction ).multiplyScalar( t ).add( this.origin );
8691
8692         }
8693
8694         lookAt( v ) {
8695
8696                 this.direction.copy( v ).sub( this.origin ).normalize();
8697
8698                 return this;
8699
8700         }
8701
8702         recast( t ) {
8703
8704                 this.origin.copy( this.at( t, _vector$2 ) );
8705
8706                 return this;
8707
8708         }
8709
8710         closestPointToPoint( point, target ) {
8711
8712                 if ( target === undefined ) {
8713
8714                         console.warn( 'THREE.Ray: .closestPointToPoint() target is now required' );
8715                         target = new Vector3();
8716
8717                 }
8718
8719                 target.subVectors( point, this.origin );
8720
8721                 const directionDistance = target.dot( this.direction );
8722
8723                 if ( directionDistance < 0 ) {
8724
8725                         return target.copy( this.origin );
8726
8727                 }
8728
8729                 return target.copy( this.direction ).multiplyScalar( directionDistance ).add( this.origin );
8730
8731         }
8732
8733         distanceToPoint( point ) {
8734
8735                 return Math.sqrt( this.distanceSqToPoint( point ) );
8736
8737         }
8738
8739         distanceSqToPoint( point ) {
8740
8741                 const directionDistance = _vector$2.subVectors( point, this.origin ).dot( this.direction );
8742
8743                 // point behind the ray
8744
8745                 if ( directionDistance < 0 ) {
8746
8747                         return this.origin.distanceToSquared( point );
8748
8749                 }
8750
8751                 _vector$2.copy( this.direction ).multiplyScalar( directionDistance ).add( this.origin );
8752
8753                 return _vector$2.distanceToSquared( point );
8754
8755         }
8756
8757         distanceSqToSegment( v0, v1, optionalPointOnRay, optionalPointOnSegment ) {
8758
8759                 // from http://www.geometrictools.com/GTEngine/Include/Mathematics/GteDistRaySegment.h
8760                 // It returns the min distance between the ray and the segment
8761                 // defined by v0 and v1
8762                 // It can also set two optional targets :
8763                 // - The closest point on the ray
8764                 // - The closest point on the segment
8765
8766                 _segCenter.copy( v0 ).add( v1 ).multiplyScalar( 0.5 );
8767                 _segDir.copy( v1 ).sub( v0 ).normalize();
8768                 _diff.copy( this.origin ).sub( _segCenter );
8769
8770                 const segExtent = v0.distanceTo( v1 ) * 0.5;
8771                 const a01 = - this.direction.dot( _segDir );
8772                 const b0 = _diff.dot( this.direction );
8773                 const b1 = - _diff.dot( _segDir );
8774                 const c = _diff.lengthSq();
8775                 const det = Math.abs( 1 - a01 * a01 );
8776                 let s0, s1, sqrDist, extDet;
8777
8778                 if ( det > 0 ) {
8779
8780                         // The ray and segment are not parallel.
8781
8782                         s0 = a01 * b1 - b0;
8783                         s1 = a01 * b0 - b1;
8784                         extDet = segExtent * det;
8785
8786                         if ( s0 >= 0 ) {
8787
8788                                 if ( s1 >= - extDet ) {
8789
8790                                         if ( s1 <= extDet ) {
8791
8792                                                 // region 0
8793                                                 // Minimum at interior points of ray and segment.
8794
8795                                                 const invDet = 1 / det;
8796                                                 s0 *= invDet;
8797                                                 s1 *= invDet;
8798                                                 sqrDist = s0 * ( s0 + a01 * s1 + 2 * b0 ) + s1 * ( a01 * s0 + s1 + 2 * b1 ) + c;
8799
8800                                         } else {
8801
8802                                                 // region 1
8803
8804                                                 s1 = segExtent;
8805                                                 s0 = Math.max( 0, - ( a01 * s1 + b0 ) );
8806                                                 sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;
8807
8808                                         }
8809
8810                                 } else {
8811
8812                                         // region 5
8813
8814                                         s1 = - segExtent;
8815                                         s0 = Math.max( 0, - ( a01 * s1 + b0 ) );
8816                                         sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;
8817
8818                                 }
8819
8820                         } else {
8821
8822                                 if ( s1 <= - extDet ) {
8823
8824                                         // region 4
8825
8826                                         s0 = Math.max( 0, - ( - a01 * segExtent + b0 ) );
8827                                         s1 = ( s0 > 0 ) ? - segExtent : Math.min( Math.max( - segExtent, - b1 ), segExtent );
8828                                         sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;
8829
8830                                 } else if ( s1 <= extDet ) {
8831
8832                                         // region 3
8833
8834                                         s0 = 0;
8835                                         s1 = Math.min( Math.max( - segExtent, - b1 ), segExtent );
8836                                         sqrDist = s1 * ( s1 + 2 * b1 ) + c;
8837
8838                                 } else {
8839
8840                                         // region 2
8841
8842                                         s0 = Math.max( 0, - ( a01 * segExtent + b0 ) );
8843                                         s1 = ( s0 > 0 ) ? segExtent : Math.min( Math.max( - segExtent, - b1 ), segExtent );
8844                                         sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;
8845
8846                                 }
8847
8848                         }
8849
8850                 } else {
8851
8852                         // Ray and segment are parallel.
8853
8854                         s1 = ( a01 > 0 ) ? - segExtent : segExtent;
8855                         s0 = Math.max( 0, - ( a01 * s1 + b0 ) );
8856                         sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;
8857
8858                 }
8859
8860                 if ( optionalPointOnRay ) {
8861
8862                         optionalPointOnRay.copy( this.direction ).multiplyScalar( s0 ).add( this.origin );
8863
8864                 }
8865
8866                 if ( optionalPointOnSegment ) {
8867
8868                         optionalPointOnSegment.copy( _segDir ).multiplyScalar( s1 ).add( _segCenter );
8869
8870                 }
8871
8872                 return sqrDist;
8873
8874         }
8875
8876         intersectSphere( sphere, target ) {
8877
8878                 _vector$2.subVectors( sphere.center, this.origin );
8879                 const tca = _vector$2.dot( this.direction );
8880                 const d2 = _vector$2.dot( _vector$2 ) - tca * tca;
8881                 const radius2 = sphere.radius * sphere.radius;
8882
8883                 if ( d2 > radius2 ) return null;
8884
8885                 const thc = Math.sqrt( radius2 - d2 );
8886
8887                 // t0 = first intersect point - entrance on front of sphere
8888                 const t0 = tca - thc;
8889
8890                 // t1 = second intersect point - exit point on back of sphere
8891                 const t1 = tca + thc;
8892
8893                 // test to see if both t0 and t1 are behind the ray - if so, return null
8894                 if ( t0 < 0 && t1 < 0 ) return null;
8895
8896                 // test to see if t0 is behind the ray:
8897                 // if it is, the ray is inside the sphere, so return the second exit point scaled by t1,
8898                 // in order to always return an intersect point that is in front of the ray.
8899                 if ( t0 < 0 ) return this.at( t1, target );
8900
8901                 // else t0 is in front of the ray, so return the first collision point scaled by t0
8902                 return this.at( t0, target );
8903
8904         }
8905
8906         intersectsSphere( sphere ) {
8907
8908                 return this.distanceSqToPoint( sphere.center ) <= ( sphere.radius * sphere.radius );
8909
8910         }
8911
8912         distanceToPlane( plane ) {
8913
8914                 const denominator = plane.normal.dot( this.direction );
8915
8916                 if ( denominator === 0 ) {
8917
8918                         // line is coplanar, return origin
8919                         if ( plane.distanceToPoint( this.origin ) === 0 ) {
8920
8921                                 return 0;
8922
8923                         }
8924
8925                         // Null is preferable to undefined since undefined means.... it is undefined
8926
8927                         return null;
8928
8929                 }
8930
8931                 const t = - ( this.origin.dot( plane.normal ) + plane.constant ) / denominator;
8932
8933                 // Return if the ray never intersects the plane
8934
8935                 return t >= 0 ? t : null;
8936
8937         }
8938
8939         intersectPlane( plane, target ) {
8940
8941                 const t = this.distanceToPlane( plane );
8942
8943                 if ( t === null ) {
8944
8945                         return null;
8946
8947                 }
8948
8949                 return this.at( t, target );
8950
8951         }
8952
8953         intersectsPlane( plane ) {
8954
8955                 // check if the ray lies on the plane first
8956
8957                 const distToPoint = plane.distanceToPoint( this.origin );
8958
8959                 if ( distToPoint === 0 ) {
8960
8961                         return true;
8962
8963                 }
8964
8965                 const denominator = plane.normal.dot( this.direction );
8966
8967                 if ( denominator * distToPoint < 0 ) {
8968
8969                         return true;
8970
8971                 }
8972
8973                 // ray origin is behind the plane (and is pointing behind it)
8974
8975                 return false;
8976
8977         }
8978
8979         intersectBox( box, target ) {
8980
8981                 let tmin, tmax, tymin, tymax, tzmin, tzmax;
8982
8983                 const invdirx = 1 / this.direction.x,
8984                         invdiry = 1 / this.direction.y,
8985                         invdirz = 1 / this.direction.z;
8986
8987                 const origin = this.origin;
8988
8989                 if ( invdirx >= 0 ) {
8990
8991                         tmin = ( box.min.x - origin.x ) * invdirx;
8992                         tmax = ( box.max.x - origin.x ) * invdirx;
8993
8994                 } else {
8995
8996                         tmin = ( box.max.x - origin.x ) * invdirx;
8997                         tmax = ( box.min.x - origin.x ) * invdirx;
8998
8999                 }
9000
9001                 if ( invdiry >= 0 ) {
9002
9003                         tymin = ( box.min.y - origin.y ) * invdiry;
9004                         tymax = ( box.max.y - origin.y ) * invdiry;
9005
9006                 } else {
9007
9008                         tymin = ( box.max.y - origin.y ) * invdiry;
9009                         tymax = ( box.min.y - origin.y ) * invdiry;
9010
9011                 }
9012
9013                 if ( ( tmin > tymax ) || ( tymin > tmax ) ) return null;
9014
9015                 // These lines also handle the case where tmin or tmax is NaN
9016                 // (result of 0 * Infinity). x !== x returns true if x is NaN
9017
9018                 if ( tymin > tmin || tmin !== tmin ) tmin = tymin;
9019
9020                 if ( tymax < tmax || tmax !== tmax ) tmax = tymax;
9021
9022                 if ( invdirz >= 0 ) {
9023
9024                         tzmin = ( box.min.z - origin.z ) * invdirz;
9025                         tzmax = ( box.max.z - origin.z ) * invdirz;
9026
9027                 } else {
9028
9029                         tzmin = ( box.max.z - origin.z ) * invdirz;
9030                         tzmax = ( box.min.z - origin.z ) * invdirz;
9031
9032                 }
9033
9034                 if ( ( tmin > tzmax ) || ( tzmin > tmax ) ) return null;
9035
9036                 if ( tzmin > tmin || tmin !== tmin ) tmin = tzmin;
9037
9038                 if ( tzmax < tmax || tmax !== tmax ) tmax = tzmax;
9039
9040                 //return point closest to the ray (positive side)
9041
9042                 if ( tmax < 0 ) return null;
9043
9044                 return this.at( tmin >= 0 ? tmin : tmax, target );
9045
9046         }
9047
9048         intersectsBox( box ) {
9049
9050                 return this.intersectBox( box, _vector$2 ) !== null;
9051
9052         }
9053
9054         intersectTriangle( a, b, c, backfaceCulling, target ) {
9055
9056                 // Compute the offset origin, edges, and normal.
9057
9058                 // from http://www.geometrictools.com/GTEngine/Include/Mathematics/GteIntrRay3Triangle3.h
9059
9060                 _edge1.subVectors( b, a );
9061                 _edge2.subVectors( c, a );
9062                 _normal.crossVectors( _edge1, _edge2 );
9063
9064                 // Solve Q + t*D = b1*E1 + b2*E2 (Q = kDiff, D = ray direction,
9065                 // E1 = kEdge1, E2 = kEdge2, N = Cross(E1,E2)) by
9066                 //   |Dot(D,N)|*b1 = sign(Dot(D,N))*Dot(D,Cross(Q,E2))
9067                 //   |Dot(D,N)|*b2 = sign(Dot(D,N))*Dot(D,Cross(E1,Q))
9068                 //   |Dot(D,N)|*t = -sign(Dot(D,N))*Dot(Q,N)
9069                 let DdN = this.direction.dot( _normal );
9070                 let sign;
9071
9072                 if ( DdN > 0 ) {
9073
9074                         if ( backfaceCulling ) return null;
9075                         sign = 1;
9076
9077                 } else if ( DdN < 0 ) {
9078
9079                         sign = - 1;
9080                         DdN = - DdN;
9081
9082                 } else {
9083
9084                         return null;
9085
9086                 }
9087
9088                 _diff.subVectors( this.origin, a );
9089                 const DdQxE2 = sign * this.direction.dot( _edge2.crossVectors( _diff, _edge2 ) );
9090
9091                 // b1 < 0, no intersection
9092                 if ( DdQxE2 < 0 ) {
9093
9094                         return null;
9095
9096                 }
9097
9098                 const DdE1xQ = sign * this.direction.dot( _edge1.cross( _diff ) );
9099
9100                 // b2 < 0, no intersection
9101                 if ( DdE1xQ < 0 ) {
9102
9103                         return null;
9104
9105                 }
9106
9107                 // b1+b2 > 1, no intersection
9108                 if ( DdQxE2 + DdE1xQ > DdN ) {
9109
9110                         return null;
9111
9112                 }
9113
9114                 // Line intersects triangle, check if ray does.
9115                 const QdN = - sign * _diff.dot( _normal );
9116
9117                 // t < 0, no intersection
9118                 if ( QdN < 0 ) {
9119
9120                         return null;
9121
9122                 }
9123
9124                 // Ray intersects triangle.
9125                 return this.at( QdN / DdN, target );
9126
9127         }
9128
9129         applyMatrix4( matrix4 ) {
9130
9131                 this.origin.applyMatrix4( matrix4 );
9132                 this.direction.transformDirection( matrix4 );
9133
9134                 return this;
9135
9136         }
9137
9138         equals( ray ) {
9139
9140                 return ray.origin.equals( this.origin ) && ray.direction.equals( this.direction );
9141
9142         }
9143
9144 }
9145
9146 class Matrix4 {
9147
9148         constructor() {
9149
9150                 Object.defineProperty( this, 'isMatrix4', { value: true } );
9151
9152                 this.elements = [
9153
9154                         1, 0, 0, 0,
9155                         0, 1, 0, 0,
9156                         0, 0, 1, 0,
9157                         0, 0, 0, 1
9158
9159                 ];
9160
9161                 if ( arguments.length > 0 ) {
9162
9163                         console.error( 'THREE.Matrix4: the constructor no longer reads arguments. use .set() instead.' );
9164
9165                 }
9166
9167         }
9168
9169         set( n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44 ) {
9170
9171                 const te = this.elements;
9172
9173                 te[ 0 ] = n11; te[ 4 ] = n12; te[ 8 ] = n13; te[ 12 ] = n14;
9174                 te[ 1 ] = n21; te[ 5 ] = n22; te[ 9 ] = n23; te[ 13 ] = n24;
9175                 te[ 2 ] = n31; te[ 6 ] = n32; te[ 10 ] = n33; te[ 14 ] = n34;
9176                 te[ 3 ] = n41; te[ 7 ] = n42; te[ 11 ] = n43; te[ 15 ] = n44;
9177
9178                 return this;
9179
9180         }
9181
9182         identity() {
9183
9184                 this.set(
9185
9186                         1, 0, 0, 0,
9187                         0, 1, 0, 0,
9188                         0, 0, 1, 0,
9189                         0, 0, 0, 1
9190
9191                 );
9192
9193                 return this;
9194
9195         }
9196
9197         clone() {
9198
9199                 return new Matrix4().fromArray( this.elements );
9200
9201         }
9202
9203         copy( m ) {
9204
9205                 const te = this.elements;
9206                 const me = m.elements;
9207
9208                 te[ 0 ] = me[ 0 ]; te[ 1 ] = me[ 1 ]; te[ 2 ] = me[ 2 ]; te[ 3 ] = me[ 3 ];
9209                 te[ 4 ] = me[ 4 ]; te[ 5 ] = me[ 5 ]; te[ 6 ] = me[ 6 ]; te[ 7 ] = me[ 7 ];
9210                 te[ 8 ] = me[ 8 ]; te[ 9 ] = me[ 9 ]; te[ 10 ] = me[ 10 ]; te[ 11 ] = me[ 11 ];
9211                 te[ 12 ] = me[ 12 ]; te[ 13 ] = me[ 13 ]; te[ 14 ] = me[ 14 ]; te[ 15 ] = me[ 15 ];
9212
9213                 return this;
9214
9215         }
9216
9217         copyPosition( m ) {
9218
9219                 const te = this.elements, me = m.elements;
9220
9221                 te[ 12 ] = me[ 12 ];
9222                 te[ 13 ] = me[ 13 ];
9223                 te[ 14 ] = me[ 14 ];
9224
9225                 return this;
9226
9227         }
9228
9229         setFromMatrix3( m ) {
9230
9231                 const me = m.elements;
9232
9233                 this.set(
9234
9235                         me[ 0 ], me[ 3 ], me[ 6 ], 0,
9236                         me[ 1 ], me[ 4 ], me[ 7 ], 0,
9237                         me[ 2 ], me[ 5 ], me[ 8 ], 0,
9238                         0, 0, 0, 1
9239
9240                 );
9241
9242                 return this;
9243
9244         }
9245
9246         extractBasis( xAxis, yAxis, zAxis ) {
9247
9248                 xAxis.setFromMatrixColumn( this, 0 );
9249                 yAxis.setFromMatrixColumn( this, 1 );
9250                 zAxis.setFromMatrixColumn( this, 2 );
9251
9252                 return this;
9253
9254         }
9255
9256         makeBasis( xAxis, yAxis, zAxis ) {
9257
9258                 this.set(
9259                         xAxis.x, yAxis.x, zAxis.x, 0,
9260                         xAxis.y, yAxis.y, zAxis.y, 0,
9261                         xAxis.z, yAxis.z, zAxis.z, 0,
9262                         0, 0, 0, 1
9263                 );
9264
9265                 return this;
9266
9267         }
9268
9269         extractRotation( m ) {
9270
9271                 // this method does not support reflection matrices
9272
9273                 const te = this.elements;
9274                 const me = m.elements;
9275
9276                 const scaleX = 1 / _v1$1.setFromMatrixColumn( m, 0 ).length();
9277                 const scaleY = 1 / _v1$1.setFromMatrixColumn( m, 1 ).length();
9278                 const scaleZ = 1 / _v1$1.setFromMatrixColumn( m, 2 ).length();
9279
9280                 te[ 0 ] = me[ 0 ] * scaleX;
9281                 te[ 1 ] = me[ 1 ] * scaleX;
9282                 te[ 2 ] = me[ 2 ] * scaleX;
9283                 te[ 3 ] = 0;
9284
9285                 te[ 4 ] = me[ 4 ] * scaleY;
9286                 te[ 5 ] = me[ 5 ] * scaleY;
9287                 te[ 6 ] = me[ 6 ] * scaleY;
9288                 te[ 7 ] = 0;
9289
9290                 te[ 8 ] = me[ 8 ] * scaleZ;
9291                 te[ 9 ] = me[ 9 ] * scaleZ;
9292                 te[ 10 ] = me[ 10 ] * scaleZ;
9293                 te[ 11 ] = 0;
9294
9295                 te[ 12 ] = 0;
9296                 te[ 13 ] = 0;
9297                 te[ 14 ] = 0;
9298                 te[ 15 ] = 1;
9299
9300                 return this;
9301
9302         }
9303
9304         makeRotationFromEuler( euler ) {
9305
9306                 if ( ! ( euler && euler.isEuler ) ) {
9307
9308                         console.error( 'THREE.Matrix4: .makeRotationFromEuler() now expects a Euler rotation rather than a Vector3 and order.' );
9309
9310                 }
9311
9312                 const te = this.elements;
9313
9314                 const x = euler.x, y = euler.y, z = euler.z;
9315                 const a = Math.cos( x ), b = Math.sin( x );
9316                 const c = Math.cos( y ), d = Math.sin( y );
9317                 const e = Math.cos( z ), f = Math.sin( z );
9318
9319                 if ( euler.order === 'XYZ' ) {
9320
9321                         const ae = a * e, af = a * f, be = b * e, bf = b * f;
9322
9323                         te[ 0 ] = c * e;
9324                         te[ 4 ] = - c * f;
9325                         te[ 8 ] = d;
9326
9327                         te[ 1 ] = af + be * d;
9328                         te[ 5 ] = ae - bf * d;
9329                         te[ 9 ] = - b * c;
9330
9331                         te[ 2 ] = bf - ae * d;
9332                         te[ 6 ] = be + af * d;
9333                         te[ 10 ] = a * c;
9334
9335                 } else if ( euler.order === 'YXZ' ) {
9336
9337                         const ce = c * e, cf = c * f, de = d * e, df = d * f;
9338
9339                         te[ 0 ] = ce + df * b;
9340                         te[ 4 ] = de * b - cf;
9341                         te[ 8 ] = a * d;
9342
9343                         te[ 1 ] = a * f;
9344                         te[ 5 ] = a * e;
9345                         te[ 9 ] = - b;
9346
9347                         te[ 2 ] = cf * b - de;
9348                         te[ 6 ] = df + ce * b;
9349                         te[ 10 ] = a * c;
9350
9351                 } else if ( euler.order === 'ZXY' ) {
9352
9353                         const ce = c * e, cf = c * f, de = d * e, df = d * f;
9354
9355                         te[ 0 ] = ce - df * b;
9356                         te[ 4 ] = - a * f;
9357                         te[ 8 ] = de + cf * b;
9358
9359                         te[ 1 ] = cf + de * b;
9360                         te[ 5 ] = a * e;
9361                         te[ 9 ] = df - ce * b;
9362
9363                         te[ 2 ] = - a * d;
9364                         te[ 6 ] = b;
9365                         te[ 10 ] = a * c;
9366
9367                 } else if ( euler.order === 'ZYX' ) {
9368
9369                         const ae = a * e, af = a * f, be = b * e, bf = b * f;
9370
9371                         te[ 0 ] = c * e;
9372                         te[ 4 ] = be * d - af;
9373                         te[ 8 ] = ae * d + bf;
9374
9375                         te[ 1 ] = c * f;
9376                         te[ 5 ] = bf * d + ae;
9377                         te[ 9 ] = af * d - be;
9378
9379                         te[ 2 ] = - d;
9380                         te[ 6 ] = b * c;
9381                         te[ 10 ] = a * c;
9382
9383                 } else if ( euler.order === 'YZX' ) {
9384
9385                         const ac = a * c, ad = a * d, bc = b * c, bd = b * d;
9386
9387                         te[ 0 ] = c * e;
9388                         te[ 4 ] = bd - ac * f;
9389                         te[ 8 ] = bc * f + ad;
9390
9391                         te[ 1 ] = f;
9392                         te[ 5 ] = a * e;
9393                         te[ 9 ] = - b * e;
9394
9395                         te[ 2 ] = - d * e;
9396                         te[ 6 ] = ad * f + bc;
9397                         te[ 10 ] = ac - bd * f;
9398
9399                 } else if ( euler.order === 'XZY' ) {
9400
9401                         const ac = a * c, ad = a * d, bc = b * c, bd = b * d;
9402
9403                         te[ 0 ] = c * e;
9404                         te[ 4 ] = - f;
9405                         te[ 8 ] = d * e;
9406
9407                         te[ 1 ] = ac * f + bd;
9408                         te[ 5 ] = a * e;
9409                         te[ 9 ] = ad * f - bc;
9410
9411                         te[ 2 ] = bc * f - ad;
9412                         te[ 6 ] = b * e;
9413                         te[ 10 ] = bd * f + ac;
9414
9415                 }
9416
9417                 // bottom row
9418                 te[ 3 ] = 0;
9419                 te[ 7 ] = 0;
9420                 te[ 11 ] = 0;
9421
9422                 // last column
9423                 te[ 12 ] = 0;
9424                 te[ 13 ] = 0;
9425                 te[ 14 ] = 0;
9426                 te[ 15 ] = 1;
9427
9428                 return this;
9429
9430         }
9431
9432         makeRotationFromQuaternion( q ) {
9433
9434                 return this.compose( _zero, q, _one );
9435
9436         }
9437
9438         lookAt( eye, target, up ) {
9439
9440                 const te = this.elements;
9441
9442                 _z.subVectors( eye, target );
9443
9444                 if ( _z.lengthSq() === 0 ) {
9445
9446                         // eye and target are in the same position
9447
9448                         _z.z = 1;
9449
9450                 }
9451
9452                 _z.normalize();
9453                 _x.crossVectors( up, _z );
9454
9455                 if ( _x.lengthSq() === 0 ) {
9456
9457                         // up and z are parallel
9458
9459                         if ( Math.abs( up.z ) === 1 ) {
9460
9461                                 _z.x += 0.0001;
9462
9463                         } else {
9464
9465                                 _z.z += 0.0001;
9466
9467                         }
9468
9469                         _z.normalize();
9470                         _x.crossVectors( up, _z );
9471
9472                 }
9473
9474                 _x.normalize();
9475                 _y.crossVectors( _z, _x );
9476
9477                 te[ 0 ] = _x.x; te[ 4 ] = _y.x; te[ 8 ] = _z.x;
9478                 te[ 1 ] = _x.y; te[ 5 ] = _y.y; te[ 9 ] = _z.y;
9479                 te[ 2 ] = _x.z; te[ 6 ] = _y.z; te[ 10 ] = _z.z;
9480
9481                 return this;
9482
9483         }
9484
9485         multiply( m, n ) {
9486
9487                 if ( n !== undefined ) {
9488
9489                         console.warn( 'THREE.Matrix4: .multiply() now only accepts one argument. Use .multiplyMatrices( a, b ) instead.' );
9490                         return this.multiplyMatrices( m, n );
9491
9492                 }
9493
9494                 return this.multiplyMatrices( this, m );
9495
9496         }
9497
9498         premultiply( m ) {
9499
9500                 return this.multiplyMatrices( m, this );
9501
9502         }
9503
9504         multiplyMatrices( a, b ) {
9505
9506                 const ae = a.elements;
9507                 const be = b.elements;
9508                 const te = this.elements;
9509
9510                 const a11 = ae[ 0 ], a12 = ae[ 4 ], a13 = ae[ 8 ], a14 = ae[ 12 ];
9511                 const a21 = ae[ 1 ], a22 = ae[ 5 ], a23 = ae[ 9 ], a24 = ae[ 13 ];
9512                 const a31 = ae[ 2 ], a32 = ae[ 6 ], a33 = ae[ 10 ], a34 = ae[ 14 ];
9513                 const a41 = ae[ 3 ], a42 = ae[ 7 ], a43 = ae[ 11 ], a44 = ae[ 15 ];
9514
9515                 const b11 = be[ 0 ], b12 = be[ 4 ], b13 = be[ 8 ], b14 = be[ 12 ];
9516                 const b21 = be[ 1 ], b22 = be[ 5 ], b23 = be[ 9 ], b24 = be[ 13 ];
9517                 const b31 = be[ 2 ], b32 = be[ 6 ], b33 = be[ 10 ], b34 = be[ 14 ];
9518                 const b41 = be[ 3 ], b42 = be[ 7 ], b43 = be[ 11 ], b44 = be[ 15 ];
9519
9520                 te[ 0 ] = a11 * b11 + a12 * b21 + a13 * b31 + a14 * b41;
9521                 te[ 4 ] = a11 * b12 + a12 * b22 + a13 * b32 + a14 * b42;
9522                 te[ 8 ] = a11 * b13 + a12 * b23 + a13 * b33 + a14 * b43;
9523                 te[ 12 ] = a11 * b14 + a12 * b24 + a13 * b34 + a14 * b44;
9524
9525                 te[ 1 ] = a21 * b11 + a22 * b21 + a23 * b31 + a24 * b41;
9526                 te[ 5 ] = a21 * b12 + a22 * b22 + a23 * b32 + a24 * b42;
9527                 te[ 9 ] = a21 * b13 + a22 * b23 + a23 * b33 + a24 * b43;
9528                 te[ 13 ] = a21 * b14 + a22 * b24 + a23 * b34 + a24 * b44;
9529
9530                 te[ 2 ] = a31 * b11 + a32 * b21 + a33 * b31 + a34 * b41;
9531                 te[ 6 ] = a31 * b12 + a32 * b22 + a33 * b32 + a34 * b42;
9532                 te[ 10 ] = a31 * b13 + a32 * b23 + a33 * b33 + a34 * b43;
9533                 te[ 14 ] = a31 * b14 + a32 * b24 + a33 * b34 + a34 * b44;
9534
9535                 te[ 3 ] = a41 * b11 + a42 * b21 + a43 * b31 + a44 * b41;
9536                 te[ 7 ] = a41 * b12 + a42 * b22 + a43 * b32 + a44 * b42;
9537                 te[ 11 ] = a41 * b13 + a42 * b23 + a43 * b33 + a44 * b43;
9538                 te[ 15 ] = a41 * b14 + a42 * b24 + a43 * b34 + a44 * b44;
9539
9540                 return this;
9541
9542         }
9543
9544         multiplyScalar( s ) {
9545
9546                 const te = this.elements;
9547
9548                 te[ 0 ] *= s; te[ 4 ] *= s; te[ 8 ] *= s; te[ 12 ] *= s;
9549                 te[ 1 ] *= s; te[ 5 ] *= s; te[ 9 ] *= s; te[ 13 ] *= s;
9550                 te[ 2 ] *= s; te[ 6 ] *= s; te[ 10 ] *= s; te[ 14 ] *= s;
9551                 te[ 3 ] *= s; te[ 7 ] *= s; te[ 11 ] *= s; te[ 15 ] *= s;
9552
9553                 return this;
9554
9555         }
9556
9557         determinant() {
9558
9559                 const te = this.elements;
9560
9561                 const n11 = te[ 0 ], n12 = te[ 4 ], n13 = te[ 8 ], n14 = te[ 12 ];
9562                 const n21 = te[ 1 ], n22 = te[ 5 ], n23 = te[ 9 ], n24 = te[ 13 ];
9563                 const n31 = te[ 2 ], n32 = te[ 6 ], n33 = te[ 10 ], n34 = te[ 14 ];
9564                 const n41 = te[ 3 ], n42 = te[ 7 ], n43 = te[ 11 ], n44 = te[ 15 ];
9565
9566                 //TODO: make this more efficient
9567                 //( based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm )
9568
9569                 return (
9570                         n41 * (
9571                                 + n14 * n23 * n32
9572                                  - n13 * n24 * n32
9573                                  - n14 * n22 * n33
9574                                  + n12 * n24 * n33
9575                                  + n13 * n22 * n34
9576                                  - n12 * n23 * n34
9577                         ) +
9578                         n42 * (
9579                                 + n11 * n23 * n34
9580                                  - n11 * n24 * n33
9581                                  + n14 * n21 * n33
9582                                  - n13 * n21 * n34
9583                                  + n13 * n24 * n31
9584                                  - n14 * n23 * n31
9585                         ) +
9586                         n43 * (
9587                                 + n11 * n24 * n32
9588                                  - n11 * n22 * n34
9589                                  - n14 * n21 * n32
9590                                  + n12 * n21 * n34
9591                                  + n14 * n22 * n31
9592                                  - n12 * n24 * n31
9593                         ) +
9594                         n44 * (
9595                                 - n13 * n22 * n31
9596                                  - n11 * n23 * n32
9597                                  + n11 * n22 * n33
9598                                  + n13 * n21 * n32
9599                                  - n12 * n21 * n33
9600                                  + n12 * n23 * n31
9601                         )
9602
9603                 );
9604
9605         }
9606
9607         transpose() {
9608
9609                 const te = this.elements;
9610                 let tmp;
9611
9612                 tmp = te[ 1 ]; te[ 1 ] = te[ 4 ]; te[ 4 ] = tmp;
9613                 tmp = te[ 2 ]; te[ 2 ] = te[ 8 ]; te[ 8 ] = tmp;
9614                 tmp = te[ 6 ]; te[ 6 ] = te[ 9 ]; te[ 9 ] = tmp;
9615
9616                 tmp = te[ 3 ]; te[ 3 ] = te[ 12 ]; te[ 12 ] = tmp;
9617                 tmp = te[ 7 ]; te[ 7 ] = te[ 13 ]; te[ 13 ] = tmp;
9618                 tmp = te[ 11 ]; te[ 11 ] = te[ 14 ]; te[ 14 ] = tmp;
9619
9620                 return this;
9621
9622         }
9623
9624         setPosition( x, y, z ) {
9625
9626                 const te = this.elements;
9627
9628                 if ( x.isVector3 ) {
9629
9630                         te[ 12 ] = x.x;
9631                         te[ 13 ] = x.y;
9632                         te[ 14 ] = x.z;
9633
9634                 } else {
9635
9636                         te[ 12 ] = x;
9637                         te[ 13 ] = y;
9638                         te[ 14 ] = z;
9639
9640                 }
9641
9642                 return this;
9643
9644         }
9645
9646         invert() {
9647
9648                 // based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm
9649                 const te = this.elements,
9650
9651                         n11 = te[ 0 ], n21 = te[ 1 ], n31 = te[ 2 ], n41 = te[ 3 ],
9652                         n12 = te[ 4 ], n22 = te[ 5 ], n32 = te[ 6 ], n42 = te[ 7 ],
9653                         n13 = te[ 8 ], n23 = te[ 9 ], n33 = te[ 10 ], n43 = te[ 11 ],
9654                         n14 = te[ 12 ], n24 = te[ 13 ], n34 = te[ 14 ], n44 = te[ 15 ],
9655
9656                         t11 = n23 * n34 * n42 - n24 * n33 * n42 + n24 * n32 * n43 - n22 * n34 * n43 - n23 * n32 * n44 + n22 * n33 * n44,
9657                         t12 = n14 * n33 * n42 - n13 * n34 * n42 - n14 * n32 * n43 + n12 * n34 * n43 + n13 * n32 * n44 - n12 * n33 * n44,
9658                         t13 = n13 * n24 * n42 - n14 * n23 * n42 + n14 * n22 * n43 - n12 * n24 * n43 - n13 * n22 * n44 + n12 * n23 * n44,
9659                         t14 = n14 * n23 * n32 - n13 * n24 * n32 - n14 * n22 * n33 + n12 * n24 * n33 + n13 * n22 * n34 - n12 * n23 * n34;
9660
9661                 const det = n11 * t11 + n21 * t12 + n31 * t13 + n41 * t14;
9662
9663                 if ( det === 0 ) return this.set( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 );
9664
9665                 const detInv = 1 / det;
9666
9667                 te[ 0 ] = t11 * detInv;
9668                 te[ 1 ] = ( n24 * n33 * n41 - n23 * n34 * n41 - n24 * n31 * n43 + n21 * n34 * n43 + n23 * n31 * n44 - n21 * n33 * n44 ) * detInv;
9669                 te[ 2 ] = ( n22 * n34 * n41 - n24 * n32 * n41 + n24 * n31 * n42 - n21 * n34 * n42 - n22 * n31 * n44 + n21 * n32 * n44 ) * detInv;
9670                 te[ 3 ] = ( n23 * n32 * n41 - n22 * n33 * n41 - n23 * n31 * n42 + n21 * n33 * n42 + n22 * n31 * n43 - n21 * n32 * n43 ) * detInv;
9671
9672                 te[ 4 ] = t12 * detInv;
9673                 te[ 5 ] = ( n13 * n34 * n41 - n14 * n33 * n41 + n14 * n31 * n43 - n11 * n34 * n43 - n13 * n31 * n44 + n11 * n33 * n44 ) * detInv;
9674                 te[ 6 ] = ( n14 * n32 * n41 - n12 * n34 * n41 - n14 * n31 * n42 + n11 * n34 * n42 + n12 * n31 * n44 - n11 * n32 * n44 ) * detInv;
9675                 te[ 7 ] = ( n12 * n33 * n41 - n13 * n32 * n41 + n13 * n31 * n42 - n11 * n33 * n42 - n12 * n31 * n43 + n11 * n32 * n43 ) * detInv;
9676
9677                 te[ 8 ] = t13 * detInv;
9678                 te[ 9 ] = ( n14 * n23 * n41 - n13 * n24 * n41 - n14 * n21 * n43 + n11 * n24 * n43 + n13 * n21 * n44 - n11 * n23 * n44 ) * detInv;
9679                 te[ 10 ] = ( n12 * n24 * n41 - n14 * n22 * n41 + n14 * n21 * n42 - n11 * n24 * n42 - n12 * n21 * n44 + n11 * n22 * n44 ) * detInv;
9680                 te[ 11 ] = ( n13 * n22 * n41 - n12 * n23 * n41 - n13 * n21 * n42 + n11 * n23 * n42 + n12 * n21 * n43 - n11 * n22 * n43 ) * detInv;
9681
9682                 te[ 12 ] = t14 * detInv;
9683                 te[ 13 ] = ( n13 * n24 * n31 - n14 * n23 * n31 + n14 * n21 * n33 - n11 * n24 * n33 - n13 * n21 * n34 + n11 * n23 * n34 ) * detInv;
9684                 te[ 14 ] = ( n14 * n22 * n31 - n12 * n24 * n31 - n14 * n21 * n32 + n11 * n24 * n32 + n12 * n21 * n34 - n11 * n22 * n34 ) * detInv;
9685                 te[ 15 ] = ( n12 * n23 * n31 - n13 * n22 * n31 + n13 * n21 * n32 - n11 * n23 * n32 - n12 * n21 * n33 + n11 * n22 * n33 ) * detInv;
9686
9687                 return this;
9688
9689         }
9690
9691         scale( v ) {
9692
9693                 const te = this.elements;
9694                 const x = v.x, y = v.y, z = v.z;
9695
9696                 te[ 0 ] *= x; te[ 4 ] *= y; te[ 8 ] *= z;
9697                 te[ 1 ] *= x; te[ 5 ] *= y; te[ 9 ] *= z;
9698                 te[ 2 ] *= x; te[ 6 ] *= y; te[ 10 ] *= z;
9699                 te[ 3 ] *= x; te[ 7 ] *= y; te[ 11 ] *= z;
9700
9701                 return this;
9702
9703         }
9704
9705         getMaxScaleOnAxis() {
9706
9707                 const te = this.elements;
9708
9709                 const scaleXSq = te[ 0 ] * te[ 0 ] + te[ 1 ] * te[ 1 ] + te[ 2 ] * te[ 2 ];
9710                 const scaleYSq = te[ 4 ] * te[ 4 ] + te[ 5 ] * te[ 5 ] + te[ 6 ] * te[ 6 ];
9711                 const scaleZSq = te[ 8 ] * te[ 8 ] + te[ 9 ] * te[ 9 ] + te[ 10 ] * te[ 10 ];
9712
9713                 return Math.sqrt( Math.max( scaleXSq, scaleYSq, scaleZSq ) );
9714
9715         }
9716
9717         makeTranslation( x, y, z ) {
9718
9719                 this.set(
9720
9721                         1, 0, 0, x,
9722                         0, 1, 0, y,
9723                         0, 0, 1, z,
9724                         0, 0, 0, 1
9725
9726                 );
9727
9728                 return this;
9729
9730         }
9731
9732         makeRotationX( theta ) {
9733
9734                 const c = Math.cos( theta ), s = Math.sin( theta );
9735
9736                 this.set(
9737
9738                         1, 0, 0, 0,
9739                         0, c, - s, 0,
9740                         0, s, c, 0,
9741                         0, 0, 0, 1
9742
9743                 );
9744
9745                 return this;
9746
9747         }
9748
9749         makeRotationY( theta ) {
9750
9751                 const c = Math.cos( theta ), s = Math.sin( theta );
9752
9753                 this.set(
9754
9755                          c, 0, s, 0,
9756                          0, 1, 0, 0,
9757                         - s, 0, c, 0,
9758                          0, 0, 0, 1
9759
9760                 );
9761
9762                 return this;
9763
9764         }
9765
9766         makeRotationZ( theta ) {
9767
9768                 const c = Math.cos( theta ), s = Math.sin( theta );
9769
9770                 this.set(
9771
9772                         c, - s, 0, 0,
9773                         s, c, 0, 0,
9774                         0, 0, 1, 0,
9775                         0, 0, 0, 1
9776
9777                 );
9778
9779                 return this;
9780
9781         }
9782
9783         makeRotationAxis( axis, angle ) {
9784
9785                 // Based on http://www.gamedev.net/reference/articles/article1199.asp
9786
9787                 const c = Math.cos( angle );
9788                 const s = Math.sin( angle );
9789                 const t = 1 - c;
9790                 const x = axis.x, y = axis.y, z = axis.z;
9791                 const tx = t * x, ty = t * y;
9792
9793                 this.set(
9794
9795                         tx * x + c, tx * y - s * z, tx * z + s * y, 0,
9796                         tx * y + s * z, ty * y + c, ty * z - s * x, 0,
9797                         tx * z - s * y, ty * z + s * x, t * z * z + c, 0,
9798                         0, 0, 0, 1
9799
9800                 );
9801
9802                 return this;
9803
9804         }
9805
9806         makeScale( x, y, z ) {
9807
9808                 this.set(
9809
9810                         x, 0, 0, 0,
9811                         0, y, 0, 0,
9812                         0, 0, z, 0,
9813                         0, 0, 0, 1
9814
9815                 );
9816
9817                 return this;
9818
9819         }
9820
9821         makeShear( x, y, z ) {
9822
9823                 this.set(
9824
9825                         1, y, z, 0,
9826                         x, 1, z, 0,
9827                         x, y, 1, 0,
9828                         0, 0, 0, 1
9829
9830                 );
9831
9832                 return this;
9833
9834         }
9835
9836         compose( position, quaternion, scale ) {
9837
9838                 const te = this.elements;
9839
9840                 const x = quaternion._x, y = quaternion._y, z = quaternion._z, w = quaternion._w;
9841                 const x2 = x + x,       y2 = y + y, z2 = z + z;
9842                 const xx = x * x2, xy = x * y2, xz = x * z2;
9843                 const yy = y * y2, yz = y * z2, zz = z * z2;
9844                 const wx = w * x2, wy = w * y2, wz = w * z2;
9845
9846                 const sx = scale.x, sy = scale.y, sz = scale.z;
9847
9848                 te[ 0 ] = ( 1 - ( yy + zz ) ) * sx;
9849                 te[ 1 ] = ( xy + wz ) * sx;
9850                 te[ 2 ] = ( xz - wy ) * sx;
9851                 te[ 3 ] = 0;
9852
9853                 te[ 4 ] = ( xy - wz ) * sy;
9854                 te[ 5 ] = ( 1 - ( xx + zz ) ) * sy;
9855                 te[ 6 ] = ( yz + wx ) * sy;
9856                 te[ 7 ] = 0;
9857
9858                 te[ 8 ] = ( xz + wy ) * sz;
9859                 te[ 9 ] = ( yz - wx ) * sz;
9860                 te[ 10 ] = ( 1 - ( xx + yy ) ) * sz;
9861                 te[ 11 ] = 0;
9862
9863                 te[ 12 ] = position.x;
9864                 te[ 13 ] = position.y;
9865                 te[ 14 ] = position.z;
9866                 te[ 15 ] = 1;
9867
9868                 return this;
9869
9870         }
9871
9872         decompose( position, quaternion, scale ) {
9873
9874                 const te = this.elements;
9875
9876                 let sx = _v1$1.set( te[ 0 ], te[ 1 ], te[ 2 ] ).length();
9877                 const sy = _v1$1.set( te[ 4 ], te[ 5 ], te[ 6 ] ).length();
9878                 const sz = _v1$1.set( te[ 8 ], te[ 9 ], te[ 10 ] ).length();
9879
9880                 // if determine is negative, we need to invert one scale
9881                 const det = this.determinant();
9882                 if ( det < 0 ) sx = - sx;
9883
9884                 position.x = te[ 12 ];
9885                 position.y = te[ 13 ];
9886                 position.z = te[ 14 ];
9887
9888                 // scale the rotation part
9889                 _m1.copy( this );
9890
9891                 const invSX = 1 / sx;
9892                 const invSY = 1 / sy;
9893                 const invSZ = 1 / sz;
9894
9895                 _m1.elements[ 0 ] *= invSX;
9896                 _m1.elements[ 1 ] *= invSX;
9897                 _m1.elements[ 2 ] *= invSX;
9898
9899                 _m1.elements[ 4 ] *= invSY;
9900                 _m1.elements[ 5 ] *= invSY;
9901                 _m1.elements[ 6 ] *= invSY;
9902
9903                 _m1.elements[ 8 ] *= invSZ;
9904                 _m1.elements[ 9 ] *= invSZ;
9905                 _m1.elements[ 10 ] *= invSZ;
9906
9907                 quaternion.setFromRotationMatrix( _m1 );
9908
9909                 scale.x = sx;
9910                 scale.y = sy;
9911                 scale.z = sz;
9912
9913                 return this;
9914
9915         }
9916
9917         makePerspective( left, right, top, bottom, near, far ) {
9918
9919                 if ( far === undefined ) {
9920
9921                         console.warn( 'THREE.Matrix4: .makePerspective() has been redefined and has a new signature. Please check the docs.' );
9922
9923                 }
9924
9925                 const te = this.elements;
9926                 const x = 2 * near / ( right - left );
9927                 const y = 2 * near / ( top - bottom );
9928
9929                 const a = ( right + left ) / ( right - left );
9930                 const b = ( top + bottom ) / ( top - bottom );
9931                 const c = - ( far + near ) / ( far - near );
9932                 const d = - 2 * far * near / ( far - near );
9933
9934                 te[ 0 ] = x;    te[ 4 ] = 0;    te[ 8 ] = a;    te[ 12 ] = 0;
9935                 te[ 1 ] = 0;    te[ 5 ] = y;    te[ 9 ] = b;    te[ 13 ] = 0;
9936                 te[ 2 ] = 0;    te[ 6 ] = 0;    te[ 10 ] = c;   te[ 14 ] = d;
9937                 te[ 3 ] = 0;    te[ 7 ] = 0;    te[ 11 ] = - 1; te[ 15 ] = 0;
9938
9939                 return this;
9940
9941         }
9942
9943         makeOrthographic( left, right, top, bottom, near, far ) {
9944
9945                 const te = this.elements;
9946                 const w = 1.0 / ( right - left );
9947                 const h = 1.0 / ( top - bottom );
9948                 const p = 1.0 / ( far - near );
9949
9950                 const x = ( right + left ) * w;
9951                 const y = ( top + bottom ) * h;
9952                 const z = ( far + near ) * p;
9953
9954                 te[ 0 ] = 2 * w;        te[ 4 ] = 0;    te[ 8 ] = 0;    te[ 12 ] = - x;
9955                 te[ 1 ] = 0;    te[ 5 ] = 2 * h;        te[ 9 ] = 0;    te[ 13 ] = - y;
9956                 te[ 2 ] = 0;    te[ 6 ] = 0;    te[ 10 ] = - 2 * p;     te[ 14 ] = - z;
9957                 te[ 3 ] = 0;    te[ 7 ] = 0;    te[ 11 ] = 0;   te[ 15 ] = 1;
9958
9959                 return this;
9960
9961         }
9962
9963         equals( matrix ) {
9964
9965                 const te = this.elements;
9966                 const me = matrix.elements;
9967
9968                 for ( let i = 0; i < 16; i ++ ) {
9969
9970                         if ( te[ i ] !== me[ i ] ) return false;
9971
9972                 }
9973
9974                 return true;
9975
9976         }
9977
9978         fromArray( array, offset = 0 ) {
9979
9980                 for ( let i = 0; i < 16; i ++ ) {
9981
9982                         this.elements[ i ] = array[ i + offset ];
9983
9984                 }
9985
9986                 return this;
9987
9988         }
9989
9990         toArray( array = [], offset = 0 ) {
9991
9992                 const te = this.elements;
9993
9994                 array[ offset ] = te[ 0 ];
9995                 array[ offset + 1 ] = te[ 1 ];
9996                 array[ offset + 2 ] = te[ 2 ];
9997                 array[ offset + 3 ] = te[ 3 ];
9998
9999                 array[ offset + 4 ] = te[ 4 ];
10000                 array[ offset + 5 ] = te[ 5 ];
10001                 array[ offset + 6 ] = te[ 6 ];
10002                 array[ offset + 7 ] = te[ 7 ];
10003
10004                 array[ offset + 8 ] = te[ 8 ];
10005                 array[ offset + 9 ] = te[ 9 ];
10006                 array[ offset + 10 ] = te[ 10 ];
10007                 array[ offset + 11 ] = te[ 11 ];
10008
10009                 array[ offset + 12 ] = te[ 12 ];
10010                 array[ offset + 13 ] = te[ 13 ];
10011                 array[ offset + 14 ] = te[ 14 ];
10012                 array[ offset + 15 ] = te[ 15 ];
10013
10014                 return array;
10015
10016         }
10017
10018 }
10019
10020 const _v1$1 = /*@__PURE__*/ new Vector3();
10021 const _m1 = /*@__PURE__*/ new Matrix4();
10022 const _zero = /*@__PURE__*/ new Vector3( 0, 0, 0 );
10023 const _one = /*@__PURE__*/ new Vector3( 1, 1, 1 );
10024 const _x = /*@__PURE__*/ new Vector3();
10025 const _y = /*@__PURE__*/ new Vector3();
10026 const _z = /*@__PURE__*/ new Vector3();
10027
10028 class Euler {
10029
10030         constructor( x = 0, y = 0, z = 0, order = Euler.DefaultOrder ) {
10031
10032                 Object.defineProperty( this, 'isEuler', { value: true } );
10033
10034                 this._x = x;
10035                 this._y = y;
10036                 this._z = z;
10037                 this._order = order;
10038
10039         }
10040
10041         get x() {
10042
10043                 return this._x;
10044
10045         }
10046
10047         set x( value ) {
10048
10049                 this._x = value;
10050                 this._onChangeCallback();
10051
10052         }
10053
10054         get y() {
10055
10056                 return this._y;
10057
10058         }
10059
10060         set y( value ) {
10061
10062                 this._y = value;
10063                 this._onChangeCallback();
10064
10065         }
10066
10067         get z() {
10068
10069                 return this._z;
10070
10071         }
10072
10073         set z( value ) {
10074
10075                 this._z = value;
10076                 this._onChangeCallback();
10077
10078         }
10079
10080         get order() {
10081
10082                 return this._order;
10083
10084         }
10085
10086         set order( value ) {
10087
10088                 this._order = value;
10089                 this._onChangeCallback();
10090
10091         }
10092
10093         set( x, y, z, order ) {
10094
10095                 this._x = x;
10096                 this._y = y;
10097                 this._z = z;
10098                 this._order = order || this._order;
10099
10100                 this._onChangeCallback();
10101
10102                 return this;
10103
10104         }
10105
10106         clone() {
10107
10108                 return new this.constructor( this._x, this._y, this._z, this._order );
10109
10110         }
10111
10112         copy( euler ) {
10113
10114                 this._x = euler._x;
10115                 this._y = euler._y;
10116                 this._z = euler._z;
10117                 this._order = euler._order;
10118
10119                 this._onChangeCallback();
10120
10121                 return this;
10122
10123         }
10124
10125         setFromRotationMatrix( m, order, update ) {
10126
10127                 const clamp = MathUtils.clamp;
10128
10129                 // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)
10130
10131                 const te = m.elements;
10132                 const m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ];
10133                 const m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ];
10134                 const m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ];
10135
10136                 order = order || this._order;
10137
10138                 switch ( order ) {
10139
10140                         case 'XYZ':
10141
10142                                 this._y = Math.asin( clamp( m13, - 1, 1 ) );
10143
10144                                 if ( Math.abs( m13 ) < 0.9999999 ) {
10145
10146                                         this._x = Math.atan2( - m23, m33 );
10147                                         this._z = Math.atan2( - m12, m11 );
10148
10149                                 } else {
10150
10151                                         this._x = Math.atan2( m32, m22 );
10152                                         this._z = 0;
10153
10154                                 }
10155
10156                                 break;
10157
10158                         case 'YXZ':
10159
10160                                 this._x = Math.asin( - clamp( m23, - 1, 1 ) );
10161
10162                                 if ( Math.abs( m23 ) < 0.9999999 ) {
10163
10164                                         this._y = Math.atan2( m13, m33 );
10165                                         this._z = Math.atan2( m21, m22 );
10166
10167                                 } else {
10168
10169                                         this._y = Math.atan2( - m31, m11 );
10170                                         this._z = 0;
10171
10172                                 }
10173
10174                                 break;
10175
10176                         case 'ZXY':
10177
10178                                 this._x = Math.asin( clamp( m32, - 1, 1 ) );
10179
10180                                 if ( Math.abs( m32 ) < 0.9999999 ) {
10181
10182                                         this._y = Math.atan2( - m31, m33 );
10183                                         this._z = Math.atan2( - m12, m22 );
10184
10185                                 } else {
10186
10187                                         this._y = 0;
10188                                         this._z = Math.atan2( m21, m11 );
10189
10190                                 }
10191
10192                                 break;
10193
10194                         case 'ZYX':
10195
10196                                 this._y = Math.asin( - clamp( m31, - 1, 1 ) );
10197
10198                                 if ( Math.abs( m31 ) < 0.9999999 ) {
10199
10200                                         this._x = Math.atan2( m32, m33 );
10201                                         this._z = Math.atan2( m21, m11 );
10202
10203                                 } else {
10204
10205                                         this._x = 0;
10206                                         this._z = Math.atan2( - m12, m22 );
10207
10208                                 }
10209
10210                                 break;
10211
10212                         case 'YZX':
10213
10214                                 this._z = Math.asin( clamp( m21, - 1, 1 ) );
10215
10216                                 if ( Math.abs( m21 ) < 0.9999999 ) {
10217
10218                                         this._x = Math.atan2( - m23, m22 );
10219                                         this._y = Math.atan2( - m31, m11 );
10220
10221                                 } else {
10222
10223                                         this._x = 0;
10224                                         this._y = Math.atan2( m13, m33 );
10225
10226                                 }
10227
10228                                 break;
10229
10230                         case 'XZY':
10231
10232                                 this._z = Math.asin( - clamp( m12, - 1, 1 ) );
10233
10234                                 if ( Math.abs( m12 ) < 0.9999999 ) {
10235
10236                                         this._x = Math.atan2( m32, m22 );
10237                                         this._y = Math.atan2( m13, m11 );
10238
10239                                 } else {
10240
10241                                         this._x = Math.atan2( - m23, m33 );
10242                                         this._y = 0;
10243
10244                                 }
10245
10246                                 break;
10247
10248                         default:
10249
10250                                 console.warn( 'THREE.Euler: .setFromRotationMatrix() encountered an unknown order: ' + order );
10251
10252                 }
10253
10254                 this._order = order;
10255
10256                 if ( update !== false ) this._onChangeCallback();
10257
10258                 return this;
10259
10260         }
10261
10262         setFromQuaternion( q, order, update ) {
10263
10264                 _matrix.makeRotationFromQuaternion( q );
10265
10266                 return this.setFromRotationMatrix( _matrix, order, update );
10267
10268         }
10269
10270         setFromVector3( v, order ) {
10271
10272                 return this.set( v.x, v.y, v.z, order || this._order );
10273
10274         }
10275
10276         reorder( newOrder ) {
10277
10278                 // WARNING: this discards revolution information -bhouston
10279
10280                 _quaternion$1.setFromEuler( this );
10281
10282                 return this.setFromQuaternion( _quaternion$1, newOrder );
10283
10284         }
10285
10286         equals( euler ) {
10287
10288                 return ( euler._x === this._x ) && ( euler._y === this._y ) && ( euler._z === this._z ) && ( euler._order === this._order );
10289
10290         }
10291
10292         fromArray( array ) {
10293
10294                 this._x = array[ 0 ];
10295                 this._y = array[ 1 ];
10296                 this._z = array[ 2 ];
10297                 if ( array[ 3 ] !== undefined ) this._order = array[ 3 ];
10298
10299                 this._onChangeCallback();
10300
10301                 return this;
10302
10303         }
10304
10305         toArray( array = [], offset = 0 ) {
10306
10307                 array[ offset ] = this._x;
10308                 array[ offset + 1 ] = this._y;
10309                 array[ offset + 2 ] = this._z;
10310                 array[ offset + 3 ] = this._order;
10311
10312                 return array;
10313
10314         }
10315
10316         toVector3( optionalResult ) {
10317
10318                 if ( optionalResult ) {
10319
10320                         return optionalResult.set( this._x, this._y, this._z );
10321
10322                 } else {
10323
10324                         return new Vector3( this._x, this._y, this._z );
10325
10326                 }
10327
10328         }
10329
10330         _onChange( callback ) {
10331
10332                 this._onChangeCallback = callback;
10333
10334                 return this;
10335
10336         }
10337
10338         _onChangeCallback() {}
10339
10340 }
10341
10342 Euler.DefaultOrder = 'XYZ';
10343 Euler.RotationOrders = [ 'XYZ', 'YZX', 'ZXY', 'XZY', 'YXZ', 'ZYX' ];
10344
10345 const _matrix = /*@__PURE__*/ new Matrix4();
10346 const _quaternion$1 = /*@__PURE__*/ new Quaternion();
10347
10348 class Layers {
10349
10350         constructor() {
10351
10352                 this.mask = 1 | 0;
10353
10354         }
10355
10356         set( channel ) {
10357
10358                 this.mask = 1 << channel | 0;
10359
10360         }
10361
10362         enable( channel ) {
10363
10364                 this.mask |= 1 << channel | 0;
10365
10366         }
10367
10368         enableAll() {
10369
10370                 this.mask = 0xffffffff | 0;
10371
10372         }
10373
10374         toggle( channel ) {
10375
10376                 this.mask ^= 1 << channel | 0;
10377
10378         }
10379
10380         disable( channel ) {
10381
10382                 this.mask &= ~ ( 1 << channel | 0 );
10383
10384         }
10385
10386         disableAll() {
10387
10388                 this.mask = 0;
10389
10390         }
10391
10392         test( layers ) {
10393
10394                 return ( this.mask & layers.mask ) !== 0;
10395
10396         }
10397
10398 }
10399
10400 let _object3DId = 0;
10401
10402 const _v1$2 = new Vector3();
10403 const _q1 = new Quaternion();
10404 const _m1$1 = new Matrix4();
10405 const _target = new Vector3();
10406
10407 const _position = new Vector3();
10408 const _scale = new Vector3();
10409 const _quaternion$2 = new Quaternion();
10410
10411 const _xAxis = new Vector3( 1, 0, 0 );
10412 const _yAxis = new Vector3( 0, 1, 0 );
10413 const _zAxis = new Vector3( 0, 0, 1 );
10414
10415 const _addedEvent = { type: 'added' };
10416 const _removedEvent = { type: 'removed' };
10417
10418 function Object3D() {
10419
10420         Object.defineProperty( this, 'id', { value: _object3DId ++ } );
10421
10422         this.uuid = MathUtils.generateUUID();
10423
10424         this.name = '';
10425         this.type = 'Object3D';
10426
10427         this.parent = null;
10428         this.children = [];
10429
10430         this.up = Object3D.DefaultUp.clone();
10431
10432         const position = new Vector3();
10433         const rotation = new Euler();
10434         const quaternion = new Quaternion();
10435         const scale = new Vector3( 1, 1, 1 );
10436
10437         function onRotationChange() {
10438
10439                 quaternion.setFromEuler( rotation, false );
10440
10441         }
10442
10443         function onQuaternionChange() {
10444
10445                 rotation.setFromQuaternion( quaternion, undefined, false );
10446
10447         }
10448
10449         rotation._onChange( onRotationChange );
10450         quaternion._onChange( onQuaternionChange );
10451
10452         Object.defineProperties( this, {
10453                 position: {
10454                         configurable: true,
10455                         enumerable: true,
10456                         value: position
10457                 },
10458                 rotation: {
10459                         configurable: true,
10460                         enumerable: true,
10461                         value: rotation
10462                 },
10463                 quaternion: {
10464                         configurable: true,
10465                         enumerable: true,
10466                         value: quaternion
10467                 },
10468                 scale: {
10469                         configurable: true,
10470                         enumerable: true,
10471                         value: scale
10472                 },
10473                 modelViewMatrix: {
10474                         value: new Matrix4()
10475                 },
10476                 normalMatrix: {
10477                         value: new Matrix3()
10478                 }
10479         } );
10480
10481         this.matrix = new Matrix4();
10482         this.matrixWorld = new Matrix4();
10483
10484         this.matrixAutoUpdate = Object3D.DefaultMatrixAutoUpdate;
10485         this.matrixWorldNeedsUpdate = false;
10486
10487         this.layers = new Layers();
10488         this.visible = true;
10489
10490         this.castShadow = false;
10491         this.receiveShadow = false;
10492
10493         this.frustumCulled = true;
10494         this.renderOrder = 0;
10495
10496         this.animations = [];
10497
10498         this.userData = {};
10499
10500 }
10501
10502 Object3D.DefaultUp = new Vector3( 0, 1, 0 );
10503 Object3D.DefaultMatrixAutoUpdate = true;
10504
10505 Object3D.prototype = Object.assign( Object.create( EventDispatcher.prototype ), {
10506
10507         constructor: Object3D,
10508
10509         isObject3D: true,
10510
10511         onBeforeRender: function () {},
10512         onAfterRender: function () {},
10513
10514         applyMatrix4: function ( matrix ) {
10515
10516                 if ( this.matrixAutoUpdate ) this.updateMatrix();
10517
10518                 this.matrix.premultiply( matrix );
10519
10520                 this.matrix.decompose( this.position, this.quaternion, this.scale );
10521
10522         },
10523
10524         applyQuaternion: function ( q ) {
10525
10526                 this.quaternion.premultiply( q );
10527
10528                 return this;
10529
10530         },
10531
10532         setRotationFromAxisAngle: function ( axis, angle ) {
10533
10534                 // assumes axis is normalized
10535
10536                 this.quaternion.setFromAxisAngle( axis, angle );
10537
10538         },
10539
10540         setRotationFromEuler: function ( euler ) {
10541
10542                 this.quaternion.setFromEuler( euler, true );
10543
10544         },
10545
10546         setRotationFromMatrix: function ( m ) {
10547
10548                 // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)
10549
10550                 this.quaternion.setFromRotationMatrix( m );
10551
10552         },
10553
10554         setRotationFromQuaternion: function ( q ) {
10555
10556                 // assumes q is normalized
10557
10558                 this.quaternion.copy( q );
10559
10560         },
10561
10562         rotateOnAxis: function ( axis, angle ) {
10563
10564                 // rotate object on axis in object space
10565                 // axis is assumed to be normalized
10566
10567                 _q1.setFromAxisAngle( axis, angle );
10568
10569                 this.quaternion.multiply( _q1 );
10570
10571                 return this;
10572
10573         },
10574
10575         rotateOnWorldAxis: function ( axis, angle ) {
10576
10577                 // rotate object on axis in world space
10578                 // axis is assumed to be normalized
10579                 // method assumes no rotated parent
10580
10581                 _q1.setFromAxisAngle( axis, angle );
10582
10583                 this.quaternion.premultiply( _q1 );
10584
10585                 return this;
10586
10587         },
10588
10589         rotateX: function ( angle ) {
10590
10591                 return this.rotateOnAxis( _xAxis, angle );
10592
10593         },
10594
10595         rotateY: function ( angle ) {
10596
10597                 return this.rotateOnAxis( _yAxis, angle );
10598
10599         },
10600
10601         rotateZ: function ( angle ) {
10602
10603                 return this.rotateOnAxis( _zAxis, angle );
10604
10605         },
10606
10607         translateOnAxis: function ( axis, distance ) {
10608
10609                 // translate object by distance along axis in object space
10610                 // axis is assumed to be normalized
10611
10612                 _v1$2.copy( axis ).applyQuaternion( this.quaternion );
10613
10614                 this.position.add( _v1$2.multiplyScalar( distance ) );
10615
10616                 return this;
10617
10618         },
10619
10620         translateX: function ( distance ) {
10621
10622                 return this.translateOnAxis( _xAxis, distance );
10623
10624         },
10625
10626         translateY: function ( distance ) {
10627
10628                 return this.translateOnAxis( _yAxis, distance );
10629
10630         },
10631
10632         translateZ: function ( distance ) {
10633
10634                 return this.translateOnAxis( _zAxis, distance );
10635
10636         },
10637
10638         localToWorld: function ( vector ) {
10639
10640                 return vector.applyMatrix4( this.matrixWorld );
10641
10642         },
10643
10644         worldToLocal: function ( vector ) {
10645
10646                 return vector.applyMatrix4( _m1$1.copy( this.matrixWorld ).invert() );
10647
10648         },
10649
10650         lookAt: function ( x, y, z ) {
10651
10652                 // This method does not support objects having non-uniformly-scaled parent(s)
10653
10654                 if ( x.isVector3 ) {
10655
10656                         _target.copy( x );
10657
10658                 } else {
10659
10660                         _target.set( x, y, z );
10661
10662                 }
10663
10664                 const parent = this.parent;
10665
10666                 this.updateWorldMatrix( true, false );
10667
10668                 _position.setFromMatrixPosition( this.matrixWorld );
10669
10670                 if ( this.isCamera || this.isLight ) {
10671
10672                         _m1$1.lookAt( _position, _target, this.up );
10673
10674                 } else {
10675
10676                         _m1$1.lookAt( _target, _position, this.up );
10677
10678                 }
10679
10680                 this.quaternion.setFromRotationMatrix( _m1$1 );
10681
10682                 if ( parent ) {
10683
10684                         _m1$1.extractRotation( parent.matrixWorld );
10685                         _q1.setFromRotationMatrix( _m1$1 );
10686                         this.quaternion.premultiply( _q1.invert() );
10687
10688                 }
10689
10690         },
10691
10692         add: function ( object ) {
10693
10694                 if ( arguments.length > 1 ) {
10695
10696                         for ( let i = 0; i < arguments.length; i ++ ) {
10697
10698                                 this.add( arguments[ i ] );
10699
10700                         }
10701
10702                         return this;
10703
10704                 }
10705
10706                 if ( object === this ) {
10707
10708                         console.error( 'THREE.Object3D.add: object can\'t be added as a child of itself.', object );
10709                         return this;
10710
10711                 }
10712
10713                 if ( object && object.isObject3D ) {
10714
10715                         if ( object.parent !== null ) {
10716
10717                                 object.parent.remove( object );
10718
10719                         }
10720
10721                         object.parent = this;
10722                         this.children.push( object );
10723
10724                         object.dispatchEvent( _addedEvent );
10725
10726                 } else {
10727
10728                         console.error( 'THREE.Object3D.add: object not an instance of THREE.Object3D.', object );
10729
10730                 }
10731
10732                 return this;
10733
10734         },
10735
10736         remove: function ( object ) {
10737
10738                 if ( arguments.length > 1 ) {
10739
10740                         for ( let i = 0; i < arguments.length; i ++ ) {
10741
10742                                 this.remove( arguments[ i ] );
10743
10744                         }
10745
10746                         return this;
10747
10748                 }
10749
10750                 const index = this.children.indexOf( object );
10751
10752                 if ( index !== - 1 ) {
10753
10754                         object.parent = null;
10755                         this.children.splice( index, 1 );
10756
10757                         object.dispatchEvent( _removedEvent );
10758
10759                 }
10760
10761                 return this;
10762
10763         },
10764
10765         clear: function () {
10766
10767                 for ( let i = 0; i < this.children.length; i ++ ) {
10768
10769                         const object = this.children[ i ];
10770
10771                         object.parent = null;
10772
10773                         object.dispatchEvent( _removedEvent );
10774
10775                 }
10776
10777                 this.children.length = 0;
10778
10779                 return this;
10780
10781
10782         },
10783
10784         attach: function ( object ) {
10785
10786                 // adds object as a child of this, while maintaining the object's world transform
10787
10788                 this.updateWorldMatrix( true, false );
10789
10790                 _m1$1.copy( this.matrixWorld ).invert();
10791
10792                 if ( object.parent !== null ) {
10793
10794                         object.parent.updateWorldMatrix( true, false );
10795
10796                         _m1$1.multiply( object.parent.matrixWorld );
10797
10798                 }
10799
10800                 object.applyMatrix4( _m1$1 );
10801
10802                 object.updateWorldMatrix( false, false );
10803
10804                 this.add( object );
10805
10806                 return this;
10807
10808         },
10809
10810         getObjectById: function ( id ) {
10811
10812                 return this.getObjectByProperty( 'id', id );
10813
10814         },
10815
10816         getObjectByName: function ( name ) {
10817
10818                 return this.getObjectByProperty( 'name', name );
10819
10820         },
10821
10822         getObjectByProperty: function ( name, value ) {
10823
10824                 if ( this[ name ] === value ) return this;
10825
10826                 for ( let i = 0, l = this.children.length; i < l; i ++ ) {
10827
10828                         const child = this.children[ i ];
10829                         const object = child.getObjectByProperty( name, value );
10830
10831                         if ( object !== undefined ) {
10832
10833                                 return object;
10834
10835                         }
10836
10837                 }
10838
10839                 return undefined;
10840
10841         },
10842
10843         getWorldPosition: function ( target ) {
10844
10845                 if ( target === undefined ) {
10846
10847                         console.warn( 'THREE.Object3D: .getWorldPosition() target is now required' );
10848                         target = new Vector3();
10849
10850                 }
10851
10852                 this.updateWorldMatrix( true, false );
10853
10854                 return target.setFromMatrixPosition( this.matrixWorld );
10855
10856         },
10857
10858         getWorldQuaternion: function ( target ) {
10859
10860                 if ( target === undefined ) {
10861
10862                         console.warn( 'THREE.Object3D: .getWorldQuaternion() target is now required' );
10863                         target = new Quaternion();
10864
10865                 }
10866
10867                 this.updateWorldMatrix( true, false );
10868
10869                 this.matrixWorld.decompose( _position, target, _scale );
10870
10871                 return target;
10872
10873         },
10874
10875         getWorldScale: function ( target ) {
10876
10877                 if ( target === undefined ) {
10878
10879                         console.warn( 'THREE.Object3D: .getWorldScale() target is now required' );
10880                         target = new Vector3();
10881
10882                 }
10883
10884                 this.updateWorldMatrix( true, false );
10885
10886                 this.matrixWorld.decompose( _position, _quaternion$2, target );
10887
10888                 return target;
10889
10890         },
10891
10892         getWorldDirection: function ( target ) {
10893
10894                 if ( target === undefined ) {
10895
10896                         console.warn( 'THREE.Object3D: .getWorldDirection() target is now required' );
10897                         target = new Vector3();
10898
10899                 }
10900
10901                 this.updateWorldMatrix( true, false );
10902
10903                 const e = this.matrixWorld.elements;
10904
10905                 return target.set( e[ 8 ], e[ 9 ], e[ 10 ] ).normalize();
10906
10907         },
10908
10909         raycast: function () {},
10910
10911         traverse: function ( callback ) {
10912
10913                 callback( this );
10914
10915                 const children = this.children;
10916
10917                 for ( let i = 0, l = children.length; i < l; i ++ ) {
10918
10919                         children[ i ].traverse( callback );
10920
10921                 }
10922
10923         },
10924
10925         traverseVisible: function ( callback ) {
10926
10927                 if ( this.visible === false ) return;
10928
10929                 callback( this );
10930
10931                 const children = this.children;
10932
10933                 for ( let i = 0, l = children.length; i < l; i ++ ) {
10934
10935                         children[ i ].traverseVisible( callback );
10936
10937                 }
10938
10939         },
10940
10941         traverseAncestors: function ( callback ) {
10942
10943                 const parent = this.parent;
10944
10945                 if ( parent !== null ) {
10946
10947                         callback( parent );
10948
10949                         parent.traverseAncestors( callback );
10950
10951                 }
10952
10953         },
10954
10955         updateMatrix: function () {
10956
10957                 this.matrix.compose( this.position, this.quaternion, this.scale );
10958
10959                 this.matrixWorldNeedsUpdate = true;
10960
10961         },
10962
10963         updateMatrixWorld: function ( force ) {
10964
10965                 if ( this.matrixAutoUpdate ) this.updateMatrix();
10966
10967                 if ( this.matrixWorldNeedsUpdate || force ) {
10968
10969                         if ( this.parent === null ) {
10970
10971                                 this.matrixWorld.copy( this.matrix );
10972
10973                         } else {
10974
10975                                 this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix );
10976
10977                         }
10978
10979                         this.matrixWorldNeedsUpdate = false;
10980
10981                         force = true;
10982
10983                 }
10984
10985                 // update children
10986
10987                 const children = this.children;
10988
10989                 for ( let i = 0, l = children.length; i < l; i ++ ) {
10990
10991                         children[ i ].updateMatrixWorld( force );
10992
10993                 }
10994
10995         },
10996
10997         updateWorldMatrix: function ( updateParents, updateChildren ) {
10998
10999                 const parent = this.parent;
11000
11001                 if ( updateParents === true && parent !== null ) {
11002
11003                         parent.updateWorldMatrix( true, false );
11004
11005                 }
11006
11007                 if ( this.matrixAutoUpdate ) this.updateMatrix();
11008
11009                 if ( this.parent === null ) {
11010
11011                         this.matrixWorld.copy( this.matrix );
11012
11013                 } else {
11014
11015                         this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix );
11016
11017                 }
11018
11019                 // update children
11020
11021                 if ( updateChildren === true ) {
11022
11023                         const children = this.children;
11024
11025                         for ( let i = 0, l = children.length; i < l; i ++ ) {
11026
11027                                 children[ i ].updateWorldMatrix( false, true );
11028
11029                         }
11030
11031                 }
11032
11033         },
11034
11035         toJSON: function ( meta ) {
11036
11037                 // meta is a string when called from JSON.stringify
11038                 const isRootObject = ( meta === undefined || typeof meta === 'string' );
11039
11040                 const output = {};
11041
11042                 // meta is a hash used to collect geometries, materials.
11043                 // not providing it implies that this is the root object
11044                 // being serialized.
11045                 if ( isRootObject ) {
11046
11047                         // initialize meta obj
11048                         meta = {
11049                                 geometries: {},
11050                                 materials: {},
11051                                 textures: {},
11052                                 images: {},
11053                                 shapes: {},
11054                                 skeletons: {},
11055                                 animations: {}
11056                         };
11057
11058                         output.metadata = {
11059                                 version: 4.5,
11060                                 type: 'Object',
11061                                 generator: 'Object3D.toJSON'
11062                         };
11063
11064                 }
11065
11066                 // standard Object3D serialization
11067
11068                 const object = {};
11069
11070                 object.uuid = this.uuid;
11071                 object.type = this.type;
11072
11073                 if ( this.name !== '' ) object.name = this.name;
11074                 if ( this.castShadow === true ) object.castShadow = true;
11075                 if ( this.receiveShadow === true ) object.receiveShadow = true;
11076                 if ( this.visible === false ) object.visible = false;
11077                 if ( this.frustumCulled === false ) object.frustumCulled = false;
11078                 if ( this.renderOrder !== 0 ) object.renderOrder = this.renderOrder;
11079                 if ( JSON.stringify( this.userData ) !== '{}' ) object.userData = this.userData;
11080
11081                 object.layers = this.layers.mask;
11082                 object.matrix = this.matrix.toArray();
11083
11084                 if ( this.matrixAutoUpdate === false ) object.matrixAutoUpdate = false;
11085
11086                 // object specific properties
11087
11088                 if ( this.isInstancedMesh ) {
11089
11090                         object.type = 'InstancedMesh';
11091                         object.count = this.count;
11092                         object.instanceMatrix = this.instanceMatrix.toJSON();
11093
11094                 }
11095
11096                 //
11097
11098                 function serialize( library, element ) {
11099
11100                         if ( library[ element.uuid ] === undefined ) {
11101
11102                                 library[ element.uuid ] = element.toJSON( meta );
11103
11104                         }
11105
11106                         return element.uuid;
11107
11108                 }
11109
11110                 if ( this.isMesh || this.isLine || this.isPoints ) {
11111
11112                         object.geometry = serialize( meta.geometries, this.geometry );
11113
11114                         const parameters = this.geometry.parameters;
11115
11116                         if ( parameters !== undefined && parameters.shapes !== undefined ) {
11117
11118                                 const shapes = parameters.shapes;
11119
11120                                 if ( Array.isArray( shapes ) ) {
11121
11122                                         for ( let i = 0, l = shapes.length; i < l; i ++ ) {
11123
11124                                                 const shape = shapes[ i ];
11125
11126                                                 serialize( meta.shapes, shape );
11127
11128                                         }
11129
11130                                 } else {
11131
11132                                         serialize( meta.shapes, shapes );
11133
11134                                 }
11135
11136                         }
11137
11138                 }
11139
11140                 if ( this.isSkinnedMesh ) {
11141
11142                         object.bindMode = this.bindMode;
11143                         object.bindMatrix = this.bindMatrix.toArray();
11144
11145                         if ( this.skeleton !== undefined ) {
11146
11147                                 serialize( meta.skeletons, this.skeleton );
11148
11149                                 object.skeleton = this.skeleton.uuid;
11150
11151                         }
11152
11153                 }
11154
11155                 if ( this.material !== undefined ) {
11156
11157                         if ( Array.isArray( this.material ) ) {
11158
11159                                 const uuids = [];
11160
11161                                 for ( let i = 0, l = this.material.length; i < l; i ++ ) {
11162
11163                                         uuids.push( serialize( meta.materials, this.material[ i ] ) );
11164
11165                                 }
11166
11167                                 object.material = uuids;
11168
11169                         } else {
11170
11171                                 object.material = serialize( meta.materials, this.material );
11172
11173                         }
11174
11175                 }
11176
11177                 //
11178
11179                 if ( this.children.length > 0 ) {
11180
11181                         object.children = [];
11182
11183                         for ( let i = 0; i < this.children.length; i ++ ) {
11184
11185                                 object.children.push( this.children[ i ].toJSON( meta ).object );
11186
11187                         }
11188
11189                 }
11190
11191                 //
11192
11193                 if ( this.animations.length > 0 ) {
11194
11195                         object.animations = [];
11196
11197                         for ( let i = 0; i < this.animations.length; i ++ ) {
11198
11199                                 const animation = this.animations[ i ];
11200
11201                                 object.animations.push( serialize( meta.animations, animation ) );
11202
11203                         }
11204
11205                 }
11206
11207                 if ( isRootObject ) {
11208
11209                         const geometries = extractFromCache( meta.geometries );
11210                         const materials = extractFromCache( meta.materials );
11211                         const textures = extractFromCache( meta.textures );
11212                         const images = extractFromCache( meta.images );
11213                         const shapes = extractFromCache( meta.shapes );
11214                         const skeletons = extractFromCache( meta.skeletons );
11215                         const animations = extractFromCache( meta.animations );
11216
11217                         if ( geometries.length > 0 ) output.geometries = geometries;
11218                         if ( materials.length > 0 ) output.materials = materials;
11219                         if ( textures.length > 0 ) output.textures = textures;
11220                         if ( images.length > 0 ) output.images = images;
11221                         if ( shapes.length > 0 ) output.shapes = shapes;
11222                         if ( skeletons.length > 0 ) output.skeletons = skeletons;
11223                         if ( animations.length > 0 ) output.animations = animations;
11224
11225                 }
11226
11227                 output.object = object;
11228
11229                 return output;
11230
11231                 // extract data from the cache hash
11232                 // remove metadata on each item
11233                 // and return as array
11234                 function extractFromCache( cache ) {
11235
11236                         const values = [];
11237                         for ( const key in cache ) {
11238
11239                                 const data = cache[ key ];
11240                                 delete data.metadata;
11241                                 values.push( data );
11242
11243                         }
11244
11245                         return values;
11246
11247                 }
11248
11249         },
11250
11251         clone: function ( recursive ) {
11252
11253                 return new this.constructor().copy( this, recursive );
11254
11255         },
11256
11257         copy: function ( source, recursive = true ) {
11258
11259                 this.name = source.name;
11260
11261                 this.up.copy( source.up );
11262
11263                 this.position.copy( source.position );
11264                 this.rotation.order = source.rotation.order;
11265                 this.quaternion.copy( source.quaternion );
11266                 this.scale.copy( source.scale );
11267
11268                 this.matrix.copy( source.matrix );
11269                 this.matrixWorld.copy( source.matrixWorld );
11270
11271                 this.matrixAutoUpdate = source.matrixAutoUpdate;
11272                 this.matrixWorldNeedsUpdate = source.matrixWorldNeedsUpdate;
11273
11274                 this.layers.mask = source.layers.mask;
11275                 this.visible = source.visible;
11276
11277                 this.castShadow = source.castShadow;
11278                 this.receiveShadow = source.receiveShadow;
11279
11280                 this.frustumCulled = source.frustumCulled;
11281                 this.renderOrder = source.renderOrder;
11282
11283                 this.userData = JSON.parse( JSON.stringify( source.userData ) );
11284
11285                 if ( recursive === true ) {
11286
11287                         for ( let i = 0; i < source.children.length; i ++ ) {
11288
11289                                 const child = source.children[ i ];
11290                                 this.add( child.clone() );
11291
11292                         }
11293
11294                 }
11295
11296                 return this;
11297
11298         }
11299
11300 } );
11301
11302 const _vector1 = /*@__PURE__*/ new Vector3();
11303 const _vector2 = /*@__PURE__*/ new Vector3();
11304 const _normalMatrix = /*@__PURE__*/ new Matrix3();
11305
11306 class Plane {
11307
11308         constructor( normal, constant ) {
11309
11310                 Object.defineProperty( this, 'isPlane', { value: true } );
11311
11312                 // normal is assumed to be normalized
11313
11314                 this.normal = ( normal !== undefined ) ? normal : new Vector3( 1, 0, 0 );
11315                 this.constant = ( constant !== undefined ) ? constant : 0;
11316
11317         }
11318
11319         set( normal, constant ) {
11320
11321                 this.normal.copy( normal );
11322                 this.constant = constant;
11323
11324                 return this;
11325
11326         }
11327
11328         setComponents( x, y, z, w ) {
11329
11330                 this.normal.set( x, y, z );
11331                 this.constant = w;
11332
11333                 return this;
11334
11335         }
11336
11337         setFromNormalAndCoplanarPoint( normal, point ) {
11338
11339                 this.normal.copy( normal );
11340                 this.constant = - point.dot( this.normal );
11341
11342                 return this;
11343
11344         }
11345
11346         setFromCoplanarPoints( a, b, c ) {
11347
11348                 const normal = _vector1.subVectors( c, b ).cross( _vector2.subVectors( a, b ) ).normalize();
11349
11350                 // Q: should an error be thrown if normal is zero (e.g. degenerate plane)?
11351
11352                 this.setFromNormalAndCoplanarPoint( normal, a );
11353
11354                 return this;
11355
11356         }
11357
11358         clone() {
11359
11360                 return new this.constructor().copy( this );
11361
11362         }
11363
11364         copy( plane ) {
11365
11366                 this.normal.copy( plane.normal );
11367                 this.constant = plane.constant;
11368
11369                 return this;
11370
11371         }
11372
11373         normalize() {
11374
11375                 // Note: will lead to a divide by zero if the plane is invalid.
11376
11377                 const inverseNormalLength = 1.0 / this.normal.length();
11378                 this.normal.multiplyScalar( inverseNormalLength );
11379                 this.constant *= inverseNormalLength;
11380
11381                 return this;
11382
11383         }
11384
11385         negate() {
11386
11387                 this.constant *= - 1;
11388                 this.normal.negate();
11389
11390                 return this;
11391
11392         }
11393
11394         distanceToPoint( point ) {
11395
11396                 return this.normal.dot( point ) + this.constant;
11397
11398         }
11399
11400         distanceToSphere( sphere ) {
11401
11402                 return this.distanceToPoint( sphere.center ) - sphere.radius;
11403
11404         }
11405
11406         projectPoint( point, target ) {
11407
11408                 if ( target === undefined ) {
11409
11410                         console.warn( 'THREE.Plane: .projectPoint() target is now required' );
11411                         target = new Vector3();
11412
11413                 }
11414
11415                 return target.copy( this.normal ).multiplyScalar( - this.distanceToPoint( point ) ).add( point );
11416
11417         }
11418
11419         intersectLine( line, target ) {
11420
11421                 if ( target === undefined ) {
11422
11423                         console.warn( 'THREE.Plane: .intersectLine() target is now required' );
11424                         target = new Vector3();
11425
11426                 }
11427
11428                 const direction = line.delta( _vector1 );
11429
11430                 const denominator = this.normal.dot( direction );
11431
11432                 if ( denominator === 0 ) {
11433
11434                         // line is coplanar, return origin
11435                         if ( this.distanceToPoint( line.start ) === 0 ) {
11436
11437                                 return target.copy( line.start );
11438
11439                         }
11440
11441                         // Unsure if this is the correct method to handle this case.
11442                         return undefined;
11443
11444                 }
11445
11446                 const t = - ( line.start.dot( this.normal ) + this.constant ) / denominator;
11447
11448                 if ( t < 0 || t > 1 ) {
11449
11450                         return undefined;
11451
11452                 }
11453
11454                 return target.copy( direction ).multiplyScalar( t ).add( line.start );
11455
11456         }
11457
11458         intersectsLine( line ) {
11459
11460                 // Note: this tests if a line intersects the plane, not whether it (or its end-points) are coplanar with it.
11461
11462                 const startSign = this.distanceToPoint( line.start );
11463                 const endSign = this.distanceToPoint( line.end );
11464
11465                 return ( startSign < 0 && endSign > 0 ) || ( endSign < 0 && startSign > 0 );
11466
11467         }
11468
11469         intersectsBox( box ) {
11470
11471                 return box.intersectsPlane( this );
11472
11473         }
11474
11475         intersectsSphere( sphere ) {
11476
11477                 return sphere.intersectsPlane( this );
11478
11479         }
11480
11481         coplanarPoint( target ) {
11482
11483                 if ( target === undefined ) {
11484
11485                         console.warn( 'THREE.Plane: .coplanarPoint() target is now required' );
11486                         target = new Vector3();
11487
11488                 }
11489
11490                 return target.copy( this.normal ).multiplyScalar( - this.constant );
11491
11492         }
11493
11494         applyMatrix4( matrix, optionalNormalMatrix ) {
11495
11496                 const normalMatrix = optionalNormalMatrix || _normalMatrix.getNormalMatrix( matrix );
11497
11498                 const referencePoint = this.coplanarPoint( _vector1 ).applyMatrix4( matrix );
11499
11500                 const normal = this.normal.applyMatrix3( normalMatrix ).normalize();
11501
11502                 this.constant = - referencePoint.dot( normal );
11503
11504                 return this;
11505
11506         }
11507
11508         translate( offset ) {
11509
11510                 this.constant -= offset.dot( this.normal );
11511
11512                 return this;
11513
11514         }
11515
11516         equals( plane ) {
11517
11518                 return plane.normal.equals( this.normal ) && ( plane.constant === this.constant );
11519
11520         }
11521
11522 }
11523
11524 const _v0$1 = /*@__PURE__*/ new Vector3();
11525 const _v1$3 = /*@__PURE__*/ new Vector3();
11526 const _v2$1 = /*@__PURE__*/ new Vector3();
11527 const _v3 = /*@__PURE__*/ new Vector3();
11528
11529 const _vab = /*@__PURE__*/ new Vector3();
11530 const _vac = /*@__PURE__*/ new Vector3();
11531 const _vbc = /*@__PURE__*/ new Vector3();
11532 const _vap = /*@__PURE__*/ new Vector3();
11533 const _vbp = /*@__PURE__*/ new Vector3();
11534 const _vcp = /*@__PURE__*/ new Vector3();
11535
11536 class Triangle {
11537
11538         constructor( a, b, c ) {
11539
11540                 this.a = ( a !== undefined ) ? a : new Vector3();
11541                 this.b = ( b !== undefined ) ? b : new Vector3();
11542                 this.c = ( c !== undefined ) ? c : new Vector3();
11543
11544         }
11545
11546         static getNormal( a, b, c, target ) {
11547
11548                 if ( target === undefined ) {
11549
11550                         console.warn( 'THREE.Triangle: .getNormal() target is now required' );
11551                         target = new Vector3();
11552
11553                 }
11554
11555                 target.subVectors( c, b );
11556                 _v0$1.subVectors( a, b );
11557                 target.cross( _v0$1 );
11558
11559                 const targetLengthSq = target.lengthSq();
11560                 if ( targetLengthSq > 0 ) {
11561
11562                         return target.multiplyScalar( 1 / Math.sqrt( targetLengthSq ) );
11563
11564                 }
11565
11566                 return target.set( 0, 0, 0 );
11567
11568         }
11569
11570         // static/instance method to calculate barycentric coordinates
11571         // based on: http://www.blackpawn.com/texts/pointinpoly/default.html
11572         static getBarycoord( point, a, b, c, target ) {
11573
11574                 _v0$1.subVectors( c, a );
11575                 _v1$3.subVectors( b, a );
11576                 _v2$1.subVectors( point, a );
11577
11578                 const dot00 = _v0$1.dot( _v0$1 );
11579                 const dot01 = _v0$1.dot( _v1$3 );
11580                 const dot02 = _v0$1.dot( _v2$1 );
11581                 const dot11 = _v1$3.dot( _v1$3 );
11582                 const dot12 = _v1$3.dot( _v2$1 );
11583
11584                 const denom = ( dot00 * dot11 - dot01 * dot01 );
11585
11586                 if ( target === undefined ) {
11587
11588                         console.warn( 'THREE.Triangle: .getBarycoord() target is now required' );
11589                         target = new Vector3();
11590
11591                 }
11592
11593                 // collinear or singular triangle
11594                 if ( denom === 0 ) {
11595
11596                         // arbitrary location outside of triangle?
11597                         // not sure if this is the best idea, maybe should be returning undefined
11598                         return target.set( - 2, - 1, - 1 );
11599
11600                 }
11601
11602                 const invDenom = 1 / denom;
11603                 const u = ( dot11 * dot02 - dot01 * dot12 ) * invDenom;
11604                 const v = ( dot00 * dot12 - dot01 * dot02 ) * invDenom;
11605
11606                 // barycentric coordinates must always sum to 1
11607                 return target.set( 1 - u - v, v, u );
11608
11609         }
11610
11611         static containsPoint( point, a, b, c ) {
11612
11613                 this.getBarycoord( point, a, b, c, _v3 );
11614
11615                 return ( _v3.x >= 0 ) && ( _v3.y >= 0 ) && ( ( _v3.x + _v3.y ) <= 1 );
11616
11617         }
11618
11619         static getUV( point, p1, p2, p3, uv1, uv2, uv3, target ) {
11620
11621                 this.getBarycoord( point, p1, p2, p3, _v3 );
11622
11623                 target.set( 0, 0 );
11624                 target.addScaledVector( uv1, _v3.x );
11625                 target.addScaledVector( uv2, _v3.y );
11626                 target.addScaledVector( uv3, _v3.z );
11627
11628                 return target;
11629
11630         }
11631
11632         static isFrontFacing( a, b, c, direction ) {
11633
11634                 _v0$1.subVectors( c, b );
11635                 _v1$3.subVectors( a, b );
11636
11637                 // strictly front facing
11638                 return ( _v0$1.cross( _v1$3 ).dot( direction ) < 0 ) ? true : false;
11639
11640         }
11641
11642         set( a, b, c ) {
11643
11644                 this.a.copy( a );
11645                 this.b.copy( b );
11646                 this.c.copy( c );
11647
11648                 return this;
11649
11650         }
11651
11652         setFromPointsAndIndices( points, i0, i1, i2 ) {
11653
11654                 this.a.copy( points[ i0 ] );
11655                 this.b.copy( points[ i1 ] );
11656                 this.c.copy( points[ i2 ] );
11657
11658                 return this;
11659
11660         }
11661
11662         clone() {
11663
11664                 return new this.constructor().copy( this );
11665
11666         }
11667
11668         copy( triangle ) {
11669
11670                 this.a.copy( triangle.a );
11671                 this.b.copy( triangle.b );
11672                 this.c.copy( triangle.c );
11673
11674                 return this;
11675
11676         }
11677
11678         getArea() {
11679
11680                 _v0$1.subVectors( this.c, this.b );
11681                 _v1$3.subVectors( this.a, this.b );
11682
11683                 return _v0$1.cross( _v1$3 ).length() * 0.5;
11684
11685         }
11686
11687         getMidpoint( target ) {
11688
11689                 if ( target === undefined ) {
11690
11691                         console.warn( 'THREE.Triangle: .getMidpoint() target is now required' );
11692                         target = new Vector3();
11693
11694                 }
11695
11696                 return target.addVectors( this.a, this.b ).add( this.c ).multiplyScalar( 1 / 3 );
11697
11698         }
11699
11700         getNormal( target ) {
11701
11702                 return Triangle.getNormal( this.a, this.b, this.c, target );
11703
11704         }
11705
11706         getPlane( target ) {
11707
11708                 if ( target === undefined ) {
11709
11710                         console.warn( 'THREE.Triangle: .getPlane() target is now required' );
11711                         target = new Plane();
11712
11713                 }
11714
11715                 return target.setFromCoplanarPoints( this.a, this.b, this.c );
11716
11717         }
11718
11719         getBarycoord( point, target ) {
11720
11721                 return Triangle.getBarycoord( point, this.a, this.b, this.c, target );
11722
11723         }
11724
11725         getUV( point, uv1, uv2, uv3, target ) {
11726
11727                 return Triangle.getUV( point, this.a, this.b, this.c, uv1, uv2, uv3, target );
11728
11729         }
11730
11731         containsPoint( point ) {
11732
11733                 return Triangle.containsPoint( point, this.a, this.b, this.c );
11734
11735         }
11736
11737         isFrontFacing( direction ) {
11738
11739                 return Triangle.isFrontFacing( this.a, this.b, this.c, direction );
11740
11741         }
11742
11743         intersectsBox( box ) {
11744
11745                 return box.intersectsTriangle( this );
11746
11747         }
11748
11749         closestPointToPoint( p, target ) {
11750
11751                 if ( target === undefined ) {
11752
11753                         console.warn( 'THREE.Triangle: .closestPointToPoint() target is now required' );
11754                         target = new Vector3();
11755
11756                 }
11757
11758                 const a = this.a, b = this.b, c = this.c;
11759                 let v, w;
11760
11761                 // algorithm thanks to Real-Time Collision Detection by Christer Ericson,
11762                 // published by Morgan Kaufmann Publishers, (c) 2005 Elsevier Inc.,
11763                 // under the accompanying license; see chapter 5.1.5 for detailed explanation.
11764                 // basically, we're distinguishing which of the voronoi regions of the triangle
11765                 // the point lies in with the minimum amount of redundant computation.
11766
11767                 _vab.subVectors( b, a );
11768                 _vac.subVectors( c, a );
11769                 _vap.subVectors( p, a );
11770                 const d1 = _vab.dot( _vap );
11771                 const d2 = _vac.dot( _vap );
11772                 if ( d1 <= 0 && d2 <= 0 ) {
11773
11774                         // vertex region of A; barycentric coords (1, 0, 0)
11775                         return target.copy( a );
11776
11777                 }
11778
11779                 _vbp.subVectors( p, b );
11780                 const d3 = _vab.dot( _vbp );
11781                 const d4 = _vac.dot( _vbp );
11782                 if ( d3 >= 0 && d4 <= d3 ) {
11783
11784                         // vertex region of B; barycentric coords (0, 1, 0)
11785                         return target.copy( b );
11786
11787                 }
11788
11789                 const vc = d1 * d4 - d3 * d2;
11790                 if ( vc <= 0 && d1 >= 0 && d3 <= 0 ) {
11791
11792                         v = d1 / ( d1 - d3 );
11793                         // edge region of AB; barycentric coords (1-v, v, 0)
11794                         return target.copy( a ).addScaledVector( _vab, v );
11795
11796                 }
11797
11798                 _vcp.subVectors( p, c );
11799                 const d5 = _vab.dot( _vcp );
11800                 const d6 = _vac.dot( _vcp );
11801                 if ( d6 >= 0 && d5 <= d6 ) {
11802
11803                         // vertex region of C; barycentric coords (0, 0, 1)
11804                         return target.copy( c );
11805
11806                 }
11807
11808                 const vb = d5 * d2 - d1 * d6;
11809                 if ( vb <= 0 && d2 >= 0 && d6 <= 0 ) {
11810
11811                         w = d2 / ( d2 - d6 );
11812                         // edge region of AC; barycentric coords (1-w, 0, w)
11813                         return target.copy( a ).addScaledVector( _vac, w );
11814
11815                 }
11816
11817                 const va = d3 * d6 - d5 * d4;
11818                 if ( va <= 0 && ( d4 - d3 ) >= 0 && ( d5 - d6 ) >= 0 ) {
11819
11820                         _vbc.subVectors( c, b );
11821                         w = ( d4 - d3 ) / ( ( d4 - d3 ) + ( d5 - d6 ) );
11822                         // edge region of BC; barycentric coords (0, 1-w, w)
11823                         return target.copy( b ).addScaledVector( _vbc, w ); // edge region of BC
11824
11825                 }
11826
11827                 // face region
11828                 const denom = 1 / ( va + vb + vc );
11829                 // u = va * denom
11830                 v = vb * denom;
11831                 w = vc * denom;
11832
11833                 return target.copy( a ).addScaledVector( _vab, v ).addScaledVector( _vac, w );
11834
11835         }
11836
11837         equals( triangle ) {
11838
11839                 return triangle.a.equals( this.a ) && triangle.b.equals( this.b ) && triangle.c.equals( this.c );
11840
11841         }
11842
11843 }
11844
11845 const _colorKeywords = { 'aliceblue': 0xF0F8FF, 'antiquewhite': 0xFAEBD7, 'aqua': 0x00FFFF, 'aquamarine': 0x7FFFD4, 'azure': 0xF0FFFF,
11846         'beige': 0xF5F5DC, 'bisque': 0xFFE4C4, 'black': 0x000000, 'blanchedalmond': 0xFFEBCD, 'blue': 0x0000FF, 'blueviolet': 0x8A2BE2,
11847         'brown': 0xA52A2A, 'burlywood': 0xDEB887, 'cadetblue': 0x5F9EA0, 'chartreuse': 0x7FFF00, 'chocolate': 0xD2691E, 'coral': 0xFF7F50,
11848         'cornflowerblue': 0x6495ED, 'cornsilk': 0xFFF8DC, 'crimson': 0xDC143C, 'cyan': 0x00FFFF, 'darkblue': 0x00008B, 'darkcyan': 0x008B8B,
11849         'darkgoldenrod': 0xB8860B, 'darkgray': 0xA9A9A9, 'darkgreen': 0x006400, 'darkgrey': 0xA9A9A9, 'darkkhaki': 0xBDB76B, 'darkmagenta': 0x8B008B,
11850         'darkolivegreen': 0x556B2F, 'darkorange': 0xFF8C00, 'darkorchid': 0x9932CC, 'darkred': 0x8B0000, 'darksalmon': 0xE9967A, 'darkseagreen': 0x8FBC8F,
11851         'darkslateblue': 0x483D8B, 'darkslategray': 0x2F4F4F, 'darkslategrey': 0x2F4F4F, 'darkturquoise': 0x00CED1, 'darkviolet': 0x9400D3,
11852         'deeppink': 0xFF1493, 'deepskyblue': 0x00BFFF, 'dimgray': 0x696969, 'dimgrey': 0x696969, 'dodgerblue': 0x1E90FF, 'firebrick': 0xB22222,
11853         'floralwhite': 0xFFFAF0, 'forestgreen': 0x228B22, 'fuchsia': 0xFF00FF, 'gainsboro': 0xDCDCDC, 'ghostwhite': 0xF8F8FF, 'gold': 0xFFD700,
11854         'goldenrod': 0xDAA520, 'gray': 0x808080, 'green': 0x008000, 'greenyellow': 0xADFF2F, 'grey': 0x808080, 'honeydew': 0xF0FFF0, 'hotpink': 0xFF69B4,
11855         'indianred': 0xCD5C5C, 'indigo': 0x4B0082, 'ivory': 0xFFFFF0, 'khaki': 0xF0E68C, 'lavender': 0xE6E6FA, 'lavenderblush': 0xFFF0F5, 'lawngreen': 0x7CFC00,
11856         'lemonchiffon': 0xFFFACD, 'lightblue': 0xADD8E6, 'lightcoral': 0xF08080, 'lightcyan': 0xE0FFFF, 'lightgoldenrodyellow': 0xFAFAD2, 'lightgray': 0xD3D3D3,
11857         'lightgreen': 0x90EE90, 'lightgrey': 0xD3D3D3, 'lightpink': 0xFFB6C1, 'lightsalmon': 0xFFA07A, 'lightseagreen': 0x20B2AA, 'lightskyblue': 0x87CEFA,
11858         'lightslategray': 0x778899, 'lightslategrey': 0x778899, 'lightsteelblue': 0xB0C4DE, 'lightyellow': 0xFFFFE0, 'lime': 0x00FF00, 'limegreen': 0x32CD32,
11859         'linen': 0xFAF0E6, 'magenta': 0xFF00FF, 'maroon': 0x800000, 'mediumaquamarine': 0x66CDAA, 'mediumblue': 0x0000CD, 'mediumorchid': 0xBA55D3,
11860         'mediumpurple': 0x9370DB, 'mediumseagreen': 0x3CB371, 'mediumslateblue': 0x7B68EE, 'mediumspringgreen': 0x00FA9A, 'mediumturquoise': 0x48D1CC,
11861         'mediumvioletred': 0xC71585, 'midnightblue': 0x191970, 'mintcream': 0xF5FFFA, 'mistyrose': 0xFFE4E1, 'moccasin': 0xFFE4B5, 'navajowhite': 0xFFDEAD,
11862         'navy': 0x000080, 'oldlace': 0xFDF5E6, 'olive': 0x808000, 'olivedrab': 0x6B8E23, 'orange': 0xFFA500, 'orangered': 0xFF4500, 'orchid': 0xDA70D6,
11863         'palegoldenrod': 0xEEE8AA, 'palegreen': 0x98FB98, 'paleturquoise': 0xAFEEEE, 'palevioletred': 0xDB7093, 'papayawhip': 0xFFEFD5, 'peachpuff': 0xFFDAB9,
11864         'peru': 0xCD853F, 'pink': 0xFFC0CB, 'plum': 0xDDA0DD, 'powderblue': 0xB0E0E6, 'purple': 0x800080, 'rebeccapurple': 0x663399, 'red': 0xFF0000, 'rosybrown': 0xBC8F8F,
11865         'royalblue': 0x4169E1, 'saddlebrown': 0x8B4513, 'salmon': 0xFA8072, 'sandybrown': 0xF4A460, 'seagreen': 0x2E8B57, 'seashell': 0xFFF5EE,
11866         'sienna': 0xA0522D, 'silver': 0xC0C0C0, 'skyblue': 0x87CEEB, 'slateblue': 0x6A5ACD, 'slategray': 0x708090, 'slategrey': 0x708090, 'snow': 0xFFFAFA,
11867         'springgreen': 0x00FF7F, 'steelblue': 0x4682B4, 'tan': 0xD2B48C, 'teal': 0x008080, 'thistle': 0xD8BFD8, 'tomato': 0xFF6347, 'turquoise': 0x40E0D0,
11868         'violet': 0xEE82EE, 'wheat': 0xF5DEB3, 'white': 0xFFFFFF, 'whitesmoke': 0xF5F5F5, 'yellow': 0xFFFF00, 'yellowgreen': 0x9ACD32 };
11869
11870 const _hslA = { h: 0, s: 0, l: 0 };
11871 const _hslB = { h: 0, s: 0, l: 0 };
11872
11873 function hue2rgb( p, q, t ) {
11874
11875         if ( t < 0 ) t += 1;
11876         if ( t > 1 ) t -= 1;
11877         if ( t < 1 / 6 ) return p + ( q - p ) * 6 * t;
11878         if ( t < 1 / 2 ) return q;
11879         if ( t < 2 / 3 ) return p + ( q - p ) * 6 * ( 2 / 3 - t );
11880         return p;
11881
11882 }
11883
11884 function SRGBToLinear( c ) {
11885
11886         return ( c < 0.04045 ) ? c * 0.0773993808 : Math.pow( c * 0.9478672986 + 0.0521327014, 2.4 );
11887
11888 }
11889
11890 function LinearToSRGB( c ) {
11891
11892         return ( c < 0.0031308 ) ? c * 12.92 : 1.055 * ( Math.pow( c, 0.41666 ) ) - 0.055;
11893
11894 }
11895
11896 class Color {
11897
11898         constructor( r, g, b ) {
11899
11900                 Object.defineProperty( this, 'isColor', { value: true } );
11901
11902                 if ( g === undefined && b === undefined ) {
11903
11904                         // r is THREE.Color, hex or string
11905                         return this.set( r );
11906
11907                 }
11908
11909                 return this.setRGB( r, g, b );
11910
11911         }
11912
11913         set( value ) {
11914
11915                 if ( value && value.isColor ) {
11916
11917                         this.copy( value );
11918
11919                 } else if ( typeof value === 'number' ) {
11920
11921                         this.setHex( value );
11922
11923                 } else if ( typeof value === 'string' ) {
11924
11925                         this.setStyle( value );
11926
11927                 }
11928
11929                 return this;
11930
11931         }
11932
11933         setScalar( scalar ) {
11934
11935                 this.r = scalar;
11936                 this.g = scalar;
11937                 this.b = scalar;
11938
11939                 return this;
11940
11941         }
11942
11943         setHex( hex ) {
11944
11945                 hex = Math.floor( hex );
11946
11947                 this.r = ( hex >> 16 & 255 ) / 255;
11948                 this.g = ( hex >> 8 & 255 ) / 255;
11949                 this.b = ( hex & 255 ) / 255;
11950
11951                 return this;
11952
11953         }
11954
11955         setRGB( r, g, b ) {
11956
11957                 this.r = r;
11958                 this.g = g;
11959                 this.b = b;
11960
11961                 return this;
11962
11963         }
11964
11965         setHSL( h, s, l ) {
11966
11967                 // h,s,l ranges are in 0.0 - 1.0
11968                 h = MathUtils.euclideanModulo( h, 1 );
11969                 s = MathUtils.clamp( s, 0, 1 );
11970                 l = MathUtils.clamp( l, 0, 1 );
11971
11972                 if ( s === 0 ) {
11973
11974                         this.r = this.g = this.b = l;
11975
11976                 } else {
11977
11978                         const p = l <= 0.5 ? l * ( 1 + s ) : l + s - ( l * s );
11979                         const q = ( 2 * l ) - p;
11980
11981                         this.r = hue2rgb( q, p, h + 1 / 3 );
11982                         this.g = hue2rgb( q, p, h );
11983                         this.b = hue2rgb( q, p, h - 1 / 3 );
11984
11985                 }
11986
11987                 return this;
11988
11989         }
11990
11991         setStyle( style ) {
11992
11993                 function handleAlpha( string ) {
11994
11995                         if ( string === undefined ) return;
11996
11997                         if ( parseFloat( string ) < 1 ) {
11998
11999                                 console.warn( 'THREE.Color: Alpha component of ' + style + ' will be ignored.' );
12000
12001                         }
12002
12003                 }
12004
12005
12006                 let m;
12007
12008                 if ( m = /^((?:rgb|hsl)a?)\(([^\)]*)\)/.exec( style ) ) {
12009
12010                         // rgb / hsl
12011
12012                         let color;
12013                         const name = m[ 1 ];
12014                         const components = m[ 2 ];
12015
12016                         switch ( name ) {
12017
12018                                 case 'rgb':
12019                                 case 'rgba':
12020
12021                                         if ( color = /^\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec( components ) ) {
12022
12023                                                 // rgb(255,0,0) rgba(255,0,0,0.5)
12024                                                 this.r = Math.min( 255, parseInt( color[ 1 ], 10 ) ) / 255;
12025                                                 this.g = Math.min( 255, parseInt( color[ 2 ], 10 ) ) / 255;
12026                                                 this.b = Math.min( 255, parseInt( color[ 3 ], 10 ) ) / 255;
12027
12028                                                 handleAlpha( color[ 4 ] );
12029
12030                                                 return this;
12031
12032                                         }
12033
12034                                         if ( color = /^\s*(\d+)\%\s*,\s*(\d+)\%\s*,\s*(\d+)\%\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec( components ) ) {
12035
12036                                                 // rgb(100%,0%,0%) rgba(100%,0%,0%,0.5)
12037                                                 this.r = Math.min( 100, parseInt( color[ 1 ], 10 ) ) / 100;
12038                                                 this.g = Math.min( 100, parseInt( color[ 2 ], 10 ) ) / 100;
12039                                                 this.b = Math.min( 100, parseInt( color[ 3 ], 10 ) ) / 100;
12040
12041                                                 handleAlpha( color[ 4 ] );
12042
12043                                                 return this;
12044
12045                                         }
12046
12047                                         break;
12048
12049                                 case 'hsl':
12050                                 case 'hsla':
12051
12052                                         if ( color = /^\s*(\d*\.?\d+)\s*,\s*(\d+)\%\s*,\s*(\d+)\%\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec( components ) ) {
12053
12054                                                 // hsl(120,50%,50%) hsla(120,50%,50%,0.5)
12055                                                 const h = parseFloat( color[ 1 ] ) / 360;
12056                                                 const s = parseInt( color[ 2 ], 10 ) / 100;
12057                                                 const l = parseInt( color[ 3 ], 10 ) / 100;
12058
12059                                                 handleAlpha( color[ 4 ] );
12060
12061                                                 return this.setHSL( h, s, l );
12062
12063                                         }
12064
12065                                         break;
12066
12067                         }
12068
12069                 } else if ( m = /^\#([A-Fa-f\d]+)$/.exec( style ) ) {
12070
12071                         // hex color
12072
12073                         const hex = m[ 1 ];
12074                         const size = hex.length;
12075
12076                         if ( size === 3 ) {
12077
12078                                 // #ff0
12079                                 this.r = parseInt( hex.charAt( 0 ) + hex.charAt( 0 ), 16 ) / 255;
12080                                 this.g = parseInt( hex.charAt( 1 ) + hex.charAt( 1 ), 16 ) / 255;
12081                                 this.b = parseInt( hex.charAt( 2 ) + hex.charAt( 2 ), 16 ) / 255;
12082
12083                                 return this;
12084
12085                         } else if ( size === 6 ) {
12086
12087                                 // #ff0000
12088                                 this.r = parseInt( hex.charAt( 0 ) + hex.charAt( 1 ), 16 ) / 255;
12089                                 this.g = parseInt( hex.charAt( 2 ) + hex.charAt( 3 ), 16 ) / 255;
12090                                 this.b = parseInt( hex.charAt( 4 ) + hex.charAt( 5 ), 16 ) / 255;
12091
12092                                 return this;
12093
12094                         }
12095
12096                 }
12097
12098                 if ( style && style.length > 0 ) {
12099
12100                         return this.setColorName( style );
12101
12102                 }
12103
12104                 return this;
12105
12106         }
12107
12108         setColorName( style ) {
12109
12110                 // color keywords
12111                 const hex = _colorKeywords[ style ];
12112
12113                 if ( hex !== undefined ) {
12114
12115                         // red
12116                         this.setHex( hex );
12117
12118                 } else {
12119
12120                         // unknown color
12121                         console.warn( 'THREE.Color: Unknown color ' + style );
12122
12123                 }
12124
12125                 return this;
12126
12127         }
12128
12129         clone() {
12130
12131                 return new this.constructor( this.r, this.g, this.b );
12132
12133         }
12134
12135         copy( color ) {
12136
12137                 this.r = color.r;
12138                 this.g = color.g;
12139                 this.b = color.b;
12140
12141                 return this;
12142
12143         }
12144
12145         copyGammaToLinear( color, gammaFactor = 2.0 ) {
12146
12147                 this.r = Math.pow( color.r, gammaFactor );
12148                 this.g = Math.pow( color.g, gammaFactor );
12149                 this.b = Math.pow( color.b, gammaFactor );
12150
12151                 return this;
12152
12153         }
12154
12155         copyLinearToGamma( color, gammaFactor = 2.0 ) {
12156
12157                 const safeInverse = ( gammaFactor > 0 ) ? ( 1.0 / gammaFactor ) : 1.0;
12158
12159                 this.r = Math.pow( color.r, safeInverse );
12160                 this.g = Math.pow( color.g, safeInverse );
12161                 this.b = Math.pow( color.b, safeInverse );
12162
12163                 return this;
12164
12165         }
12166
12167         convertGammaToLinear( gammaFactor ) {
12168
12169                 this.copyGammaToLinear( this, gammaFactor );
12170
12171                 return this;
12172
12173         }
12174
12175         convertLinearToGamma( gammaFactor ) {
12176
12177                 this.copyLinearToGamma( this, gammaFactor );
12178
12179                 return this;
12180
12181         }
12182
12183         copySRGBToLinear( color ) {
12184
12185                 this.r = SRGBToLinear( color.r );
12186                 this.g = SRGBToLinear( color.g );
12187                 this.b = SRGBToLinear( color.b );
12188
12189                 return this;
12190
12191         }
12192
12193         copyLinearToSRGB( color ) {
12194
12195                 this.r = LinearToSRGB( color.r );
12196                 this.g = LinearToSRGB( color.g );
12197                 this.b = LinearToSRGB( color.b );
12198
12199                 return this;
12200
12201         }
12202
12203         convertSRGBToLinear() {
12204
12205                 this.copySRGBToLinear( this );
12206
12207                 return this;
12208
12209         }
12210
12211         convertLinearToSRGB() {
12212
12213                 this.copyLinearToSRGB( this );
12214
12215                 return this;
12216
12217         }
12218
12219         getHex() {
12220
12221                 return ( this.r * 255 ) << 16 ^ ( this.g * 255 ) << 8 ^ ( this.b * 255 ) << 0;
12222
12223         }
12224
12225         getHexString() {
12226
12227                 return ( '000000' + this.getHex().toString( 16 ) ).slice( - 6 );
12228
12229         }
12230
12231         getHSL( target ) {
12232
12233                 // h,s,l ranges are in 0.0 - 1.0
12234
12235                 if ( target === undefined ) {
12236
12237                         console.warn( 'THREE.Color: .getHSL() target is now required' );
12238                         target = { h: 0, s: 0, l: 0 };
12239
12240                 }
12241
12242                 const r = this.r, g = this.g, b = this.b;
12243
12244                 const max = Math.max( r, g, b );
12245                 const min = Math.min( r, g, b );
12246
12247                 let hue, saturation;
12248                 const lightness = ( min + max ) / 2.0;
12249
12250                 if ( min === max ) {
12251
12252                         hue = 0;
12253                         saturation = 0;
12254
12255                 } else {
12256
12257                         const delta = max - min;
12258
12259                         saturation = lightness <= 0.5 ? delta / ( max + min ) : delta / ( 2 - max - min );
12260
12261                         switch ( max ) {
12262
12263                                 case r: hue = ( g - b ) / delta + ( g < b ? 6 : 0 ); break;
12264                                 case g: hue = ( b - r ) / delta + 2; break;
12265                                 case b: hue = ( r - g ) / delta + 4; break;
12266
12267                         }
12268
12269                         hue /= 6;
12270
12271                 }
12272
12273                 target.h = hue;
12274                 target.s = saturation;
12275                 target.l = lightness;
12276
12277                 return target;
12278
12279         }
12280
12281         getStyle() {
12282
12283                 return 'rgb(' + ( ( this.r * 255 ) | 0 ) + ',' + ( ( this.g * 255 ) | 0 ) + ',' + ( ( this.b * 255 ) | 0 ) + ')';
12284
12285         }
12286
12287         offsetHSL( h, s, l ) {
12288
12289                 this.getHSL( _hslA );
12290
12291                 _hslA.h += h; _hslA.s += s; _hslA.l += l;
12292
12293                 this.setHSL( _hslA.h, _hslA.s, _hslA.l );
12294
12295                 return this;
12296
12297         }
12298
12299         add( color ) {
12300
12301                 this.r += color.r;
12302                 this.g += color.g;
12303                 this.b += color.b;
12304
12305                 return this;
12306
12307         }
12308
12309         addColors( color1, color2 ) {
12310
12311                 this.r = color1.r + color2.r;
12312                 this.g = color1.g + color2.g;
12313                 this.b = color1.b + color2.b;
12314
12315                 return this;
12316
12317         }
12318
12319         addScalar( s ) {
12320
12321                 this.r += s;
12322                 this.g += s;
12323                 this.b += s;
12324
12325                 return this;
12326
12327         }
12328
12329         sub( color ) {
12330
12331                 this.r = Math.max( 0, this.r - color.r );
12332                 this.g = Math.max( 0, this.g - color.g );
12333                 this.b = Math.max( 0, this.b - color.b );
12334
12335                 return this;
12336
12337         }
12338
12339         multiply( color ) {
12340
12341                 this.r *= color.r;
12342                 this.g *= color.g;
12343                 this.b *= color.b;
12344
12345                 return this;
12346
12347         }
12348
12349         multiplyScalar( s ) {
12350
12351                 this.r *= s;
12352                 this.g *= s;
12353                 this.b *= s;
12354
12355                 return this;
12356
12357         }
12358
12359         lerp( color, alpha ) {
12360
12361                 this.r += ( color.r - this.r ) * alpha;
12362                 this.g += ( color.g - this.g ) * alpha;
12363                 this.b += ( color.b - this.b ) * alpha;
12364
12365                 return this;
12366
12367         }
12368
12369         lerpColors( color1, color2, alpha ) {
12370
12371                 this.r = color1.r + ( color2.r - color1.r ) * alpha;
12372                 this.g = color1.g + ( color2.g - color1.g ) * alpha;
12373                 this.b = color1.b + ( color2.b - color1.b ) * alpha;
12374
12375                 return this;
12376
12377         }
12378
12379         lerpHSL( color, alpha ) {
12380
12381                 this.getHSL( _hslA );
12382                 color.getHSL( _hslB );
12383
12384                 const h = MathUtils.lerp( _hslA.h, _hslB.h, alpha );
12385                 const s = MathUtils.lerp( _hslA.s, _hslB.s, alpha );
12386                 const l = MathUtils.lerp( _hslA.l, _hslB.l, alpha );
12387
12388                 this.setHSL( h, s, l );
12389
12390                 return this;
12391
12392         }
12393
12394         equals( c ) {
12395
12396                 return ( c.r === this.r ) && ( c.g === this.g ) && ( c.b === this.b );
12397
12398         }
12399
12400         fromArray( array, offset = 0 ) {
12401
12402                 this.r = array[ offset ];
12403                 this.g = array[ offset + 1 ];
12404                 this.b = array[ offset + 2 ];
12405
12406                 return this;
12407
12408         }
12409
12410         toArray( array = [], offset = 0 ) {
12411
12412                 array[ offset ] = this.r;
12413                 array[ offset + 1 ] = this.g;
12414                 array[ offset + 2 ] = this.b;
12415
12416                 return array;
12417
12418         }
12419
12420         fromBufferAttribute( attribute, index ) {
12421
12422                 this.r = attribute.getX( index );
12423                 this.g = attribute.getY( index );
12424                 this.b = attribute.getZ( index );
12425
12426                 if ( attribute.normalized === true ) {
12427
12428                         // assuming Uint8Array
12429
12430                         this.r /= 255;
12431                         this.g /= 255;
12432                         this.b /= 255;
12433
12434                 }
12435
12436                 return this;
12437
12438         }
12439
12440         toJSON() {
12441
12442                 return this.getHex();
12443
12444         }
12445
12446 }
12447
12448 Color.NAMES = _colorKeywords;
12449 Color.prototype.r = 1;
12450 Color.prototype.g = 1;
12451 Color.prototype.b = 1;
12452
12453 class Face3 {
12454
12455         constructor( a, b, c, normal, color, materialIndex = 0 ) {
12456
12457                 this.a = a;
12458                 this.b = b;
12459                 this.c = c;
12460
12461                 this.normal = ( normal && normal.isVector3 ) ? normal : new Vector3();
12462                 this.vertexNormals = Array.isArray( normal ) ? normal : [];
12463
12464                 this.color = ( color && color.isColor ) ? color : new Color();
12465                 this.vertexColors = Array.isArray( color ) ? color : [];
12466
12467                 this.materialIndex = materialIndex;
12468
12469         }
12470
12471         clone() {
12472
12473                 return new this.constructor().copy( this );
12474
12475         }
12476
12477         copy( source ) {
12478
12479                 this.a = source.a;
12480                 this.b = source.b;
12481                 this.c = source.c;
12482
12483                 this.normal.copy( source.normal );
12484                 this.color.copy( source.color );
12485
12486                 this.materialIndex = source.materialIndex;
12487
12488                 for ( let i = 0, il = source.vertexNormals.length; i < il; i ++ ) {
12489
12490                         this.vertexNormals[ i ] = source.vertexNormals[ i ].clone();
12491
12492                 }
12493
12494                 for ( let i = 0, il = source.vertexColors.length; i < il; i ++ ) {
12495
12496                         this.vertexColors[ i ] = source.vertexColors[ i ].clone();
12497
12498                 }
12499
12500                 return this;
12501
12502         }
12503
12504 }
12505
12506 let materialId = 0;
12507
12508 function Material() {
12509
12510         Object.defineProperty( this, 'id', { value: materialId ++ } );
12511
12512         this.uuid = MathUtils.generateUUID();
12513
12514         this.name = '';
12515         this.type = 'Material';
12516
12517         this.fog = true;
12518
12519         this.blending = NormalBlending;
12520         this.side = FrontSide;
12521         this.flatShading = false;
12522         this.vertexColors = false;
12523
12524         this.opacity = 1;
12525         this.transparent = false;
12526
12527         this.blendSrc = SrcAlphaFactor;
12528         this.blendDst = OneMinusSrcAlphaFactor;
12529         this.blendEquation = AddEquation;
12530         this.blendSrcAlpha = null;
12531         this.blendDstAlpha = null;
12532         this.blendEquationAlpha = null;
12533
12534         this.depthFunc = LessEqualDepth;
12535         this.depthTest = true;
12536         this.depthWrite = true;
12537
12538         this.stencilWriteMask = 0xff;
12539         this.stencilFunc = AlwaysStencilFunc;
12540         this.stencilRef = 0;
12541         this.stencilFuncMask = 0xff;
12542         this.stencilFail = KeepStencilOp;
12543         this.stencilZFail = KeepStencilOp;
12544         this.stencilZPass = KeepStencilOp;
12545         this.stencilWrite = false;
12546
12547         this.clippingPlanes = null;
12548         this.clipIntersection = false;
12549         this.clipShadows = false;
12550
12551         this.shadowSide = null;
12552
12553         this.colorWrite = true;
12554
12555         this.precision = null; // override the renderer's default precision for this material
12556
12557         this.polygonOffset = false;
12558         this.polygonOffsetFactor = 0;
12559         this.polygonOffsetUnits = 0;
12560
12561         this.dithering = false;
12562
12563         this.alphaTest = 0;
12564         this.premultipliedAlpha = false;
12565
12566         this.visible = true;
12567
12568         this.toneMapped = true;
12569
12570         this.userData = {};
12571
12572         this.version = 0;
12573
12574 }
12575
12576 Material.prototype = Object.assign( Object.create( EventDispatcher.prototype ), {
12577
12578         constructor: Material,
12579
12580         isMaterial: true,
12581
12582         onBeforeCompile: function ( /* shaderobject, renderer */ ) {},
12583
12584         customProgramCacheKey: function () {
12585
12586                 return this.onBeforeCompile.toString();
12587
12588         },
12589
12590         setValues: function ( values ) {
12591
12592                 if ( values === undefined ) return;
12593
12594                 for ( const key in values ) {
12595
12596                         const newValue = values[ key ];
12597
12598                         if ( newValue === undefined ) {
12599
12600                                 console.warn( 'THREE.Material: \'' + key + '\' parameter is undefined.' );
12601                                 continue;
12602
12603                         }
12604
12605                         // for backward compatability if shading is set in the constructor
12606                         if ( key === 'shading' ) {
12607
12608                                 console.warn( 'THREE.' + this.type + ': .shading has been removed. Use the boolean .flatShading instead.' );
12609                                 this.flatShading = ( newValue === FlatShading ) ? true : false;
12610                                 continue;
12611
12612                         }
12613
12614                         const currentValue = this[ key ];
12615
12616                         if ( currentValue === undefined ) {
12617
12618                                 console.warn( 'THREE.' + this.type + ': \'' + key + '\' is not a property of this material.' );
12619                                 continue;
12620
12621                         }
12622
12623                         if ( currentValue && currentValue.isColor ) {
12624
12625                                 currentValue.set( newValue );
12626
12627                         } else if ( ( currentValue && currentValue.isVector3 ) && ( newValue && newValue.isVector3 ) ) {
12628
12629                                 currentValue.copy( newValue );
12630
12631                         } else {
12632
12633                                 this[ key ] = newValue;
12634
12635                         }
12636
12637                 }
12638
12639         },
12640
12641         toJSON: function ( meta ) {
12642
12643                 const isRoot = ( meta === undefined || typeof meta === 'string' );
12644
12645                 if ( isRoot ) {
12646
12647                         meta = {
12648                                 textures: {},
12649                                 images: {}
12650                         };
12651
12652                 }
12653
12654                 const data = {
12655                         metadata: {
12656                                 version: 4.5,
12657                                 type: 'Material',
12658                                 generator: 'Material.toJSON'
12659                         }
12660                 };
12661
12662                 // standard Material serialization
12663                 data.uuid = this.uuid;
12664                 data.type = this.type;
12665
12666                 if ( this.name !== '' ) data.name = this.name;
12667
12668                 if ( this.color && this.color.isColor ) data.color = this.color.getHex();
12669
12670                 if ( this.roughness !== undefined ) data.roughness = this.roughness;
12671                 if ( this.metalness !== undefined ) data.metalness = this.metalness;
12672
12673                 if ( this.sheen && this.sheen.isColor ) data.sheen = this.sheen.getHex();
12674                 if ( this.emissive && this.emissive.isColor ) data.emissive = this.emissive.getHex();
12675                 if ( this.emissiveIntensity && this.emissiveIntensity !== 1 ) data.emissiveIntensity = this.emissiveIntensity;
12676
12677                 if ( this.specular && this.specular.isColor ) data.specular = this.specular.getHex();
12678                 if ( this.shininess !== undefined ) data.shininess = this.shininess;
12679                 if ( this.clearcoat !== undefined ) data.clearcoat = this.clearcoat;
12680                 if ( this.clearcoatRoughness !== undefined ) data.clearcoatRoughness = this.clearcoatRoughness;
12681
12682                 if ( this.clearcoatMap && this.clearcoatMap.isTexture ) {
12683
12684                         data.clearcoatMap = this.clearcoatMap.toJSON( meta ).uuid;
12685
12686                 }
12687
12688                 if ( this.clearcoatRoughnessMap && this.clearcoatRoughnessMap.isTexture ) {
12689
12690                         data.clearcoatRoughnessMap = this.clearcoatRoughnessMap.toJSON( meta ).uuid;
12691
12692                 }
12693
12694                 if ( this.clearcoatNormalMap && this.clearcoatNormalMap.isTexture ) {
12695
12696                         data.clearcoatNormalMap = this.clearcoatNormalMap.toJSON( meta ).uuid;
12697                         data.clearcoatNormalScale = this.clearcoatNormalScale.toArray();
12698
12699                 }
12700
12701                 if ( this.map && this.map.isTexture ) data.map = this.map.toJSON( meta ).uuid;
12702                 if ( this.matcap && this.matcap.isTexture ) data.matcap = this.matcap.toJSON( meta ).uuid;
12703                 if ( this.alphaMap && this.alphaMap.isTexture ) data.alphaMap = this.alphaMap.toJSON( meta ).uuid;
12704                 if ( this.lightMap && this.lightMap.isTexture ) data.lightMap = this.lightMap.toJSON( meta ).uuid;
12705
12706                 if ( this.aoMap && this.aoMap.isTexture ) {
12707
12708                         data.aoMap = this.aoMap.toJSON( meta ).uuid;
12709                         data.aoMapIntensity = this.aoMapIntensity;
12710
12711                 }
12712
12713                 if ( this.bumpMap && this.bumpMap.isTexture ) {
12714
12715                         data.bumpMap = this.bumpMap.toJSON( meta ).uuid;
12716                         data.bumpScale = this.bumpScale;
12717
12718                 }
12719
12720                 if ( this.normalMap && this.normalMap.isTexture ) {
12721
12722                         data.normalMap = this.normalMap.toJSON( meta ).uuid;
12723                         data.normalMapType = this.normalMapType;
12724                         data.normalScale = this.normalScale.toArray();
12725
12726                 }
12727
12728                 if ( this.displacementMap && this.displacementMap.isTexture ) {
12729
12730                         data.displacementMap = this.displacementMap.toJSON( meta ).uuid;
12731                         data.displacementScale = this.displacementScale;
12732                         data.displacementBias = this.displacementBias;
12733
12734                 }
12735
12736                 if ( this.roughnessMap && this.roughnessMap.isTexture ) data.roughnessMap = this.roughnessMap.toJSON( meta ).uuid;
12737                 if ( this.metalnessMap && this.metalnessMap.isTexture ) data.metalnessMap = this.metalnessMap.toJSON( meta ).uuid;
12738
12739                 if ( this.emissiveMap && this.emissiveMap.isTexture ) data.emissiveMap = this.emissiveMap.toJSON( meta ).uuid;
12740                 if ( this.specularMap && this.specularMap.isTexture ) data.specularMap = this.specularMap.toJSON( meta ).uuid;
12741
12742                 if ( this.envMap && this.envMap.isTexture ) {
12743
12744                         data.envMap = this.envMap.toJSON( meta ).uuid;
12745                         data.reflectivity = this.reflectivity; // Scale behind envMap
12746                         data.refractionRatio = this.refractionRatio;
12747
12748                         if ( this.combine !== undefined ) data.combine = this.combine;
12749                         if ( this.envMapIntensity !== undefined ) data.envMapIntensity = this.envMapIntensity;
12750
12751                 }
12752
12753                 if ( this.gradientMap && this.gradientMap.isTexture ) {
12754
12755                         data.gradientMap = this.gradientMap.toJSON( meta ).uuid;
12756
12757                 }
12758
12759                 if ( this.size !== undefined ) data.size = this.size;
12760                 if ( this.sizeAttenuation !== undefined ) data.sizeAttenuation = this.sizeAttenuation;
12761
12762                 if ( this.blending !== NormalBlending ) data.blending = this.blending;
12763                 if ( this.flatShading === true ) data.flatShading = this.flatShading;
12764                 if ( this.side !== FrontSide ) data.side = this.side;
12765                 if ( this.vertexColors ) data.vertexColors = true;
12766
12767                 if ( this.opacity < 1 ) data.opacity = this.opacity;
12768                 if ( this.transparent === true ) data.transparent = this.transparent;
12769
12770                 data.depthFunc = this.depthFunc;
12771                 data.depthTest = this.depthTest;
12772                 data.depthWrite = this.depthWrite;
12773
12774                 data.stencilWrite = this.stencilWrite;
12775                 data.stencilWriteMask = this.stencilWriteMask;
12776                 data.stencilFunc = this.stencilFunc;
12777                 data.stencilRef = this.stencilRef;
12778                 data.stencilFuncMask = this.stencilFuncMask;
12779                 data.stencilFail = this.stencilFail;
12780                 data.stencilZFail = this.stencilZFail;
12781                 data.stencilZPass = this.stencilZPass;
12782
12783                 // rotation (SpriteMaterial)
12784                 if ( this.rotation && this.rotation !== 0 ) data.rotation = this.rotation;
12785
12786                 if ( this.polygonOffset === true ) data.polygonOffset = true;
12787                 if ( this.polygonOffsetFactor !== 0 ) data.polygonOffsetFactor = this.polygonOffsetFactor;
12788                 if ( this.polygonOffsetUnits !== 0 ) data.polygonOffsetUnits = this.polygonOffsetUnits;
12789
12790                 if ( this.linewidth && this.linewidth !== 1 ) data.linewidth = this.linewidth;
12791                 if ( this.dashSize !== undefined ) data.dashSize = this.dashSize;
12792                 if ( this.gapSize !== undefined ) data.gapSize = this.gapSize;
12793                 if ( this.scale !== undefined ) data.scale = this.scale;
12794
12795                 if ( this.dithering === true ) data.dithering = true;
12796
12797                 if ( this.alphaTest > 0 ) data.alphaTest = this.alphaTest;
12798                 if ( this.premultipliedAlpha === true ) data.premultipliedAlpha = this.premultipliedAlpha;
12799
12800                 if ( this.wireframe === true ) data.wireframe = this.wireframe;
12801                 if ( this.wireframeLinewidth > 1 ) data.wireframeLinewidth = this.wireframeLinewidth;
12802                 if ( this.wireframeLinecap !== 'round' ) data.wireframeLinecap = this.wireframeLinecap;
12803                 if ( this.wireframeLinejoin !== 'round' ) data.wireframeLinejoin = this.wireframeLinejoin;
12804
12805                 if ( this.morphTargets === true ) data.morphTargets = true;
12806                 if ( this.morphNormals === true ) data.morphNormals = true;
12807                 if ( this.skinning === true ) data.skinning = true;
12808
12809                 if ( this.visible === false ) data.visible = false;
12810
12811                 if ( this.toneMapped === false ) data.toneMapped = false;
12812
12813                 if ( JSON.stringify( this.userData ) !== '{}' ) data.userData = this.userData;
12814
12815                 // TODO: Copied from Object3D.toJSON
12816
12817                 function extractFromCache( cache ) {
12818
12819                         const values = [];
12820
12821                         for ( const key in cache ) {
12822
12823                                 const data = cache[ key ];
12824                                 delete data.metadata;
12825                                 values.push( data );
12826
12827                         }
12828
12829                         return values;
12830
12831                 }
12832
12833                 if ( isRoot ) {
12834
12835                         const textures = extractFromCache( meta.textures );
12836                         const images = extractFromCache( meta.images );
12837
12838                         if ( textures.length > 0 ) data.textures = textures;
12839                         if ( images.length > 0 ) data.images = images;
12840
12841                 }
12842
12843                 return data;
12844
12845         },
12846
12847         clone: function () {
12848
12849                 return new this.constructor().copy( this );
12850
12851         },
12852
12853         copy: function ( source ) {
12854
12855                 this.name = source.name;
12856
12857                 this.fog = source.fog;
12858
12859                 this.blending = source.blending;
12860                 this.side = source.side;
12861                 this.flatShading = source.flatShading;
12862                 this.vertexColors = source.vertexColors;
12863
12864                 this.opacity = source.opacity;
12865                 this.transparent = source.transparent;
12866
12867                 this.blendSrc = source.blendSrc;
12868                 this.blendDst = source.blendDst;
12869                 this.blendEquation = source.blendEquation;
12870                 this.blendSrcAlpha = source.blendSrcAlpha;
12871                 this.blendDstAlpha = source.blendDstAlpha;
12872                 this.blendEquationAlpha = source.blendEquationAlpha;
12873
12874                 this.depthFunc = source.depthFunc;
12875                 this.depthTest = source.depthTest;
12876                 this.depthWrite = source.depthWrite;
12877
12878                 this.stencilWriteMask = source.stencilWriteMask;
12879                 this.stencilFunc = source.stencilFunc;
12880                 this.stencilRef = source.stencilRef;
12881                 this.stencilFuncMask = source.stencilFuncMask;
12882                 this.stencilFail = source.stencilFail;
12883                 this.stencilZFail = source.stencilZFail;
12884                 this.stencilZPass = source.stencilZPass;
12885                 this.stencilWrite = source.stencilWrite;
12886
12887                 const srcPlanes = source.clippingPlanes;
12888                 let dstPlanes = null;
12889
12890                 if ( srcPlanes !== null ) {
12891
12892                         const n = srcPlanes.length;
12893                         dstPlanes = new Array( n );
12894
12895                         for ( let i = 0; i !== n; ++ i ) {
12896
12897                                 dstPlanes[ i ] = srcPlanes[ i ].clone();
12898
12899                         }
12900
12901                 }
12902
12903                 this.clippingPlanes = dstPlanes;
12904                 this.clipIntersection = source.clipIntersection;
12905                 this.clipShadows = source.clipShadows;
12906
12907                 this.shadowSide = source.shadowSide;
12908
12909                 this.colorWrite = source.colorWrite;
12910
12911                 this.precision = source.precision;
12912
12913                 this.polygonOffset = source.polygonOffset;
12914                 this.polygonOffsetFactor = source.polygonOffsetFactor;
12915                 this.polygonOffsetUnits = source.polygonOffsetUnits;
12916
12917                 this.dithering = source.dithering;
12918
12919                 this.alphaTest = source.alphaTest;
12920                 this.premultipliedAlpha = source.premultipliedAlpha;
12921
12922                 this.visible = source.visible;
12923
12924                 this.toneMapped = source.toneMapped;
12925
12926                 this.userData = JSON.parse( JSON.stringify( source.userData ) );
12927
12928                 return this;
12929
12930         },
12931
12932         dispose: function () {
12933
12934                 this.dispatchEvent( { type: 'dispose' } );
12935
12936         }
12937
12938 } );
12939
12940 Object.defineProperty( Material.prototype, 'needsUpdate', {
12941
12942         set: function ( value ) {
12943
12944                 if ( value === true ) this.version ++;
12945
12946         }
12947
12948 } );
12949
12950 /**
12951  * parameters = {
12952  *  color: <hex>,
12953  *  opacity: <float>,
12954  *  map: new THREE.Texture( <Image> ),
12955  *
12956  *  lightMap: new THREE.Texture( <Image> ),
12957  *  lightMapIntensity: <float>
12958  *
12959  *  aoMap: new THREE.Texture( <Image> ),
12960  *  aoMapIntensity: <float>
12961  *
12962  *  specularMap: new THREE.Texture( <Image> ),
12963  *
12964  *  alphaMap: new THREE.Texture( <Image> ),
12965  *
12966  *  envMap: new THREE.CubeTexture( [posx, negx, posy, negy, posz, negz] ),
12967  *  combine: THREE.Multiply,
12968  *  reflectivity: <float>,
12969  *  refractionRatio: <float>,
12970  *
12971  *  depthTest: <bool>,
12972  *  depthWrite: <bool>,
12973  *
12974  *  wireframe: <boolean>,
12975  *  wireframeLinewidth: <float>,
12976  *
12977  *  skinning: <bool>,
12978  *  morphTargets: <bool>
12979  * }
12980  */
12981
12982 function MeshBasicMaterial( parameters ) {
12983
12984         Material.call( this );
12985
12986         this.type = 'MeshBasicMaterial';
12987
12988         this.color = new Color( 0xffffff ); // emissive
12989
12990         this.map = null;
12991
12992         this.lightMap = null;
12993         this.lightMapIntensity = 1.0;
12994
12995         this.aoMap = null;
12996         this.aoMapIntensity = 1.0;
12997
12998         this.specularMap = null;
12999
13000         this.alphaMap = null;
13001
13002         this.envMap = null;
13003         this.combine = MultiplyOperation;
13004         this.reflectivity = 1;
13005         this.refractionRatio = 0.98;
13006
13007         this.wireframe = false;
13008         this.wireframeLinewidth = 1;
13009         this.wireframeLinecap = 'round';
13010         this.wireframeLinejoin = 'round';
13011
13012         this.skinning = false;
13013         this.morphTargets = false;
13014
13015         this.setValues( parameters );
13016
13017 }
13018
13019 MeshBasicMaterial.prototype = Object.create( Material.prototype );
13020 MeshBasicMaterial.prototype.constructor = MeshBasicMaterial;
13021
13022 MeshBasicMaterial.prototype.isMeshBasicMaterial = true;
13023
13024 MeshBasicMaterial.prototype.copy = function ( source ) {
13025
13026         Material.prototype.copy.call( this, source );
13027
13028         this.color.copy( source.color );
13029
13030         this.map = source.map;
13031
13032         this.lightMap = source.lightMap;
13033         this.lightMapIntensity = source.lightMapIntensity;
13034
13035         this.aoMap = source.aoMap;
13036         this.aoMapIntensity = source.aoMapIntensity;
13037
13038         this.specularMap = source.specularMap;
13039
13040         this.alphaMap = source.alphaMap;
13041
13042         this.envMap = source.envMap;
13043         this.combine = source.combine;
13044         this.reflectivity = source.reflectivity;
13045         this.refractionRatio = source.refractionRatio;
13046
13047         this.wireframe = source.wireframe;
13048         this.wireframeLinewidth = source.wireframeLinewidth;
13049         this.wireframeLinecap = source.wireframeLinecap;
13050         this.wireframeLinejoin = source.wireframeLinejoin;
13051
13052         this.skinning = source.skinning;
13053         this.morphTargets = source.morphTargets;
13054
13055         return this;
13056
13057 };
13058
13059 const _vector$3 = new Vector3();
13060 const _vector2$1 = new Vector2();
13061
13062 function BufferAttribute( array, itemSize, normalized ) {
13063
13064         if ( Array.isArray( array ) ) {
13065
13066                 throw new TypeError( 'THREE.BufferAttribute: array should be a Typed Array.' );
13067
13068         }
13069
13070         this.name = '';
13071
13072         this.array = array;
13073         this.itemSize = itemSize;
13074         this.count = array !== undefined ? array.length / itemSize : 0;
13075         this.normalized = normalized === true;
13076
13077         this.usage = StaticDrawUsage;
13078         this.updateRange = { offset: 0, count: - 1 };
13079
13080         this.version = 0;
13081
13082 }
13083
13084 Object.defineProperty( BufferAttribute.prototype, 'needsUpdate', {
13085
13086         set: function ( value ) {
13087
13088                 if ( value === true ) this.version ++;
13089
13090         }
13091
13092 } );
13093
13094 Object.assign( BufferAttribute.prototype, {
13095
13096         isBufferAttribute: true,
13097
13098         onUploadCallback: function () {},
13099
13100         setUsage: function ( value ) {
13101
13102                 this.usage = value;
13103
13104                 return this;
13105
13106         },
13107
13108         copy: function ( source ) {
13109
13110                 this.name = source.name;
13111                 this.array = new source.array.constructor( source.array );
13112                 this.itemSize = source.itemSize;
13113                 this.count = source.count;
13114                 this.normalized = source.normalized;
13115
13116                 this.usage = source.usage;
13117
13118                 return this;
13119
13120         },
13121
13122         copyAt: function ( index1, attribute, index2 ) {
13123
13124                 index1 *= this.itemSize;
13125                 index2 *= attribute.itemSize;
13126
13127                 for ( let i = 0, l = this.itemSize; i < l; i ++ ) {
13128
13129                         this.array[ index1 + i ] = attribute.array[ index2 + i ];
13130
13131                 }
13132
13133                 return this;
13134
13135         },
13136
13137         copyArray: function ( array ) {
13138
13139                 this.array.set( array );
13140
13141                 return this;
13142
13143         },
13144
13145         copyColorsArray: function ( colors ) {
13146
13147                 const array = this.array;
13148                 let offset = 0;
13149
13150                 for ( let i = 0, l = colors.length; i < l; i ++ ) {
13151
13152                         let color = colors[ i ];
13153
13154                         if ( color === undefined ) {
13155
13156                                 console.warn( 'THREE.BufferAttribute.copyColorsArray(): color is undefined', i );
13157                                 color = new Color();
13158
13159                         }
13160
13161                         array[ offset ++ ] = color.r;
13162                         array[ offset ++ ] = color.g;
13163                         array[ offset ++ ] = color.b;
13164
13165                 }
13166
13167                 return this;
13168
13169         },
13170
13171         copyVector2sArray: function ( vectors ) {
13172
13173                 const array = this.array;
13174                 let offset = 0;
13175
13176                 for ( let i = 0, l = vectors.length; i < l; i ++ ) {
13177
13178                         let vector = vectors[ i ];
13179
13180                         if ( vector === undefined ) {
13181
13182                                 console.warn( 'THREE.BufferAttribute.copyVector2sArray(): vector is undefined', i );
13183                                 vector = new Vector2();
13184
13185                         }
13186
13187                         array[ offset ++ ] = vector.x;
13188                         array[ offset ++ ] = vector.y;
13189
13190                 }
13191
13192                 return this;
13193
13194         },
13195
13196         copyVector3sArray: function ( vectors ) {
13197
13198                 const array = this.array;
13199                 let offset = 0;
13200
13201                 for ( let i = 0, l = vectors.length; i < l; i ++ ) {
13202
13203                         let vector = vectors[ i ];
13204
13205                         if ( vector === undefined ) {
13206
13207                                 console.warn( 'THREE.BufferAttribute.copyVector3sArray(): vector is undefined', i );
13208                                 vector = new Vector3();
13209
13210                         }
13211
13212                         array[ offset ++ ] = vector.x;
13213                         array[ offset ++ ] = vector.y;
13214                         array[ offset ++ ] = vector.z;
13215
13216                 }
13217
13218                 return this;
13219
13220         },
13221
13222         copyVector4sArray: function ( vectors ) {
13223
13224                 const array = this.array;
13225                 let offset = 0;
13226
13227                 for ( let i = 0, l = vectors.length; i < l; i ++ ) {
13228
13229                         let vector = vectors[ i ];
13230
13231                         if ( vector === undefined ) {
13232
13233                                 console.warn( 'THREE.BufferAttribute.copyVector4sArray(): vector is undefined', i );
13234                                 vector = new Vector4();
13235
13236                         }
13237
13238                         array[ offset ++ ] = vector.x;
13239                         array[ offset ++ ] = vector.y;
13240                         array[ offset ++ ] = vector.z;
13241                         array[ offset ++ ] = vector.w;
13242
13243                 }
13244
13245                 return this;
13246
13247         },
13248
13249         applyMatrix3: function ( m ) {
13250
13251                 if ( this.itemSize === 2 ) {
13252
13253                         for ( let i = 0, l = this.count; i < l; i ++ ) {
13254
13255                                 _vector2$1.fromBufferAttribute( this, i );
13256                                 _vector2$1.applyMatrix3( m );
13257
13258                                 this.setXY( i, _vector2$1.x, _vector2$1.y );
13259
13260                         }
13261
13262                 } else if ( this.itemSize === 3 ) {
13263
13264                         for ( let i = 0, l = this.count; i < l; i ++ ) {
13265
13266                                 _vector$3.fromBufferAttribute( this, i );
13267                                 _vector$3.applyMatrix3( m );
13268
13269                                 this.setXYZ( i, _vector$3.x, _vector$3.y, _vector$3.z );
13270
13271                         }
13272
13273                 }
13274
13275                 return this;
13276
13277         },
13278
13279         applyMatrix4: function ( m ) {
13280
13281                 for ( let i = 0, l = this.count; i < l; i ++ ) {
13282
13283                         _vector$3.x = this.getX( i );
13284                         _vector$3.y = this.getY( i );
13285                         _vector$3.z = this.getZ( i );
13286
13287                         _vector$3.applyMatrix4( m );
13288
13289                         this.setXYZ( i, _vector$3.x, _vector$3.y, _vector$3.z );
13290
13291                 }
13292
13293                 return this;
13294
13295         },
13296
13297         applyNormalMatrix: function ( m ) {
13298
13299                 for ( let i = 0, l = this.count; i < l; i ++ ) {
13300
13301                         _vector$3.x = this.getX( i );
13302                         _vector$3.y = this.getY( i );
13303                         _vector$3.z = this.getZ( i );
13304
13305                         _vector$3.applyNormalMatrix( m );
13306
13307                         this.setXYZ( i, _vector$3.x, _vector$3.y, _vector$3.z );
13308
13309                 }
13310
13311                 return this;
13312
13313         },
13314
13315         transformDirection: function ( m ) {
13316
13317                 for ( let i = 0, l = this.count; i < l; i ++ ) {
13318
13319                         _vector$3.x = this.getX( i );
13320                         _vector$3.y = this.getY( i );
13321                         _vector$3.z = this.getZ( i );
13322
13323                         _vector$3.transformDirection( m );
13324
13325                         this.setXYZ( i, _vector$3.x, _vector$3.y, _vector$3.z );
13326
13327                 }
13328
13329                 return this;
13330
13331         },
13332
13333         set: function ( value, offset = 0 ) {
13334
13335                 this.array.set( value, offset );
13336
13337                 return this;
13338
13339         },
13340
13341         getX: function ( index ) {
13342
13343                 return this.array[ index * this.itemSize ];
13344
13345         },
13346
13347         setX: function ( index, x ) {
13348
13349                 this.array[ index * this.itemSize ] = x;
13350
13351                 return this;
13352
13353         },
13354
13355         getY: function ( index ) {
13356
13357                 return this.array[ index * this.itemSize + 1 ];
13358
13359         },
13360
13361         setY: function ( index, y ) {
13362
13363                 this.array[ index * this.itemSize + 1 ] = y;
13364
13365                 return this;
13366
13367         },
13368
13369         getZ: function ( index ) {
13370
13371                 return this.array[ index * this.itemSize + 2 ];
13372
13373         },
13374
13375         setZ: function ( index, z ) {
13376
13377                 this.array[ index * this.itemSize + 2 ] = z;
13378
13379                 return this;
13380
13381         },
13382
13383         getW: function ( index ) {
13384
13385                 return this.array[ index * this.itemSize + 3 ];
13386
13387         },
13388
13389         setW: function ( index, w ) {
13390
13391                 this.array[ index * this.itemSize + 3 ] = w;
13392
13393                 return this;
13394
13395         },
13396
13397         setXY: function ( index, x, y ) {
13398
13399                 index *= this.itemSize;
13400
13401                 this.array[ index + 0 ] = x;
13402                 this.array[ index + 1 ] = y;
13403
13404                 return this;
13405
13406         },
13407
13408         setXYZ: function ( index, x, y, z ) {
13409
13410                 index *= this.itemSize;
13411
13412                 this.array[ index + 0 ] = x;
13413                 this.array[ index + 1 ] = y;
13414                 this.array[ index + 2 ] = z;
13415
13416                 return this;
13417
13418         },
13419
13420         setXYZW: function ( index, x, y, z, w ) {
13421
13422                 index *= this.itemSize;
13423
13424                 this.array[ index + 0 ] = x;
13425                 this.array[ index + 1 ] = y;
13426                 this.array[ index + 2 ] = z;
13427                 this.array[ index + 3 ] = w;
13428
13429                 return this;
13430
13431         },
13432
13433         onUpload: function ( callback ) {
13434
13435                 this.onUploadCallback = callback;
13436
13437                 return this;
13438
13439         },
13440
13441         clone: function () {
13442
13443                 return new this.constructor( this.array, this.itemSize ).copy( this );
13444
13445         },
13446
13447         toJSON: function () {
13448
13449                 return {
13450                         itemSize: this.itemSize,
13451                         type: this.array.constructor.name,
13452                         array: Array.prototype.slice.call( this.array ),
13453                         normalized: this.normalized
13454                 };
13455
13456         }
13457
13458 } );
13459
13460 //
13461
13462 function Int8BufferAttribute( array, itemSize, normalized ) {
13463
13464         BufferAttribute.call( this, new Int8Array( array ), itemSize, normalized );
13465
13466 }
13467
13468 Int8BufferAttribute.prototype = Object.create( BufferAttribute.prototype );
13469 Int8BufferAttribute.prototype.constructor = Int8BufferAttribute;
13470
13471
13472 function Uint8BufferAttribute( array, itemSize, normalized ) {
13473
13474         BufferAttribute.call( this, new Uint8Array( array ), itemSize, normalized );
13475
13476 }
13477
13478 Uint8BufferAttribute.prototype = Object.create( BufferAttribute.prototype );
13479 Uint8BufferAttribute.prototype.constructor = Uint8BufferAttribute;
13480
13481
13482 function Uint8ClampedBufferAttribute( array, itemSize, normalized ) {
13483
13484         BufferAttribute.call( this, new Uint8ClampedArray( array ), itemSize, normalized );
13485
13486 }
13487
13488 Uint8ClampedBufferAttribute.prototype = Object.create( BufferAttribute.prototype );
13489 Uint8ClampedBufferAttribute.prototype.constructor = Uint8ClampedBufferAttribute;
13490
13491
13492 function Int16BufferAttribute( array, itemSize, normalized ) {
13493
13494         BufferAttribute.call( this, new Int16Array( array ), itemSize, normalized );
13495
13496 }
13497
13498 Int16BufferAttribute.prototype = Object.create( BufferAttribute.prototype );
13499 Int16BufferAttribute.prototype.constructor = Int16BufferAttribute;
13500
13501
13502 function Uint16BufferAttribute( array, itemSize, normalized ) {
13503
13504         BufferAttribute.call( this, new Uint16Array( array ), itemSize, normalized );
13505
13506 }
13507
13508 Uint16BufferAttribute.prototype = Object.create( BufferAttribute.prototype );
13509 Uint16BufferAttribute.prototype.constructor = Uint16BufferAttribute;
13510
13511
13512 function Int32BufferAttribute( array, itemSize, normalized ) {
13513
13514         BufferAttribute.call( this, new Int32Array( array ), itemSize, normalized );
13515
13516 }
13517
13518 Int32BufferAttribute.prototype = Object.create( BufferAttribute.prototype );
13519 Int32BufferAttribute.prototype.constructor = Int32BufferAttribute;
13520
13521
13522 function Uint32BufferAttribute( array, itemSize, normalized ) {
13523
13524         BufferAttribute.call( this, new Uint32Array( array ), itemSize, normalized );
13525
13526 }
13527
13528 Uint32BufferAttribute.prototype = Object.create( BufferAttribute.prototype );
13529 Uint32BufferAttribute.prototype.constructor = Uint32BufferAttribute;
13530
13531 function Float16BufferAttribute( array, itemSize, normalized ) {
13532
13533         BufferAttribute.call( this, new Uint16Array( array ), itemSize, normalized );
13534
13535 }
13536
13537 Float16BufferAttribute.prototype = Object.create( BufferAttribute.prototype );
13538 Float16BufferAttribute.prototype.constructor = Float16BufferAttribute;
13539 Float16BufferAttribute.prototype.isFloat16BufferAttribute = true;
13540
13541 function Float32BufferAttribute( array, itemSize, normalized ) {
13542
13543         BufferAttribute.call( this, new Float32Array( array ), itemSize, normalized );
13544
13545 }
13546
13547 Float32BufferAttribute.prototype = Object.create( BufferAttribute.prototype );
13548 Float32BufferAttribute.prototype.constructor = Float32BufferAttribute;
13549
13550
13551 function Float64BufferAttribute( array, itemSize, normalized ) {
13552
13553         BufferAttribute.call( this, new Float64Array( array ), itemSize, normalized );
13554
13555 }
13556
13557 Float64BufferAttribute.prototype = Object.create( BufferAttribute.prototype );
13558 Float64BufferAttribute.prototype.constructor = Float64BufferAttribute;
13559
13560 function arrayMax( array ) {
13561
13562         if ( array.length === 0 ) return - Infinity;
13563
13564         let max = array[ 0 ];
13565
13566         for ( let i = 1, l = array.length; i < l; ++ i ) {
13567
13568                 if ( array[ i ] > max ) max = array[ i ];
13569
13570         }
13571
13572         return max;
13573
13574 }
13575
13576 const TYPED_ARRAYS = {
13577         Int8Array: Int8Array,
13578         Uint8Array: Uint8Array,
13579         // Workaround for IE11 pre KB2929437. See #11440
13580         Uint8ClampedArray: typeof Uint8ClampedArray !== 'undefined' ? Uint8ClampedArray : Uint8Array,
13581         Int16Array: Int16Array,
13582         Uint16Array: Uint16Array,
13583         Int32Array: Int32Array,
13584         Uint32Array: Uint32Array,
13585         Float32Array: Float32Array,
13586         Float64Array: Float64Array
13587 };
13588
13589 function getTypedArray( type, buffer ) {
13590
13591         return new TYPED_ARRAYS[ type ]( buffer );
13592
13593 }
13594
13595 let _id = 0;
13596
13597 const _m1$2 = new Matrix4();
13598 const _obj = new Object3D();
13599 const _offset = new Vector3();
13600 const _box$2 = new Box3();
13601 const _boxMorphTargets = new Box3();
13602 const _vector$4 = new Vector3();
13603
13604 function BufferGeometry() {
13605
13606         Object.defineProperty( this, 'id', { value: _id ++ } );
13607
13608         this.uuid = MathUtils.generateUUID();
13609
13610         this.name = '';
13611         this.type = 'BufferGeometry';
13612
13613         this.index = null;
13614         this.attributes = {};
13615
13616         this.morphAttributes = {};
13617         this.morphTargetsRelative = false;
13618
13619         this.groups = [];
13620
13621         this.boundingBox = null;
13622         this.boundingSphere = null;
13623
13624         this.drawRange = { start: 0, count: Infinity };
13625
13626         this.userData = {};
13627
13628 }
13629
13630 BufferGeometry.prototype = Object.assign( Object.create( EventDispatcher.prototype ), {
13631
13632         constructor: BufferGeometry,
13633
13634         isBufferGeometry: true,
13635
13636         getIndex: function () {
13637
13638                 return this.index;
13639
13640         },
13641
13642         setIndex: function ( index ) {
13643
13644                 if ( Array.isArray( index ) ) {
13645
13646                         this.index = new ( arrayMax( index ) > 65535 ? Uint32BufferAttribute : Uint16BufferAttribute )( index, 1 );
13647
13648                 } else {
13649
13650                         this.index = index;
13651
13652                 }
13653
13654                 return this;
13655
13656         },
13657
13658         getAttribute: function ( name ) {
13659
13660                 return this.attributes[ name ];
13661
13662         },
13663
13664         setAttribute: function ( name, attribute ) {
13665
13666                 this.attributes[ name ] = attribute;
13667
13668                 return this;
13669
13670         },
13671
13672         deleteAttribute: function ( name ) {
13673
13674                 delete this.attributes[ name ];
13675
13676                 return this;
13677
13678         },
13679
13680         hasAttribute: function ( name ) {
13681
13682                 return this.attributes[ name ] !== undefined;
13683
13684         },
13685
13686         addGroup: function ( start, count, materialIndex = 0 ) {
13687
13688                 this.groups.push( {
13689
13690                         start: start,
13691                         count: count,
13692                         materialIndex: materialIndex
13693
13694                 } );
13695
13696         },
13697
13698         clearGroups: function () {
13699
13700                 this.groups = [];
13701
13702         },
13703
13704         setDrawRange: function ( start, count ) {
13705
13706                 this.drawRange.start = start;
13707                 this.drawRange.count = count;
13708
13709         },
13710
13711         applyMatrix4: function ( matrix ) {
13712
13713                 const position = this.attributes.position;
13714
13715                 if ( position !== undefined ) {
13716
13717                         position.applyMatrix4( matrix );
13718
13719                         position.needsUpdate = true;
13720
13721                 }
13722
13723                 const normal = this.attributes.normal;
13724
13725                 if ( normal !== undefined ) {
13726
13727                         const normalMatrix = new Matrix3().getNormalMatrix( matrix );
13728
13729                         normal.applyNormalMatrix( normalMatrix );
13730
13731                         normal.needsUpdate = true;
13732
13733                 }
13734
13735                 const tangent = this.attributes.tangent;
13736
13737                 if ( tangent !== undefined ) {
13738
13739                         tangent.transformDirection( matrix );
13740
13741                         tangent.needsUpdate = true;
13742
13743                 }
13744
13745                 if ( this.boundingBox !== null ) {
13746
13747                         this.computeBoundingBox();
13748
13749                 }
13750
13751                 if ( this.boundingSphere !== null ) {
13752
13753                         this.computeBoundingSphere();
13754
13755                 }
13756
13757                 return this;
13758
13759         },
13760
13761         rotateX: function ( angle ) {
13762
13763                 // rotate geometry around world x-axis
13764
13765                 _m1$2.makeRotationX( angle );
13766
13767                 this.applyMatrix4( _m1$2 );
13768
13769                 return this;
13770
13771         },
13772
13773         rotateY: function ( angle ) {
13774
13775                 // rotate geometry around world y-axis
13776
13777                 _m1$2.makeRotationY( angle );
13778
13779                 this.applyMatrix4( _m1$2 );
13780
13781                 return this;
13782
13783         },
13784
13785         rotateZ: function ( angle ) {
13786
13787                 // rotate geometry around world z-axis
13788
13789                 _m1$2.makeRotationZ( angle );
13790
13791                 this.applyMatrix4( _m1$2 );
13792
13793                 return this;
13794
13795         },
13796
13797         translate: function ( x, y, z ) {
13798
13799                 // translate geometry
13800
13801                 _m1$2.makeTranslation( x, y, z );
13802
13803                 this.applyMatrix4( _m1$2 );
13804
13805                 return this;
13806
13807         },
13808
13809         scale: function ( x, y, z ) {
13810
13811                 // scale geometry
13812
13813                 _m1$2.makeScale( x, y, z );
13814
13815                 this.applyMatrix4( _m1$2 );
13816
13817                 return this;
13818
13819         },
13820
13821         lookAt: function ( vector ) {
13822
13823                 _obj.lookAt( vector );
13824
13825                 _obj.updateMatrix();
13826
13827                 this.applyMatrix4( _obj.matrix );
13828
13829                 return this;
13830
13831         },
13832
13833         center: function () {
13834
13835                 this.computeBoundingBox();
13836
13837                 this.boundingBox.getCenter( _offset ).negate();
13838
13839                 this.translate( _offset.x, _offset.y, _offset.z );
13840
13841                 return this;
13842
13843         },
13844
13845         setFromPoints: function ( points ) {
13846
13847                 const position = [];
13848
13849                 for ( let i = 0, l = points.length; i < l; i ++ ) {
13850
13851                         const point = points[ i ];
13852                         position.push( point.x, point.y, point.z || 0 );
13853
13854                 }
13855
13856                 this.setAttribute( 'position', new Float32BufferAttribute( position, 3 ) );
13857
13858                 return this;
13859
13860         },
13861
13862         computeBoundingBox: function () {
13863
13864                 if ( this.boundingBox === null ) {
13865
13866                         this.boundingBox = new Box3();
13867
13868                 }
13869
13870                 const position = this.attributes.position;
13871                 const morphAttributesPosition = this.morphAttributes.position;
13872
13873                 if ( position && position.isGLBufferAttribute ) {
13874
13875                         console.error( 'THREE.BufferGeometry.computeBoundingBox(): GLBufferAttribute requires a manual bounding box. Alternatively set "mesh.frustumCulled" to "false".', this );
13876
13877                         this.boundingBox.set(
13878                                 new Vector3( - Infinity, - Infinity, - Infinity ),
13879                                 new Vector3( + Infinity, + Infinity, + Infinity )
13880                         );
13881
13882                         return;
13883
13884                 }
13885
13886                 if ( position !== undefined ) {
13887
13888                         this.boundingBox.setFromBufferAttribute( position );
13889
13890                         // process morph attributes if present
13891
13892                         if ( morphAttributesPosition ) {
13893
13894                                 for ( let i = 0, il = morphAttributesPosition.length; i < il; i ++ ) {
13895
13896                                         const morphAttribute = morphAttributesPosition[ i ];
13897                                         _box$2.setFromBufferAttribute( morphAttribute );
13898
13899                                         if ( this.morphTargetsRelative ) {
13900
13901                                                 _vector$4.addVectors( this.boundingBox.min, _box$2.min );
13902                                                 this.boundingBox.expandByPoint( _vector$4 );
13903
13904                                                 _vector$4.addVectors( this.boundingBox.max, _box$2.max );
13905                                                 this.boundingBox.expandByPoint( _vector$4 );
13906
13907                                         } else {
13908
13909                                                 this.boundingBox.expandByPoint( _box$2.min );
13910                                                 this.boundingBox.expandByPoint( _box$2.max );
13911
13912                                         }
13913
13914                                 }
13915
13916                         }
13917
13918                 } else {
13919
13920                         this.boundingBox.makeEmpty();
13921
13922                 }
13923
13924                 if ( isNaN( this.boundingBox.min.x ) || isNaN( this.boundingBox.min.y ) || isNaN( this.boundingBox.min.z ) ) {
13925
13926                         console.error( 'THREE.BufferGeometry.computeBoundingBox(): Computed min/max have NaN values. The "position" attribute is likely to have NaN values.', this );
13927
13928                 }
13929
13930         },
13931
13932         computeBoundingSphere: function () {
13933
13934                 if ( this.boundingSphere === null ) {
13935
13936                         this.boundingSphere = new Sphere();
13937
13938                 }
13939
13940                 const position = this.attributes.position;
13941                 const morphAttributesPosition = this.morphAttributes.position;
13942
13943                 if ( position && position.isGLBufferAttribute ) {
13944
13945                         console.error( 'THREE.BufferGeometry.computeBoundingSphere(): GLBufferAttribute requires a manual bounding sphere. Alternatively set "mesh.frustumCulled" to "false".', this );
13946
13947                         this.boundingSphere.set( new Vector3(), Infinity );
13948
13949                         return;
13950
13951                 }
13952
13953                 if ( position ) {
13954
13955                         // first, find the center of the bounding sphere
13956
13957                         const center = this.boundingSphere.center;
13958
13959                         _box$2.setFromBufferAttribute( position );
13960
13961                         // process morph attributes if present
13962
13963                         if ( morphAttributesPosition ) {
13964
13965                                 for ( let i = 0, il = morphAttributesPosition.length; i < il; i ++ ) {
13966
13967                                         const morphAttribute = morphAttributesPosition[ i ];
13968                                         _boxMorphTargets.setFromBufferAttribute( morphAttribute );
13969
13970                                         if ( this.morphTargetsRelative ) {
13971
13972                                                 _vector$4.addVectors( _box$2.min, _boxMorphTargets.min );
13973                                                 _box$2.expandByPoint( _vector$4 );
13974
13975                                                 _vector$4.addVectors( _box$2.max, _boxMorphTargets.max );
13976                                                 _box$2.expandByPoint( _vector$4 );
13977
13978                                         } else {
13979
13980                                                 _box$2.expandByPoint( _boxMorphTargets.min );
13981                                                 _box$2.expandByPoint( _boxMorphTargets.max );
13982
13983                                         }
13984
13985                                 }
13986
13987                         }
13988
13989                         _box$2.getCenter( center );
13990
13991                         // second, try to find a boundingSphere with a radius smaller than the
13992                         // boundingSphere of the boundingBox: sqrt(3) smaller in the best case
13993
13994                         let maxRadiusSq = 0;
13995
13996                         for ( let i = 0, il = position.count; i < il; i ++ ) {
13997
13998                                 _vector$4.fromBufferAttribute( position, i );
13999
14000                                 maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( _vector$4 ) );
14001
14002                         }
14003
14004                         // process morph attributes if present
14005
14006                         if ( morphAttributesPosition ) {
14007
14008                                 for ( let i = 0, il = morphAttributesPosition.length; i < il; i ++ ) {
14009
14010                                         const morphAttribute = morphAttributesPosition[ i ];
14011                                         const morphTargetsRelative = this.morphTargetsRelative;
14012
14013                                         for ( let j = 0, jl = morphAttribute.count; j < jl; j ++ ) {
14014
14015                                                 _vector$4.fromBufferAttribute( morphAttribute, j );
14016
14017                                                 if ( morphTargetsRelative ) {
14018
14019                                                         _offset.fromBufferAttribute( position, j );
14020                                                         _vector$4.add( _offset );
14021
14022                                                 }
14023
14024                                                 maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( _vector$4 ) );
14025
14026                                         }
14027
14028                                 }
14029
14030                         }
14031
14032                         this.boundingSphere.radius = Math.sqrt( maxRadiusSq );
14033
14034                         if ( isNaN( this.boundingSphere.radius ) ) {
14035
14036                                 console.error( 'THREE.BufferGeometry.computeBoundingSphere(): Computed radius is NaN. The "position" attribute is likely to have NaN values.', this );
14037
14038                         }
14039
14040                 }
14041
14042         },
14043
14044         computeFaceNormals: function () {
14045
14046                 // backwards compatibility
14047
14048         },
14049
14050         computeTangents: function () {
14051
14052                 const index = this.index;
14053                 const attributes = this.attributes;
14054
14055                 // based on http://www.terathon.com/code/tangent.html
14056                 // (per vertex tangents)
14057
14058                 if ( index === null ||
14059                          attributes.position === undefined ||
14060                          attributes.normal === undefined ||
14061                          attributes.uv === undefined ) {
14062
14063                         console.error( 'THREE.BufferGeometry: .computeTangents() failed. Missing required attributes (index, position, normal or uv)' );
14064                         return;
14065
14066                 }
14067
14068                 const indices = index.array;
14069                 const positions = attributes.position.array;
14070                 const normals = attributes.normal.array;
14071                 const uvs = attributes.uv.array;
14072
14073                 const nVertices = positions.length / 3;
14074
14075                 if ( attributes.tangent === undefined ) {
14076
14077                         this.setAttribute( 'tangent', new BufferAttribute( new Float32Array( 4 * nVertices ), 4 ) );
14078
14079                 }
14080
14081                 const tangents = attributes.tangent.array;
14082
14083                 const tan1 = [], tan2 = [];
14084
14085                 for ( let i = 0; i < nVertices; i ++ ) {
14086
14087                         tan1[ i ] = new Vector3();
14088                         tan2[ i ] = new Vector3();
14089
14090                 }
14091
14092                 const vA = new Vector3(),
14093                         vB = new Vector3(),
14094                         vC = new Vector3(),
14095
14096                         uvA = new Vector2(),
14097                         uvB = new Vector2(),
14098                         uvC = new Vector2(),
14099
14100                         sdir = new Vector3(),
14101                         tdir = new Vector3();
14102
14103                 function handleTriangle( a, b, c ) {
14104
14105                         vA.fromArray( positions, a * 3 );
14106                         vB.fromArray( positions, b * 3 );
14107                         vC.fromArray( positions, c * 3 );
14108
14109                         uvA.fromArray( uvs, a * 2 );
14110                         uvB.fromArray( uvs, b * 2 );
14111                         uvC.fromArray( uvs, c * 2 );
14112
14113                         vB.sub( vA );
14114                         vC.sub( vA );
14115
14116                         uvB.sub( uvA );
14117                         uvC.sub( uvA );
14118
14119                         const r = 1.0 / ( uvB.x * uvC.y - uvC.x * uvB.y );
14120
14121                         // silently ignore degenerate uv triangles having coincident or colinear vertices
14122
14123                         if ( ! isFinite( r ) ) return;
14124
14125                         sdir.copy( vB ).multiplyScalar( uvC.y ).addScaledVector( vC, - uvB.y ).multiplyScalar( r );
14126                         tdir.copy( vC ).multiplyScalar( uvB.x ).addScaledVector( vB, - uvC.x ).multiplyScalar( r );
14127
14128                         tan1[ a ].add( sdir );
14129                         tan1[ b ].add( sdir );
14130                         tan1[ c ].add( sdir );
14131
14132                         tan2[ a ].add( tdir );
14133                         tan2[ b ].add( tdir );
14134                         tan2[ c ].add( tdir );
14135
14136                 }
14137
14138                 let groups = this.groups;
14139
14140                 if ( groups.length === 0 ) {
14141
14142                         groups = [ {
14143                                 start: 0,
14144                                 count: indices.length
14145                         } ];
14146
14147                 }
14148
14149                 for ( let i = 0, il = groups.length; i < il; ++ i ) {
14150
14151                         const group = groups[ i ];
14152
14153                         const start = group.start;
14154                         const count = group.count;
14155
14156                         for ( let j = start, jl = start + count; j < jl; j += 3 ) {
14157
14158                                 handleTriangle(
14159                                         indices[ j + 0 ],
14160                                         indices[ j + 1 ],
14161                                         indices[ j + 2 ]
14162                                 );
14163
14164                         }
14165
14166                 }
14167
14168                 const tmp = new Vector3(), tmp2 = new Vector3();
14169                 const n = new Vector3(), n2 = new Vector3();
14170
14171                 function handleVertex( v ) {
14172
14173                         n.fromArray( normals, v * 3 );
14174                         n2.copy( n );
14175
14176                         const t = tan1[ v ];
14177
14178                         // Gram-Schmidt orthogonalize
14179
14180                         tmp.copy( t );
14181                         tmp.sub( n.multiplyScalar( n.dot( t ) ) ).normalize();
14182
14183                         // Calculate handedness
14184
14185                         tmp2.crossVectors( n2, t );
14186                         const test = tmp2.dot( tan2[ v ] );
14187                         const w = ( test < 0.0 ) ? - 1.0 : 1.0;
14188
14189                         tangents[ v * 4 ] = tmp.x;
14190                         tangents[ v * 4 + 1 ] = tmp.y;
14191                         tangents[ v * 4 + 2 ] = tmp.z;
14192                         tangents[ v * 4 + 3 ] = w;
14193
14194                 }
14195
14196                 for ( let i = 0, il = groups.length; i < il; ++ i ) {
14197
14198                         const group = groups[ i ];
14199
14200                         const start = group.start;
14201                         const count = group.count;
14202
14203                         for ( let j = start, jl = start + count; j < jl; j += 3 ) {
14204
14205                                 handleVertex( indices[ j + 0 ] );
14206                                 handleVertex( indices[ j + 1 ] );
14207                                 handleVertex( indices[ j + 2 ] );
14208
14209                         }
14210
14211                 }
14212
14213         },
14214
14215         computeVertexNormals: function () {
14216
14217                 const index = this.index;
14218                 const positionAttribute = this.getAttribute( 'position' );
14219
14220                 if ( positionAttribute !== undefined ) {
14221
14222                         let normalAttribute = this.getAttribute( 'normal' );
14223
14224                         if ( normalAttribute === undefined ) {
14225
14226                                 normalAttribute = new BufferAttribute( new Float32Array( positionAttribute.count * 3 ), 3 );
14227                                 this.setAttribute( 'normal', normalAttribute );
14228
14229                         } else {
14230
14231                                 // reset existing normals to zero
14232
14233                                 for ( let i = 0, il = normalAttribute.count; i < il; i ++ ) {
14234
14235                                         normalAttribute.setXYZ( i, 0, 0, 0 );
14236
14237                                 }
14238
14239                         }
14240
14241                         const pA = new Vector3(), pB = new Vector3(), pC = new Vector3();
14242                         const nA = new Vector3(), nB = new Vector3(), nC = new Vector3();
14243                         const cb = new Vector3(), ab = new Vector3();
14244
14245                         // indexed elements
14246
14247                         if ( index ) {
14248
14249                                 for ( let i = 0, il = index.count; i < il; i += 3 ) {
14250
14251                                         const vA = index.getX( i + 0 );
14252                                         const vB = index.getX( i + 1 );
14253                                         const vC = index.getX( i + 2 );
14254
14255                                         pA.fromBufferAttribute( positionAttribute, vA );
14256                                         pB.fromBufferAttribute( positionAttribute, vB );
14257                                         pC.fromBufferAttribute( positionAttribute, vC );
14258
14259                                         cb.subVectors( pC, pB );
14260                                         ab.subVectors( pA, pB );
14261                                         cb.cross( ab );
14262
14263                                         nA.fromBufferAttribute( normalAttribute, vA );
14264                                         nB.fromBufferAttribute( normalAttribute, vB );
14265                                         nC.fromBufferAttribute( normalAttribute, vC );
14266
14267                                         nA.add( cb );
14268                                         nB.add( cb );
14269                                         nC.add( cb );
14270
14271                                         normalAttribute.setXYZ( vA, nA.x, nA.y, nA.z );
14272                                         normalAttribute.setXYZ( vB, nB.x, nB.y, nB.z );
14273                                         normalAttribute.setXYZ( vC, nC.x, nC.y, nC.z );
14274
14275                                 }
14276
14277                         } else {
14278
14279                                 // non-indexed elements (unconnected triangle soup)
14280
14281                                 for ( let i = 0, il = positionAttribute.count; i < il; i += 3 ) {
14282
14283                                         pA.fromBufferAttribute( positionAttribute, i + 0 );
14284                                         pB.fromBufferAttribute( positionAttribute, i + 1 );
14285                                         pC.fromBufferAttribute( positionAttribute, i + 2 );
14286
14287                                         cb.subVectors( pC, pB );
14288                                         ab.subVectors( pA, pB );
14289                                         cb.cross( ab );
14290
14291                                         normalAttribute.setXYZ( i + 0, cb.x, cb.y, cb.z );
14292                                         normalAttribute.setXYZ( i + 1, cb.x, cb.y, cb.z );
14293                                         normalAttribute.setXYZ( i + 2, cb.x, cb.y, cb.z );
14294
14295                                 }
14296
14297                         }
14298
14299                         this.normalizeNormals();
14300
14301                         normalAttribute.needsUpdate = true;
14302
14303                 }
14304
14305         },
14306
14307         merge: function ( geometry, offset ) {
14308
14309                 if ( ! ( geometry && geometry.isBufferGeometry ) ) {
14310
14311                         console.error( 'THREE.BufferGeometry.merge(): geometry not an instance of THREE.BufferGeometry.', geometry );
14312                         return;
14313
14314                 }
14315
14316                 if ( offset === undefined ) {
14317
14318                         offset = 0;
14319
14320                         console.warn(
14321                                 'THREE.BufferGeometry.merge(): Overwriting original geometry, starting at offset=0. '
14322                                 + 'Use BufferGeometryUtils.mergeBufferGeometries() for lossless merge.'
14323                         );
14324
14325                 }
14326
14327                 const attributes = this.attributes;
14328
14329                 for ( const key in attributes ) {
14330
14331                         if ( geometry.attributes[ key ] === undefined ) continue;
14332
14333                         const attribute1 = attributes[ key ];
14334                         const attributeArray1 = attribute1.array;
14335
14336                         const attribute2 = geometry.attributes[ key ];
14337                         const attributeArray2 = attribute2.array;
14338
14339                         const attributeOffset = attribute2.itemSize * offset;
14340                         const length = Math.min( attributeArray2.length, attributeArray1.length - attributeOffset );
14341
14342                         for ( let i = 0, j = attributeOffset; i < length; i ++, j ++ ) {
14343
14344                                 attributeArray1[ j ] = attributeArray2[ i ];
14345
14346                         }
14347
14348                 }
14349
14350                 return this;
14351
14352         },
14353
14354         normalizeNormals: function () {
14355
14356                 const normals = this.attributes.normal;
14357
14358                 for ( let i = 0, il = normals.count; i < il; i ++ ) {
14359
14360                         _vector$4.fromBufferAttribute( normals, i );
14361
14362                         _vector$4.normalize();
14363
14364                         normals.setXYZ( i, _vector$4.x, _vector$4.y, _vector$4.z );
14365
14366                 }
14367
14368         },
14369
14370         toNonIndexed: function () {
14371
14372                 function convertBufferAttribute( attribute, indices ) {
14373
14374                         const array = attribute.array;
14375                         const itemSize = attribute.itemSize;
14376                         const normalized = attribute.normalized;
14377
14378                         const array2 = new array.constructor( indices.length * itemSize );
14379
14380                         let index = 0, index2 = 0;
14381
14382                         for ( let i = 0, l = indices.length; i < l; i ++ ) {
14383
14384                                 index = indices[ i ] * itemSize;
14385
14386                                 for ( let j = 0; j < itemSize; j ++ ) {
14387
14388                                         array2[ index2 ++ ] = array[ index ++ ];
14389
14390                                 }
14391
14392                         }
14393
14394                         return new BufferAttribute( array2, itemSize, normalized );
14395
14396                 }
14397
14398                 //
14399
14400                 if ( this.index === null ) {
14401
14402                         console.warn( 'THREE.BufferGeometry.toNonIndexed(): BufferGeometry is already non-indexed.' );
14403                         return this;
14404
14405                 }
14406
14407                 const geometry2 = new BufferGeometry();
14408
14409                 const indices = this.index.array;
14410                 const attributes = this.attributes;
14411
14412                 // attributes
14413
14414                 for ( const name in attributes ) {
14415
14416                         const attribute = attributes[ name ];
14417
14418                         const newAttribute = convertBufferAttribute( attribute, indices );
14419
14420                         geometry2.setAttribute( name, newAttribute );
14421
14422                 }
14423
14424                 // morph attributes
14425
14426                 const morphAttributes = this.morphAttributes;
14427
14428                 for ( const name in morphAttributes ) {
14429
14430                         const morphArray = [];
14431                         const morphAttribute = morphAttributes[ name ]; // morphAttribute: array of Float32BufferAttributes
14432
14433                         for ( let i = 0, il = morphAttribute.length; i < il; i ++ ) {
14434
14435                                 const attribute = morphAttribute[ i ];
14436
14437                                 const newAttribute = convertBufferAttribute( attribute, indices );
14438
14439                                 morphArray.push( newAttribute );
14440
14441                         }
14442
14443                         geometry2.morphAttributes[ name ] = morphArray;
14444
14445                 }
14446
14447                 geometry2.morphTargetsRelative = this.morphTargetsRelative;
14448
14449                 // groups
14450
14451                 const groups = this.groups;
14452
14453                 for ( let i = 0, l = groups.length; i < l; i ++ ) {
14454
14455                         const group = groups[ i ];
14456                         geometry2.addGroup( group.start, group.count, group.materialIndex );
14457
14458                 }
14459
14460                 return geometry2;
14461
14462         },
14463
14464         toJSON: function () {
14465
14466                 const data = {
14467                         metadata: {
14468                                 version: 4.5,
14469                                 type: 'BufferGeometry',
14470                                 generator: 'BufferGeometry.toJSON'
14471                         }
14472                 };
14473
14474                 // standard BufferGeometry serialization
14475
14476                 data.uuid = this.uuid;
14477                 data.type = this.type;
14478                 if ( this.name !== '' ) data.name = this.name;
14479                 if ( Object.keys( this.userData ).length > 0 ) data.userData = this.userData;
14480
14481                 if ( this.parameters !== undefined ) {
14482
14483                         const parameters = this.parameters;
14484
14485                         for ( const key in parameters ) {
14486
14487                                 if ( parameters[ key ] !== undefined ) data[ key ] = parameters[ key ];
14488
14489                         }
14490
14491                         return data;
14492
14493                 }
14494
14495                 data.data = { attributes: {} };
14496
14497                 const index = this.index;
14498
14499                 if ( index !== null ) {
14500
14501                         data.data.index = {
14502                                 type: index.array.constructor.name,
14503                                 array: Array.prototype.slice.call( index.array )
14504                         };
14505
14506                 }
14507
14508                 const attributes = this.attributes;
14509
14510                 for ( const key in attributes ) {
14511
14512                         const attribute = attributes[ key ];
14513
14514                         const attributeData = attribute.toJSON( data.data );
14515
14516                         if ( attribute.name !== '' ) attributeData.name = attribute.name;
14517
14518                         data.data.attributes[ key ] = attributeData;
14519
14520                 }
14521
14522                 const morphAttributes = {};
14523                 let hasMorphAttributes = false;
14524
14525                 for ( const key in this.morphAttributes ) {
14526
14527                         const attributeArray = this.morphAttributes[ key ];
14528
14529                         const array = [];
14530
14531                         for ( let i = 0, il = attributeArray.length; i < il; i ++ ) {
14532
14533                                 const attribute = attributeArray[ i ];
14534
14535                                 const attributeData = attribute.toJSON( data.data );
14536
14537                                 if ( attribute.name !== '' ) attributeData.name = attribute.name;
14538
14539                                 array.push( attributeData );
14540
14541                         }
14542
14543                         if ( array.length > 0 ) {
14544
14545                                 morphAttributes[ key ] = array;
14546
14547                                 hasMorphAttributes = true;
14548
14549                         }
14550
14551                 }
14552
14553                 if ( hasMorphAttributes ) {
14554
14555                         data.data.morphAttributes = morphAttributes;
14556                         data.data.morphTargetsRelative = this.morphTargetsRelative;
14557
14558                 }
14559
14560                 const groups = this.groups;
14561
14562                 if ( groups.length > 0 ) {
14563
14564                         data.data.groups = JSON.parse( JSON.stringify( groups ) );
14565
14566                 }
14567
14568                 const boundingSphere = this.boundingSphere;
14569
14570                 if ( boundingSphere !== null ) {
14571
14572                         data.data.boundingSphere = {
14573                                 center: boundingSphere.center.toArray(),
14574                                 radius: boundingSphere.radius
14575                         };
14576
14577                 }
14578
14579                 return data;
14580
14581         },
14582
14583         clone: function () {
14584
14585                 /*
14586                  // Handle primitives
14587
14588                  const parameters = this.parameters;
14589
14590                  if ( parameters !== undefined ) {
14591
14592                  const values = [];
14593
14594                  for ( const key in parameters ) {
14595
14596                  values.push( parameters[ key ] );
14597
14598                  }
14599
14600                  const geometry = Object.create( this.constructor.prototype );
14601                  this.constructor.apply( geometry, values );
14602                  return geometry;
14603
14604                  }
14605
14606                  return new this.constructor().copy( this );
14607                  */
14608
14609                 return new BufferGeometry().copy( this );
14610
14611         },
14612
14613         copy: function ( source ) {
14614
14615                 // reset
14616
14617                 this.index = null;
14618                 this.attributes = {};
14619                 this.morphAttributes = {};
14620                 this.groups = [];
14621                 this.boundingBox = null;
14622                 this.boundingSphere = null;
14623
14624                 // used for storing cloned, shared data
14625
14626                 const data = {};
14627
14628                 // name
14629
14630                 this.name = source.name;
14631
14632                 // index
14633
14634                 const index = source.index;
14635
14636                 if ( index !== null ) {
14637
14638                         this.setIndex( index.clone( data ) );
14639
14640                 }
14641
14642                 // attributes
14643
14644                 const attributes = source.attributes;
14645
14646                 for ( const name in attributes ) {
14647
14648                         const attribute = attributes[ name ];
14649                         this.setAttribute( name, attribute.clone( data ) );
14650
14651                 }
14652
14653                 // morph attributes
14654
14655                 const morphAttributes = source.morphAttributes;
14656
14657                 for ( const name in morphAttributes ) {
14658
14659                         const array = [];
14660                         const morphAttribute = morphAttributes[ name ]; // morphAttribute: array of Float32BufferAttributes
14661
14662                         for ( let i = 0, l = morphAttribute.length; i < l; i ++ ) {
14663
14664                                 array.push( morphAttribute[ i ].clone( data ) );
14665
14666                         }
14667
14668                         this.morphAttributes[ name ] = array;
14669
14670                 }
14671
14672                 this.morphTargetsRelative = source.morphTargetsRelative;
14673
14674                 // groups
14675
14676                 const groups = source.groups;
14677
14678                 for ( let i = 0, l = groups.length; i < l; i ++ ) {
14679
14680                         const group = groups[ i ];
14681                         this.addGroup( group.start, group.count, group.materialIndex );
14682
14683                 }
14684
14685                 // bounding box
14686
14687                 const boundingBox = source.boundingBox;
14688
14689                 if ( boundingBox !== null ) {
14690
14691                         this.boundingBox = boundingBox.clone();
14692
14693                 }
14694
14695                 // bounding sphere
14696
14697                 const boundingSphere = source.boundingSphere;
14698
14699                 if ( boundingSphere !== null ) {
14700
14701                         this.boundingSphere = boundingSphere.clone();
14702
14703                 }
14704
14705                 // draw range
14706
14707                 this.drawRange.start = source.drawRange.start;
14708                 this.drawRange.count = source.drawRange.count;
14709
14710                 // user data
14711
14712                 this.userData = source.userData;
14713
14714                 return this;
14715
14716         },
14717
14718         dispose: function () {
14719
14720                 this.dispatchEvent( { type: 'dispose' } );
14721
14722         }
14723
14724 } );
14725
14726 const _inverseMatrix = new Matrix4();
14727 const _ray = new Ray();
14728 const _sphere = new Sphere();
14729
14730 const _vA = new Vector3();
14731 const _vB = new Vector3();
14732 const _vC = new Vector3();
14733
14734 const _tempA = new Vector3();
14735 const _tempB = new Vector3();
14736 const _tempC = new Vector3();
14737
14738 const _morphA = new Vector3();
14739 const _morphB = new Vector3();
14740 const _morphC = new Vector3();
14741
14742 const _uvA = new Vector2();
14743 const _uvB = new Vector2();
14744 const _uvC = new Vector2();
14745
14746 const _intersectionPoint = new Vector3();
14747 const _intersectionPointWorld = new Vector3();
14748
14749 function Mesh( geometry = new BufferGeometry(), material = new MeshBasicMaterial() ) {
14750
14751         Object3D.call( this );
14752
14753         this.type = 'Mesh';
14754
14755         this.geometry = geometry;
14756         this.material = material;
14757
14758         this.updateMorphTargets();
14759
14760 }
14761
14762 Mesh.prototype = Object.assign( Object.create( Object3D.prototype ), {
14763
14764         constructor: Mesh,
14765
14766         isMesh: true,
14767
14768         copy: function ( source ) {
14769
14770                 Object3D.prototype.copy.call( this, source );
14771
14772                 if ( source.morphTargetInfluences !== undefined ) {
14773
14774                         this.morphTargetInfluences = source.morphTargetInfluences.slice();
14775
14776                 }
14777
14778                 if ( source.morphTargetDictionary !== undefined ) {
14779
14780                         this.morphTargetDictionary = Object.assign( {}, source.morphTargetDictionary );
14781
14782                 }
14783
14784                 this.material = source.material;
14785                 this.geometry = source.geometry;
14786
14787                 return this;
14788
14789         },
14790
14791         updateMorphTargets: function () {
14792
14793                 const geometry = this.geometry;
14794
14795                 if ( geometry.isBufferGeometry ) {
14796
14797                         const morphAttributes = geometry.morphAttributes;
14798                         const keys = Object.keys( morphAttributes );
14799
14800                         if ( keys.length > 0 ) {
14801
14802                                 const morphAttribute = morphAttributes[ keys[ 0 ] ];
14803
14804                                 if ( morphAttribute !== undefined ) {
14805
14806                                         this.morphTargetInfluences = [];
14807                                         this.morphTargetDictionary = {};
14808
14809                                         for ( let m = 0, ml = morphAttribute.length; m < ml; m ++ ) {
14810
14811                                                 const name = morphAttribute[ m ].name || String( m );
14812
14813                                                 this.morphTargetInfluences.push( 0 );
14814                                                 this.morphTargetDictionary[ name ] = m;
14815
14816                                         }
14817
14818                                 }
14819
14820                         }
14821
14822                 } else {
14823
14824                         const morphTargets = geometry.morphTargets;
14825
14826                         if ( morphTargets !== undefined && morphTargets.length > 0 ) {
14827
14828                                 console.error( 'THREE.Mesh.updateMorphTargets() no longer supports THREE.Geometry. Use THREE.BufferGeometry instead.' );
14829
14830                         }
14831
14832                 }
14833
14834         },
14835
14836         raycast: function ( raycaster, intersects ) {
14837
14838                 const geometry = this.geometry;
14839                 const material = this.material;
14840                 const matrixWorld = this.matrixWorld;
14841
14842                 if ( material === undefined ) return;
14843
14844                 // Checking boundingSphere distance to ray
14845
14846                 if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere();
14847
14848                 _sphere.copy( geometry.boundingSphere );
14849                 _sphere.applyMatrix4( matrixWorld );
14850
14851                 if ( raycaster.ray.intersectsSphere( _sphere ) === false ) return;
14852
14853                 //
14854
14855                 _inverseMatrix.copy( matrixWorld ).invert();
14856                 _ray.copy( raycaster.ray ).applyMatrix4( _inverseMatrix );
14857
14858                 // Check boundingBox before continuing
14859
14860                 if ( geometry.boundingBox !== null ) {
14861
14862                         if ( _ray.intersectsBox( geometry.boundingBox ) === false ) return;
14863
14864                 }
14865
14866                 let intersection;
14867
14868                 if ( geometry.isBufferGeometry ) {
14869
14870                         const index = geometry.index;
14871                         const position = geometry.attributes.position;
14872                         const morphPosition = geometry.morphAttributes.position;
14873                         const morphTargetsRelative = geometry.morphTargetsRelative;
14874                         const uv = geometry.attributes.uv;
14875                         const uv2 = geometry.attributes.uv2;
14876                         const groups = geometry.groups;
14877                         const drawRange = geometry.drawRange;
14878
14879                         if ( index !== null ) {
14880
14881                                 // indexed buffer geometry
14882
14883                                 if ( Array.isArray( material ) ) {
14884
14885                                         for ( let i = 0, il = groups.length; i < il; i ++ ) {
14886
14887                                                 const group = groups[ i ];
14888                                                 const groupMaterial = material[ group.materialIndex ];
14889
14890                                                 const start = Math.max( group.start, drawRange.start );
14891                                                 const end = Math.min( ( group.start + group.count ), ( drawRange.start + drawRange.count ) );
14892
14893                                                 for ( let j = start, jl = end; j < jl; j += 3 ) {
14894
14895                                                         const a = index.getX( j );
14896                                                         const b = index.getX( j + 1 );
14897                                                         const c = index.getX( j + 2 );
14898
14899                                                         intersection = checkBufferGeometryIntersection( this, groupMaterial, raycaster, _ray, position, morphPosition, morphTargetsRelative, uv, uv2, a, b, c );
14900
14901                                                         if ( intersection ) {
14902
14903                                                                 intersection.faceIndex = Math.floor( j / 3 ); // triangle number in indexed buffer semantics
14904                                                                 intersection.face.materialIndex = group.materialIndex;
14905                                                                 intersects.push( intersection );
14906
14907                                                         }
14908
14909                                                 }
14910
14911                                         }
14912
14913                                 } else {
14914
14915                                         const start = Math.max( 0, drawRange.start );
14916                                         const end = Math.min( index.count, ( drawRange.start + drawRange.count ) );
14917
14918                                         for ( let i = start, il = end; i < il; i += 3 ) {
14919
14920                                                 const a = index.getX( i );
14921                                                 const b = index.getX( i + 1 );
14922                                                 const c = index.getX( i + 2 );
14923
14924                                                 intersection = checkBufferGeometryIntersection( this, material, raycaster, _ray, position, morphPosition, morphTargetsRelative, uv, uv2, a, b, c );
14925
14926                                                 if ( intersection ) {
14927
14928                                                         intersection.faceIndex = Math.floor( i / 3 ); // triangle number in indexed buffer semantics
14929                                                         intersects.push( intersection );
14930
14931                                                 }
14932
14933                                         }
14934
14935                                 }
14936
14937                         } else if ( position !== undefined ) {
14938
14939                                 // non-indexed buffer geometry
14940
14941                                 if ( Array.isArray( material ) ) {
14942
14943                                         for ( let i = 0, il = groups.length; i < il; i ++ ) {
14944
14945                                                 const group = groups[ i ];
14946                                                 const groupMaterial = material[ group.materialIndex ];
14947
14948                                                 const start = Math.max( group.start, drawRange.start );
14949                                                 const end = Math.min( ( group.start + group.count ), ( drawRange.start + drawRange.count ) );
14950
14951                                                 for ( let j = start, jl = end; j < jl; j += 3 ) {
14952
14953                                                         const a = j;
14954                                                         const b = j + 1;
14955                                                         const c = j + 2;
14956
14957                                                         intersection = checkBufferGeometryIntersection( this, groupMaterial, raycaster, _ray, position, morphPosition, morphTargetsRelative, uv, uv2, a, b, c );
14958
14959                                                         if ( intersection ) {
14960
14961                                                                 intersection.faceIndex = Math.floor( j / 3 ); // triangle number in non-indexed buffer semantics
14962                                                                 intersection.face.materialIndex = group.materialIndex;
14963                                                                 intersects.push( intersection );
14964
14965                                                         }
14966
14967                                                 }
14968
14969                                         }
14970
14971                                 } else {
14972
14973                                         const start = Math.max( 0, drawRange.start );
14974                                         const end = Math.min( position.count, ( drawRange.start + drawRange.count ) );
14975
14976                                         for ( let i = start, il = end; i < il; i += 3 ) {
14977
14978                                                 const a = i;
14979                                                 const b = i + 1;
14980                                                 const c = i + 2;
14981
14982                                                 intersection = checkBufferGeometryIntersection( this, material, raycaster, _ray, position, morphPosition, morphTargetsRelative, uv, uv2, a, b, c );
14983
14984                                                 if ( intersection ) {
14985
14986                                                         intersection.faceIndex = Math.floor( i / 3 ); // triangle number in non-indexed buffer semantics
14987                                                         intersects.push( intersection );
14988
14989                                                 }
14990
14991                                         }
14992
14993                                 }
14994
14995                         }
14996
14997                 } else if ( geometry.isGeometry ) {
14998
14999                         console.error( 'THREE.Mesh.raycast() no longer supports THREE.Geometry. Use THREE.BufferGeometry instead.' );
15000
15001                 }
15002
15003         }
15004
15005 } );
15006
15007 function checkIntersection( object, material, raycaster, ray, pA, pB, pC, point ) {
15008
15009         let intersect;
15010
15011         if ( material.side === BackSide ) {
15012
15013                 intersect = ray.intersectTriangle( pC, pB, pA, true, point );
15014
15015         } else {
15016
15017                 intersect = ray.intersectTriangle( pA, pB, pC, material.side !== DoubleSide, point );
15018
15019         }
15020
15021         if ( intersect === null ) return null;
15022
15023         _intersectionPointWorld.copy( point );
15024         _intersectionPointWorld.applyMatrix4( object.matrixWorld );
15025
15026         const distance = raycaster.ray.origin.distanceTo( _intersectionPointWorld );
15027
15028         if ( distance < raycaster.near || distance > raycaster.far ) return null;
15029
15030         return {
15031                 distance: distance,
15032                 point: _intersectionPointWorld.clone(),
15033                 object: object
15034         };
15035
15036 }
15037
15038 function checkBufferGeometryIntersection( object, material, raycaster, ray, position, morphPosition, morphTargetsRelative, uv, uv2, a, b, c ) {
15039
15040         _vA.fromBufferAttribute( position, a );
15041         _vB.fromBufferAttribute( position, b );
15042         _vC.fromBufferAttribute( position, c );
15043
15044         const morphInfluences = object.morphTargetInfluences;
15045
15046         if ( material.morphTargets && morphPosition && morphInfluences ) {
15047
15048                 _morphA.set( 0, 0, 0 );
15049                 _morphB.set( 0, 0, 0 );
15050                 _morphC.set( 0, 0, 0 );
15051
15052                 for ( let i = 0, il = morphPosition.length; i < il; i ++ ) {
15053
15054                         const influence = morphInfluences[ i ];
15055                         const morphAttribute = morphPosition[ i ];
15056
15057                         if ( influence === 0 ) continue;
15058
15059                         _tempA.fromBufferAttribute( morphAttribute, a );
15060                         _tempB.fromBufferAttribute( morphAttribute, b );
15061                         _tempC.fromBufferAttribute( morphAttribute, c );
15062
15063                         if ( morphTargetsRelative ) {
15064
15065                                 _morphA.addScaledVector( _tempA, influence );
15066                                 _morphB.addScaledVector( _tempB, influence );
15067                                 _morphC.addScaledVector( _tempC, influence );
15068
15069                         } else {
15070
15071                                 _morphA.addScaledVector( _tempA.sub( _vA ), influence );
15072                                 _morphB.addScaledVector( _tempB.sub( _vB ), influence );
15073                                 _morphC.addScaledVector( _tempC.sub( _vC ), influence );
15074
15075                         }
15076
15077                 }
15078
15079                 _vA.add( _morphA );
15080                 _vB.add( _morphB );
15081                 _vC.add( _morphC );
15082
15083         }
15084
15085         if ( object.isSkinnedMesh ) {
15086
15087                 object.boneTransform( a, _vA );
15088                 object.boneTransform( b, _vB );
15089                 object.boneTransform( c, _vC );
15090
15091         }
15092
15093         const intersection = checkIntersection( object, material, raycaster, ray, _vA, _vB, _vC, _intersectionPoint );
15094
15095         if ( intersection ) {
15096
15097                 if ( uv ) {
15098
15099                         _uvA.fromBufferAttribute( uv, a );
15100                         _uvB.fromBufferAttribute( uv, b );
15101                         _uvC.fromBufferAttribute( uv, c );
15102
15103                         intersection.uv = Triangle.getUV( _intersectionPoint, _vA, _vB, _vC, _uvA, _uvB, _uvC, new Vector2() );
15104
15105                 }
15106
15107                 if ( uv2 ) {
15108
15109                         _uvA.fromBufferAttribute( uv2, a );
15110                         _uvB.fromBufferAttribute( uv2, b );
15111                         _uvC.fromBufferAttribute( uv2, c );
15112
15113                         intersection.uv2 = Triangle.getUV( _intersectionPoint, _vA, _vB, _vC, _uvA, _uvB, _uvC, new Vector2() );
15114
15115                 }
15116
15117                 const face = new Face3( a, b, c );
15118                 Triangle.getNormal( _vA, _vB, _vC, face.normal );
15119
15120                 intersection.face = face;
15121
15122         }
15123
15124         return intersection;
15125
15126 }
15127
15128 class BoxGeometry extends BufferGeometry {
15129
15130         constructor( width = 1, height = 1, depth = 1, widthSegments = 1, heightSegments = 1, depthSegments = 1 ) {
15131
15132                 super();
15133
15134                 this.type = 'BoxGeometry';
15135
15136                 this.parameters = {
15137                         width: width,
15138                         height: height,
15139                         depth: depth,
15140                         widthSegments: widthSegments,
15141                         heightSegments: heightSegments,
15142                         depthSegments: depthSegments
15143                 };
15144
15145                 const scope = this;
15146
15147                 // segments
15148
15149                 widthSegments = Math.floor( widthSegments );
15150                 heightSegments = Math.floor( heightSegments );
15151                 depthSegments = Math.floor( depthSegments );
15152
15153                 // buffers
15154
15155                 const indices = [];
15156                 const vertices = [];
15157                 const normals = [];
15158                 const uvs = [];
15159
15160                 // helper variables
15161
15162                 let numberOfVertices = 0;
15163                 let groupStart = 0;
15164
15165                 // build each side of the box geometry
15166
15167                 buildPlane( 'z', 'y', 'x', - 1, - 1, depth, height, width, depthSegments, heightSegments, 0 ); // px
15168                 buildPlane( 'z', 'y', 'x', 1, - 1, depth, height, - width, depthSegments, heightSegments, 1 ); // nx
15169                 buildPlane( 'x', 'z', 'y', 1, 1, width, depth, height, widthSegments, depthSegments, 2 ); // py
15170                 buildPlane( 'x', 'z', 'y', 1, - 1, width, depth, - height, widthSegments, depthSegments, 3 ); // ny
15171                 buildPlane( 'x', 'y', 'z', 1, - 1, width, height, depth, widthSegments, heightSegments, 4 ); // pz
15172                 buildPlane( 'x', 'y', 'z', - 1, - 1, width, height, - depth, widthSegments, heightSegments, 5 ); // nz
15173
15174                 // build geometry
15175
15176                 this.setIndex( indices );
15177                 this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
15178                 this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
15179                 this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
15180
15181                 function buildPlane( u, v, w, udir, vdir, width, height, depth, gridX, gridY, materialIndex ) {
15182
15183                         const segmentWidth = width / gridX;
15184                         const segmentHeight = height / gridY;
15185
15186                         const widthHalf = width / 2;
15187                         const heightHalf = height / 2;
15188                         const depthHalf = depth / 2;
15189
15190                         const gridX1 = gridX + 1;
15191                         const gridY1 = gridY + 1;
15192
15193                         let vertexCounter = 0;
15194                         let groupCount = 0;
15195
15196                         const vector = new Vector3();
15197
15198                         // generate vertices, normals and uvs
15199
15200                         for ( let iy = 0; iy < gridY1; iy ++ ) {
15201
15202                                 const y = iy * segmentHeight - heightHalf;
15203
15204                                 for ( let ix = 0; ix < gridX1; ix ++ ) {
15205
15206                                         const x = ix * segmentWidth - widthHalf;
15207
15208                                         // set values to correct vector component
15209
15210                                         vector[ u ] = x * udir;
15211                                         vector[ v ] = y * vdir;
15212                                         vector[ w ] = depthHalf;
15213
15214                                         // now apply vector to vertex buffer
15215
15216                                         vertices.push( vector.x, vector.y, vector.z );
15217
15218                                         // set values to correct vector component
15219
15220                                         vector[ u ] = 0;
15221                                         vector[ v ] = 0;
15222                                         vector[ w ] = depth > 0 ? 1 : - 1;
15223
15224                                         // now apply vector to normal buffer
15225
15226                                         normals.push( vector.x, vector.y, vector.z );
15227
15228                                         // uvs
15229
15230                                         uvs.push( ix / gridX );
15231                                         uvs.push( 1 - ( iy / gridY ) );
15232
15233                                         // counters
15234
15235                                         vertexCounter += 1;
15236
15237                                 }
15238
15239                         }
15240
15241                         // indices
15242
15243                         // 1. you need three indices to draw a single face
15244                         // 2. a single segment consists of two faces
15245                         // 3. so we need to generate six (2*3) indices per segment
15246
15247                         for ( let iy = 0; iy < gridY; iy ++ ) {
15248
15249                                 for ( let ix = 0; ix < gridX; ix ++ ) {
15250
15251                                         const a = numberOfVertices + ix + gridX1 * iy;
15252                                         const b = numberOfVertices + ix + gridX1 * ( iy + 1 );
15253                                         const c = numberOfVertices + ( ix + 1 ) + gridX1 * ( iy + 1 );
15254                                         const d = numberOfVertices + ( ix + 1 ) + gridX1 * iy;
15255
15256                                         // faces
15257
15258                                         indices.push( a, b, d );
15259                                         indices.push( b, c, d );
15260
15261                                         // increase counter
15262
15263                                         groupCount += 6;
15264
15265                                 }
15266
15267                         }
15268
15269                         // add a group to the geometry. this will ensure multi material support
15270
15271                         scope.addGroup( groupStart, groupCount, materialIndex );
15272
15273                         // calculate new start value for groups
15274
15275                         groupStart += groupCount;
15276
15277                         // update total number of vertices
15278
15279                         numberOfVertices += vertexCounter;
15280
15281                 }
15282
15283         }
15284
15285 }
15286
15287 /**
15288  * Uniform Utilities
15289  */
15290
15291 function cloneUniforms( src ) {
15292
15293         const dst = {};
15294
15295         for ( const u in src ) {
15296
15297                 dst[ u ] = {};
15298
15299                 for ( const p in src[ u ] ) {
15300
15301                         const property = src[ u ][ p ];
15302
15303                         if ( property && ( property.isColor ||
15304                                 property.isMatrix3 || property.isMatrix4 ||
15305                                 property.isVector2 || property.isVector3 || property.isVector4 ||
15306                                 property.isTexture ) ) {
15307
15308                                 dst[ u ][ p ] = property.clone();
15309
15310                         } else if ( Array.isArray( property ) ) {
15311
15312                                 dst[ u ][ p ] = property.slice();
15313
15314                         } else {
15315
15316                                 dst[ u ][ p ] = property;
15317
15318                         }
15319
15320                 }
15321
15322         }
15323
15324         return dst;
15325
15326 }
15327
15328 function mergeUniforms( uniforms ) {
15329
15330         const merged = {};
15331
15332         for ( let u = 0; u < uniforms.length; u ++ ) {
15333
15334                 const tmp = cloneUniforms( uniforms[ u ] );
15335
15336                 for ( const p in tmp ) {
15337
15338                         merged[ p ] = tmp[ p ];
15339
15340                 }
15341
15342         }
15343
15344         return merged;
15345
15346 }
15347
15348 // Legacy
15349
15350 const UniformsUtils = { clone: cloneUniforms, merge: mergeUniforms };
15351
15352 var default_vertex = "void main() {\n\tgl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n}";
15353
15354 var default_fragment = "void main() {\n\tgl_FragColor = vec4( 1.0, 0.0, 0.0, 1.0 );\n}";
15355
15356 /**
15357  * parameters = {
15358  *  defines: { "label" : "value" },
15359  *  uniforms: { "parameter1": { value: 1.0 }, "parameter2": { value2: 2 } },
15360  *
15361  *  fragmentShader: <string>,
15362  *  vertexShader: <string>,
15363  *
15364  *  wireframe: <boolean>,
15365  *  wireframeLinewidth: <float>,
15366  *
15367  *  lights: <bool>,
15368  *
15369  *  skinning: <bool>,
15370  *  morphTargets: <bool>,
15371  *  morphNormals: <bool>
15372  * }
15373  */
15374
15375 function ShaderMaterial( parameters ) {
15376
15377         Material.call( this );
15378
15379         this.type = 'ShaderMaterial';
15380
15381         this.defines = {};
15382         this.uniforms = {};
15383
15384         this.vertexShader = default_vertex;
15385         this.fragmentShader = default_fragment;
15386
15387         this.linewidth = 1;
15388
15389         this.wireframe = false;
15390         this.wireframeLinewidth = 1;
15391
15392         this.fog = false; // set to use scene fog
15393         this.lights = false; // set to use scene lights
15394         this.clipping = false; // set to use user-defined clipping planes
15395
15396         this.skinning = false; // set to use skinning attribute streams
15397         this.morphTargets = false; // set to use morph targets
15398         this.morphNormals = false; // set to use morph normals
15399
15400         this.extensions = {
15401                 derivatives: false, // set to use derivatives
15402                 fragDepth: false, // set to use fragment depth values
15403                 drawBuffers: false, // set to use draw buffers
15404                 shaderTextureLOD: false // set to use shader texture LOD
15405         };
15406
15407         // When rendered geometry doesn't include these attributes but the material does,
15408         // use these default values in WebGL. This avoids errors when buffer data is missing.
15409         this.defaultAttributeValues = {
15410                 'color': [ 1, 1, 1 ],
15411                 'uv': [ 0, 0 ],
15412                 'uv2': [ 0, 0 ]
15413         };
15414
15415         this.index0AttributeName = undefined;
15416         this.uniformsNeedUpdate = false;
15417
15418         this.glslVersion = null;
15419
15420         if ( parameters !== undefined ) {
15421
15422                 if ( parameters.attributes !== undefined ) {
15423
15424                         console.error( 'THREE.ShaderMaterial: attributes should now be defined in THREE.BufferGeometry instead.' );
15425
15426                 }
15427
15428                 this.setValues( parameters );
15429
15430         }
15431
15432 }
15433
15434 ShaderMaterial.prototype = Object.create( Material.prototype );
15435 ShaderMaterial.prototype.constructor = ShaderMaterial;
15436
15437 ShaderMaterial.prototype.isShaderMaterial = true;
15438
15439 ShaderMaterial.prototype.copy = function ( source ) {
15440
15441         Material.prototype.copy.call( this, source );
15442
15443         this.fragmentShader = source.fragmentShader;
15444         this.vertexShader = source.vertexShader;
15445
15446         this.uniforms = cloneUniforms( source.uniforms );
15447
15448         this.defines = Object.assign( {}, source.defines );
15449
15450         this.wireframe = source.wireframe;
15451         this.wireframeLinewidth = source.wireframeLinewidth;
15452
15453         this.lights = source.lights;
15454         this.clipping = source.clipping;
15455
15456         this.skinning = source.skinning;
15457
15458         this.morphTargets = source.morphTargets;
15459         this.morphNormals = source.morphNormals;
15460
15461         this.extensions = Object.assign( {}, source.extensions );
15462
15463         this.glslVersion = source.glslVersion;
15464
15465         return this;
15466
15467 };
15468
15469 ShaderMaterial.prototype.toJSON = function ( meta ) {
15470
15471         const data = Material.prototype.toJSON.call( this, meta );
15472
15473         data.glslVersion = this.glslVersion;
15474         data.uniforms = {};
15475
15476         for ( const name in this.uniforms ) {
15477
15478                 const uniform = this.uniforms[ name ];
15479                 const value = uniform.value;
15480
15481                 if ( value && value.isTexture ) {
15482
15483                         data.uniforms[ name ] = {
15484                                 type: 't',
15485                                 value: value.toJSON( meta ).uuid
15486                         };
15487
15488                 } else if ( value && value.isColor ) {
15489
15490                         data.uniforms[ name ] = {
15491                                 type: 'c',
15492                                 value: value.getHex()
15493                         };
15494
15495                 } else if ( value && value.isVector2 ) {
15496
15497                         data.uniforms[ name ] = {
15498                                 type: 'v2',
15499                                 value: value.toArray()
15500                         };
15501
15502                 } else if ( value && value.isVector3 ) {
15503
15504                         data.uniforms[ name ] = {
15505                                 type: 'v3',
15506                                 value: value.toArray()
15507                         };
15508
15509                 } else if ( value && value.isVector4 ) {
15510
15511                         data.uniforms[ name ] = {
15512                                 type: 'v4',
15513                                 value: value.toArray()
15514                         };
15515
15516                 } else if ( value && value.isMatrix3 ) {
15517
15518                         data.uniforms[ name ] = {
15519                                 type: 'm3',
15520                                 value: value.toArray()
15521                         };
15522
15523                 } else if ( value && value.isMatrix4 ) {
15524
15525                         data.uniforms[ name ] = {
15526                                 type: 'm4',
15527                                 value: value.toArray()
15528                         };
15529
15530                 } else {
15531
15532                         data.uniforms[ name ] = {
15533                                 value: value
15534                         };
15535
15536                         // note: the array variants v2v, v3v, v4v, m4v and tv are not supported so far
15537
15538                 }
15539
15540         }
15541
15542         if ( Object.keys( this.defines ).length > 0 ) data.defines = this.defines;
15543
15544         data.vertexShader = this.vertexShader;
15545         data.fragmentShader = this.fragmentShader;
15546
15547         const extensions = {};
15548
15549         for ( const key in this.extensions ) {
15550
15551                 if ( this.extensions[ key ] === true ) extensions[ key ] = true;
15552
15553         }
15554
15555         if ( Object.keys( extensions ).length > 0 ) data.extensions = extensions;
15556
15557         return data;
15558
15559 };
15560
15561 function Camera$1() {
15562
15563         Object3D.call( this );
15564
15565         this.type = 'Camera';
15566
15567         this.matrixWorldInverse = new Matrix4();
15568
15569         this.projectionMatrix = new Matrix4();
15570         this.projectionMatrixInverse = new Matrix4();
15571
15572 }
15573
15574 Camera$1.prototype = Object.assign( Object.create( Object3D.prototype ), {
15575
15576         constructor: Camera$1,
15577
15578         isCamera: true,
15579
15580         copy: function ( source, recursive ) {
15581
15582                 Object3D.prototype.copy.call( this, source, recursive );
15583
15584                 this.matrixWorldInverse.copy( source.matrixWorldInverse );
15585
15586                 this.projectionMatrix.copy( source.projectionMatrix );
15587                 this.projectionMatrixInverse.copy( source.projectionMatrixInverse );
15588
15589                 return this;
15590
15591         },
15592
15593         getWorldDirection: function ( target ) {
15594
15595                 if ( target === undefined ) {
15596
15597                         console.warn( 'THREE.Camera: .getWorldDirection() target is now required' );
15598                         target = new Vector3();
15599
15600                 }
15601
15602                 this.updateWorldMatrix( true, false );
15603
15604                 const e = this.matrixWorld.elements;
15605
15606                 return target.set( - e[ 8 ], - e[ 9 ], - e[ 10 ] ).normalize();
15607
15608         },
15609
15610         updateMatrixWorld: function ( force ) {
15611
15612                 Object3D.prototype.updateMatrixWorld.call( this, force );
15613
15614                 this.matrixWorldInverse.copy( this.matrixWorld ).invert();
15615
15616         },
15617
15618         updateWorldMatrix: function ( updateParents, updateChildren ) {
15619
15620                 Object3D.prototype.updateWorldMatrix.call( this, updateParents, updateChildren );
15621
15622                 this.matrixWorldInverse.copy( this.matrixWorld ).invert();
15623
15624         },
15625
15626         clone: function () {
15627
15628                 return new this.constructor().copy( this );
15629
15630         }
15631
15632 } );
15633
15634 function PerspectiveCamera( fov = 50, aspect = 1, near = 0.1, far = 2000 ) {
15635
15636         Camera$1.call( this );
15637
15638         this.type = 'PerspectiveCamera';
15639
15640         this.fov = fov;
15641         this.zoom = 1;
15642
15643         this.near = near;
15644         this.far = far;
15645         this.focus = 10;
15646
15647         this.aspect = aspect;
15648         this.view = null;
15649
15650         this.filmGauge = 35;    // width of the film (default in millimeters)
15651         this.filmOffset = 0;    // horizontal film offset (same unit as gauge)
15652
15653         this.updateProjectionMatrix();
15654
15655 }
15656
15657 PerspectiveCamera.prototype = Object.assign( Object.create( Camera$1.prototype ), {
15658
15659         constructor: PerspectiveCamera,
15660
15661         isPerspectiveCamera: true,
15662
15663         copy: function ( source, recursive ) {
15664
15665                 Camera$1.prototype.copy.call( this, source, recursive );
15666
15667                 this.fov = source.fov;
15668                 this.zoom = source.zoom;
15669
15670                 this.near = source.near;
15671                 this.far = source.far;
15672                 this.focus = source.focus;
15673
15674                 this.aspect = source.aspect;
15675                 this.view = source.view === null ? null : Object.assign( {}, source.view );
15676
15677                 this.filmGauge = source.filmGauge;
15678                 this.filmOffset = source.filmOffset;
15679
15680                 return this;
15681
15682         },
15683
15684         /**
15685          * Sets the FOV by focal length in respect to the current .filmGauge.
15686          *
15687          * The default film gauge is 35, so that the focal length can be specified for
15688          * a 35mm (full frame) camera.
15689          *
15690          * Values for focal length and film gauge must have the same unit.
15691          */
15692         setFocalLength: function ( focalLength ) {
15693
15694                 /** see {@link http://www.bobatkins.com/photography/technical/field_of_view.html} */
15695                 const vExtentSlope = 0.5 * this.getFilmHeight() / focalLength;
15696
15697                 this.fov = MathUtils.RAD2DEG * 2 * Math.atan( vExtentSlope );
15698                 this.updateProjectionMatrix();
15699
15700         },
15701
15702         /**
15703          * Calculates the focal length from the current .fov and .filmGauge.
15704          */
15705         getFocalLength: function () {
15706
15707                 const vExtentSlope = Math.tan( MathUtils.DEG2RAD * 0.5 * this.fov );
15708
15709                 return 0.5 * this.getFilmHeight() / vExtentSlope;
15710
15711         },
15712
15713         getEffectiveFOV: function () {
15714
15715                 return MathUtils.RAD2DEG * 2 * Math.atan(
15716                         Math.tan( MathUtils.DEG2RAD * 0.5 * this.fov ) / this.zoom );
15717
15718         },
15719
15720         getFilmWidth: function () {
15721
15722                 // film not completely covered in portrait format (aspect < 1)
15723                 return this.filmGauge * Math.min( this.aspect, 1 );
15724
15725         },
15726
15727         getFilmHeight: function () {
15728
15729                 // film not completely covered in landscape format (aspect > 1)
15730                 return this.filmGauge / Math.max( this.aspect, 1 );
15731
15732         },
15733
15734         /**
15735          * Sets an offset in a larger frustum. This is useful for multi-window or
15736          * multi-monitor/multi-machine setups.
15737          *
15738          * For example, if you have 3x2 monitors and each monitor is 1920x1080 and
15739          * the monitors are in grid like this
15740          *
15741          *   +---+---+---+
15742          *   | A | B | C |
15743          *   +---+---+---+
15744          *   | D | E | F |
15745          *   +---+---+---+
15746          *
15747          * then for each monitor you would call it like this
15748          *
15749          *   const w = 1920;
15750          *   const h = 1080;
15751          *   const fullWidth = w * 3;
15752          *   const fullHeight = h * 2;
15753          *
15754          *   --A--
15755          *   camera.setViewOffset( fullWidth, fullHeight, w * 0, h * 0, w, h );
15756          *   --B--
15757          *   camera.setViewOffset( fullWidth, fullHeight, w * 1, h * 0, w, h );
15758          *   --C--
15759          *   camera.setViewOffset( fullWidth, fullHeight, w * 2, h * 0, w, h );
15760          *   --D--
15761          *   camera.setViewOffset( fullWidth, fullHeight, w * 0, h * 1, w, h );
15762          *   --E--
15763          *   camera.setViewOffset( fullWidth, fullHeight, w * 1, h * 1, w, h );
15764          *   --F--
15765          *   camera.setViewOffset( fullWidth, fullHeight, w * 2, h * 1, w, h );
15766          *
15767          *   Note there is no reason monitors have to be the same size or in a grid.
15768          */
15769         setViewOffset: function ( fullWidth, fullHeight, x, y, width, height ) {
15770
15771                 this.aspect = fullWidth / fullHeight;
15772
15773                 if ( this.view === null ) {
15774
15775                         this.view = {
15776                                 enabled: true,
15777                                 fullWidth: 1,
15778                                 fullHeight: 1,
15779                                 offsetX: 0,
15780                                 offsetY: 0,
15781                                 width: 1,
15782                                 height: 1
15783                         };
15784
15785                 }
15786
15787                 this.view.enabled = true;
15788                 this.view.fullWidth = fullWidth;
15789                 this.view.fullHeight = fullHeight;
15790                 this.view.offsetX = x;
15791                 this.view.offsetY = y;
15792                 this.view.width = width;
15793                 this.view.height = height;
15794
15795                 this.updateProjectionMatrix();
15796
15797         },
15798
15799         clearViewOffset: function () {
15800
15801                 if ( this.view !== null ) {
15802
15803                         this.view.enabled = false;
15804
15805                 }
15806
15807                 this.updateProjectionMatrix();
15808
15809         },
15810
15811         updateProjectionMatrix: function () {
15812
15813                 const near = this.near;
15814                 let top = near * Math.tan( MathUtils.DEG2RAD * 0.5 * this.fov ) / this.zoom;
15815                 let height = 2 * top;
15816                 let width = this.aspect * height;
15817                 let left = - 0.5 * width;
15818                 const view = this.view;
15819
15820                 if ( this.view !== null && this.view.enabled ) {
15821
15822                         const fullWidth = view.fullWidth,
15823                                 fullHeight = view.fullHeight;
15824
15825                         left += view.offsetX * width / fullWidth;
15826                         top -= view.offsetY * height / fullHeight;
15827                         width *= view.width / fullWidth;
15828                         height *= view.height / fullHeight;
15829
15830                 }
15831
15832                 const skew = this.filmOffset;
15833                 if ( skew !== 0 ) left += near * skew / this.getFilmWidth();
15834
15835                 this.projectionMatrix.makePerspective( left, left + width, top, top - height, near, this.far );
15836
15837                 this.projectionMatrixInverse.copy( this.projectionMatrix ).invert();
15838
15839         },
15840
15841         toJSON: function ( meta ) {
15842
15843                 const data = Object3D.prototype.toJSON.call( this, meta );
15844
15845                 data.object.fov = this.fov;
15846                 data.object.zoom = this.zoom;
15847
15848                 data.object.near = this.near;
15849                 data.object.far = this.far;
15850                 data.object.focus = this.focus;
15851
15852                 data.object.aspect = this.aspect;
15853
15854                 if ( this.view !== null ) data.object.view = Object.assign( {}, this.view );
15855
15856                 data.object.filmGauge = this.filmGauge;
15857                 data.object.filmOffset = this.filmOffset;
15858
15859                 return data;
15860
15861         }
15862
15863 } );
15864
15865 const fov = 90, aspect = 1;
15866
15867 function CubeCamera( near, far, renderTarget ) {
15868
15869         Object3D.call( this );
15870
15871         this.type = 'CubeCamera';
15872
15873         if ( renderTarget.isWebGLCubeRenderTarget !== true ) {
15874
15875                 console.error( 'THREE.CubeCamera: The constructor now expects an instance of WebGLCubeRenderTarget as third parameter.' );
15876                 return;
15877
15878         }
15879
15880         this.renderTarget = renderTarget;
15881
15882         const cameraPX = new PerspectiveCamera( fov, aspect, near, far );
15883         cameraPX.layers = this.layers;
15884         cameraPX.up.set( 0, - 1, 0 );
15885         cameraPX.lookAt( new Vector3( 1, 0, 0 ) );
15886         this.add( cameraPX );
15887
15888         const cameraNX = new PerspectiveCamera( fov, aspect, near, far );
15889         cameraNX.layers = this.layers;
15890         cameraNX.up.set( 0, - 1, 0 );
15891         cameraNX.lookAt( new Vector3( - 1, 0, 0 ) );
15892         this.add( cameraNX );
15893
15894         const cameraPY = new PerspectiveCamera( fov, aspect, near, far );
15895         cameraPY.layers = this.layers;
15896         cameraPY.up.set( 0, 0, 1 );
15897         cameraPY.lookAt( new Vector3( 0, 1, 0 ) );
15898         this.add( cameraPY );
15899
15900         const cameraNY = new PerspectiveCamera( fov, aspect, near, far );
15901         cameraNY.layers = this.layers;
15902         cameraNY.up.set( 0, 0, - 1 );
15903         cameraNY.lookAt( new Vector3( 0, - 1, 0 ) );
15904         this.add( cameraNY );
15905
15906         const cameraPZ = new PerspectiveCamera( fov, aspect, near, far );
15907         cameraPZ.layers = this.layers;
15908         cameraPZ.up.set( 0, - 1, 0 );
15909         cameraPZ.lookAt( new Vector3( 0, 0, 1 ) );
15910         this.add( cameraPZ );
15911
15912         const cameraNZ = new PerspectiveCamera( fov, aspect, near, far );
15913         cameraNZ.layers = this.layers;
15914         cameraNZ.up.set( 0, - 1, 0 );
15915         cameraNZ.lookAt( new Vector3( 0, 0, - 1 ) );
15916         this.add( cameraNZ );
15917
15918         this.update = function ( renderer, scene ) {
15919
15920                 if ( this.parent === null ) this.updateMatrixWorld();
15921
15922                 const currentXrEnabled = renderer.xr.enabled;
15923                 const currentRenderTarget = renderer.getRenderTarget();
15924
15925                 renderer.xr.enabled = false;
15926
15927                 const generateMipmaps = renderTarget.texture.generateMipmaps;
15928
15929                 renderTarget.texture.generateMipmaps = false;
15930
15931                 renderer.setRenderTarget( renderTarget, 0 );
15932                 renderer.render( scene, cameraPX );
15933
15934                 renderer.setRenderTarget( renderTarget, 1 );
15935                 renderer.render( scene, cameraNX );
15936
15937                 renderer.setRenderTarget( renderTarget, 2 );
15938                 renderer.render( scene, cameraPY );
15939
15940                 renderer.setRenderTarget( renderTarget, 3 );
15941                 renderer.render( scene, cameraNY );
15942
15943                 renderer.setRenderTarget( renderTarget, 4 );
15944                 renderer.render( scene, cameraPZ );
15945
15946                 renderTarget.texture.generateMipmaps = generateMipmaps;
15947
15948                 renderer.setRenderTarget( renderTarget, 5 );
15949                 renderer.render( scene, cameraNZ );
15950
15951                 renderer.setRenderTarget( currentRenderTarget );
15952
15953                 renderer.xr.enabled = currentXrEnabled;
15954
15955         };
15956
15957 }
15958
15959 CubeCamera.prototype = Object.create( Object3D.prototype );
15960 CubeCamera.prototype.constructor = CubeCamera;
15961
15962 function CubeTexture( images, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding ) {
15963
15964         images = images !== undefined ? images : [];
15965         mapping = mapping !== undefined ? mapping : CubeReflectionMapping;
15966         format = format !== undefined ? format : RGBFormat;
15967
15968         Texture.call( this, images, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding );
15969
15970         this.flipY = false;
15971
15972         // Why CubeTexture._needsFlipEnvMap is necessary:
15973         //
15974         // By convention -- likely based on the RenderMan spec from the 1990's -- cube maps are specified by WebGL (and three.js)
15975         // in a coordinate system in which positive-x is to the right when looking up the positive-z axis -- in other words,
15976         // in a left-handed coordinate system. By continuing this convention, preexisting cube maps continued to render correctly.
15977
15978         // three.js uses a right-handed coordinate system. So environment maps used in three.js appear to have px and nx swapped
15979         // and the flag _needsFlipEnvMap controls this conversion. The flip is not required (and thus _needsFlipEnvMap is set to false)
15980         // when using WebGLCubeRenderTarget.texture as a cube texture.
15981
15982         this._needsFlipEnvMap = true;
15983
15984 }
15985
15986 CubeTexture.prototype = Object.create( Texture.prototype );
15987 CubeTexture.prototype.constructor = CubeTexture;
15988
15989 CubeTexture.prototype.isCubeTexture = true;
15990
15991 Object.defineProperty( CubeTexture.prototype, 'images', {
15992
15993         get: function () {
15994
15995                 return this.image;
15996
15997         },
15998
15999         set: function ( value ) {
16000
16001                 this.image = value;
16002
16003         }
16004
16005 } );
16006
16007 class WebGLCubeRenderTarget extends WebGLRenderTarget {
16008
16009         constructor( size, options, dummy ) {
16010
16011                 if ( Number.isInteger( options ) ) {
16012
16013                         console.warn( 'THREE.WebGLCubeRenderTarget: constructor signature is now WebGLCubeRenderTarget( size, options )' );
16014
16015                         options = dummy;
16016
16017                 }
16018
16019                 super( size, size, options );
16020
16021                 Object.defineProperty( this, 'isWebGLCubeRenderTarget', { value: true } );
16022
16023                 options = options || {};
16024
16025                 this.texture = new CubeTexture( undefined, options.mapping, options.wrapS, options.wrapT, options.magFilter, options.minFilter, options.format, options.type, options.anisotropy, options.encoding );
16026
16027                 this.texture._needsFlipEnvMap = false;
16028
16029         }
16030
16031         fromEquirectangularTexture( renderer, texture ) {
16032
16033                 this.texture.type = texture.type;
16034                 this.texture.format = RGBAFormat; // see #18859
16035                 this.texture.encoding = texture.encoding;
16036
16037                 this.texture.generateMipmaps = texture.generateMipmaps;
16038                 this.texture.minFilter = texture.minFilter;
16039                 this.texture.magFilter = texture.magFilter;
16040
16041                 const shader = {
16042
16043                         uniforms: {
16044                                 tEquirect: { value: null },
16045                         },
16046
16047                         vertexShader: /* glsl */`
16048
16049                                 varying vec3 vWorldDirection;
16050
16051                                 vec3 transformDirection( in vec3 dir, in mat4 matrix ) {
16052
16053                                         return normalize( ( matrix * vec4( dir, 0.0 ) ).xyz );
16054
16055                                 }
16056
16057                                 void main() {
16058
16059                                         vWorldDirection = transformDirection( position, modelMatrix );
16060
16061                                         #include <begin_vertex>
16062                                         #include <project_vertex>
16063
16064                                 }
16065                         `,
16066
16067                         fragmentShader: /* glsl */`
16068
16069                                 uniform sampler2D tEquirect;
16070
16071                                 varying vec3 vWorldDirection;
16072
16073                                 #include <common>
16074
16075                                 void main() {
16076
16077                                         vec3 direction = normalize( vWorldDirection );
16078
16079                                         vec2 sampleUV = equirectUv( direction );
16080
16081                                         gl_FragColor = texture2D( tEquirect, sampleUV );
16082
16083                                 }
16084                         `
16085                 };
16086
16087                 const geometry = new BoxGeometry( 5, 5, 5 );
16088
16089                 const material = new ShaderMaterial( {
16090
16091                         name: 'CubemapFromEquirect',
16092
16093                         uniforms: cloneUniforms( shader.uniforms ),
16094                         vertexShader: shader.vertexShader,
16095                         fragmentShader: shader.fragmentShader,
16096                         side: BackSide,
16097                         blending: NoBlending
16098
16099                 } );
16100
16101                 material.uniforms.tEquirect.value = texture;
16102
16103                 const mesh = new Mesh( geometry, material );
16104
16105                 const currentMinFilter = texture.minFilter;
16106
16107                 // Avoid blurred poles
16108                 if ( texture.minFilter === LinearMipmapLinearFilter ) texture.minFilter = LinearFilter;
16109
16110                 const camera = new CubeCamera( 1, 10, this );
16111                 camera.update( renderer, mesh );
16112
16113                 texture.minFilter = currentMinFilter;
16114
16115                 mesh.geometry.dispose();
16116                 mesh.material.dispose();
16117
16118                 return this;
16119
16120         }
16121
16122         clear( renderer, color, depth, stencil ) {
16123
16124                 const currentRenderTarget = renderer.getRenderTarget();
16125
16126                 for ( let i = 0; i < 6; i ++ ) {
16127
16128                         renderer.setRenderTarget( this, i );
16129
16130                         renderer.clear( color, depth, stencil );
16131
16132                 }
16133
16134                 renderer.setRenderTarget( currentRenderTarget );
16135
16136         }
16137
16138 }
16139
16140 function DataTexture( data, width, height, format, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy, encoding ) {
16141
16142         Texture.call( this, null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding );
16143
16144         this.image = { data: data || null, width: width || 1, height: height || 1 };
16145
16146         this.magFilter = magFilter !== undefined ? magFilter : NearestFilter;
16147         this.minFilter = minFilter !== undefined ? minFilter : NearestFilter;
16148
16149         this.generateMipmaps = false;
16150         this.flipY = false;
16151         this.unpackAlignment = 1;
16152
16153         this.needsUpdate = true;
16154
16155 }
16156
16157 DataTexture.prototype = Object.create( Texture.prototype );
16158 DataTexture.prototype.constructor = DataTexture;
16159
16160 DataTexture.prototype.isDataTexture = true;
16161
16162 const _sphere$1 = /*@__PURE__*/ new Sphere();
16163 const _vector$5 = /*@__PURE__*/ new Vector3();
16164
16165 class Frustum {
16166
16167         constructor( p0, p1, p2, p3, p4, p5 ) {
16168
16169                 this.planes = [
16170
16171                         ( p0 !== undefined ) ? p0 : new Plane(),
16172                         ( p1 !== undefined ) ? p1 : new Plane(),
16173                         ( p2 !== undefined ) ? p2 : new Plane(),
16174                         ( p3 !== undefined ) ? p3 : new Plane(),
16175                         ( p4 !== undefined ) ? p4 : new Plane(),
16176                         ( p5 !== undefined ) ? p5 : new Plane()
16177
16178                 ];
16179
16180         }
16181
16182         set( p0, p1, p2, p3, p4, p5 ) {
16183
16184                 const planes = this.planes;
16185
16186                 planes[ 0 ].copy( p0 );
16187                 planes[ 1 ].copy( p1 );
16188                 planes[ 2 ].copy( p2 );
16189                 planes[ 3 ].copy( p3 );
16190                 planes[ 4 ].copy( p4 );
16191                 planes[ 5 ].copy( p5 );
16192
16193                 return this;
16194
16195         }
16196
16197         clone() {
16198
16199                 return new this.constructor().copy( this );
16200
16201         }
16202
16203         copy( frustum ) {
16204
16205                 const planes = this.planes;
16206
16207                 for ( let i = 0; i < 6; i ++ ) {
16208
16209                         planes[ i ].copy( frustum.planes[ i ] );
16210
16211                 }
16212
16213                 return this;
16214
16215         }
16216
16217         setFromProjectionMatrix( m ) {
16218
16219                 const planes = this.planes;
16220                 const me = m.elements;
16221                 const me0 = me[ 0 ], me1 = me[ 1 ], me2 = me[ 2 ], me3 = me[ 3 ];
16222                 const me4 = me[ 4 ], me5 = me[ 5 ], me6 = me[ 6 ], me7 = me[ 7 ];
16223                 const me8 = me[ 8 ], me9 = me[ 9 ], me10 = me[ 10 ], me11 = me[ 11 ];
16224                 const me12 = me[ 12 ], me13 = me[ 13 ], me14 = me[ 14 ], me15 = me[ 15 ];
16225
16226                 planes[ 0 ].setComponents( me3 - me0, me7 - me4, me11 - me8, me15 - me12 ).normalize();
16227                 planes[ 1 ].setComponents( me3 + me0, me7 + me4, me11 + me8, me15 + me12 ).normalize();
16228                 planes[ 2 ].setComponents( me3 + me1, me7 + me5, me11 + me9, me15 + me13 ).normalize();
16229                 planes[ 3 ].setComponents( me3 - me1, me7 - me5, me11 - me9, me15 - me13 ).normalize();
16230                 planes[ 4 ].setComponents( me3 - me2, me7 - me6, me11 - me10, me15 - me14 ).normalize();
16231                 planes[ 5 ].setComponents( me3 + me2, me7 + me6, me11 + me10, me15 + me14 ).normalize();
16232
16233                 return this;
16234
16235         }
16236
16237         intersectsObject( object ) {
16238
16239                 const geometry = object.geometry;
16240
16241                 if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere();
16242
16243                 _sphere$1.copy( geometry.boundingSphere ).applyMatrix4( object.matrixWorld );
16244
16245                 return this.intersectsSphere( _sphere$1 );
16246
16247         }
16248
16249         intersectsSprite( sprite ) {
16250
16251                 _sphere$1.center.set( 0, 0, 0 );
16252                 _sphere$1.radius = 0.7071067811865476;
16253                 _sphere$1.applyMatrix4( sprite.matrixWorld );
16254
16255                 return this.intersectsSphere( _sphere$1 );
16256
16257         }
16258
16259         intersectsSphere( sphere ) {
16260
16261                 const planes = this.planes;
16262                 const center = sphere.center;
16263                 const negRadius = - sphere.radius;
16264
16265                 for ( let i = 0; i < 6; i ++ ) {
16266
16267                         const distance = planes[ i ].distanceToPoint( center );
16268
16269                         if ( distance < negRadius ) {
16270
16271                                 return false;
16272
16273                         }
16274
16275                 }
16276
16277                 return true;
16278
16279         }
16280
16281         intersectsBox( box ) {
16282
16283                 const planes = this.planes;
16284
16285                 for ( let i = 0; i < 6; i ++ ) {
16286
16287                         const plane = planes[ i ];
16288
16289                         // corner at max distance
16290
16291                         _vector$5.x = plane.normal.x > 0 ? box.max.x : box.min.x;
16292                         _vector$5.y = plane.normal.y > 0 ? box.max.y : box.min.y;
16293                         _vector$5.z = plane.normal.z > 0 ? box.max.z : box.min.z;
16294
16295                         if ( plane.distanceToPoint( _vector$5 ) < 0 ) {
16296
16297                                 return false;
16298
16299                         }
16300
16301                 }
16302
16303                 return true;
16304
16305         }
16306
16307         containsPoint( point ) {
16308
16309                 const planes = this.planes;
16310
16311                 for ( let i = 0; i < 6; i ++ ) {
16312
16313                         if ( planes[ i ].distanceToPoint( point ) < 0 ) {
16314
16315                                 return false;
16316
16317                         }
16318
16319                 }
16320
16321                 return true;
16322
16323         }
16324
16325 }
16326
16327 function WebGLAnimation() {
16328
16329         let context = null;
16330         let isAnimating = false;
16331         let animationLoop = null;
16332         let requestId = null;
16333
16334         function onAnimationFrame( time, frame ) {
16335
16336                 animationLoop( time, frame );
16337
16338                 requestId = context.requestAnimationFrame( onAnimationFrame );
16339
16340         }
16341
16342         return {
16343
16344                 start: function () {
16345
16346                         if ( isAnimating === true ) return;
16347                         if ( animationLoop === null ) return;
16348
16349                         requestId = context.requestAnimationFrame( onAnimationFrame );
16350
16351                         isAnimating = true;
16352
16353                 },
16354
16355                 stop: function () {
16356
16357                         context.cancelAnimationFrame( requestId );
16358
16359                         isAnimating = false;
16360
16361                 },
16362
16363                 setAnimationLoop: function ( callback ) {
16364
16365                         animationLoop = callback;
16366
16367                 },
16368
16369                 setContext: function ( value ) {
16370
16371                         context = value;
16372
16373                 }
16374
16375         };
16376
16377 }
16378
16379 function WebGLAttributes( gl, capabilities ) {
16380
16381         const isWebGL2 = capabilities.isWebGL2;
16382
16383         const buffers = new WeakMap();
16384
16385         function createBuffer( attribute, bufferType ) {
16386
16387                 const array = attribute.array;
16388                 const usage = attribute.usage;
16389
16390                 const buffer = gl.createBuffer();
16391
16392                 gl.bindBuffer( bufferType, buffer );
16393                 gl.bufferData( bufferType, array, usage );
16394
16395                 attribute.onUploadCallback();
16396
16397                 let type = 5126;
16398
16399                 if ( array instanceof Float32Array ) {
16400
16401                         type = 5126;
16402
16403                 } else if ( array instanceof Float64Array ) {
16404
16405                         console.warn( 'THREE.WebGLAttributes: Unsupported data buffer format: Float64Array.' );
16406
16407                 } else if ( array instanceof Uint16Array ) {
16408
16409                         if ( attribute.isFloat16BufferAttribute ) {
16410
16411                                 if ( isWebGL2 ) {
16412
16413                                         type = 5131;
16414
16415                                 } else {
16416
16417                                         console.warn( 'THREE.WebGLAttributes: Usage of Float16BufferAttribute requires WebGL2.' );
16418
16419                                 }
16420
16421                         } else {
16422
16423                                 type = 5123;
16424
16425                         }
16426
16427                 } else if ( array instanceof Int16Array ) {
16428
16429                         type = 5122;
16430
16431                 } else if ( array instanceof Uint32Array ) {
16432
16433                         type = 5125;
16434
16435                 } else if ( array instanceof Int32Array ) {
16436
16437                         type = 5124;
16438
16439                 } else if ( array instanceof Int8Array ) {
16440
16441                         type = 5120;
16442
16443                 } else if ( array instanceof Uint8Array ) {
16444
16445                         type = 5121;
16446
16447                 }
16448
16449                 return {
16450                         buffer: buffer,
16451                         type: type,
16452                         bytesPerElement: array.BYTES_PER_ELEMENT,
16453                         version: attribute.version
16454                 };
16455
16456         }
16457
16458         function updateBuffer( buffer, attribute, bufferType ) {
16459
16460                 const array = attribute.array;
16461                 const updateRange = attribute.updateRange;
16462
16463                 gl.bindBuffer( bufferType, buffer );
16464
16465                 if ( updateRange.count === - 1 ) {
16466
16467                         // Not using update ranges
16468
16469                         gl.bufferSubData( bufferType, 0, array );
16470
16471                 } else {
16472
16473                         if ( isWebGL2 ) {
16474
16475                                 gl.bufferSubData( bufferType, updateRange.offset * array.BYTES_PER_ELEMENT,
16476                                         array, updateRange.offset, updateRange.count );
16477
16478                         } else {
16479
16480                                 gl.bufferSubData( bufferType, updateRange.offset * array.BYTES_PER_ELEMENT,
16481                                         array.subarray( updateRange.offset, updateRange.offset + updateRange.count ) );
16482
16483                         }
16484
16485                         updateRange.count = - 1; // reset range
16486
16487                 }
16488
16489         }
16490
16491         //
16492
16493         function get( attribute ) {
16494
16495                 if ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data;
16496
16497                 return buffers.get( attribute );
16498
16499         }
16500
16501         function remove( attribute ) {
16502
16503                 if ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data;
16504
16505                 const data = buffers.get( attribute );
16506
16507                 if ( data ) {
16508
16509                         gl.deleteBuffer( data.buffer );
16510
16511                         buffers.delete( attribute );
16512
16513                 }
16514
16515         }
16516
16517         function update( attribute, bufferType ) {
16518
16519                 if ( attribute.isGLBufferAttribute ) {
16520
16521                         const cached = buffers.get( attribute );
16522
16523                         if ( ! cached || cached.version < attribute.version ) {
16524
16525                                 buffers.set( attribute, {
16526                                         buffer: attribute.buffer,
16527                                         type: attribute.type,
16528                                         bytesPerElement: attribute.elementSize,
16529                                         version: attribute.version
16530                                 } );
16531
16532                         }
16533
16534                         return;
16535
16536                 }
16537
16538                 if ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data;
16539
16540                 const data = buffers.get( attribute );
16541
16542                 if ( data === undefined ) {
16543
16544                         buffers.set( attribute, createBuffer( attribute, bufferType ) );
16545
16546                 } else if ( data.version < attribute.version ) {
16547
16548                         updateBuffer( data.buffer, attribute, bufferType );
16549
16550                         data.version = attribute.version;
16551
16552                 }
16553
16554         }
16555
16556         return {
16557
16558                 get: get,
16559                 remove: remove,
16560                 update: update
16561
16562         };
16563
16564 }
16565
16566 class PlaneGeometry extends BufferGeometry {
16567
16568         constructor( width = 1, height = 1, widthSegments = 1, heightSegments = 1 ) {
16569
16570                 super();
16571                 this.type = 'PlaneGeometry';
16572
16573                 this.parameters = {
16574                         width: width,
16575                         height: height,
16576                         widthSegments: widthSegments,
16577                         heightSegments: heightSegments
16578                 };
16579
16580                 const width_half = width / 2;
16581                 const height_half = height / 2;
16582
16583                 const gridX = Math.floor( widthSegments );
16584                 const gridY = Math.floor( heightSegments );
16585
16586                 const gridX1 = gridX + 1;
16587                 const gridY1 = gridY + 1;
16588
16589                 const segment_width = width / gridX;
16590                 const segment_height = height / gridY;
16591
16592                 //
16593
16594                 const indices = [];
16595                 const vertices = [];
16596                 const normals = [];
16597                 const uvs = [];
16598
16599                 for ( let iy = 0; iy < gridY1; iy ++ ) {
16600
16601                         const y = iy * segment_height - height_half;
16602
16603                         for ( let ix = 0; ix < gridX1; ix ++ ) {
16604
16605                                 const x = ix * segment_width - width_half;
16606
16607                                 vertices.push( x, - y, 0 );
16608
16609                                 normals.push( 0, 0, 1 );
16610
16611                                 uvs.push( ix / gridX );
16612                                 uvs.push( 1 - ( iy / gridY ) );
16613
16614                         }
16615
16616                 }
16617
16618                 for ( let iy = 0; iy < gridY; iy ++ ) {
16619
16620                         for ( let ix = 0; ix < gridX; ix ++ ) {
16621
16622                                 const a = ix + gridX1 * iy;
16623                                 const b = ix + gridX1 * ( iy + 1 );
16624                                 const c = ( ix + 1 ) + gridX1 * ( iy + 1 );
16625                                 const d = ( ix + 1 ) + gridX1 * iy;
16626
16627                                 indices.push( a, b, d );
16628                                 indices.push( b, c, d );
16629
16630                         }
16631
16632                 }
16633
16634                 this.setIndex( indices );
16635                 this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
16636                 this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
16637                 this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
16638
16639         }
16640
16641 }
16642
16643 var alphamap_fragment = "#ifdef USE_ALPHAMAP\n\tdiffuseColor.a *= texture2D( alphaMap, vUv ).g;\n#endif";
16644
16645 var alphamap_pars_fragment = "#ifdef USE_ALPHAMAP\n\tuniform sampler2D alphaMap;\n#endif";
16646
16647 var alphatest_fragment = "#ifdef ALPHATEST\n\tif ( diffuseColor.a < ALPHATEST ) discard;\n#endif";
16648
16649 var aomap_fragment = "#ifdef USE_AOMAP\n\tfloat ambientOcclusion = ( texture2D( aoMap, vUv2 ).r - 1.0 ) * aoMapIntensity + 1.0;\n\treflectedLight.indirectDiffuse *= ambientOcclusion;\n\t#if defined( USE_ENVMAP ) && defined( STANDARD )\n\t\tfloat dotNV = saturate( dot( geometry.normal, geometry.viewDir ) );\n\t\treflectedLight.indirectSpecular *= computeSpecularOcclusion( dotNV, ambientOcclusion, material.specularRoughness );\n\t#endif\n#endif";
16650
16651 var aomap_pars_fragment = "#ifdef USE_AOMAP\n\tuniform sampler2D aoMap;\n\tuniform float aoMapIntensity;\n#endif";
16652
16653 var begin_vertex = "vec3 transformed = vec3( position );";
16654
16655 var beginnormal_vertex = "vec3 objectNormal = vec3( normal );\n#ifdef USE_TANGENT\n\tvec3 objectTangent = vec3( tangent.xyz );\n#endif";
16656
16657 var bsdfs = "vec2 integrateSpecularBRDF( const in float dotNV, const in float roughness ) {\n\tconst vec4 c0 = vec4( - 1, - 0.0275, - 0.572, 0.022 );\n\tconst vec4 c1 = vec4( 1, 0.0425, 1.04, - 0.04 );\n\tvec4 r = roughness * c0 + c1;\n\tfloat a004 = min( r.x * r.x, exp2( - 9.28 * dotNV ) ) * r.x + r.y;\n\treturn vec2( -1.04, 1.04 ) * a004 + r.zw;\n}\nfloat punctualLightIntensityToIrradianceFactor( const in float lightDistance, const in float cutoffDistance, const in float decayExponent ) {\n#if defined ( PHYSICALLY_CORRECT_LIGHTS )\n\tfloat distanceFalloff = 1.0 / max( pow( lightDistance, decayExponent ), 0.01 );\n\tif( cutoffDistance > 0.0 ) {\n\t\tdistanceFalloff *= pow2( saturate( 1.0 - pow4( lightDistance / cutoffDistance ) ) );\n\t}\n\treturn distanceFalloff;\n#else\n\tif( cutoffDistance > 0.0 && decayExponent > 0.0 ) {\n\t\treturn pow( saturate( -lightDistance / cutoffDistance + 1.0 ), decayExponent );\n\t}\n\treturn 1.0;\n#endif\n}\nvec3 BRDF_Diffuse_Lambert( const in vec3 diffuseColor ) {\n\treturn RECIPROCAL_PI * diffuseColor;\n}\nvec3 F_Schlick( const in vec3 specularColor, const in float dotLH ) {\n\tfloat fresnel = exp2( ( -5.55473 * dotLH - 6.98316 ) * dotLH );\n\treturn ( 1.0 - specularColor ) * fresnel + specularColor;\n}\nvec3 F_Schlick_RoughnessDependent( const in vec3 F0, const in float dotNV, const in float roughness ) {\n\tfloat fresnel = exp2( ( -5.55473 * dotNV - 6.98316 ) * dotNV );\n\tvec3 Fr = max( vec3( 1.0 - roughness ), F0 ) - F0;\n\treturn Fr * fresnel + F0;\n}\nfloat G_GGX_Smith( const in float alpha, const in float dotNL, const in float dotNV ) {\n\tfloat a2 = pow2( alpha );\n\tfloat gl = dotNL + sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNL ) );\n\tfloat gv = dotNV + sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNV ) );\n\treturn 1.0 / ( gl * gv );\n}\nfloat G_GGX_SmithCorrelated( const in float alpha, const in float dotNL, const in float dotNV ) {\n\tfloat a2 = pow2( alpha );\n\tfloat gv = dotNL * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNV ) );\n\tfloat gl = dotNV * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNL ) );\n\treturn 0.5 / max( gv + gl, EPSILON );\n}\nfloat D_GGX( const in float alpha, const in float dotNH ) {\n\tfloat a2 = pow2( alpha );\n\tfloat denom = pow2( dotNH ) * ( a2 - 1.0 ) + 1.0;\n\treturn RECIPROCAL_PI * a2 / pow2( denom );\n}\nvec3 BRDF_Specular_GGX( const in IncidentLight incidentLight, const in vec3 viewDir, const in vec3 normal, const in vec3 specularColor, const in float roughness ) {\n\tfloat alpha = pow2( roughness );\n\tvec3 halfDir = normalize( incidentLight.direction + viewDir );\n\tfloat dotNL = saturate( dot( normal, incidentLight.direction ) );\n\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\tfloat dotNH = saturate( dot( normal, halfDir ) );\n\tfloat dotLH = saturate( dot( incidentLight.direction, halfDir ) );\n\tvec3 F = F_Schlick( specularColor, dotLH );\n\tfloat G = G_GGX_SmithCorrelated( alpha, dotNL, dotNV );\n\tfloat D = D_GGX( alpha, dotNH );\n\treturn F * ( G * D );\n}\nvec2 LTC_Uv( const in vec3 N, const in vec3 V, const in float roughness ) {\n\tconst float LUT_SIZE = 64.0;\n\tconst float LUT_SCALE = ( LUT_SIZE - 1.0 ) / LUT_SIZE;\n\tconst float LUT_BIAS = 0.5 / LUT_SIZE;\n\tfloat dotNV = saturate( dot( N, V ) );\n\tvec2 uv = vec2( roughness, sqrt( 1.0 - dotNV ) );\n\tuv = uv * LUT_SCALE + LUT_BIAS;\n\treturn uv;\n}\nfloat LTC_ClippedSphereFormFactor( const in vec3 f ) {\n\tfloat l = length( f );\n\treturn max( ( l * l + f.z ) / ( l + 1.0 ), 0.0 );\n}\nvec3 LTC_EdgeVectorFormFactor( const in vec3 v1, const in vec3 v2 ) {\n\tfloat x = dot( v1, v2 );\n\tfloat y = abs( x );\n\tfloat a = 0.8543985 + ( 0.4965155 + 0.0145206 * y ) * y;\n\tfloat b = 3.4175940 + ( 4.1616724 + y ) * y;\n\tfloat v = a / b;\n\tfloat theta_sintheta = ( x > 0.0 ) ? v : 0.5 * inversesqrt( max( 1.0 - x * x, 1e-7 ) ) - v;\n\treturn cross( v1, v2 ) * theta_sintheta;\n}\nvec3 LTC_Evaluate( const in vec3 N, const in vec3 V, const in vec3 P, const in mat3 mInv, const in vec3 rectCoords[ 4 ] ) {\n\tvec3 v1 = rectCoords[ 1 ] - rectCoords[ 0 ];\n\tvec3 v2 = rectCoords[ 3 ] - rectCoords[ 0 ];\n\tvec3 lightNormal = cross( v1, v2 );\n\tif( dot( lightNormal, P - rectCoords[ 0 ] ) < 0.0 ) return vec3( 0.0 );\n\tvec3 T1, T2;\n\tT1 = normalize( V - N * dot( V, N ) );\n\tT2 = - cross( N, T1 );\n\tmat3 mat = mInv * transposeMat3( mat3( T1, T2, N ) );\n\tvec3 coords[ 4 ];\n\tcoords[ 0 ] = mat * ( rectCoords[ 0 ] - P );\n\tcoords[ 1 ] = mat * ( rectCoords[ 1 ] - P );\n\tcoords[ 2 ] = mat * ( rectCoords[ 2 ] - P );\n\tcoords[ 3 ] = mat * ( rectCoords[ 3 ] - P );\n\tcoords[ 0 ] = normalize( coords[ 0 ] );\n\tcoords[ 1 ] = normalize( coords[ 1 ] );\n\tcoords[ 2 ] = normalize( coords[ 2 ] );\n\tcoords[ 3 ] = normalize( coords[ 3 ] );\n\tvec3 vectorFormFactor = vec3( 0.0 );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 0 ], coords[ 1 ] );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 1 ], coords[ 2 ] );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 2 ], coords[ 3 ] );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 3 ], coords[ 0 ] );\n\tfloat result = LTC_ClippedSphereFormFactor( vectorFormFactor );\n\treturn vec3( result );\n}\nvec3 BRDF_Specular_GGX_Environment( const in vec3 viewDir, const in vec3 normal, const in vec3 specularColor, const in float roughness ) {\n\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\tvec2 brdf = integrateSpecularBRDF( dotNV, roughness );\n\treturn specularColor * brdf.x + brdf.y;\n}\nvoid BRDF_Specular_Multiscattering_Environment( const in GeometricContext geometry, const in vec3 specularColor, const in float roughness, inout vec3 singleScatter, inout vec3 multiScatter ) {\n\tfloat dotNV = saturate( dot( geometry.normal, geometry.viewDir ) );\n\tvec3 F = F_Schlick_RoughnessDependent( specularColor, dotNV, roughness );\n\tvec2 brdf = integrateSpecularBRDF( dotNV, roughness );\n\tvec3 FssEss = F * brdf.x + brdf.y;\n\tfloat Ess = brdf.x + brdf.y;\n\tfloat Ems = 1.0 - Ess;\n\tvec3 Favg = specularColor + ( 1.0 - specularColor ) * 0.047619;\tvec3 Fms = FssEss * Favg / ( 1.0 - Ems * Favg );\n\tsingleScatter += FssEss;\n\tmultiScatter += Fms * Ems;\n}\nfloat G_BlinnPhong_Implicit( ) {\n\treturn 0.25;\n}\nfloat D_BlinnPhong( const in float shininess, const in float dotNH ) {\n\treturn RECIPROCAL_PI * ( shininess * 0.5 + 1.0 ) * pow( dotNH, shininess );\n}\nvec3 BRDF_Specular_BlinnPhong( const in IncidentLight incidentLight, const in GeometricContext geometry, const in vec3 specularColor, const in float shininess ) {\n\tvec3 halfDir = normalize( incidentLight.direction + geometry.viewDir );\n\tfloat dotNH = saturate( dot( geometry.normal, halfDir ) );\n\tfloat dotLH = saturate( dot( incidentLight.direction, halfDir ) );\n\tvec3 F = F_Schlick( specularColor, dotLH );\n\tfloat G = G_BlinnPhong_Implicit( );\n\tfloat D = D_BlinnPhong( shininess, dotNH );\n\treturn F * ( G * D );\n}\nfloat GGXRoughnessToBlinnExponent( const in float ggxRoughness ) {\n\treturn ( 2.0 / pow2( ggxRoughness + 0.0001 ) - 2.0 );\n}\nfloat BlinnExponentToGGXRoughness( const in float blinnExponent ) {\n\treturn sqrt( 2.0 / ( blinnExponent + 2.0 ) );\n}\n#if defined( USE_SHEEN )\nfloat D_Charlie(float roughness, float NoH) {\n\tfloat invAlpha = 1.0 / roughness;\n\tfloat cos2h = NoH * NoH;\n\tfloat sin2h = max(1.0 - cos2h, 0.0078125);\treturn (2.0 + invAlpha) * pow(sin2h, invAlpha * 0.5) / (2.0 * PI);\n}\nfloat V_Neubelt(float NoV, float NoL) {\n\treturn saturate(1.0 / (4.0 * (NoL + NoV - NoL * NoV)));\n}\nvec3 BRDF_Specular_Sheen( const in float roughness, const in vec3 L, const in GeometricContext geometry, vec3 specularColor ) {\n\tvec3 N = geometry.normal;\n\tvec3 V = geometry.viewDir;\n\tvec3 H = normalize( V + L );\n\tfloat dotNH = saturate( dot( N, H ) );\n\treturn specularColor * D_Charlie( roughness, dotNH ) * V_Neubelt( dot(N, V), dot(N, L) );\n}\n#endif";
16658
16659 var bumpmap_pars_fragment = "#ifdef USE_BUMPMAP\n\tuniform sampler2D bumpMap;\n\tuniform float bumpScale;\n\tvec2 dHdxy_fwd() {\n\t\tvec2 dSTdx = dFdx( vUv );\n\t\tvec2 dSTdy = dFdy( vUv );\n\t\tfloat Hll = bumpScale * texture2D( bumpMap, vUv ).x;\n\t\tfloat dBx = bumpScale * texture2D( bumpMap, vUv + dSTdx ).x - Hll;\n\t\tfloat dBy = bumpScale * texture2D( bumpMap, vUv + dSTdy ).x - Hll;\n\t\treturn vec2( dBx, dBy );\n\t}\n\tvec3 perturbNormalArb( vec3 surf_pos, vec3 surf_norm, vec2 dHdxy ) {\n\t\tvec3 vSigmaX = vec3( dFdx( surf_pos.x ), dFdx( surf_pos.y ), dFdx( surf_pos.z ) );\n\t\tvec3 vSigmaY = vec3( dFdy( surf_pos.x ), dFdy( surf_pos.y ), dFdy( surf_pos.z ) );\n\t\tvec3 vN = surf_norm;\n\t\tvec3 R1 = cross( vSigmaY, vN );\n\t\tvec3 R2 = cross( vN, vSigmaX );\n\t\tfloat fDet = dot( vSigmaX, R1 );\n\t\tfDet *= ( float( gl_FrontFacing ) * 2.0 - 1.0 );\n\t\tvec3 vGrad = sign( fDet ) * ( dHdxy.x * R1 + dHdxy.y * R2 );\n\t\treturn normalize( abs( fDet ) * surf_norm - vGrad );\n\t}\n#endif";
16660
16661 var clipping_planes_fragment = "#if NUM_CLIPPING_PLANES > 0\n\tvec4 plane;\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < UNION_CLIPPING_PLANES; i ++ ) {\n\t\tplane = clippingPlanes[ i ];\n\t\tif ( dot( vClipPosition, plane.xyz ) > plane.w ) discard;\n\t}\n\t#pragma unroll_loop_end\n\t#if UNION_CLIPPING_PLANES < NUM_CLIPPING_PLANES\n\t\tbool clipped = true;\n\t\t#pragma unroll_loop_start\n\t\tfor ( int i = UNION_CLIPPING_PLANES; i < NUM_CLIPPING_PLANES; i ++ ) {\n\t\t\tplane = clippingPlanes[ i ];\n\t\t\tclipped = ( dot( vClipPosition, plane.xyz ) > plane.w ) && clipped;\n\t\t}\n\t\t#pragma unroll_loop_end\n\t\tif ( clipped ) discard;\n\t#endif\n#endif";
16662
16663 var clipping_planes_pars_fragment = "#if NUM_CLIPPING_PLANES > 0\n\tvarying vec3 vClipPosition;\n\tuniform vec4 clippingPlanes[ NUM_CLIPPING_PLANES ];\n#endif";
16664
16665 var clipping_planes_pars_vertex = "#if NUM_CLIPPING_PLANES > 0\n\tvarying vec3 vClipPosition;\n#endif";
16666
16667 var clipping_planes_vertex = "#if NUM_CLIPPING_PLANES > 0\n\tvClipPosition = - mvPosition.xyz;\n#endif";
16668
16669 var color_fragment = "#ifdef USE_COLOR\n\tdiffuseColor.rgb *= vColor;\n#endif";
16670
16671 var color_pars_fragment = "#ifdef USE_COLOR\n\tvarying vec3 vColor;\n#endif";
16672
16673 var color_pars_vertex = "#if defined( USE_COLOR ) || defined( USE_INSTANCING_COLOR )\n\tvarying vec3 vColor;\n#endif";
16674
16675 var color_vertex = "#if defined( USE_COLOR ) || defined( USE_INSTANCING_COLOR )\n\tvColor = vec3( 1.0 );\n#endif\n#ifdef USE_COLOR\n\tvColor.xyz *= color.xyz;\n#endif\n#ifdef USE_INSTANCING_COLOR\n\tvColor.xyz *= instanceColor.xyz;\n#endif";
16676
16677 var common$1 = "#define PI 3.141592653589793\n#define PI2 6.283185307179586\n#define PI_HALF 1.5707963267948966\n#define RECIPROCAL_PI 0.3183098861837907\n#define RECIPROCAL_PI2 0.15915494309189535\n#define EPSILON 1e-6\n#ifndef saturate\n#define saturate(a) clamp( a, 0.0, 1.0 )\n#endif\n#define whiteComplement(a) ( 1.0 - saturate( a ) )\nfloat pow2( const in float x ) { return x*x; }\nfloat pow3( const in float x ) { return x*x*x; }\nfloat pow4( const in float x ) { float x2 = x*x; return x2*x2; }\nfloat average( const in vec3 color ) { return dot( color, vec3( 0.3333 ) ); }\nhighp float rand( const in vec2 uv ) {\n\tconst highp float a = 12.9898, b = 78.233, c = 43758.5453;\n\thighp float dt = dot( uv.xy, vec2( a,b ) ), sn = mod( dt, PI );\n\treturn fract(sin(sn) * c);\n}\n#ifdef HIGH_PRECISION\n\tfloat precisionSafeLength( vec3 v ) { return length( v ); }\n#else\n\tfloat max3( vec3 v ) { return max( max( v.x, v.y ), v.z ); }\n\tfloat precisionSafeLength( vec3 v ) {\n\t\tfloat maxComponent = max3( abs( v ) );\n\t\treturn length( v / maxComponent ) * maxComponent;\n\t}\n#endif\nstruct IncidentLight {\n\tvec3 color;\n\tvec3 direction;\n\tbool visible;\n};\nstruct ReflectedLight {\n\tvec3 directDiffuse;\n\tvec3 directSpecular;\n\tvec3 indirectDiffuse;\n\tvec3 indirectSpecular;\n};\nstruct GeometricContext {\n\tvec3 position;\n\tvec3 normal;\n\tvec3 viewDir;\n#ifdef CLEARCOAT\n\tvec3 clearcoatNormal;\n#endif\n};\nvec3 transformDirection( in vec3 dir, in mat4 matrix ) {\n\treturn normalize( ( matrix * vec4( dir, 0.0 ) ).xyz );\n}\nvec3 inverseTransformDirection( in vec3 dir, in mat4 matrix ) {\n\treturn normalize( ( vec4( dir, 0.0 ) * matrix ).xyz );\n}\nvec3 projectOnPlane(in vec3 point, in vec3 pointOnPlane, in vec3 planeNormal ) {\n\tfloat distance = dot( planeNormal, point - pointOnPlane );\n\treturn - distance * planeNormal + point;\n}\nfloat sideOfPlane( in vec3 point, in vec3 pointOnPlane, in vec3 planeNormal ) {\n\treturn sign( dot( point - pointOnPlane, planeNormal ) );\n}\nvec3 linePlaneIntersect( in vec3 pointOnLine, in vec3 lineDirection, in vec3 pointOnPlane, in vec3 planeNormal ) {\n\treturn lineDirection * ( dot( planeNormal, pointOnPlane - pointOnLine ) / dot( planeNormal, lineDirection ) ) + pointOnLine;\n}\nmat3 transposeMat3( const in mat3 m ) {\n\tmat3 tmp;\n\ttmp[ 0 ] = vec3( m[ 0 ].x, m[ 1 ].x, m[ 2 ].x );\n\ttmp[ 1 ] = vec3( m[ 0 ].y, m[ 1 ].y, m[ 2 ].y );\n\ttmp[ 2 ] = vec3( m[ 0 ].z, m[ 1 ].z, m[ 2 ].z );\n\treturn tmp;\n}\nfloat linearToRelativeLuminance( const in vec3 color ) {\n\tvec3 weights = vec3( 0.2126, 0.7152, 0.0722 );\n\treturn dot( weights, color.rgb );\n}\nbool isPerspectiveMatrix( mat4 m ) {\n\treturn m[ 2 ][ 3 ] == - 1.0;\n}\nvec2 equirectUv( in vec3 dir ) {\n\tfloat u = atan( dir.z, dir.x ) * RECIPROCAL_PI2 + 0.5;\n\tfloat v = asin( clamp( dir.y, - 1.0, 1.0 ) ) * RECIPROCAL_PI + 0.5;\n\treturn vec2( u, v );\n}";
16678
16679 var cube_uv_reflection_fragment = "#ifdef ENVMAP_TYPE_CUBE_UV\n\t#define cubeUV_maxMipLevel 8.0\n\t#define cubeUV_minMipLevel 4.0\n\t#define cubeUV_maxTileSize 256.0\n\t#define cubeUV_minTileSize 16.0\n\tfloat getFace( vec3 direction ) {\n\t\tvec3 absDirection = abs( direction );\n\t\tfloat face = - 1.0;\n\t\tif ( absDirection.x > absDirection.z ) {\n\t\t\tif ( absDirection.x > absDirection.y )\n\t\t\t\tface = direction.x > 0.0 ? 0.0 : 3.0;\n\t\t\telse\n\t\t\t\tface = direction.y > 0.0 ? 1.0 : 4.0;\n\t\t} else {\n\t\t\tif ( absDirection.z > absDirection.y )\n\t\t\t\tface = direction.z > 0.0 ? 2.0 : 5.0;\n\t\t\telse\n\t\t\t\tface = direction.y > 0.0 ? 1.0 : 4.0;\n\t\t}\n\t\treturn face;\n\t}\n\tvec2 getUV( vec3 direction, float face ) {\n\t\tvec2 uv;\n\t\tif ( face == 0.0 ) {\n\t\t\tuv = vec2( direction.z, direction.y ) / abs( direction.x );\n\t\t} else if ( face == 1.0 ) {\n\t\t\tuv = vec2( - direction.x, - direction.z ) / abs( direction.y );\n\t\t} else if ( face == 2.0 ) {\n\t\t\tuv = vec2( - direction.x, direction.y ) / abs( direction.z );\n\t\t} else if ( face == 3.0 ) {\n\t\t\tuv = vec2( - direction.z, direction.y ) / abs( direction.x );\n\t\t} else if ( face == 4.0 ) {\n\t\t\tuv = vec2( - direction.x, direction.z ) / abs( direction.y );\n\t\t} else {\n\t\t\tuv = vec2( direction.x, direction.y ) / abs( direction.z );\n\t\t}\n\t\treturn 0.5 * ( uv + 1.0 );\n\t}\n\tvec3 bilinearCubeUV( sampler2D envMap, vec3 direction, float mipInt ) {\n\t\tfloat face = getFace( direction );\n\t\tfloat filterInt = max( cubeUV_minMipLevel - mipInt, 0.0 );\n\t\tmipInt = max( mipInt, cubeUV_minMipLevel );\n\t\tfloat faceSize = exp2( mipInt );\n\t\tfloat texelSize = 1.0 / ( 3.0 * cubeUV_maxTileSize );\n\t\tvec2 uv = getUV( direction, face ) * ( faceSize - 1.0 );\n\t\tvec2 f = fract( uv );\n\t\tuv += 0.5 - f;\n\t\tif ( face > 2.0 ) {\n\t\t\tuv.y += faceSize;\n\t\t\tface -= 3.0;\n\t\t}\n\t\tuv.x += face * faceSize;\n\t\tif ( mipInt < cubeUV_maxMipLevel ) {\n\t\t\tuv.y += 2.0 * cubeUV_maxTileSize;\n\t\t}\n\t\tuv.y += filterInt * 2.0 * cubeUV_minTileSize;\n\t\tuv.x += 3.0 * max( 0.0, cubeUV_maxTileSize - 2.0 * faceSize );\n\t\tuv *= texelSize;\n\t\tvec3 tl = envMapTexelToLinear( texture2D( envMap, uv ) ).rgb;\n\t\tuv.x += texelSize;\n\t\tvec3 tr = envMapTexelToLinear( texture2D( envMap, uv ) ).rgb;\n\t\tuv.y += texelSize;\n\t\tvec3 br = envMapTexelToLinear( texture2D( envMap, uv ) ).rgb;\n\t\tuv.x -= texelSize;\n\t\tvec3 bl = envMapTexelToLinear( texture2D( envMap, uv ) ).rgb;\n\t\tvec3 tm = mix( tl, tr, f.x );\n\t\tvec3 bm = mix( bl, br, f.x );\n\t\treturn mix( tm, bm, f.y );\n\t}\n\t#define r0 1.0\n\t#define v0 0.339\n\t#define m0 - 2.0\n\t#define r1 0.8\n\t#define v1 0.276\n\t#define m1 - 1.0\n\t#define r4 0.4\n\t#define v4 0.046\n\t#define m4 2.0\n\t#define r5 0.305\n\t#define v5 0.016\n\t#define m5 3.0\n\t#define r6 0.21\n\t#define v6 0.0038\n\t#define m6 4.0\n\tfloat roughnessToMip( float roughness ) {\n\t\tfloat mip = 0.0;\n\t\tif ( roughness >= r1 ) {\n\t\t\tmip = ( r0 - roughness ) * ( m1 - m0 ) / ( r0 - r1 ) + m0;\n\t\t} else if ( roughness >= r4 ) {\n\t\t\tmip = ( r1 - roughness ) * ( m4 - m1 ) / ( r1 - r4 ) + m1;\n\t\t} else if ( roughness >= r5 ) {\n\t\t\tmip = ( r4 - roughness ) * ( m5 - m4 ) / ( r4 - r5 ) + m4;\n\t\t} else if ( roughness >= r6 ) {\n\t\t\tmip = ( r5 - roughness ) * ( m6 - m5 ) / ( r5 - r6 ) + m5;\n\t\t} else {\n\t\t\tmip = - 2.0 * log2( 1.16 * roughness );\t\t}\n\t\treturn mip;\n\t}\n\tvec4 textureCubeUV( sampler2D envMap, vec3 sampleDir, float roughness ) {\n\t\tfloat mip = clamp( roughnessToMip( roughness ), m0, cubeUV_maxMipLevel );\n\t\tfloat mipF = fract( mip );\n\t\tfloat mipInt = floor( mip );\n\t\tvec3 color0 = bilinearCubeUV( envMap, sampleDir, mipInt );\n\t\tif ( mipF == 0.0 ) {\n\t\t\treturn vec4( color0, 1.0 );\n\t\t} else {\n\t\t\tvec3 color1 = bilinearCubeUV( envMap, sampleDir, mipInt + 1.0 );\n\t\t\treturn vec4( mix( color0, color1, mipF ), 1.0 );\n\t\t}\n\t}\n#endif";
16680
16681 var defaultnormal_vertex = "vec3 transformedNormal = objectNormal;\n#ifdef USE_INSTANCING\n\tmat3 m = mat3( instanceMatrix );\n\ttransformedNormal /= vec3( dot( m[ 0 ], m[ 0 ] ), dot( m[ 1 ], m[ 1 ] ), dot( m[ 2 ], m[ 2 ] ) );\n\ttransformedNormal = m * transformedNormal;\n#endif\ntransformedNormal = normalMatrix * transformedNormal;\n#ifdef FLIP_SIDED\n\ttransformedNormal = - transformedNormal;\n#endif\n#ifdef USE_TANGENT\n\tvec3 transformedTangent = ( modelViewMatrix * vec4( objectTangent, 0.0 ) ).xyz;\n\t#ifdef FLIP_SIDED\n\t\ttransformedTangent = - transformedTangent;\n\t#endif\n#endif";
16682
16683 var displacementmap_pars_vertex = "#ifdef USE_DISPLACEMENTMAP\n\tuniform sampler2D displacementMap;\n\tuniform float displacementScale;\n\tuniform float displacementBias;\n#endif";
16684
16685 var displacementmap_vertex = "#ifdef USE_DISPLACEMENTMAP\n\ttransformed += normalize( objectNormal ) * ( texture2D( displacementMap, vUv ).x * displacementScale + displacementBias );\n#endif";
16686
16687 var emissivemap_fragment = "#ifdef USE_EMISSIVEMAP\n\tvec4 emissiveColor = texture2D( emissiveMap, vUv );\n\temissiveColor.rgb = emissiveMapTexelToLinear( emissiveColor ).rgb;\n\ttotalEmissiveRadiance *= emissiveColor.rgb;\n#endif";
16688
16689 var emissivemap_pars_fragment = "#ifdef USE_EMISSIVEMAP\n\tuniform sampler2D emissiveMap;\n#endif";
16690
16691 var encodings_fragment = "gl_FragColor = linearToOutputTexel( gl_FragColor );";
16692
16693 var encodings_pars_fragment = "\nvec4 LinearToLinear( in vec4 value ) {\n\treturn value;\n}\nvec4 GammaToLinear( in vec4 value, in float gammaFactor ) {\n\treturn vec4( pow( value.rgb, vec3( gammaFactor ) ), value.a );\n}\nvec4 LinearToGamma( in vec4 value, in float gammaFactor ) {\n\treturn vec4( pow( value.rgb, vec3( 1.0 / gammaFactor ) ), value.a );\n}\nvec4 sRGBToLinear( in vec4 value ) {\n\treturn vec4( mix( pow( value.rgb * 0.9478672986 + vec3( 0.0521327014 ), vec3( 2.4 ) ), value.rgb * 0.0773993808, vec3( lessThanEqual( value.rgb, vec3( 0.04045 ) ) ) ), value.a );\n}\nvec4 LinearTosRGB( in vec4 value ) {\n\treturn vec4( mix( pow( value.rgb, vec3( 0.41666 ) ) * 1.055 - vec3( 0.055 ), value.rgb * 12.92, vec3( lessThanEqual( value.rgb, vec3( 0.0031308 ) ) ) ), value.a );\n}\nvec4 RGBEToLinear( in vec4 value ) {\n\treturn vec4( value.rgb * exp2( value.a * 255.0 - 128.0 ), 1.0 );\n}\nvec4 LinearToRGBE( in vec4 value ) {\n\tfloat maxComponent = max( max( value.r, value.g ), value.b );\n\tfloat fExp = clamp( ceil( log2( maxComponent ) ), -128.0, 127.0 );\n\treturn vec4( value.rgb / exp2( fExp ), ( fExp + 128.0 ) / 255.0 );\n}\nvec4 RGBMToLinear( in vec4 value, in float maxRange ) {\n\treturn vec4( value.rgb * value.a * maxRange, 1.0 );\n}\nvec4 LinearToRGBM( in vec4 value, in float maxRange ) {\n\tfloat maxRGB = max( value.r, max( value.g, value.b ) );\n\tfloat M = clamp( maxRGB / maxRange, 0.0, 1.0 );\n\tM = ceil( M * 255.0 ) / 255.0;\n\treturn vec4( value.rgb / ( M * maxRange ), M );\n}\nvec4 RGBDToLinear( in vec4 value, in float maxRange ) {\n\treturn vec4( value.rgb * ( ( maxRange / 255.0 ) / value.a ), 1.0 );\n}\nvec4 LinearToRGBD( in vec4 value, in float maxRange ) {\n\tfloat maxRGB = max( value.r, max( value.g, value.b ) );\n\tfloat D = max( maxRange / maxRGB, 1.0 );\n\tD = clamp( floor( D ) / 255.0, 0.0, 1.0 );\n\treturn vec4( value.rgb * ( D * ( 255.0 / maxRange ) ), D );\n}\nconst mat3 cLogLuvM = mat3( 0.2209, 0.3390, 0.4184, 0.1138, 0.6780, 0.7319, 0.0102, 0.1130, 0.2969 );\nvec4 LinearToLogLuv( in vec4 value ) {\n\tvec3 Xp_Y_XYZp = cLogLuvM * value.rgb;\n\tXp_Y_XYZp = max( Xp_Y_XYZp, vec3( 1e-6, 1e-6, 1e-6 ) );\n\tvec4 vResult;\n\tvResult.xy = Xp_Y_XYZp.xy / Xp_Y_XYZp.z;\n\tfloat Le = 2.0 * log2(Xp_Y_XYZp.y) + 127.0;\n\tvResult.w = fract( Le );\n\tvResult.z = ( Le - ( floor( vResult.w * 255.0 ) ) / 255.0 ) / 255.0;\n\treturn vResult;\n}\nconst mat3 cLogLuvInverseM = mat3( 6.0014, -2.7008, -1.7996, -1.3320, 3.1029, -5.7721, 0.3008, -1.0882, 5.6268 );\nvec4 LogLuvToLinear( in vec4 value ) {\n\tfloat Le = value.z * 255.0 + value.w;\n\tvec3 Xp_Y_XYZp;\n\tXp_Y_XYZp.y = exp2( ( Le - 127.0 ) / 2.0 );\n\tXp_Y_XYZp.z = Xp_Y_XYZp.y / value.y;\n\tXp_Y_XYZp.x = value.x * Xp_Y_XYZp.z;\n\tvec3 vRGB = cLogLuvInverseM * Xp_Y_XYZp.rgb;\n\treturn vec4( max( vRGB, 0.0 ), 1.0 );\n}";
16694
16695 var envmap_fragment = "#ifdef USE_ENVMAP\n\t#ifdef ENV_WORLDPOS\n\t\tvec3 cameraToFrag;\n\t\tif ( isOrthographic ) {\n\t\t\tcameraToFrag = normalize( vec3( - viewMatrix[ 0 ][ 2 ], - viewMatrix[ 1 ][ 2 ], - viewMatrix[ 2 ][ 2 ] ) );\n\t\t} else {\n\t\t\tcameraToFrag = normalize( vWorldPosition - cameraPosition );\n\t\t}\n\t\tvec3 worldNormal = inverseTransformDirection( normal, viewMatrix );\n\t\t#ifdef ENVMAP_MODE_REFLECTION\n\t\t\tvec3 reflectVec = reflect( cameraToFrag, worldNormal );\n\t\t#else\n\t\t\tvec3 reflectVec = refract( cameraToFrag, worldNormal, refractionRatio );\n\t\t#endif\n\t#else\n\t\tvec3 reflectVec = vReflect;\n\t#endif\n\t#ifdef ENVMAP_TYPE_CUBE\n\t\tvec4 envColor = textureCube( envMap, vec3( flipEnvMap * reflectVec.x, reflectVec.yz ) );\n\t#elif defined( ENVMAP_TYPE_CUBE_UV )\n\t\tvec4 envColor = textureCubeUV( envMap, reflectVec, 0.0 );\n\t#else\n\t\tvec4 envColor = vec4( 0.0 );\n\t#endif\n\t#ifndef ENVMAP_TYPE_CUBE_UV\n\t\tenvColor = envMapTexelToLinear( envColor );\n\t#endif\n\t#ifdef ENVMAP_BLENDING_MULTIPLY\n\t\toutgoingLight = mix( outgoingLight, outgoingLight * envColor.xyz, specularStrength * reflectivity );\n\t#elif defined( ENVMAP_BLENDING_MIX )\n\t\toutgoingLight = mix( outgoingLight, envColor.xyz, specularStrength * reflectivity );\n\t#elif defined( ENVMAP_BLENDING_ADD )\n\t\toutgoingLight += envColor.xyz * specularStrength * reflectivity;\n\t#endif\n#endif";
16696
16697 var envmap_common_pars_fragment = "#ifdef USE_ENVMAP\n\tuniform float envMapIntensity;\n\tuniform float flipEnvMap;\n\tuniform int maxMipLevel;\n\t#ifdef ENVMAP_TYPE_CUBE\n\t\tuniform samplerCube envMap;\n\t#else\n\t\tuniform sampler2D envMap;\n\t#endif\n\t\n#endif";
16698
16699 var envmap_pars_fragment = "#ifdef USE_ENVMAP\n\tuniform float reflectivity;\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG )\n\t\t#define ENV_WORLDPOS\n\t#endif\n\t#ifdef ENV_WORLDPOS\n\t\tvarying vec3 vWorldPosition;\n\t\tuniform float refractionRatio;\n\t#else\n\t\tvarying vec3 vReflect;\n\t#endif\n#endif";
16700
16701 var envmap_pars_vertex = "#ifdef USE_ENVMAP\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) ||defined( PHONG )\n\t\t#define ENV_WORLDPOS\n\t#endif\n\t#ifdef ENV_WORLDPOS\n\t\t\n\t\tvarying vec3 vWorldPosition;\n\t#else\n\t\tvarying vec3 vReflect;\n\t\tuniform float refractionRatio;\n\t#endif\n#endif";
16702
16703 var envmap_vertex = "#ifdef USE_ENVMAP\n\t#ifdef ENV_WORLDPOS\n\t\tvWorldPosition = worldPosition.xyz;\n\t#else\n\t\tvec3 cameraToVertex;\n\t\tif ( isOrthographic ) {\n\t\t\tcameraToVertex = normalize( vec3( - viewMatrix[ 0 ][ 2 ], - viewMatrix[ 1 ][ 2 ], - viewMatrix[ 2 ][ 2 ] ) );\n\t\t} else {\n\t\t\tcameraToVertex = normalize( worldPosition.xyz - cameraPosition );\n\t\t}\n\t\tvec3 worldNormal = inverseTransformDirection( transformedNormal, viewMatrix );\n\t\t#ifdef ENVMAP_MODE_REFLECTION\n\t\t\tvReflect = reflect( cameraToVertex, worldNormal );\n\t\t#else\n\t\t\tvReflect = refract( cameraToVertex, worldNormal, refractionRatio );\n\t\t#endif\n\t#endif\n#endif";
16704
16705 var fog_vertex = "#ifdef USE_FOG\n\tfogDepth = - mvPosition.z;\n#endif";
16706
16707 var fog_pars_vertex = "#ifdef USE_FOG\n\tvarying float fogDepth;\n#endif";
16708
16709 var fog_fragment = "#ifdef USE_FOG\n\t#ifdef FOG_EXP2\n\t\tfloat fogFactor = 1.0 - exp( - fogDensity * fogDensity * fogDepth * fogDepth );\n\t#else\n\t\tfloat fogFactor = smoothstep( fogNear, fogFar, fogDepth );\n\t#endif\n\tgl_FragColor.rgb = mix( gl_FragColor.rgb, fogColor, fogFactor );\n#endif";
16710
16711 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";
16712
16713 var gradientmap_pars_fragment = "#ifdef USE_GRADIENTMAP\n\tuniform sampler2D gradientMap;\n#endif\nvec3 getGradientIrradiance( vec3 normal, vec3 lightDirection ) {\n\tfloat dotNL = dot( normal, lightDirection );\n\tvec2 coord = vec2( dotNL * 0.5 + 0.5, 0.0 );\n\t#ifdef USE_GRADIENTMAP\n\t\treturn texture2D( gradientMap, coord ).rgb;\n\t#else\n\t\treturn ( coord.x < 0.7 ) ? vec3( 0.7 ) : vec3( 1.0 );\n\t#endif\n}";
16714
16715 var lightmap_fragment = "#ifdef USE_LIGHTMAP\n\tvec4 lightMapTexel= texture2D( lightMap, vUv2 );\n\treflectedLight.indirectDiffuse += PI * lightMapTexelToLinear( lightMapTexel ).rgb * lightMapIntensity;\n#endif";
16716
16717 var lightmap_pars_fragment = "#ifdef USE_LIGHTMAP\n\tuniform sampler2D lightMap;\n\tuniform float lightMapIntensity;\n#endif";
16718
16719 var lights_lambert_vertex = "vec3 diffuse = vec3( 1.0 );\nGeometricContext geometry;\ngeometry.position = mvPosition.xyz;\ngeometry.normal = normalize( transformedNormal );\ngeometry.viewDir = ( isOrthographic ) ? vec3( 0, 0, 1 ) : normalize( -mvPosition.xyz );\nGeometricContext backGeometry;\nbackGeometry.position = geometry.position;\nbackGeometry.normal = -geometry.normal;\nbackGeometry.viewDir = geometry.viewDir;\nvLightFront = vec3( 0.0 );\nvIndirectFront = vec3( 0.0 );\n#ifdef DOUBLE_SIDED\n\tvLightBack = vec3( 0.0 );\n\tvIndirectBack = vec3( 0.0 );\n#endif\nIncidentLight directLight;\nfloat dotNL;\nvec3 directLightColor_Diffuse;\nvIndirectFront += getAmbientLightIrradiance( ambientLightColor );\nvIndirectFront += getLightProbeIrradiance( lightProbe, geometry );\n#ifdef DOUBLE_SIDED\n\tvIndirectBack += getAmbientLightIrradiance( ambientLightColor );\n\tvIndirectBack += getLightProbeIrradiance( lightProbe, backGeometry );\n#endif\n#if NUM_POINT_LIGHTS > 0\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {\n\t\tgetPointDirectLightIrradiance( pointLights[ i ], geometry, directLight );\n\t\tdotNL = dot( geometry.normal, directLight.direction );\n\t\tdirectLightColor_Diffuse = PI * directLight.color;\n\t\tvLightFront += saturate( dotNL ) * directLightColor_Diffuse;\n\t\t#ifdef DOUBLE_SIDED\n\t\t\tvLightBack += saturate( -dotNL ) * directLightColor_Diffuse;\n\t\t#endif\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if NUM_SPOT_LIGHTS > 0\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {\n\t\tgetSpotDirectLightIrradiance( spotLights[ i ], geometry, directLight );\n\t\tdotNL = dot( geometry.normal, directLight.direction );\n\t\tdirectLightColor_Diffuse = PI * directLight.color;\n\t\tvLightFront += saturate( dotNL ) * directLightColor_Diffuse;\n\t\t#ifdef DOUBLE_SIDED\n\t\t\tvLightBack += saturate( -dotNL ) * directLightColor_Diffuse;\n\t\t#endif\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if NUM_DIR_LIGHTS > 0\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\n\t\tgetDirectionalDirectLightIrradiance( directionalLights[ i ], geometry, directLight );\n\t\tdotNL = dot( geometry.normal, directLight.direction );\n\t\tdirectLightColor_Diffuse = PI * directLight.color;\n\t\tvLightFront += saturate( dotNL ) * directLightColor_Diffuse;\n\t\t#ifdef DOUBLE_SIDED\n\t\t\tvLightBack += saturate( -dotNL ) * directLightColor_Diffuse;\n\t\t#endif\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if NUM_HEMI_LIGHTS > 0\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_HEMI_LIGHTS; i ++ ) {\n\t\tvIndirectFront += getHemisphereLightIrradiance( hemisphereLights[ i ], geometry );\n\t\t#ifdef DOUBLE_SIDED\n\t\t\tvIndirectBack += getHemisphereLightIrradiance( hemisphereLights[ i ], backGeometry );\n\t\t#endif\n\t}\n\t#pragma unroll_loop_end\n#endif";
16720
16721 var lights_pars_begin = "uniform bool receiveShadow;\nuniform vec3 ambientLightColor;\nuniform vec3 lightProbe[ 9 ];\nvec3 shGetIrradianceAt( in vec3 normal, in vec3 shCoefficients[ 9 ] ) {\n\tfloat x = normal.x, y = normal.y, z = normal.z;\n\tvec3 result = shCoefficients[ 0 ] * 0.886227;\n\tresult += shCoefficients[ 1 ] * 2.0 * 0.511664 * y;\n\tresult += shCoefficients[ 2 ] * 2.0 * 0.511664 * z;\n\tresult += shCoefficients[ 3 ] * 2.0 * 0.511664 * x;\n\tresult += shCoefficients[ 4 ] * 2.0 * 0.429043 * x * y;\n\tresult += shCoefficients[ 5 ] * 2.0 * 0.429043 * y * z;\n\tresult += shCoefficients[ 6 ] * ( 0.743125 * z * z - 0.247708 );\n\tresult += shCoefficients[ 7 ] * 2.0 * 0.429043 * x * z;\n\tresult += shCoefficients[ 8 ] * 0.429043 * ( x * x - y * y );\n\treturn result;\n}\nvec3 getLightProbeIrradiance( const in vec3 lightProbe[ 9 ], const in GeometricContext geometry ) {\n\tvec3 worldNormal = inverseTransformDirection( geometry.normal, viewMatrix );\n\tvec3 irradiance = shGetIrradianceAt( worldNormal, lightProbe );\n\treturn irradiance;\n}\nvec3 getAmbientLightIrradiance( const in vec3 ambientLightColor ) {\n\tvec3 irradiance = ambientLightColor;\n\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\tirradiance *= PI;\n\t#endif\n\treturn irradiance;\n}\n#if NUM_DIR_LIGHTS > 0\n\tstruct DirectionalLight {\n\t\tvec3 direction;\n\t\tvec3 color;\n\t};\n\tuniform DirectionalLight directionalLights[ NUM_DIR_LIGHTS ];\n\tvoid getDirectionalDirectLightIrradiance( const in DirectionalLight directionalLight, const in GeometricContext geometry, out IncidentLight directLight ) {\n\t\tdirectLight.color = directionalLight.color;\n\t\tdirectLight.direction = directionalLight.direction;\n\t\tdirectLight.visible = true;\n\t}\n#endif\n#if NUM_POINT_LIGHTS > 0\n\tstruct PointLight {\n\t\tvec3 position;\n\t\tvec3 color;\n\t\tfloat distance;\n\t\tfloat decay;\n\t};\n\tuniform PointLight pointLights[ NUM_POINT_LIGHTS ];\n\tvoid getPointDirectLightIrradiance( const in PointLight pointLight, const in GeometricContext geometry, out IncidentLight directLight ) {\n\t\tvec3 lVector = pointLight.position - geometry.position;\n\t\tdirectLight.direction = normalize( lVector );\n\t\tfloat lightDistance = length( lVector );\n\t\tdirectLight.color = pointLight.color;\n\t\tdirectLight.color *= punctualLightIntensityToIrradianceFactor( lightDistance, pointLight.distance, pointLight.decay );\n\t\tdirectLight.visible = ( directLight.color != vec3( 0.0 ) );\n\t}\n#endif\n#if NUM_SPOT_LIGHTS > 0\n\tstruct SpotLight {\n\t\tvec3 position;\n\t\tvec3 direction;\n\t\tvec3 color;\n\t\tfloat distance;\n\t\tfloat decay;\n\t\tfloat coneCos;\n\t\tfloat penumbraCos;\n\t};\n\tuniform SpotLight spotLights[ NUM_SPOT_LIGHTS ];\n\tvoid getSpotDirectLightIrradiance( const in SpotLight spotLight, const in GeometricContext geometry, out IncidentLight directLight ) {\n\t\tvec3 lVector = spotLight.position - geometry.position;\n\t\tdirectLight.direction = normalize( lVector );\n\t\tfloat lightDistance = length( lVector );\n\t\tfloat angleCos = dot( directLight.direction, spotLight.direction );\n\t\tif ( angleCos > spotLight.coneCos ) {\n\t\t\tfloat spotEffect = smoothstep( spotLight.coneCos, spotLight.penumbraCos, angleCos );\n\t\t\tdirectLight.color = spotLight.color;\n\t\t\tdirectLight.color *= spotEffect * punctualLightIntensityToIrradianceFactor( lightDistance, spotLight.distance, spotLight.decay );\n\t\t\tdirectLight.visible = true;\n\t\t} else {\n\t\t\tdirectLight.color = vec3( 0.0 );\n\t\t\tdirectLight.visible = false;\n\t\t}\n\t}\n#endif\n#if NUM_RECT_AREA_LIGHTS > 0\n\tstruct RectAreaLight {\n\t\tvec3 color;\n\t\tvec3 position;\n\t\tvec3 halfWidth;\n\t\tvec3 halfHeight;\n\t};\n\tuniform sampler2D ltc_1;\tuniform sampler2D ltc_2;\n\tuniform RectAreaLight rectAreaLights[ NUM_RECT_AREA_LIGHTS ];\n#endif\n#if NUM_HEMI_LIGHTS > 0\n\tstruct HemisphereLight {\n\t\tvec3 direction;\n\t\tvec3 skyColor;\n\t\tvec3 groundColor;\n\t};\n\tuniform HemisphereLight hemisphereLights[ NUM_HEMI_LIGHTS ];\n\tvec3 getHemisphereLightIrradiance( const in HemisphereLight hemiLight, const in GeometricContext geometry ) {\n\t\tfloat dotNL = dot( geometry.normal, hemiLight.direction );\n\t\tfloat hemiDiffuseWeight = 0.5 * dotNL + 0.5;\n\t\tvec3 irradiance = mix( hemiLight.groundColor, hemiLight.skyColor, hemiDiffuseWeight );\n\t\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\t\tirradiance *= PI;\n\t\t#endif\n\t\treturn irradiance;\n\t}\n#endif";
16722
16723 var envmap_physical_pars_fragment = "#if defined( USE_ENVMAP )\n\t#ifdef ENVMAP_MODE_REFRACTION\n\t\tuniform float refractionRatio;\n\t#endif\n\tvec3 getLightProbeIndirectIrradiance( const in GeometricContext geometry, const in int maxMIPLevel ) {\n\t\tvec3 worldNormal = inverseTransformDirection( geometry.normal, viewMatrix );\n\t\t#ifdef ENVMAP_TYPE_CUBE\n\t\t\tvec3 queryVec = vec3( flipEnvMap * worldNormal.x, worldNormal.yz );\n\t\t\t#ifdef TEXTURE_LOD_EXT\n\t\t\t\tvec4 envMapColor = textureCubeLodEXT( envMap, queryVec, float( maxMIPLevel ) );\n\t\t\t#else\n\t\t\t\tvec4 envMapColor = textureCube( envMap, queryVec, float( maxMIPLevel ) );\n\t\t\t#endif\n\t\t\tenvMapColor.rgb = envMapTexelToLinear( envMapColor ).rgb;\n\t\t#elif defined( ENVMAP_TYPE_CUBE_UV )\n\t\t\tvec4 envMapColor = textureCubeUV( envMap, worldNormal, 1.0 );\n\t\t#else\n\t\t\tvec4 envMapColor = vec4( 0.0 );\n\t\t#endif\n\t\treturn PI * envMapColor.rgb * envMapIntensity;\n\t}\n\tfloat getSpecularMIPLevel( const in float roughness, const in int maxMIPLevel ) {\n\t\tfloat maxMIPLevelScalar = float( maxMIPLevel );\n\t\tfloat sigma = PI * roughness * roughness / ( 1.0 + roughness );\n\t\tfloat desiredMIPLevel = maxMIPLevelScalar + log2( sigma );\n\t\treturn clamp( desiredMIPLevel, 0.0, maxMIPLevelScalar );\n\t}\n\tvec3 getLightProbeIndirectRadiance( const in vec3 viewDir, const in vec3 normal, const in float roughness, const in int maxMIPLevel ) {\n\t\t#ifdef ENVMAP_MODE_REFLECTION\n\t\t\tvec3 reflectVec = reflect( -viewDir, normal );\n\t\t\treflectVec = normalize( mix( reflectVec, normal, roughness * roughness) );\n\t\t#else\n\t\t\tvec3 reflectVec = refract( -viewDir, normal, refractionRatio );\n\t\t#endif\n\t\treflectVec = inverseTransformDirection( reflectVec, viewMatrix );\n\t\tfloat specularMIPLevel = getSpecularMIPLevel( roughness, maxMIPLevel );\n\t\t#ifdef ENVMAP_TYPE_CUBE\n\t\t\tvec3 queryReflectVec = vec3( flipEnvMap * reflectVec.x, reflectVec.yz );\n\t\t\t#ifdef TEXTURE_LOD_EXT\n\t\t\t\tvec4 envMapColor = textureCubeLodEXT( envMap, queryReflectVec, specularMIPLevel );\n\t\t\t#else\n\t\t\t\tvec4 envMapColor = textureCube( envMap, queryReflectVec, specularMIPLevel );\n\t\t\t#endif\n\t\t\tenvMapColor.rgb = envMapTexelToLinear( envMapColor ).rgb;\n\t\t#elif defined( ENVMAP_TYPE_CUBE_UV )\n\t\t\tvec4 envMapColor = textureCubeUV( envMap, reflectVec, roughness );\n\t\t#endif\n\t\treturn envMapColor.rgb * envMapIntensity;\n\t}\n#endif";
16724
16725 var lights_toon_fragment = "ToonMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb;";
16726
16727 var lights_toon_pars_fragment = "varying vec3 vViewPosition;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\nstruct ToonMaterial {\n\tvec3 diffuseColor;\n};\nvoid RE_Direct_Toon( const in IncidentLight directLight, const in GeometricContext geometry, const in ToonMaterial material, inout ReflectedLight reflectedLight ) {\n\tvec3 irradiance = getGradientIrradiance( geometry.normal, directLight.direction ) * directLight.color;\n\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\tirradiance *= PI;\n\t#endif\n\treflectedLight.directDiffuse += irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\n}\nvoid RE_IndirectDiffuse_Toon( const in vec3 irradiance, const in GeometricContext geometry, const in ToonMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\n}\n#define RE_Direct\t\t\t\tRE_Direct_Toon\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_Toon\n#define Material_LightProbeLOD( material )\t(0)";
16728
16729 var lights_phong_fragment = "BlinnPhongMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb;\nmaterial.specularColor = specular;\nmaterial.specularShininess = shininess;\nmaterial.specularStrength = specularStrength;";
16730
16731 var lights_phong_pars_fragment = "varying vec3 vViewPosition;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\nstruct BlinnPhongMaterial {\n\tvec3 diffuseColor;\n\tvec3 specularColor;\n\tfloat specularShininess;\n\tfloat specularStrength;\n};\nvoid RE_Direct_BlinnPhong( const in IncidentLight directLight, const in GeometricContext geometry, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) {\n\tfloat dotNL = saturate( dot( geometry.normal, directLight.direction ) );\n\tvec3 irradiance = dotNL * directLight.color;\n\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\tirradiance *= PI;\n\t#endif\n\treflectedLight.directDiffuse += irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\n\treflectedLight.directSpecular += irradiance * BRDF_Specular_BlinnPhong( directLight, geometry, material.specularColor, material.specularShininess ) * material.specularStrength;\n}\nvoid RE_IndirectDiffuse_BlinnPhong( const in vec3 irradiance, const in GeometricContext geometry, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\n}\n#define RE_Direct\t\t\t\tRE_Direct_BlinnPhong\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_BlinnPhong\n#define Material_LightProbeLOD( material )\t(0)";
16732
16733 var lights_physical_fragment = "PhysicalMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb * ( 1.0 - metalnessFactor );\nvec3 dxy = max( abs( dFdx( geometryNormal ) ), abs( dFdy( geometryNormal ) ) );\nfloat geometryRoughness = max( max( dxy.x, dxy.y ), dxy.z );\nmaterial.specularRoughness = max( roughnessFactor, 0.0525 );material.specularRoughness += geometryRoughness;\nmaterial.specularRoughness = min( material.specularRoughness, 1.0 );\n#ifdef REFLECTIVITY\n\tmaterial.specularColor = mix( vec3( MAXIMUM_SPECULAR_COEFFICIENT * pow2( reflectivity ) ), diffuseColor.rgb, metalnessFactor );\n#else\n\tmaterial.specularColor = mix( vec3( DEFAULT_SPECULAR_COEFFICIENT ), diffuseColor.rgb, metalnessFactor );\n#endif\n#ifdef CLEARCOAT\n\tmaterial.clearcoat = clearcoat;\n\tmaterial.clearcoatRoughness = clearcoatRoughness;\n\t#ifdef USE_CLEARCOATMAP\n\t\tmaterial.clearcoat *= texture2D( clearcoatMap, vUv ).x;\n\t#endif\n\t#ifdef USE_CLEARCOAT_ROUGHNESSMAP\n\t\tmaterial.clearcoatRoughness *= texture2D( clearcoatRoughnessMap, vUv ).y;\n\t#endif\n\tmaterial.clearcoat = saturate( material.clearcoat );\tmaterial.clearcoatRoughness = max( material.clearcoatRoughness, 0.0525 );\n\tmaterial.clearcoatRoughness += geometryRoughness;\n\tmaterial.clearcoatRoughness = min( material.clearcoatRoughness, 1.0 );\n#endif\n#ifdef USE_SHEEN\n\tmaterial.sheenColor = sheen;\n#endif";
16734
16735 var lights_physical_pars_fragment = "struct PhysicalMaterial {\n\tvec3 diffuseColor;\n\tfloat specularRoughness;\n\tvec3 specularColor;\n#ifdef CLEARCOAT\n\tfloat clearcoat;\n\tfloat clearcoatRoughness;\n#endif\n#ifdef USE_SHEEN\n\tvec3 sheenColor;\n#endif\n};\n#define MAXIMUM_SPECULAR_COEFFICIENT 0.16\n#define DEFAULT_SPECULAR_COEFFICIENT 0.04\nfloat clearcoatDHRApprox( const in float roughness, const in float dotNL ) {\n\treturn DEFAULT_SPECULAR_COEFFICIENT + ( 1.0 - DEFAULT_SPECULAR_COEFFICIENT ) * ( pow( 1.0 - dotNL, 5.0 ) * pow( 1.0 - roughness, 2.0 ) );\n}\n#if NUM_RECT_AREA_LIGHTS > 0\n\tvoid RE_Direct_RectArea_Physical( const in RectAreaLight rectAreaLight, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\t\tvec3 normal = geometry.normal;\n\t\tvec3 viewDir = geometry.viewDir;\n\t\tvec3 position = geometry.position;\n\t\tvec3 lightPos = rectAreaLight.position;\n\t\tvec3 halfWidth = rectAreaLight.halfWidth;\n\t\tvec3 halfHeight = rectAreaLight.halfHeight;\n\t\tvec3 lightColor = rectAreaLight.color;\n\t\tfloat roughness = material.specularRoughness;\n\t\tvec3 rectCoords[ 4 ];\n\t\trectCoords[ 0 ] = lightPos + halfWidth - halfHeight;\t\trectCoords[ 1 ] = lightPos - halfWidth - halfHeight;\n\t\trectCoords[ 2 ] = lightPos - halfWidth + halfHeight;\n\t\trectCoords[ 3 ] = lightPos + halfWidth + halfHeight;\n\t\tvec2 uv = LTC_Uv( normal, viewDir, roughness );\n\t\tvec4 t1 = texture2D( ltc_1, uv );\n\t\tvec4 t2 = texture2D( ltc_2, uv );\n\t\tmat3 mInv = mat3(\n\t\t\tvec3( t1.x, 0, t1.y ),\n\t\t\tvec3(    0, 1,    0 ),\n\t\t\tvec3( t1.z, 0, t1.w )\n\t\t);\n\t\tvec3 fresnel = ( material.specularColor * t2.x + ( vec3( 1.0 ) - material.specularColor ) * t2.y );\n\t\treflectedLight.directSpecular += lightColor * fresnel * LTC_Evaluate( normal, viewDir, position, mInv, rectCoords );\n\t\treflectedLight.directDiffuse += lightColor * material.diffuseColor * LTC_Evaluate( normal, viewDir, position, mat3( 1.0 ), rectCoords );\n\t}\n#endif\nvoid RE_Direct_Physical( const in IncidentLight directLight, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\tfloat dotNL = saturate( dot( geometry.normal, directLight.direction ) );\n\tvec3 irradiance = dotNL * directLight.color;\n\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\tirradiance *= PI;\n\t#endif\n\t#ifdef CLEARCOAT\n\t\tfloat ccDotNL = saturate( dot( geometry.clearcoatNormal, directLight.direction ) );\n\t\tvec3 ccIrradiance = ccDotNL * directLight.color;\n\t\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\t\tccIrradiance *= PI;\n\t\t#endif\n\t\tfloat clearcoatDHR = material.clearcoat * clearcoatDHRApprox( material.clearcoatRoughness, ccDotNL );\n\t\treflectedLight.directSpecular += ccIrradiance * material.clearcoat * BRDF_Specular_GGX( directLight, geometry.viewDir, geometry.clearcoatNormal, vec3( DEFAULT_SPECULAR_COEFFICIENT ), material.clearcoatRoughness );\n\t#else\n\t\tfloat clearcoatDHR = 0.0;\n\t#endif\n\t#ifdef USE_SHEEN\n\t\treflectedLight.directSpecular += ( 1.0 - clearcoatDHR ) * irradiance * BRDF_Specular_Sheen(\n\t\t\tmaterial.specularRoughness,\n\t\t\tdirectLight.direction,\n\t\t\tgeometry,\n\t\t\tmaterial.sheenColor\n\t\t);\n\t#else\n\t\treflectedLight.directSpecular += ( 1.0 - clearcoatDHR ) * irradiance * BRDF_Specular_GGX( directLight, geometry.viewDir, geometry.normal, material.specularColor, material.specularRoughness);\n\t#endif\n\treflectedLight.directDiffuse += ( 1.0 - clearcoatDHR ) * irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\n}\nvoid RE_IndirectDiffuse_Physical( const in vec3 irradiance, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\n}\nvoid RE_IndirectSpecular_Physical( const in vec3 radiance, const in vec3 irradiance, const in vec3 clearcoatRadiance, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight) {\n\t#ifdef CLEARCOAT\n\t\tfloat ccDotNV = saturate( dot( geometry.clearcoatNormal, geometry.viewDir ) );\n\t\treflectedLight.indirectSpecular += clearcoatRadiance * material.clearcoat * BRDF_Specular_GGX_Environment( geometry.viewDir, geometry.clearcoatNormal, vec3( DEFAULT_SPECULAR_COEFFICIENT ), material.clearcoatRoughness );\n\t\tfloat ccDotNL = ccDotNV;\n\t\tfloat clearcoatDHR = material.clearcoat * clearcoatDHRApprox( material.clearcoatRoughness, ccDotNL );\n\t#else\n\t\tfloat clearcoatDHR = 0.0;\n\t#endif\n\tfloat clearcoatInv = 1.0 - clearcoatDHR;\n\tvec3 singleScattering = vec3( 0.0 );\n\tvec3 multiScattering = vec3( 0.0 );\n\tvec3 cosineWeightedIrradiance = irradiance * RECIPROCAL_PI;\n\tBRDF_Specular_Multiscattering_Environment( geometry, material.specularColor, material.specularRoughness, singleScattering, multiScattering );\n\tvec3 diffuse = material.diffuseColor * ( 1.0 - ( singleScattering + multiScattering ) );\n\treflectedLight.indirectSpecular += clearcoatInv * radiance * singleScattering;\n\treflectedLight.indirectSpecular += multiScattering * cosineWeightedIrradiance;\n\treflectedLight.indirectDiffuse += diffuse * cosineWeightedIrradiance;\n}\n#define RE_Direct\t\t\t\tRE_Direct_Physical\n#define RE_Direct_RectArea\t\tRE_Direct_RectArea_Physical\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_Physical\n#define RE_IndirectSpecular\t\tRE_IndirectSpecular_Physical\nfloat computeSpecularOcclusion( const in float dotNV, const in float ambientOcclusion, const in float roughness ) {\n\treturn saturate( pow( dotNV + ambientOcclusion, exp2( - 16.0 * roughness - 1.0 ) ) - 1.0 + ambientOcclusion );\n}";
16736
16737 var lights_fragment_begin = "\nGeometricContext geometry;\ngeometry.position = - vViewPosition;\ngeometry.normal = normal;\ngeometry.viewDir = ( isOrthographic ) ? vec3( 0, 0, 1 ) : normalize( vViewPosition );\n#ifdef CLEARCOAT\n\tgeometry.clearcoatNormal = clearcoatNormal;\n#endif\nIncidentLight directLight;\n#if ( NUM_POINT_LIGHTS > 0 ) && defined( RE_Direct )\n\tPointLight pointLight;\n\t#if defined( USE_SHADOWMAP ) && NUM_POINT_LIGHT_SHADOWS > 0\n\tPointLightShadow pointLightShadow;\n\t#endif\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {\n\t\tpointLight = pointLights[ i ];\n\t\tgetPointDirectLightIrradiance( pointLight, geometry, directLight );\n\t\t#if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_POINT_LIGHT_SHADOWS )\n\t\tpointLightShadow = pointLightShadows[ i ];\n\t\tdirectLight.color *= all( bvec2( directLight.visible, receiveShadow ) ) ? getPointShadow( pointShadowMap[ i ], pointLightShadow.shadowMapSize, pointLightShadow.shadowBias, pointLightShadow.shadowRadius, vPointShadowCoord[ i ], pointLightShadow.shadowCameraNear, pointLightShadow.shadowCameraFar ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometry, material, reflectedLight );\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if ( NUM_SPOT_LIGHTS > 0 ) && defined( RE_Direct )\n\tSpotLight spotLight;\n\t#if defined( USE_SHADOWMAP ) && NUM_SPOT_LIGHT_SHADOWS > 0\n\tSpotLightShadow spotLightShadow;\n\t#endif\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {\n\t\tspotLight = spotLights[ i ];\n\t\tgetSpotDirectLightIrradiance( spotLight, geometry, directLight );\n\t\t#if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS )\n\t\tspotLightShadow = spotLightShadows[ i ];\n\t\tdirectLight.color *= all( bvec2( directLight.visible, receiveShadow ) ) ? getShadow( spotShadowMap[ i ], spotLightShadow.shadowMapSize, spotLightShadow.shadowBias, spotLightShadow.shadowRadius, vSpotShadowCoord[ i ] ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometry, material, reflectedLight );\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if ( NUM_DIR_LIGHTS > 0 ) && defined( RE_Direct )\n\tDirectionalLight directionalLight;\n\t#if defined( USE_SHADOWMAP ) && NUM_DIR_LIGHT_SHADOWS > 0\n\tDirectionalLightShadow directionalLightShadow;\n\t#endif\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\n\t\tdirectionalLight = directionalLights[ i ];\n\t\tgetDirectionalDirectLightIrradiance( directionalLight, geometry, directLight );\n\t\t#if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_DIR_LIGHT_SHADOWS )\n\t\tdirectionalLightShadow = directionalLightShadows[ i ];\n\t\tdirectLight.color *= all( bvec2( directLight.visible, receiveShadow ) ) ? getShadow( directionalShadowMap[ i ], directionalLightShadow.shadowMapSize, directionalLightShadow.shadowBias, directionalLightShadow.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometry, material, reflectedLight );\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if ( NUM_RECT_AREA_LIGHTS > 0 ) && defined( RE_Direct_RectArea )\n\tRectAreaLight rectAreaLight;\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_RECT_AREA_LIGHTS; i ++ ) {\n\t\trectAreaLight = rectAreaLights[ i ];\n\t\tRE_Direct_RectArea( rectAreaLight, geometry, material, reflectedLight );\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if defined( RE_IndirectDiffuse )\n\tvec3 iblIrradiance = vec3( 0.0 );\n\tvec3 irradiance = getAmbientLightIrradiance( ambientLightColor );\n\tirradiance += getLightProbeIrradiance( lightProbe, geometry );\n\t#if ( NUM_HEMI_LIGHTS > 0 )\n\t\t#pragma unroll_loop_start\n\t\tfor ( int i = 0; i < NUM_HEMI_LIGHTS; i ++ ) {\n\t\t\tirradiance += getHemisphereLightIrradiance( hemisphereLights[ i ], geometry );\n\t\t}\n\t\t#pragma unroll_loop_end\n\t#endif\n#endif\n#if defined( RE_IndirectSpecular )\n\tvec3 radiance = vec3( 0.0 );\n\tvec3 clearcoatRadiance = vec3( 0.0 );\n#endif";
16738
16739 var lights_fragment_maps = "#if defined( RE_IndirectDiffuse )\n\t#ifdef USE_LIGHTMAP\n\t\tvec4 lightMapTexel= texture2D( lightMap, vUv2 );\n\t\tvec3 lightMapIrradiance = lightMapTexelToLinear( lightMapTexel ).rgb * lightMapIntensity;\n\t\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\t\tlightMapIrradiance *= PI;\n\t\t#endif\n\t\tirradiance += lightMapIrradiance;\n\t#endif\n\t#if defined( USE_ENVMAP ) && defined( STANDARD ) && defined( ENVMAP_TYPE_CUBE_UV )\n\t\tiblIrradiance += getLightProbeIndirectIrradiance( geometry, maxMipLevel );\n\t#endif\n#endif\n#if defined( USE_ENVMAP ) && defined( RE_IndirectSpecular )\n\tradiance += getLightProbeIndirectRadiance( geometry.viewDir, geometry.normal, material.specularRoughness, maxMipLevel );\n\t#ifdef CLEARCOAT\n\t\tclearcoatRadiance += getLightProbeIndirectRadiance( geometry.viewDir, geometry.clearcoatNormal, material.clearcoatRoughness, maxMipLevel );\n\t#endif\n#endif";
16740
16741 var lights_fragment_end = "#if defined( RE_IndirectDiffuse )\n\tRE_IndirectDiffuse( irradiance, geometry, material, reflectedLight );\n#endif\n#if defined( RE_IndirectSpecular )\n\tRE_IndirectSpecular( radiance, iblIrradiance, clearcoatRadiance, geometry, material, reflectedLight );\n#endif";
16742
16743 var logdepthbuf_fragment = "#if defined( USE_LOGDEPTHBUF ) && defined( USE_LOGDEPTHBUF_EXT )\n\tgl_FragDepthEXT = vIsPerspective == 0.0 ? gl_FragCoord.z : log2( vFragDepth ) * logDepthBufFC * 0.5;\n#endif";
16744
16745 var logdepthbuf_pars_fragment = "#if defined( USE_LOGDEPTHBUF ) && defined( USE_LOGDEPTHBUF_EXT )\n\tuniform float logDepthBufFC;\n\tvarying float vFragDepth;\n\tvarying float vIsPerspective;\n#endif";
16746
16747 var logdepthbuf_pars_vertex = "#ifdef USE_LOGDEPTHBUF\n\t#ifdef USE_LOGDEPTHBUF_EXT\n\t\tvarying float vFragDepth;\n\t\tvarying float vIsPerspective;\n\t#else\n\t\tuniform float logDepthBufFC;\n\t#endif\n#endif";
16748
16749 var logdepthbuf_vertex = "#ifdef USE_LOGDEPTHBUF\n\t#ifdef USE_LOGDEPTHBUF_EXT\n\t\tvFragDepth = 1.0 + gl_Position.w;\n\t\tvIsPerspective = float( isPerspectiveMatrix( projectionMatrix ) );\n\t#else\n\t\tif ( isPerspectiveMatrix( projectionMatrix ) ) {\n\t\t\tgl_Position.z = log2( max( EPSILON, gl_Position.w + 1.0 ) ) * logDepthBufFC - 1.0;\n\t\t\tgl_Position.z *= gl_Position.w;\n\t\t}\n\t#endif\n#endif";
16750
16751 var map_fragment = "#ifdef USE_MAP\n\tvec4 texelColor = texture2D( map, vUv );\n\ttexelColor = mapTexelToLinear( texelColor );\n\tdiffuseColor *= texelColor;\n#endif";
16752
16753 var map_pars_fragment = "#ifdef USE_MAP\n\tuniform sampler2D map;\n#endif";
16754
16755 var map_particle_fragment = "#if defined( USE_MAP ) || defined( USE_ALPHAMAP )\n\tvec2 uv = ( uvTransform * vec3( gl_PointCoord.x, 1.0 - gl_PointCoord.y, 1 ) ).xy;\n#endif\n#ifdef USE_MAP\n\tvec4 mapTexel = texture2D( map, uv );\n\tdiffuseColor *= mapTexelToLinear( mapTexel );\n#endif\n#ifdef USE_ALPHAMAP\n\tdiffuseColor.a *= texture2D( alphaMap, uv ).g;\n#endif";
16756
16757 var map_particle_pars_fragment = "#if defined( USE_MAP ) || defined( USE_ALPHAMAP )\n\tuniform mat3 uvTransform;\n#endif\n#ifdef USE_MAP\n\tuniform sampler2D map;\n#endif\n#ifdef USE_ALPHAMAP\n\tuniform sampler2D alphaMap;\n#endif";
16758
16759 var metalnessmap_fragment = "float metalnessFactor = metalness;\n#ifdef USE_METALNESSMAP\n\tvec4 texelMetalness = texture2D( metalnessMap, vUv );\n\tmetalnessFactor *= texelMetalness.b;\n#endif";
16760
16761 var metalnessmap_pars_fragment = "#ifdef USE_METALNESSMAP\n\tuniform sampler2D metalnessMap;\n#endif";
16762
16763 var morphnormal_vertex = "#ifdef USE_MORPHNORMALS\n\tobjectNormal *= morphTargetBaseInfluence;\n\tobjectNormal += morphNormal0 * morphTargetInfluences[ 0 ];\n\tobjectNormal += morphNormal1 * morphTargetInfluences[ 1 ];\n\tobjectNormal += morphNormal2 * morphTargetInfluences[ 2 ];\n\tobjectNormal += morphNormal3 * morphTargetInfluences[ 3 ];\n#endif";
16764
16765 var morphtarget_pars_vertex = "#ifdef USE_MORPHTARGETS\n\tuniform float morphTargetBaseInfluence;\n\t#ifndef USE_MORPHNORMALS\n\t\tuniform float morphTargetInfluences[ 8 ];\n\t#else\n\t\tuniform float morphTargetInfluences[ 4 ];\n\t#endif\n#endif";
16766
16767 var morphtarget_vertex = "#ifdef USE_MORPHTARGETS\n\ttransformed *= morphTargetBaseInfluence;\n\ttransformed += morphTarget0 * morphTargetInfluences[ 0 ];\n\ttransformed += morphTarget1 * morphTargetInfluences[ 1 ];\n\ttransformed += morphTarget2 * morphTargetInfluences[ 2 ];\n\ttransformed += morphTarget3 * morphTargetInfluences[ 3 ];\n\t#ifndef USE_MORPHNORMALS\n\t\ttransformed += morphTarget4 * morphTargetInfluences[ 4 ];\n\t\ttransformed += morphTarget5 * morphTargetInfluences[ 5 ];\n\t\ttransformed += morphTarget6 * morphTargetInfluences[ 6 ];\n\t\ttransformed += morphTarget7 * morphTargetInfluences[ 7 ];\n\t#endif\n#endif";
16768
16769 var normal_fragment_begin = "#ifdef FLAT_SHADED\n\tvec3 fdx = vec3( dFdx( vViewPosition.x ), dFdx( vViewPosition.y ), dFdx( vViewPosition.z ) );\n\tvec3 fdy = vec3( dFdy( vViewPosition.x ), dFdy( vViewPosition.y ), dFdy( vViewPosition.z ) );\n\tvec3 normal = normalize( cross( fdx, fdy ) );\n#else\n\tvec3 normal = normalize( vNormal );\n\t#ifdef DOUBLE_SIDED\n\t\tnormal = normal * ( float( gl_FrontFacing ) * 2.0 - 1.0 );\n\t#endif\n\t#ifdef USE_TANGENT\n\t\tvec3 tangent = normalize( vTangent );\n\t\tvec3 bitangent = normalize( vBitangent );\n\t\t#ifdef DOUBLE_SIDED\n\t\t\ttangent = tangent * ( float( gl_FrontFacing ) * 2.0 - 1.0 );\n\t\t\tbitangent = bitangent * ( float( gl_FrontFacing ) * 2.0 - 1.0 );\n\t\t#endif\n\t\t#if defined( TANGENTSPACE_NORMALMAP ) || defined( USE_CLEARCOAT_NORMALMAP )\n\t\t\tmat3 vTBN = mat3( tangent, bitangent, normal );\n\t\t#endif\n\t#endif\n#endif\nvec3 geometryNormal = normal;";
16770
16771 var normal_fragment_maps = "#ifdef OBJECTSPACE_NORMALMAP\n\tnormal = texture2D( normalMap, vUv ).xyz * 2.0 - 1.0;\n\t#ifdef FLIP_SIDED\n\t\tnormal = - normal;\n\t#endif\n\t#ifdef DOUBLE_SIDED\n\t\tnormal = normal * ( float( gl_FrontFacing ) * 2.0 - 1.0 );\n\t#endif\n\tnormal = normalize( normalMatrix * normal );\n#elif defined( TANGENTSPACE_NORMALMAP )\n\tvec3 mapN = texture2D( normalMap, vUv ).xyz * 2.0 - 1.0;\n\tmapN.xy *= normalScale;\n\t#ifdef USE_TANGENT\n\t\tnormal = normalize( vTBN * mapN );\n\t#else\n\t\tnormal = perturbNormal2Arb( -vViewPosition, normal, mapN );\n\t#endif\n#elif defined( USE_BUMPMAP )\n\tnormal = perturbNormalArb( -vViewPosition, normal, dHdxy_fwd() );\n#endif";
16772
16773 var normalmap_pars_fragment = "#ifdef USE_NORMALMAP\n\tuniform sampler2D normalMap;\n\tuniform vec2 normalScale;\n#endif\n#ifdef OBJECTSPACE_NORMALMAP\n\tuniform mat3 normalMatrix;\n#endif\n#if ! defined ( USE_TANGENT ) && ( defined ( TANGENTSPACE_NORMALMAP ) || defined ( USE_CLEARCOAT_NORMALMAP ) )\n\tvec3 perturbNormal2Arb( vec3 eye_pos, vec3 surf_norm, vec3 mapN ) {\n\t\tvec3 q0 = vec3( dFdx( eye_pos.x ), dFdx( eye_pos.y ), dFdx( eye_pos.z ) );\n\t\tvec3 q1 = vec3( dFdy( eye_pos.x ), dFdy( eye_pos.y ), dFdy( eye_pos.z ) );\n\t\tvec2 st0 = dFdx( vUv.st );\n\t\tvec2 st1 = dFdy( vUv.st );\n\t\tfloat scale = sign( st1.t * st0.s - st0.t * st1.s );\n\t\tvec3 S = normalize( ( q0 * st1.t - q1 * st0.t ) * scale );\n\t\tvec3 T = normalize( ( - q0 * st1.s + q1 * st0.s ) * scale );\n\t\tvec3 N = normalize( surf_norm );\n\t\tmat3 tsn = mat3( S, T, N );\n\t\tmapN.xy *= ( float( gl_FrontFacing ) * 2.0 - 1.0 );\n\t\treturn normalize( tsn * mapN );\n\t}\n#endif";
16774
16775 var clearcoat_normal_fragment_begin = "#ifdef CLEARCOAT\n\tvec3 clearcoatNormal = geometryNormal;\n#endif";
16776
16777 var clearcoat_normal_fragment_maps = "#ifdef USE_CLEARCOAT_NORMALMAP\n\tvec3 clearcoatMapN = texture2D( clearcoatNormalMap, vUv ).xyz * 2.0 - 1.0;\n\tclearcoatMapN.xy *= clearcoatNormalScale;\n\t#ifdef USE_TANGENT\n\t\tclearcoatNormal = normalize( vTBN * clearcoatMapN );\n\t#else\n\t\tclearcoatNormal = perturbNormal2Arb( - vViewPosition, clearcoatNormal, clearcoatMapN );\n\t#endif\n#endif";
16778
16779 var clearcoat_pars_fragment = "#ifdef USE_CLEARCOATMAP\n\tuniform sampler2D clearcoatMap;\n#endif\n#ifdef USE_CLEARCOAT_ROUGHNESSMAP\n\tuniform sampler2D clearcoatRoughnessMap;\n#endif\n#ifdef USE_CLEARCOAT_NORMALMAP\n\tuniform sampler2D clearcoatNormalMap;\n\tuniform vec2 clearcoatNormalScale;\n#endif";
16780
16781 var packing = "vec3 packNormalToRGB( const in vec3 normal ) {\n\treturn normalize( normal ) * 0.5 + 0.5;\n}\nvec3 unpackRGBToNormal( const in vec3 rgb ) {\n\treturn 2.0 * rgb.xyz - 1.0;\n}\nconst float PackUpscale = 256. / 255.;const float UnpackDownscale = 255. / 256.;\nconst vec3 PackFactors = vec3( 256. * 256. * 256., 256. * 256., 256. );\nconst vec4 UnpackFactors = UnpackDownscale / vec4( PackFactors, 1. );\nconst float ShiftRight8 = 1. / 256.;\nvec4 packDepthToRGBA( const in float v ) {\n\tvec4 r = vec4( fract( v * PackFactors ), v );\n\tr.yzw -= r.xyz * ShiftRight8;\treturn r * PackUpscale;\n}\nfloat unpackRGBAToDepth( const in vec4 v ) {\n\treturn dot( v, UnpackFactors );\n}\nvec4 pack2HalfToRGBA( vec2 v ) {\n\tvec4 r = vec4( v.x, fract( v.x * 255.0 ), v.y, fract( v.y * 255.0 ));\n\treturn vec4( r.x - r.y / 255.0, r.y, r.z - r.w / 255.0, r.w);\n}\nvec2 unpackRGBATo2Half( vec4 v ) {\n\treturn vec2( v.x + ( v.y / 255.0 ), v.z + ( v.w / 255.0 ) );\n}\nfloat viewZToOrthographicDepth( const in float viewZ, const in float near, const in float far ) {\n\treturn ( viewZ + near ) / ( near - far );\n}\nfloat orthographicDepthToViewZ( const in float linearClipZ, const in float near, const in float far ) {\n\treturn linearClipZ * ( near - far ) - near;\n}\nfloat viewZToPerspectiveDepth( const in float viewZ, const in float near, const in float far ) {\n\treturn (( near + viewZ ) * far ) / (( far - near ) * viewZ );\n}\nfloat perspectiveDepthToViewZ( const in float invClipZ, const in float near, const in float far ) {\n\treturn ( near * far ) / ( ( far - near ) * invClipZ - far );\n}";
16782
16783 var premultiplied_alpha_fragment = "#ifdef PREMULTIPLIED_ALPHA\n\tgl_FragColor.rgb *= gl_FragColor.a;\n#endif";
16784
16785 var project_vertex = "vec4 mvPosition = vec4( transformed, 1.0 );\n#ifdef USE_INSTANCING\n\tmvPosition = instanceMatrix * mvPosition;\n#endif\nmvPosition = modelViewMatrix * mvPosition;\ngl_Position = projectionMatrix * mvPosition;";
16786
16787 var dithering_fragment = "#ifdef DITHERING\n\tgl_FragColor.rgb = dithering( gl_FragColor.rgb );\n#endif";
16788
16789 var dithering_pars_fragment = "#ifdef DITHERING\n\tvec3 dithering( vec3 color ) {\n\t\tfloat grid_position = rand( gl_FragCoord.xy );\n\t\tvec3 dither_shift_RGB = vec3( 0.25 / 255.0, -0.25 / 255.0, 0.25 / 255.0 );\n\t\tdither_shift_RGB = mix( 2.0 * dither_shift_RGB, -2.0 * dither_shift_RGB, grid_position );\n\t\treturn color + dither_shift_RGB;\n\t}\n#endif";
16790
16791 var roughnessmap_fragment = "float roughnessFactor = roughness;\n#ifdef USE_ROUGHNESSMAP\n\tvec4 texelRoughness = texture2D( roughnessMap, vUv );\n\troughnessFactor *= texelRoughness.g;\n#endif";
16792
16793 var roughnessmap_pars_fragment = "#ifdef USE_ROUGHNESSMAP\n\tuniform sampler2D roughnessMap;\n#endif";
16794
16795 var shadowmap_pars_fragment = "#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHT_SHADOWS > 0\n\t\tuniform sampler2D directionalShadowMap[ NUM_DIR_LIGHT_SHADOWS ];\n\t\tvarying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHT_SHADOWS ];\n\t\tstruct DirectionalLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t};\n\t\tuniform DirectionalLightShadow directionalLightShadows[ NUM_DIR_LIGHT_SHADOWS ];\n\t#endif\n\t#if NUM_SPOT_LIGHT_SHADOWS > 0\n\t\tuniform sampler2D spotShadowMap[ NUM_SPOT_LIGHT_SHADOWS ];\n\t\tvarying vec4 vSpotShadowCoord[ NUM_SPOT_LIGHT_SHADOWS ];\n\t\tstruct SpotLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t};\n\t\tuniform SpotLightShadow spotLightShadows[ NUM_SPOT_LIGHT_SHADOWS ];\n\t#endif\n\t#if NUM_POINT_LIGHT_SHADOWS > 0\n\t\tuniform sampler2D pointShadowMap[ NUM_POINT_LIGHT_SHADOWS ];\n\t\tvarying vec4 vPointShadowCoord[ NUM_POINT_LIGHT_SHADOWS ];\n\t\tstruct PointLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t\tfloat shadowCameraNear;\n\t\t\tfloat shadowCameraFar;\n\t\t};\n\t\tuniform PointLightShadow pointLightShadows[ NUM_POINT_LIGHT_SHADOWS ];\n\t#endif\n\tfloat texture2DCompare( sampler2D depths, vec2 uv, float compare ) {\n\t\treturn step( compare, unpackRGBAToDepth( texture2D( depths, uv ) ) );\n\t}\n\tvec2 texture2DDistribution( sampler2D shadow, vec2 uv ) {\n\t\treturn unpackRGBATo2Half( texture2D( shadow, uv ) );\n\t}\n\tfloat VSMShadow (sampler2D shadow, vec2 uv, float compare ){\n\t\tfloat occlusion = 1.0;\n\t\tvec2 distribution = texture2DDistribution( shadow, uv );\n\t\tfloat hard_shadow = step( compare , distribution.x );\n\t\tif (hard_shadow != 1.0 ) {\n\t\t\tfloat distance = compare - distribution.x ;\n\t\t\tfloat variance = max( 0.00000, distribution.y * distribution.y );\n\t\t\tfloat softness_probability = variance / (variance + distance * distance );\t\t\tsoftness_probability = clamp( ( softness_probability - 0.3 ) / ( 0.95 - 0.3 ), 0.0, 1.0 );\t\t\tocclusion = clamp( max( hard_shadow, softness_probability ), 0.0, 1.0 );\n\t\t}\n\t\treturn occlusion;\n\t}\n\tfloat getShadow( sampler2D shadowMap, vec2 shadowMapSize, float shadowBias, float shadowRadius, vec4 shadowCoord ) {\n\t\tfloat shadow = 1.0;\n\t\tshadowCoord.xyz /= shadowCoord.w;\n\t\tshadowCoord.z += shadowBias;\n\t\tbvec4 inFrustumVec = bvec4 ( shadowCoord.x >= 0.0, shadowCoord.x <= 1.0, shadowCoord.y >= 0.0, shadowCoord.y <= 1.0 );\n\t\tbool inFrustum = all( inFrustumVec );\n\t\tbvec2 frustumTestVec = bvec2( inFrustum, shadowCoord.z <= 1.0 );\n\t\tbool frustumTest = all( frustumTestVec );\n\t\tif ( frustumTest ) {\n\t\t#if defined( SHADOWMAP_TYPE_PCF )\n\t\t\tvec2 texelSize = vec2( 1.0 ) / shadowMapSize;\n\t\t\tfloat dx0 = - texelSize.x * shadowRadius;\n\t\t\tfloat dy0 = - texelSize.y * shadowRadius;\n\t\t\tfloat dx1 = + texelSize.x * shadowRadius;\n\t\t\tfloat dy1 = + texelSize.y * shadowRadius;\n\t\t\tfloat dx2 = dx0 / 2.0;\n\t\t\tfloat dy2 = dy0 / 2.0;\n\t\t\tfloat dx3 = dx1 / 2.0;\n\t\t\tfloat dy3 = dy1 / 2.0;\n\t\t\tshadow = (\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx2, dy2 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy2 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx3, dy2 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx2, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy, shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx3, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx2, dy3 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy3 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx3, dy3 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, dy1 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy1 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, dy1 ), shadowCoord.z )\n\t\t\t) * ( 1.0 / 17.0 );\n\t\t#elif defined( SHADOWMAP_TYPE_PCF_SOFT )\n\t\t\tvec2 texelSize = vec2( 1.0 ) / shadowMapSize;\n\t\t\tfloat dx = texelSize.x;\n\t\t\tfloat dy = texelSize.y;\n\t\t\tvec2 uv = shadowCoord.xy;\n\t\t\tvec2 f = fract( uv * shadowMapSize + 0.5 );\n\t\t\tuv -= f * texelSize;\n\t\t\tshadow = (\n\t\t\t\ttexture2DCompare( shadowMap, uv, shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, uv + vec2( dx, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, uv + vec2( 0.0, dy ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, uv + texelSize, shadowCoord.z ) +\n\t\t\t\tmix( texture2DCompare( shadowMap, uv + vec2( -dx, 0.0 ), shadowCoord.z ), \n\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, 0.0 ), shadowCoord.z ),\n\t\t\t\t\t f.x ) +\n\t\t\t\tmix( texture2DCompare( shadowMap, uv + vec2( -dx, dy ), shadowCoord.z ), \n\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, dy ), shadowCoord.z ),\n\t\t\t\t\t f.x ) +\n\t\t\t\tmix( texture2DCompare( shadowMap, uv + vec2( 0.0, -dy ), shadowCoord.z ), \n\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 0.0, 2.0 * dy ), shadowCoord.z ),\n\t\t\t\t\t f.y ) +\n\t\t\t\tmix( texture2DCompare( shadowMap, uv + vec2( dx, -dy ), shadowCoord.z ), \n\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( dx, 2.0 * dy ), shadowCoord.z ),\n\t\t\t\t\t f.y ) +\n\t\t\t\tmix( mix( texture2DCompare( shadowMap, uv + vec2( -dx, -dy ), shadowCoord.z ), \n\t\t\t\t\t\t  texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, -dy ), shadowCoord.z ),\n\t\t\t\t\t\t  f.x ),\n\t\t\t\t\t mix( texture2DCompare( shadowMap, uv + vec2( -dx, 2.0 * dy ), shadowCoord.z ), \n\t\t\t\t\t\t  texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, 2.0 * dy ), shadowCoord.z ),\n\t\t\t\t\t\t  f.x ),\n\t\t\t\t\t f.y )\n\t\t\t) * ( 1.0 / 9.0 );\n\t\t#elif defined( SHADOWMAP_TYPE_VSM )\n\t\t\tshadow = VSMShadow( shadowMap, shadowCoord.xy, shadowCoord.z );\n\t\t#else\n\t\t\tshadow = texture2DCompare( shadowMap, shadowCoord.xy, shadowCoord.z );\n\t\t#endif\n\t\t}\n\t\treturn shadow;\n\t}\n\tvec2 cubeToUV( vec3 v, float texelSizeY ) {\n\t\tvec3 absV = abs( v );\n\t\tfloat scaleToCube = 1.0 / max( absV.x, max( absV.y, absV.z ) );\n\t\tabsV *= scaleToCube;\n\t\tv *= scaleToCube * ( 1.0 - 2.0 * texelSizeY );\n\t\tvec2 planar = v.xy;\n\t\tfloat almostATexel = 1.5 * texelSizeY;\n\t\tfloat almostOne = 1.0 - almostATexel;\n\t\tif ( absV.z >= almostOne ) {\n\t\t\tif ( v.z > 0.0 )\n\t\t\t\tplanar.x = 4.0 - v.x;\n\t\t} else if ( absV.x >= almostOne ) {\n\t\t\tfloat signX = sign( v.x );\n\t\t\tplanar.x = v.z * signX + 2.0 * signX;\n\t\t} else if ( absV.y >= almostOne ) {\n\t\t\tfloat signY = sign( v.y );\n\t\t\tplanar.x = v.x + 2.0 * signY + 2.0;\n\t\t\tplanar.y = v.z * signY - 2.0;\n\t\t}\n\t\treturn vec2( 0.125, 0.25 ) * planar + vec2( 0.375, 0.75 );\n\t}\n\tfloat getPointShadow( sampler2D shadowMap, vec2 shadowMapSize, float shadowBias, float shadowRadius, vec4 shadowCoord, float shadowCameraNear, float shadowCameraFar ) {\n\t\tvec2 texelSize = vec2( 1.0 ) / ( shadowMapSize * vec2( 4.0, 2.0 ) );\n\t\tvec3 lightToPosition = shadowCoord.xyz;\n\t\tfloat dp = ( length( lightToPosition ) - shadowCameraNear ) / ( shadowCameraFar - shadowCameraNear );\t\tdp += shadowBias;\n\t\tvec3 bd3D = normalize( lightToPosition );\n\t\t#if defined( SHADOWMAP_TYPE_PCF ) || defined( SHADOWMAP_TYPE_PCF_SOFT ) || defined( SHADOWMAP_TYPE_VSM )\n\t\t\tvec2 offset = vec2( - 1, 1 ) * shadowRadius * texelSize.y;\n\t\t\treturn (\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xyy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yyy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xyx, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yyx, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xxy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yxy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xxx, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yxx, texelSize.y ), dp )\n\t\t\t) * ( 1.0 / 9.0 );\n\t\t#else\n\t\t\treturn texture2DCompare( shadowMap, cubeToUV( bd3D, texelSize.y ), dp );\n\t\t#endif\n\t}\n#endif";
16796
16797 var shadowmap_pars_vertex = "#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHT_SHADOWS > 0\n\t\tuniform mat4 directionalShadowMatrix[ NUM_DIR_LIGHT_SHADOWS ];\n\t\tvarying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHT_SHADOWS ];\n\t\tstruct DirectionalLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t};\n\t\tuniform DirectionalLightShadow directionalLightShadows[ NUM_DIR_LIGHT_SHADOWS ];\n\t#endif\n\t#if NUM_SPOT_LIGHT_SHADOWS > 0\n\t\tuniform mat4 spotShadowMatrix[ NUM_SPOT_LIGHT_SHADOWS ];\n\t\tvarying vec4 vSpotShadowCoord[ NUM_SPOT_LIGHT_SHADOWS ];\n\t\tstruct SpotLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t};\n\t\tuniform SpotLightShadow spotLightShadows[ NUM_SPOT_LIGHT_SHADOWS ];\n\t#endif\n\t#if NUM_POINT_LIGHT_SHADOWS > 0\n\t\tuniform mat4 pointShadowMatrix[ NUM_POINT_LIGHT_SHADOWS ];\n\t\tvarying vec4 vPointShadowCoord[ NUM_POINT_LIGHT_SHADOWS ];\n\t\tstruct PointLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t\tfloat shadowCameraNear;\n\t\t\tfloat shadowCameraFar;\n\t\t};\n\t\tuniform PointLightShadow pointLightShadows[ NUM_POINT_LIGHT_SHADOWS ];\n\t#endif\n#endif";
16798
16799 var shadowmap_vertex = "#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHT_SHADOWS > 0 || NUM_SPOT_LIGHT_SHADOWS > 0 || NUM_POINT_LIGHT_SHADOWS > 0\n\t\tvec3 shadowWorldNormal = inverseTransformDirection( transformedNormal, viewMatrix );\n\t\tvec4 shadowWorldPosition;\n\t#endif\n\t#if NUM_DIR_LIGHT_SHADOWS > 0\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_DIR_LIGHT_SHADOWS; i ++ ) {\n\t\tshadowWorldPosition = worldPosition + vec4( shadowWorldNormal * directionalLightShadows[ i ].shadowNormalBias, 0 );\n\t\tvDirectionalShadowCoord[ i ] = directionalShadowMatrix[ i ] * shadowWorldPosition;\n\t}\n\t#pragma unroll_loop_end\n\t#endif\n\t#if NUM_SPOT_LIGHT_SHADOWS > 0\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_SPOT_LIGHT_SHADOWS; i ++ ) {\n\t\tshadowWorldPosition = worldPosition + vec4( shadowWorldNormal * spotLightShadows[ i ].shadowNormalBias, 0 );\n\t\tvSpotShadowCoord[ i ] = spotShadowMatrix[ i ] * shadowWorldPosition;\n\t}\n\t#pragma unroll_loop_end\n\t#endif\n\t#if NUM_POINT_LIGHT_SHADOWS > 0\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_POINT_LIGHT_SHADOWS; i ++ ) {\n\t\tshadowWorldPosition = worldPosition + vec4( shadowWorldNormal * pointLightShadows[ i ].shadowNormalBias, 0 );\n\t\tvPointShadowCoord[ i ] = pointShadowMatrix[ i ] * shadowWorldPosition;\n\t}\n\t#pragma unroll_loop_end\n\t#endif\n#endif";
16800
16801 var shadowmask_pars_fragment = "float getShadowMask() {\n\tfloat shadow = 1.0;\n\t#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHT_SHADOWS > 0\n\tDirectionalLightShadow directionalLight;\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_DIR_LIGHT_SHADOWS; i ++ ) {\n\t\tdirectionalLight = directionalLightShadows[ i ];\n\t\tshadow *= receiveShadow ? getShadow( directionalShadowMap[ i ], directionalLight.shadowMapSize, directionalLight.shadowBias, directionalLight.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0;\n\t}\n\t#pragma unroll_loop_end\n\t#endif\n\t#if NUM_SPOT_LIGHT_SHADOWS > 0\n\tSpotLightShadow spotLight;\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_SPOT_LIGHT_SHADOWS; i ++ ) {\n\t\tspotLight = spotLightShadows[ i ];\n\t\tshadow *= receiveShadow ? getShadow( spotShadowMap[ i ], spotLight.shadowMapSize, spotLight.shadowBias, spotLight.shadowRadius, vSpotShadowCoord[ i ] ) : 1.0;\n\t}\n\t#pragma unroll_loop_end\n\t#endif\n\t#if NUM_POINT_LIGHT_SHADOWS > 0\n\tPointLightShadow pointLight;\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_POINT_LIGHT_SHADOWS; i ++ ) {\n\t\tpointLight = pointLightShadows[ i ];\n\t\tshadow *= receiveShadow ? getPointShadow( pointShadowMap[ i ], pointLight.shadowMapSize, pointLight.shadowBias, pointLight.shadowRadius, vPointShadowCoord[ i ], pointLight.shadowCameraNear, pointLight.shadowCameraFar ) : 1.0;\n\t}\n\t#pragma unroll_loop_end\n\t#endif\n\t#endif\n\treturn shadow;\n}";
16802
16803 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";
16804
16805 var skinning_pars_vertex = "#ifdef USE_SKINNING\n\tuniform mat4 bindMatrix;\n\tuniform mat4 bindMatrixInverse;\n\t#ifdef BONE_TEXTURE\n\t\tuniform highp sampler2D boneTexture;\n\t\tuniform int boneTextureSize;\n\t\tmat4 getBoneMatrix( const in float i ) {\n\t\t\tfloat j = i * 4.0;\n\t\t\tfloat x = mod( j, float( boneTextureSize ) );\n\t\t\tfloat y = floor( j / float( boneTextureSize ) );\n\t\t\tfloat dx = 1.0 / float( boneTextureSize );\n\t\t\tfloat dy = 1.0 / float( boneTextureSize );\n\t\t\ty = dy * ( y + 0.5 );\n\t\t\tvec4 v1 = texture2D( boneTexture, vec2( dx * ( x + 0.5 ), y ) );\n\t\t\tvec4 v2 = texture2D( boneTexture, vec2( dx * ( x + 1.5 ), y ) );\n\t\t\tvec4 v3 = texture2D( boneTexture, vec2( dx * ( x + 2.5 ), y ) );\n\t\t\tvec4 v4 = texture2D( boneTexture, vec2( dx * ( x + 3.5 ), y ) );\n\t\t\tmat4 bone = mat4( v1, v2, v3, v4 );\n\t\t\treturn bone;\n\t\t}\n\t#else\n\t\tuniform mat4 boneMatrices[ MAX_BONES ];\n\t\tmat4 getBoneMatrix( const in float i ) {\n\t\t\tmat4 bone = boneMatrices[ int(i) ];\n\t\t\treturn bone;\n\t\t}\n\t#endif\n#endif";
16806
16807 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";
16808
16809 var skinnormal_vertex = "#ifdef USE_SKINNING\n\tmat4 skinMatrix = mat4( 0.0 );\n\tskinMatrix += skinWeight.x * boneMatX;\n\tskinMatrix += skinWeight.y * boneMatY;\n\tskinMatrix += skinWeight.z * boneMatZ;\n\tskinMatrix += skinWeight.w * boneMatW;\n\tskinMatrix = bindMatrixInverse * skinMatrix * bindMatrix;\n\tobjectNormal = vec4( skinMatrix * vec4( objectNormal, 0.0 ) ).xyz;\n\t#ifdef USE_TANGENT\n\t\tobjectTangent = vec4( skinMatrix * vec4( objectTangent, 0.0 ) ).xyz;\n\t#endif\n#endif";
16810
16811 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";
16812
16813 var specularmap_pars_fragment = "#ifdef USE_SPECULARMAP\n\tuniform sampler2D specularMap;\n#endif";
16814
16815 var tonemapping_fragment = "#if defined( TONE_MAPPING )\n\tgl_FragColor.rgb = toneMapping( gl_FragColor.rgb );\n#endif";
16816
16817 var tonemapping_pars_fragment = "#ifndef saturate\n#define saturate(a) clamp( a, 0.0, 1.0 )\n#endif\nuniform float toneMappingExposure;\nvec3 LinearToneMapping( vec3 color ) {\n\treturn toneMappingExposure * color;\n}\nvec3 ReinhardToneMapping( vec3 color ) {\n\tcolor *= toneMappingExposure;\n\treturn saturate( color / ( vec3( 1.0 ) + color ) );\n}\nvec3 OptimizedCineonToneMapping( vec3 color ) {\n\tcolor *= toneMappingExposure;\n\tcolor = max( vec3( 0.0 ), color - 0.004 );\n\treturn pow( ( color * ( 6.2 * color + 0.5 ) ) / ( color * ( 6.2 * color + 1.7 ) + 0.06 ), vec3( 2.2 ) );\n}\nvec3 RRTAndODTFit( vec3 v ) {\n\tvec3 a = v * ( v + 0.0245786 ) - 0.000090537;\n\tvec3 b = v * ( 0.983729 * v + 0.4329510 ) + 0.238081;\n\treturn a / b;\n}\nvec3 ACESFilmicToneMapping( vec3 color ) {\n\tconst mat3 ACESInputMat = mat3(\n\t\tvec3( 0.59719, 0.07600, 0.02840 ),\t\tvec3( 0.35458, 0.90834, 0.13383 ),\n\t\tvec3( 0.04823, 0.01566, 0.83777 )\n\t);\n\tconst mat3 ACESOutputMat = mat3(\n\t\tvec3(  1.60475, -0.10208, -0.00327 ),\t\tvec3( -0.53108,  1.10813, -0.07276 ),\n\t\tvec3( -0.07367, -0.00605,  1.07602 )\n\t);\n\tcolor *= toneMappingExposure / 0.6;\n\tcolor = ACESInputMat * color;\n\tcolor = RRTAndODTFit( color );\n\tcolor = ACESOutputMat * color;\n\treturn saturate( color );\n}\nvec3 CustomToneMapping( vec3 color ) { return color; }";
16818
16819 var transmissionmap_fragment = "#ifdef USE_TRANSMISSIONMAP\n\ttotalTransmission *= texture2D( transmissionMap, vUv ).r;\n#endif";
16820
16821 var transmissionmap_pars_fragment = "#ifdef USE_TRANSMISSIONMAP\n\tuniform sampler2D transmissionMap;\n#endif";
16822
16823 var uv_pars_fragment = "#if ( defined( USE_UV ) && ! defined( UVS_VERTEX_ONLY ) )\n\tvarying vec2 vUv;\n#endif";
16824
16825 var uv_pars_vertex = "#ifdef USE_UV\n\t#ifdef UVS_VERTEX_ONLY\n\t\tvec2 vUv;\n\t#else\n\t\tvarying vec2 vUv;\n\t#endif\n\tuniform mat3 uvTransform;\n#endif";
16826
16827 var uv_vertex = "#ifdef USE_UV\n\tvUv = ( uvTransform * vec3( uv, 1 ) ).xy;\n#endif";
16828
16829 var uv2_pars_fragment = "#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\tvarying vec2 vUv2;\n#endif";
16830
16831 var uv2_pars_vertex = "#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\tattribute vec2 uv2;\n\tvarying vec2 vUv2;\n\tuniform mat3 uv2Transform;\n#endif";
16832
16833 var uv2_vertex = "#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\tvUv2 = ( uv2Transform * vec3( uv2, 1 ) ).xy;\n#endif";
16834
16835 var worldpos_vertex = "#if defined( USE_ENVMAP ) || defined( DISTANCE ) || defined ( USE_SHADOWMAP )\n\tvec4 worldPosition = vec4( transformed, 1.0 );\n\t#ifdef USE_INSTANCING\n\t\tworldPosition = instanceMatrix * worldPosition;\n\t#endif\n\tworldPosition = modelMatrix * worldPosition;\n#endif";
16836
16837 var background_frag = "uniform sampler2D t2D;\nvarying vec2 vUv;\nvoid main() {\n\tvec4 texColor = texture2D( t2D, vUv );\n\tgl_FragColor = mapTexelToLinear( texColor );\n\t#include <tonemapping_fragment>\n\t#include <encodings_fragment>\n}";
16838
16839 var background_vert = "varying vec2 vUv;\nuniform mat3 uvTransform;\nvoid main() {\n\tvUv = ( uvTransform * vec3( uv, 1 ) ).xy;\n\tgl_Position = vec4( position.xy, 1.0, 1.0 );\n}";
16840
16841 var cube_frag = "#include <envmap_common_pars_fragment>\nuniform float opacity;\nvarying vec3 vWorldDirection;\n#include <cube_uv_reflection_fragment>\nvoid main() {\n\tvec3 vReflect = vWorldDirection;\n\t#include <envmap_fragment>\n\tgl_FragColor = envColor;\n\tgl_FragColor.a *= opacity;\n\t#include <tonemapping_fragment>\n\t#include <encodings_fragment>\n}";
16842
16843 var cube_vert = "varying vec3 vWorldDirection;\n#include <common>\nvoid main() {\n\tvWorldDirection = transformDirection( position, modelMatrix );\n\t#include <begin_vertex>\n\t#include <project_vertex>\n\tgl_Position.z = gl_Position.w;\n}";
16844
16845 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>\nvarying vec2 vHighPrecisionZW;\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\tfloat fragCoordZ = 0.5 * vHighPrecisionZW[0] / vHighPrecisionZW[1] + 0.5;\n\t#if DEPTH_PACKING == 3200\n\t\tgl_FragColor = vec4( vec3( 1.0 - fragCoordZ ), opacity );\n\t#elif DEPTH_PACKING == 3201\n\t\tgl_FragColor = packDepthToRGBA( fragCoordZ );\n\t#endif\n}";
16846
16847 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>\nvarying vec2 vHighPrecisionZW;\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\tvHighPrecisionZW = gl_Position.zw;\n}";
16848
16849 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}";
16850
16851 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}";
16852
16853 var equirect_frag = "uniform sampler2D tEquirect;\nvarying vec3 vWorldDirection;\n#include <common>\nvoid main() {\n\tvec3 direction = normalize( vWorldDirection );\n\tvec2 sampleUV = equirectUv( direction );\n\tvec4 texColor = texture2D( tEquirect, sampleUV );\n\tgl_FragColor = mapTexelToLinear( texColor );\n\t#include <tonemapping_fragment>\n\t#include <encodings_fragment>\n}";
16854
16855 var equirect_vert = "varying vec3 vWorldDirection;\n#include <common>\nvoid main() {\n\tvWorldDirection = transformDirection( position, modelMatrix );\n\t#include <begin_vertex>\n\t#include <project_vertex>\n}";
16856
16857 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 <tonemapping_fragment>\n\t#include <encodings_fragment>\n\t#include <fog_fragment>\n\t#include <premultiplied_alpha_fragment>\n}";
16858
16859 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 <morphtarget_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\tvLineDistance = scale * lineDistance;\n\t#include <color_vertex>\n\t#include <begin_vertex>\n\t#include <morphtarget_vertex>\n\t#include <project_vertex>\n\t#include <logdepthbuf_vertex>\n\t#include <clipping_planes_vertex>\n\t#include <fog_vertex>\n}";
16860
16861 var meshbasic_frag = "uniform vec3 diffuse;\nuniform float opacity;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include <common>\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 <envmap_common_pars_fragment>\n#include <envmap_pars_fragment>\n#include <cube_uv_reflection_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\n\t\tvec4 lightMapTexel= texture2D( lightMap, vUv2 );\n\t\treflectedLight.indirectDiffuse += lightMapTexelToLinear( lightMapTexel ).rgb * lightMapIntensity;\n\t#else\n\t\treflectedLight.indirectDiffuse += vec3( 1.0 );\n\t#endif\n\t#include <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 <tonemapping_fragment>\n\t#include <encodings_fragment>\n\t#include <fog_fragment>\n\t#include <premultiplied_alpha_fragment>\n\t#include <dithering_fragment>\n}";
16862
16863 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}";
16864
16865 var meshlambert_frag = "uniform vec3 diffuse;\nuniform vec3 emissive;\nuniform float opacity;\nvarying vec3 vLightFront;\nvarying vec3 vIndirectFront;\n#ifdef DOUBLE_SIDED\n\tvarying vec3 vLightBack;\n\tvarying vec3 vIndirectBack;\n#endif\n#include <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_common_pars_fragment>\n#include <envmap_pars_fragment>\n#include <cube_uv_reflection_fragment>\n#include <bsdfs>\n#include <lights_pars_begin>\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\t#ifdef DOUBLE_SIDED\n\t\treflectedLight.indirectDiffuse += ( gl_FrontFacing ) ? vIndirectFront : vIndirectBack;\n\t#else\n\t\treflectedLight.indirectDiffuse += vIndirectFront;\n\t#endif\n\t#include <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}";
16866
16867 var meshlambert_vert = "#define LAMBERT\nvarying vec3 vLightFront;\nvarying vec3 vIndirectFront;\n#ifdef DOUBLE_SIDED\n\tvarying vec3 vLightBack;\n\tvarying vec3 vIndirectBack;\n#endif\n#include <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 <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}";
16868
16869 var meshmatcap_frag = "#define MATCAP\nuniform vec3 diffuse;\nuniform float opacity;\nuniform sampler2D matcap;\nvarying vec3 vViewPosition;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include <common>\n#include <dithering_pars_fragment>\n#include <color_pars_fragment>\n#include <uv_pars_fragment>\n#include <map_pars_fragment>\n#include <alphamap_pars_fragment>\n#include <fog_pars_fragment>\n#include <bumpmap_pars_fragment>\n#include <normalmap_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 <normal_fragment_begin>\n\t#include <normal_fragment_maps>\n\tvec3 viewDir = normalize( vViewPosition );\n\tvec3 x = normalize( vec3( viewDir.z, 0.0, - viewDir.x ) );\n\tvec3 y = cross( viewDir, x );\n\tvec2 uv = vec2( dot( x, normal ), dot( y, normal ) ) * 0.495 + 0.5;\n\t#ifdef USE_MATCAP\n\t\tvec4 matcapColor = texture2D( matcap, uv );\n\t\tmatcapColor = matcapTexelToLinear( matcapColor );\n\t#else\n\t\tvec4 matcapColor = vec4( 1.0 );\n\t#endif\n\tvec3 outgoingLight = diffuseColor.rgb * matcapColor.rgb;\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include <tonemapping_fragment>\n\t#include <encodings_fragment>\n\t#include <fog_fragment>\n\t#include <premultiplied_alpha_fragment>\n\t#include <dithering_fragment>\n}";
16870
16871 var meshmatcap_vert = "#define MATCAP\nvarying vec3 vViewPosition;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include <common>\n#include <uv_pars_vertex>\n#include <color_pars_vertex>\n#include <displacementmap_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 <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#ifndef FLAT_SHADED\n\t\tvNormal = normalize( transformedNormal );\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\t#include <fog_vertex>\n\tvViewPosition = - mvPosition.xyz;\n}";
16872
16873 var meshtoon_frag = "#define TOON\nuniform vec3 diffuse;\nuniform vec3 emissive;\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 <gradientmap_pars_fragment>\n#include <fog_pars_fragment>\n#include <bsdfs>\n#include <lights_pars_begin>\n#include <lights_toon_pars_fragment>\n#include <shadowmap_pars_fragment>\n#include <bumpmap_pars_fragment>\n#include <normalmap_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 <normal_fragment_begin>\n\t#include <normal_fragment_maps>\n\t#include <emissivemap_fragment>\n\t#include <lights_toon_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 + 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}";
16874
16875 var meshtoon_vert = "#define TOON\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}";
16876
16877 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_common_pars_fragment>\n#include <envmap_pars_fragment>\n#include <cube_uv_reflection_fragment>\n#include <fog_pars_fragment>\n#include <bsdfs>\n#include <lights_pars_begin>\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}";
16878
16879 var meshphong_vert = "#define PHONG\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 <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}";
16880
16881 var meshphysical_frag = "#define STANDARD\n#ifdef PHYSICAL\n\t#define REFLECTIVITY\n\t#define CLEARCOAT\n\t#define TRANSMISSION\n#endif\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform float roughness;\nuniform float metalness;\nuniform float opacity;\n#ifdef TRANSMISSION\n\tuniform float transmission;\n#endif\n#ifdef REFLECTIVITY\n\tuniform float reflectivity;\n#endif\n#ifdef CLEARCOAT\n\tuniform float clearcoat;\n\tuniform float clearcoatRoughness;\n#endif\n#ifdef USE_SHEEN\n\tuniform vec3 sheen;\n#endif\nvarying vec3 vViewPosition;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n\t#ifdef USE_TANGENT\n\t\tvarying vec3 vTangent;\n\t\tvarying vec3 vBitangent;\n\t#endif\n#endif\n#include <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 <transmissionmap_pars_fragment>\n#include <bsdfs>\n#include <cube_uv_reflection_fragment>\n#include <envmap_common_pars_fragment>\n#include <envmap_physical_pars_fragment>\n#include <fog_pars_fragment>\n#include <lights_pars_begin>\n#include <lights_physical_pars_fragment>\n#include <shadowmap_pars_fragment>\n#include <bumpmap_pars_fragment>\n#include <normalmap_pars_fragment>\n#include <clearcoat_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#ifdef TRANSMISSION\n\t\tfloat totalTransmission = transmission;\n\t#endif\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 <clearcoat_normal_fragment_begin>\n\t#include <clearcoat_normal_fragment_maps>\n\t#include <emissivemap_fragment>\n\t#include <transmissionmap_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\t#ifdef TRANSMISSION\n\t\tdiffuseColor.a *= mix( saturate( 1. - totalTransmission + linearToRelativeLuminance( reflectedLight.directSpecular + reflectedLight.indirectSpecular ) ), 1.0, metalness );\n\t#endif\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}";
16882
16883 var meshphysical_vert = "#define STANDARD\nvarying vec3 vViewPosition;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n\t#ifdef USE_TANGENT\n\t\tvarying vec3 vTangent;\n\t\tvarying vec3 vBitangent;\n\t#endif\n#endif\n#include <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\t#ifdef USE_TANGENT\n\t\tvTangent = normalize( transformedTangent );\n\t\tvBitangent = normalize( cross( vNormal, vTangent ) * tangent.w );\n\t#endif\n#endif\n\t#include <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}";
16884
16885 var normal_frag = "#define NORMAL\nuniform float opacity;\n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( TANGENTSPACE_NORMALMAP )\n\tvarying vec3 vViewPosition;\n#endif\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n\t#ifdef USE_TANGENT\n\t\tvarying vec3 vTangent;\n\t\tvarying vec3 vBitangent;\n\t#endif\n#endif\n#include <packing>\n#include <uv_pars_fragment>\n#include <bumpmap_pars_fragment>\n#include <normalmap_pars_fragment>\n#include <logdepthbuf_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvoid main() {\n\t#include <clipping_planes_fragment>\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}";
16886
16887 var normal_vert = "#define NORMAL\n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( TANGENTSPACE_NORMALMAP )\n\tvarying vec3 vViewPosition;\n#endif\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n\t#ifdef USE_TANGENT\n\t\tvarying vec3 vTangent;\n\t\tvarying vec3 vBitangent;\n\t#endif\n#endif\n#include <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 <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\t#ifdef USE_TANGENT\n\t\tvTangent = normalize( transformedTangent );\n\t\tvBitangent = normalize( cross( vNormal, vTangent ) * tangent.w );\n\t#endif\n#endif\n\t#include <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#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( TANGENTSPACE_NORMALMAP )\n\tvViewPosition = - mvPosition.xyz;\n#endif\n}";
16888
16889 var points_frag = "uniform vec3 diffuse;\nuniform float opacity;\n#include <common>\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 <tonemapping_fragment>\n\t#include <encodings_fragment>\n\t#include <fog_fragment>\n\t#include <premultiplied_alpha_fragment>\n}";
16890
16891 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\tgl_PointSize = size;\n\t#ifdef USE_SIZEATTENUATION\n\t\tbool isPerspective = isPerspectiveMatrix( projectionMatrix );\n\t\tif ( isPerspective ) gl_PointSize *= ( scale / - mvPosition.z );\n\t#endif\n\t#include <logdepthbuf_vertex>\n\t#include <clipping_planes_vertex>\n\t#include <worldpos_vertex>\n\t#include <fog_vertex>\n}";
16892
16893 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 <tonemapping_fragment>\n\t#include <encodings_fragment>\n\t#include <fog_fragment>\n}";
16894
16895 var shadow_vert = "#include <common>\n#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 <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 <shadowmap_vertex>\n\t#include <fog_vertex>\n}";
16896
16897 var sprite_frag = "uniform vec3 diffuse;\nuniform float opacity;\n#include <common>\n#include <uv_pars_fragment>\n#include <map_pars_fragment>\n#include <alphamap_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_fragment>\n\t#include <alphamap_fragment>\n\t#include <alphatest_fragment>\n\toutgoingLight = diffuseColor.rgb;\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include <tonemapping_fragment>\n\t#include <encodings_fragment>\n\t#include <fog_fragment>\n}";
16898
16899 var sprite_vert = "uniform float rotation;\nuniform vec2 center;\n#include <common>\n#include <uv_pars_vertex>\n#include <fog_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\t#include <uv_vertex>\n\tvec4 mvPosition = modelViewMatrix * vec4( 0.0, 0.0, 0.0, 1.0 );\n\tvec2 scale;\n\tscale.x = length( vec3( modelMatrix[ 0 ].x, modelMatrix[ 0 ].y, modelMatrix[ 0 ].z ) );\n\tscale.y = length( vec3( modelMatrix[ 1 ].x, modelMatrix[ 1 ].y, modelMatrix[ 1 ].z ) );\n\t#ifndef USE_SIZEATTENUATION\n\t\tbool isPerspective = isPerspectiveMatrix( projectionMatrix );\n\t\tif ( isPerspective ) scale *= - mvPosition.z;\n\t#endif\n\tvec2 alignedPosition = ( position.xy - ( center - vec2( 0.5 ) ) ) * scale;\n\tvec2 rotatedPosition;\n\trotatedPosition.x = cos( rotation ) * alignedPosition.x - sin( rotation ) * alignedPosition.y;\n\trotatedPosition.y = sin( rotation ) * alignedPosition.x + cos( rotation ) * alignedPosition.y;\n\tmvPosition.xy += rotatedPosition;\n\tgl_Position = projectionMatrix * mvPosition;\n\t#include <logdepthbuf_vertex>\n\t#include <clipping_planes_vertex>\n\t#include <fog_vertex>\n}";
16900
16901 const ShaderChunk = {
16902         alphamap_fragment: alphamap_fragment,
16903         alphamap_pars_fragment: alphamap_pars_fragment,
16904         alphatest_fragment: alphatest_fragment,
16905         aomap_fragment: aomap_fragment,
16906         aomap_pars_fragment: aomap_pars_fragment,
16907         begin_vertex: begin_vertex,
16908         beginnormal_vertex: beginnormal_vertex,
16909         bsdfs: bsdfs,
16910         bumpmap_pars_fragment: bumpmap_pars_fragment,
16911         clipping_planes_fragment: clipping_planes_fragment,
16912         clipping_planes_pars_fragment: clipping_planes_pars_fragment,
16913         clipping_planes_pars_vertex: clipping_planes_pars_vertex,
16914         clipping_planes_vertex: clipping_planes_vertex,
16915         color_fragment: color_fragment,
16916         color_pars_fragment: color_pars_fragment,
16917         color_pars_vertex: color_pars_vertex,
16918         color_vertex: color_vertex,
16919         common: common$1,
16920         cube_uv_reflection_fragment: cube_uv_reflection_fragment,
16921         defaultnormal_vertex: defaultnormal_vertex,
16922         displacementmap_pars_vertex: displacementmap_pars_vertex,
16923         displacementmap_vertex: displacementmap_vertex,
16924         emissivemap_fragment: emissivemap_fragment,
16925         emissivemap_pars_fragment: emissivemap_pars_fragment,
16926         encodings_fragment: encodings_fragment,
16927         encodings_pars_fragment: encodings_pars_fragment,
16928         envmap_fragment: envmap_fragment,
16929         envmap_common_pars_fragment: envmap_common_pars_fragment,
16930         envmap_pars_fragment: envmap_pars_fragment,
16931         envmap_pars_vertex: envmap_pars_vertex,
16932         envmap_physical_pars_fragment: envmap_physical_pars_fragment,
16933         envmap_vertex: envmap_vertex,
16934         fog_vertex: fog_vertex,
16935         fog_pars_vertex: fog_pars_vertex,
16936         fog_fragment: fog_fragment,
16937         fog_pars_fragment: fog_pars_fragment,
16938         gradientmap_pars_fragment: gradientmap_pars_fragment,
16939         lightmap_fragment: lightmap_fragment,
16940         lightmap_pars_fragment: lightmap_pars_fragment,
16941         lights_lambert_vertex: lights_lambert_vertex,
16942         lights_pars_begin: lights_pars_begin,
16943         lights_toon_fragment: lights_toon_fragment,
16944         lights_toon_pars_fragment: lights_toon_pars_fragment,
16945         lights_phong_fragment: lights_phong_fragment,
16946         lights_phong_pars_fragment: lights_phong_pars_fragment,
16947         lights_physical_fragment: lights_physical_fragment,
16948         lights_physical_pars_fragment: lights_physical_pars_fragment,
16949         lights_fragment_begin: lights_fragment_begin,
16950         lights_fragment_maps: lights_fragment_maps,
16951         lights_fragment_end: lights_fragment_end,
16952         logdepthbuf_fragment: logdepthbuf_fragment,
16953         logdepthbuf_pars_fragment: logdepthbuf_pars_fragment,
16954         logdepthbuf_pars_vertex: logdepthbuf_pars_vertex,
16955         logdepthbuf_vertex: logdepthbuf_vertex,
16956         map_fragment: map_fragment,
16957         map_pars_fragment: map_pars_fragment,
16958         map_particle_fragment: map_particle_fragment,
16959         map_particle_pars_fragment: map_particle_pars_fragment,
16960         metalnessmap_fragment: metalnessmap_fragment,
16961         metalnessmap_pars_fragment: metalnessmap_pars_fragment,
16962         morphnormal_vertex: morphnormal_vertex,
16963         morphtarget_pars_vertex: morphtarget_pars_vertex,
16964         morphtarget_vertex: morphtarget_vertex,
16965         normal_fragment_begin: normal_fragment_begin,
16966         normal_fragment_maps: normal_fragment_maps,
16967         normalmap_pars_fragment: normalmap_pars_fragment,
16968         clearcoat_normal_fragment_begin: clearcoat_normal_fragment_begin,
16969         clearcoat_normal_fragment_maps: clearcoat_normal_fragment_maps,
16970         clearcoat_pars_fragment: clearcoat_pars_fragment,
16971         packing: packing,
16972         premultiplied_alpha_fragment: premultiplied_alpha_fragment,
16973         project_vertex: project_vertex,
16974         dithering_fragment: dithering_fragment,
16975         dithering_pars_fragment: dithering_pars_fragment,
16976         roughnessmap_fragment: roughnessmap_fragment,
16977         roughnessmap_pars_fragment: roughnessmap_pars_fragment,
16978         shadowmap_pars_fragment: shadowmap_pars_fragment,
16979         shadowmap_pars_vertex: shadowmap_pars_vertex,
16980         shadowmap_vertex: shadowmap_vertex,
16981         shadowmask_pars_fragment: shadowmask_pars_fragment,
16982         skinbase_vertex: skinbase_vertex,
16983         skinning_pars_vertex: skinning_pars_vertex,
16984         skinning_vertex: skinning_vertex,
16985         skinnormal_vertex: skinnormal_vertex,
16986         specularmap_fragment: specularmap_fragment,
16987         specularmap_pars_fragment: specularmap_pars_fragment,
16988         tonemapping_fragment: tonemapping_fragment,
16989         tonemapping_pars_fragment: tonemapping_pars_fragment,
16990         transmissionmap_fragment: transmissionmap_fragment,
16991         transmissionmap_pars_fragment: transmissionmap_pars_fragment,
16992         uv_pars_fragment: uv_pars_fragment,
16993         uv_pars_vertex: uv_pars_vertex,
16994         uv_vertex: uv_vertex,
16995         uv2_pars_fragment: uv2_pars_fragment,
16996         uv2_pars_vertex: uv2_pars_vertex,
16997         uv2_vertex: uv2_vertex,
16998         worldpos_vertex: worldpos_vertex,
16999
17000         background_frag: background_frag,
17001         background_vert: background_vert,
17002         cube_frag: cube_frag,
17003         cube_vert: cube_vert,
17004         depth_frag: depth_frag,
17005         depth_vert: depth_vert,
17006         distanceRGBA_frag: distanceRGBA_frag,
17007         distanceRGBA_vert: distanceRGBA_vert,
17008         equirect_frag: equirect_frag,
17009         equirect_vert: equirect_vert,
17010         linedashed_frag: linedashed_frag,
17011         linedashed_vert: linedashed_vert,
17012         meshbasic_frag: meshbasic_frag,
17013         meshbasic_vert: meshbasic_vert,
17014         meshlambert_frag: meshlambert_frag,
17015         meshlambert_vert: meshlambert_vert,
17016         meshmatcap_frag: meshmatcap_frag,
17017         meshmatcap_vert: meshmatcap_vert,
17018         meshtoon_frag: meshtoon_frag,
17019         meshtoon_vert: meshtoon_vert,
17020         meshphong_frag: meshphong_frag,
17021         meshphong_vert: meshphong_vert,
17022         meshphysical_frag: meshphysical_frag,
17023         meshphysical_vert: meshphysical_vert,
17024         normal_frag: normal_frag,
17025         normal_vert: normal_vert,
17026         points_frag: points_frag,
17027         points_vert: points_vert,
17028         shadow_frag: shadow_frag,
17029         shadow_vert: shadow_vert,
17030         sprite_frag: sprite_frag,
17031         sprite_vert: sprite_vert
17032 };
17033
17034 /**
17035  * Uniforms library for shared webgl shaders
17036  */
17037
17038 const UniformsLib = {
17039
17040         common: {
17041
17042                 diffuse: { value: new Color( 0xeeeeee ) },
17043                 opacity: { value: 1.0 },
17044
17045                 map: { value: null },
17046                 uvTransform: { value: new Matrix3() },
17047                 uv2Transform: { value: new Matrix3() },
17048
17049                 alphaMap: { value: null },
17050
17051         },
17052
17053         specularmap: {
17054
17055                 specularMap: { value: null },
17056
17057         },
17058
17059         envmap: {
17060
17061                 envMap: { value: null },
17062                 flipEnvMap: { value: - 1 },
17063                 reflectivity: { value: 1.0 },
17064                 refractionRatio: { value: 0.98 },
17065                 maxMipLevel: { value: 0 }
17066
17067         },
17068
17069         aomap: {
17070
17071                 aoMap: { value: null },
17072                 aoMapIntensity: { value: 1 }
17073
17074         },
17075
17076         lightmap: {
17077
17078                 lightMap: { value: null },
17079                 lightMapIntensity: { value: 1 }
17080
17081         },
17082
17083         emissivemap: {
17084
17085                 emissiveMap: { value: null }
17086
17087         },
17088
17089         bumpmap: {
17090
17091                 bumpMap: { value: null },
17092                 bumpScale: { value: 1 }
17093
17094         },
17095
17096         normalmap: {
17097
17098                 normalMap: { value: null },
17099                 normalScale: { value: new Vector2( 1, 1 ) }
17100
17101         },
17102
17103         displacementmap: {
17104
17105                 displacementMap: { value: null },
17106                 displacementScale: { value: 1 },
17107                 displacementBias: { value: 0 }
17108
17109         },
17110
17111         roughnessmap: {
17112
17113                 roughnessMap: { value: null }
17114
17115         },
17116
17117         metalnessmap: {
17118
17119                 metalnessMap: { value: null }
17120
17121         },
17122
17123         gradientmap: {
17124
17125                 gradientMap: { value: null }
17126
17127         },
17128
17129         fog: {
17130
17131                 fogDensity: { value: 0.00025 },
17132                 fogNear: { value: 1 },
17133                 fogFar: { value: 2000 },
17134                 fogColor: { value: new Color( 0xffffff ) }
17135
17136         },
17137
17138         lights: {
17139
17140                 ambientLightColor: { value: [] },
17141
17142                 lightProbe: { value: [] },
17143
17144                 directionalLights: { value: [], properties: {
17145                         direction: {},
17146                         color: {}
17147                 } },
17148
17149                 directionalLightShadows: { value: [], properties: {
17150                         shadowBias: {},
17151                         shadowNormalBias: {},
17152                         shadowRadius: {},
17153                         shadowMapSize: {}
17154                 } },
17155
17156                 directionalShadowMap: { value: [] },
17157                 directionalShadowMatrix: { value: [] },
17158
17159                 spotLights: { value: [], properties: {
17160                         color: {},
17161                         position: {},
17162                         direction: {},
17163                         distance: {},
17164                         coneCos: {},
17165                         penumbraCos: {},
17166                         decay: {}
17167                 } },
17168
17169                 spotLightShadows: { value: [], properties: {
17170                         shadowBias: {},
17171                         shadowNormalBias: {},
17172                         shadowRadius: {},
17173                         shadowMapSize: {}
17174                 } },
17175
17176                 spotShadowMap: { value: [] },
17177                 spotShadowMatrix: { value: [] },
17178
17179                 pointLights: { value: [], properties: {
17180                         color: {},
17181                         position: {},
17182                         decay: {},
17183                         distance: {}
17184                 } },
17185
17186                 pointLightShadows: { value: [], properties: {
17187                         shadowBias: {},
17188                         shadowNormalBias: {},
17189                         shadowRadius: {},
17190                         shadowMapSize: {},
17191                         shadowCameraNear: {},
17192                         shadowCameraFar: {}
17193                 } },
17194
17195                 pointShadowMap: { value: [] },
17196                 pointShadowMatrix: { value: [] },
17197
17198                 hemisphereLights: { value: [], properties: {
17199                         direction: {},
17200                         skyColor: {},
17201                         groundColor: {}
17202                 } },
17203
17204                 // TODO (abelnation): RectAreaLight BRDF data needs to be moved from example to main src
17205                 rectAreaLights: { value: [], properties: {
17206                         color: {},
17207                         position: {},
17208                         width: {},
17209                         height: {}
17210                 } },
17211
17212                 ltc_1: { value: null },
17213                 ltc_2: { value: null }
17214
17215         },
17216
17217         points: {
17218
17219                 diffuse: { value: new Color( 0xeeeeee ) },
17220                 opacity: { value: 1.0 },
17221                 size: { value: 1.0 },
17222                 scale: { value: 1.0 },
17223                 map: { value: null },
17224                 alphaMap: { value: null },
17225                 uvTransform: { value: new Matrix3() }
17226
17227         },
17228
17229         sprite: {
17230
17231                 diffuse: { value: new Color( 0xeeeeee ) },
17232                 opacity: { value: 1.0 },
17233                 center: { value: new Vector2( 0.5, 0.5 ) },
17234                 rotation: { value: 0.0 },
17235                 map: { value: null },
17236                 alphaMap: { value: null },
17237                 uvTransform: { value: new Matrix3() }
17238
17239         }
17240
17241 };
17242
17243 const ShaderLib = {
17244
17245         basic: {
17246
17247                 uniforms: mergeUniforms( [
17248                         UniformsLib.common,
17249                         UniformsLib.specularmap,
17250                         UniformsLib.envmap,
17251                         UniformsLib.aomap,
17252                         UniformsLib.lightmap,
17253                         UniformsLib.fog
17254                 ] ),
17255
17256                 vertexShader: ShaderChunk.meshbasic_vert,
17257                 fragmentShader: ShaderChunk.meshbasic_frag
17258
17259         },
17260
17261         lambert: {
17262
17263                 uniforms: mergeUniforms( [
17264                         UniformsLib.common,
17265                         UniformsLib.specularmap,
17266                         UniformsLib.envmap,
17267                         UniformsLib.aomap,
17268                         UniformsLib.lightmap,
17269                         UniformsLib.emissivemap,
17270                         UniformsLib.fog,
17271                         UniformsLib.lights,
17272                         {
17273                                 emissive: { value: new Color( 0x000000 ) }
17274                         }
17275                 ] ),
17276
17277                 vertexShader: ShaderChunk.meshlambert_vert,
17278                 fragmentShader: ShaderChunk.meshlambert_frag
17279
17280         },
17281
17282         phong: {
17283
17284                 uniforms: mergeUniforms( [
17285                         UniformsLib.common,
17286                         UniformsLib.specularmap,
17287                         UniformsLib.envmap,
17288                         UniformsLib.aomap,
17289                         UniformsLib.lightmap,
17290                         UniformsLib.emissivemap,
17291                         UniformsLib.bumpmap,
17292                         UniformsLib.normalmap,
17293                         UniformsLib.displacementmap,
17294                         UniformsLib.fog,
17295                         UniformsLib.lights,
17296                         {
17297                                 emissive: { value: new Color( 0x000000 ) },
17298                                 specular: { value: new Color( 0x111111 ) },
17299                                 shininess: { value: 30 }
17300                         }
17301                 ] ),
17302
17303                 vertexShader: ShaderChunk.meshphong_vert,
17304                 fragmentShader: ShaderChunk.meshphong_frag
17305
17306         },
17307
17308         standard: {
17309
17310                 uniforms: mergeUniforms( [
17311                         UniformsLib.common,
17312                         UniformsLib.envmap,
17313                         UniformsLib.aomap,
17314                         UniformsLib.lightmap,
17315                         UniformsLib.emissivemap,
17316                         UniformsLib.bumpmap,
17317                         UniformsLib.normalmap,
17318                         UniformsLib.displacementmap,
17319                         UniformsLib.roughnessmap,
17320                         UniformsLib.metalnessmap,
17321                         UniformsLib.fog,
17322                         UniformsLib.lights,
17323                         {
17324                                 emissive: { value: new Color( 0x000000 ) },
17325                                 roughness: { value: 1.0 },
17326                                 metalness: { value: 0.0 },
17327                                 envMapIntensity: { value: 1 } // temporary
17328                         }
17329                 ] ),
17330
17331                 vertexShader: ShaderChunk.meshphysical_vert,
17332                 fragmentShader: ShaderChunk.meshphysical_frag
17333
17334         },
17335
17336         toon: {
17337
17338                 uniforms: mergeUniforms( [
17339                         UniformsLib.common,
17340                         UniformsLib.aomap,
17341                         UniformsLib.lightmap,
17342                         UniformsLib.emissivemap,
17343                         UniformsLib.bumpmap,
17344                         UniformsLib.normalmap,
17345                         UniformsLib.displacementmap,
17346                         UniformsLib.gradientmap,
17347                         UniformsLib.fog,
17348                         UniformsLib.lights,
17349                         {
17350                                 emissive: { value: new Color( 0x000000 ) }
17351                         }
17352                 ] ),
17353
17354                 vertexShader: ShaderChunk.meshtoon_vert,
17355                 fragmentShader: ShaderChunk.meshtoon_frag
17356
17357         },
17358
17359         matcap: {
17360
17361                 uniforms: mergeUniforms( [
17362                         UniformsLib.common,
17363                         UniformsLib.bumpmap,
17364                         UniformsLib.normalmap,
17365                         UniformsLib.displacementmap,
17366                         UniformsLib.fog,
17367                         {
17368                                 matcap: { value: null }
17369                         }
17370                 ] ),
17371
17372                 vertexShader: ShaderChunk.meshmatcap_vert,
17373                 fragmentShader: ShaderChunk.meshmatcap_frag
17374
17375         },
17376
17377         points: {
17378
17379                 uniforms: mergeUniforms( [
17380                         UniformsLib.points,
17381                         UniformsLib.fog
17382                 ] ),
17383
17384                 vertexShader: ShaderChunk.points_vert,
17385                 fragmentShader: ShaderChunk.points_frag
17386
17387         },
17388
17389         dashed: {
17390
17391                 uniforms: mergeUniforms( [
17392                         UniformsLib.common,
17393                         UniformsLib.fog,
17394                         {
17395                                 scale: { value: 1 },
17396                                 dashSize: { value: 1 },
17397                                 totalSize: { value: 2 }
17398                         }
17399                 ] ),
17400
17401                 vertexShader: ShaderChunk.linedashed_vert,
17402                 fragmentShader: ShaderChunk.linedashed_frag
17403
17404         },
17405
17406         depth: {
17407
17408                 uniforms: mergeUniforms( [
17409                         UniformsLib.common,
17410                         UniformsLib.displacementmap
17411                 ] ),
17412
17413                 vertexShader: ShaderChunk.depth_vert,
17414                 fragmentShader: ShaderChunk.depth_frag
17415
17416         },
17417
17418         normal: {
17419
17420                 uniforms: mergeUniforms( [
17421                         UniformsLib.common,
17422                         UniformsLib.bumpmap,
17423                         UniformsLib.normalmap,
17424                         UniformsLib.displacementmap,
17425                         {
17426                                 opacity: { value: 1.0 }
17427                         }
17428                 ] ),
17429
17430                 vertexShader: ShaderChunk.normal_vert,
17431                 fragmentShader: ShaderChunk.normal_frag
17432
17433         },
17434
17435         sprite: {
17436
17437                 uniforms: mergeUniforms( [
17438                         UniformsLib.sprite,
17439                         UniformsLib.fog
17440                 ] ),
17441
17442                 vertexShader: ShaderChunk.sprite_vert,
17443                 fragmentShader: ShaderChunk.sprite_frag
17444
17445         },
17446
17447         background: {
17448
17449                 uniforms: {
17450                         uvTransform: { value: new Matrix3() },
17451                         t2D: { value: null },
17452                 },
17453
17454                 vertexShader: ShaderChunk.background_vert,
17455                 fragmentShader: ShaderChunk.background_frag
17456
17457         },
17458         /* -------------------------------------------------------------------------
17459         //      Cube map shader
17460          ------------------------------------------------------------------------- */
17461
17462         cube: {
17463
17464                 uniforms: mergeUniforms( [
17465                         UniformsLib.envmap,
17466                         {
17467                                 opacity: { value: 1.0 }
17468                         }
17469                 ] ),
17470
17471                 vertexShader: ShaderChunk.cube_vert,
17472                 fragmentShader: ShaderChunk.cube_frag
17473
17474         },
17475
17476         equirect: {
17477
17478                 uniforms: {
17479                         tEquirect: { value: null },
17480                 },
17481
17482                 vertexShader: ShaderChunk.equirect_vert,
17483                 fragmentShader: ShaderChunk.equirect_frag
17484
17485         },
17486
17487         distanceRGBA: {
17488
17489                 uniforms: mergeUniforms( [
17490                         UniformsLib.common,
17491                         UniformsLib.displacementmap,
17492                         {
17493                                 referencePosition: { value: new Vector3() },
17494                                 nearDistance: { value: 1 },
17495                                 farDistance: { value: 1000 }
17496                         }
17497                 ] ),
17498
17499                 vertexShader: ShaderChunk.distanceRGBA_vert,
17500                 fragmentShader: ShaderChunk.distanceRGBA_frag
17501
17502         },
17503
17504         shadow: {
17505
17506                 uniforms: mergeUniforms( [
17507                         UniformsLib.lights,
17508                         UniformsLib.fog,
17509                         {
17510                                 color: { value: new Color( 0x00000 ) },
17511                                 opacity: { value: 1.0 }
17512                         },
17513                 ] ),
17514
17515                 vertexShader: ShaderChunk.shadow_vert,
17516                 fragmentShader: ShaderChunk.shadow_frag
17517
17518         }
17519
17520 };
17521
17522 ShaderLib.physical = {
17523
17524         uniforms: mergeUniforms( [
17525                 ShaderLib.standard.uniforms,
17526                 {
17527                         clearcoat: { value: 0 },
17528                         clearcoatMap: { value: null },
17529                         clearcoatRoughness: { value: 0 },
17530                         clearcoatRoughnessMap: { value: null },
17531                         clearcoatNormalScale: { value: new Vector2( 1, 1 ) },
17532                         clearcoatNormalMap: { value: null },
17533                         sheen: { value: new Color( 0x000000 ) },
17534                         transmission: { value: 0 },
17535                         transmissionMap: { value: null },
17536                 }
17537         ] ),
17538
17539         vertexShader: ShaderChunk.meshphysical_vert,
17540         fragmentShader: ShaderChunk.meshphysical_frag
17541
17542 };
17543
17544 function WebGLBackground( renderer, cubemaps, state, objects, premultipliedAlpha ) {
17545
17546         const clearColor = new Color( 0x000000 );
17547         let clearAlpha = 0;
17548
17549         let planeMesh;
17550         let boxMesh;
17551
17552         let currentBackground = null;
17553         let currentBackgroundVersion = 0;
17554         let currentTonemapping = null;
17555
17556         function render( renderList, scene, camera, forceClear ) {
17557
17558                 let background = scene.isScene === true ? scene.background : null;
17559
17560                 if ( background && background.isTexture ) {
17561
17562                         background = cubemaps.get( background );
17563
17564                 }
17565
17566                 // Ignore background in AR
17567                 // TODO: Reconsider this.
17568
17569                 const xr = renderer.xr;
17570                 const session = xr.getSession && xr.getSession();
17571
17572                 if ( session && session.environmentBlendMode === 'additive' ) {
17573
17574                         background = null;
17575
17576                 }
17577
17578                 if ( background === null ) {
17579
17580                         setClear( clearColor, clearAlpha );
17581
17582                 } else if ( background && background.isColor ) {
17583
17584                         setClear( background, 1 );
17585                         forceClear = true;
17586
17587                 }
17588
17589                 if ( renderer.autoClear || forceClear ) {
17590
17591                         renderer.clear( renderer.autoClearColor, renderer.autoClearDepth, renderer.autoClearStencil );
17592
17593                 }
17594
17595                 if ( background && ( background.isCubeTexture || background.isWebGLCubeRenderTarget || background.mapping === CubeUVReflectionMapping ) ) {
17596
17597                         if ( boxMesh === undefined ) {
17598
17599                                 boxMesh = new Mesh(
17600                                         new BoxGeometry( 1, 1, 1 ),
17601                                         new ShaderMaterial( {
17602                                                 name: 'BackgroundCubeMaterial',
17603                                                 uniforms: cloneUniforms( ShaderLib.cube.uniforms ),
17604                                                 vertexShader: ShaderLib.cube.vertexShader,
17605                                                 fragmentShader: ShaderLib.cube.fragmentShader,
17606                                                 side: BackSide,
17607                                                 depthTest: false,
17608                                                 depthWrite: false,
17609                                                 fog: false
17610                                         } )
17611                                 );
17612
17613                                 boxMesh.geometry.deleteAttribute( 'normal' );
17614                                 boxMesh.geometry.deleteAttribute( 'uv' );
17615
17616                                 boxMesh.onBeforeRender = function ( renderer, scene, camera ) {
17617
17618                                         this.matrixWorld.copyPosition( camera.matrixWorld );
17619
17620                                 };
17621
17622                                 // enable code injection for non-built-in material
17623                                 Object.defineProperty( boxMesh.material, 'envMap', {
17624
17625                                         get: function () {
17626
17627                                                 return this.uniforms.envMap.value;
17628
17629                                         }
17630
17631                                 } );
17632
17633                                 objects.update( boxMesh );
17634
17635                         }
17636
17637                         if ( background.isWebGLCubeRenderTarget ) {
17638
17639                                 // TODO Deprecate
17640
17641                                 background = background.texture;
17642
17643                         }
17644
17645                         boxMesh.material.uniforms.envMap.value = background;
17646                         boxMesh.material.uniforms.flipEnvMap.value = ( background.isCubeTexture && background._needsFlipEnvMap ) ? - 1 : 1;
17647
17648                         if ( currentBackground !== background ||
17649                                 currentBackgroundVersion !== background.version ||
17650                                 currentTonemapping !== renderer.toneMapping ) {
17651
17652                                 boxMesh.material.needsUpdate = true;
17653
17654                                 currentBackground = background;
17655                                 currentBackgroundVersion = background.version;
17656                                 currentTonemapping = renderer.toneMapping;
17657
17658                         }
17659
17660                         // push to the pre-sorted opaque render list
17661                         renderList.unshift( boxMesh, boxMesh.geometry, boxMesh.material, 0, 0, null );
17662
17663                 } else if ( background && background.isTexture ) {
17664
17665                         if ( planeMesh === undefined ) {
17666
17667                                 planeMesh = new Mesh(
17668                                         new PlaneGeometry( 2, 2 ),
17669                                         new ShaderMaterial( {
17670                                                 name: 'BackgroundMaterial',
17671                                                 uniforms: cloneUniforms( ShaderLib.background.uniforms ),
17672                                                 vertexShader: ShaderLib.background.vertexShader,
17673                                                 fragmentShader: ShaderLib.background.fragmentShader,
17674                                                 side: FrontSide,
17675                                                 depthTest: false,
17676                                                 depthWrite: false,
17677                                                 fog: false
17678                                         } )
17679                                 );
17680
17681                                 planeMesh.geometry.deleteAttribute( 'normal' );
17682
17683                                 // enable code injection for non-built-in material
17684                                 Object.defineProperty( planeMesh.material, 'map', {
17685
17686                                         get: function () {
17687
17688                                                 return this.uniforms.t2D.value;
17689
17690                                         }
17691
17692                                 } );
17693
17694                                 objects.update( planeMesh );
17695
17696                         }
17697
17698                         planeMesh.material.uniforms.t2D.value = background;
17699
17700                         if ( background.matrixAutoUpdate === true ) {
17701
17702                                 background.updateMatrix();
17703
17704                         }
17705
17706                         planeMesh.material.uniforms.uvTransform.value.copy( background.matrix );
17707
17708                         if ( currentBackground !== background ||
17709                                 currentBackgroundVersion !== background.version ||
17710                                 currentTonemapping !== renderer.toneMapping ) {
17711
17712                                 planeMesh.material.needsUpdate = true;
17713
17714                                 currentBackground = background;
17715                                 currentBackgroundVersion = background.version;
17716                                 currentTonemapping = renderer.toneMapping;
17717
17718                         }
17719
17720
17721                         // push to the pre-sorted opaque render list
17722                         renderList.unshift( planeMesh, planeMesh.geometry, planeMesh.material, 0, 0, null );
17723
17724                 }
17725
17726         }
17727
17728         function setClear( color, alpha ) {
17729
17730                 state.buffers.color.setClear( color.r, color.g, color.b, alpha, premultipliedAlpha );
17731
17732         }
17733
17734         return {
17735
17736                 getClearColor: function () {
17737
17738                         return clearColor;
17739
17740                 },
17741                 setClearColor: function ( color, alpha = 1 ) {
17742
17743                         clearColor.set( color );
17744                         clearAlpha = alpha;
17745                         setClear( clearColor, clearAlpha );
17746
17747                 },
17748                 getClearAlpha: function () {
17749
17750                         return clearAlpha;
17751
17752                 },
17753                 setClearAlpha: function ( alpha ) {
17754
17755                         clearAlpha = alpha;
17756                         setClear( clearColor, clearAlpha );
17757
17758                 },
17759                 render: render
17760
17761         };
17762
17763 }
17764
17765 function WebGLBindingStates( gl, extensions, attributes, capabilities ) {
17766
17767         const maxVertexAttributes = gl.getParameter( 34921 );
17768
17769         const extension = capabilities.isWebGL2 ? null : extensions.get( 'OES_vertex_array_object' );
17770         const vaoAvailable = capabilities.isWebGL2 || extension !== null;
17771
17772         const bindingStates = {};
17773
17774         const defaultState = createBindingState( null );
17775         let currentState = defaultState;
17776
17777         function setup( object, material, program, geometry, index ) {
17778
17779                 let updateBuffers = false;
17780
17781                 if ( vaoAvailable ) {
17782
17783                         const state = getBindingState( geometry, program, material );
17784
17785                         if ( currentState !== state ) {
17786
17787                                 currentState = state;
17788                                 bindVertexArrayObject( currentState.object );
17789
17790                         }
17791
17792                         updateBuffers = needsUpdate( geometry, index );
17793
17794                         if ( updateBuffers ) saveCache( geometry, index );
17795
17796                 } else {
17797
17798                         const wireframe = ( material.wireframe === true );
17799
17800                         if ( currentState.geometry !== geometry.id ||
17801                                 currentState.program !== program.id ||
17802                                 currentState.wireframe !== wireframe ) {
17803
17804                                 currentState.geometry = geometry.id;
17805                                 currentState.program = program.id;
17806                                 currentState.wireframe = wireframe;
17807
17808                                 updateBuffers = true;
17809
17810                         }
17811
17812                 }
17813
17814                 if ( object.isInstancedMesh === true ) {
17815
17816                         updateBuffers = true;
17817
17818                 }
17819
17820                 if ( index !== null ) {
17821
17822                         attributes.update( index, 34963 );
17823
17824                 }
17825
17826                 if ( updateBuffers ) {
17827
17828                         setupVertexAttributes( object, material, program, geometry );
17829
17830                         if ( index !== null ) {
17831
17832                                 gl.bindBuffer( 34963, attributes.get( index ).buffer );
17833
17834                         }
17835
17836                 }
17837
17838         }
17839
17840         function createVertexArrayObject() {
17841
17842                 if ( capabilities.isWebGL2 ) return gl.createVertexArray();
17843
17844                 return extension.createVertexArrayOES();
17845
17846         }
17847
17848         function bindVertexArrayObject( vao ) {
17849
17850                 if ( capabilities.isWebGL2 ) return gl.bindVertexArray( vao );
17851
17852                 return extension.bindVertexArrayOES( vao );
17853
17854         }
17855
17856         function deleteVertexArrayObject( vao ) {
17857
17858                 if ( capabilities.isWebGL2 ) return gl.deleteVertexArray( vao );
17859
17860                 return extension.deleteVertexArrayOES( vao );
17861
17862         }
17863
17864         function getBindingState( geometry, program, material ) {
17865
17866                 const wireframe = ( material.wireframe === true );
17867
17868                 let programMap = bindingStates[ geometry.id ];
17869
17870                 if ( programMap === undefined ) {
17871
17872                         programMap = {};
17873                         bindingStates[ geometry.id ] = programMap;
17874
17875                 }
17876
17877                 let stateMap = programMap[ program.id ];
17878
17879                 if ( stateMap === undefined ) {
17880
17881                         stateMap = {};
17882                         programMap[ program.id ] = stateMap;
17883
17884                 }
17885
17886                 let state = stateMap[ wireframe ];
17887
17888                 if ( state === undefined ) {
17889
17890                         state = createBindingState( createVertexArrayObject() );
17891                         stateMap[ wireframe ] = state;
17892
17893                 }
17894
17895                 return state;
17896
17897         }
17898
17899         function createBindingState( vao ) {
17900
17901                 const newAttributes = [];
17902                 const enabledAttributes = [];
17903                 const attributeDivisors = [];
17904
17905                 for ( let i = 0; i < maxVertexAttributes; i ++ ) {
17906
17907                         newAttributes[ i ] = 0;
17908                         enabledAttributes[ i ] = 0;
17909                         attributeDivisors[ i ] = 0;
17910
17911                 }
17912
17913                 return {
17914
17915                         // for backward compatibility on non-VAO support browser
17916                         geometry: null,
17917                         program: null,
17918                         wireframe: false,
17919
17920                         newAttributes: newAttributes,
17921                         enabledAttributes: enabledAttributes,
17922                         attributeDivisors: attributeDivisors,
17923                         object: vao,
17924                         attributes: {},
17925                         index: null
17926
17927                 };
17928
17929         }
17930
17931         function needsUpdate( geometry, index ) {
17932
17933                 const cachedAttributes = currentState.attributes;
17934                 const geometryAttributes = geometry.attributes;
17935
17936                 let attributesNum = 0;
17937
17938                 for ( const key in geometryAttributes ) {
17939
17940                         const cachedAttribute = cachedAttributes[ key ];
17941                         const geometryAttribute = geometryAttributes[ key ];
17942
17943                         if ( cachedAttribute === undefined ) return true;
17944
17945                         if ( cachedAttribute.attribute !== geometryAttribute ) return true;
17946
17947                         if ( cachedAttribute.data !== geometryAttribute.data ) return true;
17948
17949                         attributesNum ++;
17950
17951                 }
17952
17953                 if ( currentState.attributesNum !== attributesNum ) return true;
17954
17955                 if ( currentState.index !== index ) return true;
17956
17957                 return false;
17958
17959         }
17960
17961         function saveCache( geometry, index ) {
17962
17963                 const cache = {};
17964                 const attributes = geometry.attributes;
17965                 let attributesNum = 0;
17966
17967                 for ( const key in attributes ) {
17968
17969                         const attribute = attributes[ key ];
17970
17971                         const data = {};
17972                         data.attribute = attribute;
17973
17974                         if ( attribute.data ) {
17975
17976                                 data.data = attribute.data;
17977
17978                         }
17979
17980                         cache[ key ] = data;
17981
17982                         attributesNum ++;
17983
17984                 }
17985
17986                 currentState.attributes = cache;
17987                 currentState.attributesNum = attributesNum;
17988
17989                 currentState.index = index;
17990
17991         }
17992
17993         function initAttributes() {
17994
17995                 const newAttributes = currentState.newAttributes;
17996
17997                 for ( let i = 0, il = newAttributes.length; i < il; i ++ ) {
17998
17999                         newAttributes[ i ] = 0;
18000
18001                 }
18002
18003         }
18004
18005         function enableAttribute( attribute ) {
18006
18007                 enableAttributeAndDivisor( attribute, 0 );
18008
18009         }
18010
18011         function enableAttributeAndDivisor( attribute, meshPerAttribute ) {
18012
18013                 const newAttributes = currentState.newAttributes;
18014                 const enabledAttributes = currentState.enabledAttributes;
18015                 const attributeDivisors = currentState.attributeDivisors;
18016
18017                 newAttributes[ attribute ] = 1;
18018
18019                 if ( enabledAttributes[ attribute ] === 0 ) {
18020
18021                         gl.enableVertexAttribArray( attribute );
18022                         enabledAttributes[ attribute ] = 1;
18023
18024                 }
18025
18026                 if ( attributeDivisors[ attribute ] !== meshPerAttribute ) {
18027
18028                         const extension = capabilities.isWebGL2 ? gl : extensions.get( 'ANGLE_instanced_arrays' );
18029
18030                         extension[ capabilities.isWebGL2 ? 'vertexAttribDivisor' : 'vertexAttribDivisorANGLE' ]( attribute, meshPerAttribute );
18031                         attributeDivisors[ attribute ] = meshPerAttribute;
18032
18033                 }
18034
18035         }
18036
18037         function disableUnusedAttributes() {
18038
18039                 const newAttributes = currentState.newAttributes;
18040                 const enabledAttributes = currentState.enabledAttributes;
18041
18042                 for ( let i = 0, il = enabledAttributes.length; i < il; i ++ ) {
18043
18044                         if ( enabledAttributes[ i ] !== newAttributes[ i ] ) {
18045
18046                                 gl.disableVertexAttribArray( i );
18047                                 enabledAttributes[ i ] = 0;
18048
18049                         }
18050
18051                 }
18052
18053         }
18054
18055         function vertexAttribPointer( index, size, type, normalized, stride, offset ) {
18056
18057                 if ( capabilities.isWebGL2 === true && ( type === 5124 || type === 5125 ) ) {
18058
18059                         gl.vertexAttribIPointer( index, size, type, stride, offset );
18060
18061                 } else {
18062
18063                         gl.vertexAttribPointer( index, size, type, normalized, stride, offset );
18064
18065                 }
18066
18067         }
18068
18069         function setupVertexAttributes( object, material, program, geometry ) {
18070
18071                 if ( capabilities.isWebGL2 === false && ( object.isInstancedMesh || geometry.isInstancedBufferGeometry ) ) {
18072
18073                         if ( extensions.get( 'ANGLE_instanced_arrays' ) === null ) return;
18074
18075                 }
18076
18077                 initAttributes();
18078
18079                 const geometryAttributes = geometry.attributes;
18080
18081                 const programAttributes = program.getAttributes();
18082
18083                 const materialDefaultAttributeValues = material.defaultAttributeValues;
18084
18085                 for ( const name in programAttributes ) {
18086
18087                         const programAttribute = programAttributes[ name ];
18088
18089                         if ( programAttribute >= 0 ) {
18090
18091                                 const geometryAttribute = geometryAttributes[ name ];
18092
18093                                 if ( geometryAttribute !== undefined ) {
18094
18095                                         const normalized = geometryAttribute.normalized;
18096                                         const size = geometryAttribute.itemSize;
18097
18098                                         const attribute = attributes.get( geometryAttribute );
18099
18100                                         // TODO Attribute may not be available on context restore
18101
18102                                         if ( attribute === undefined ) continue;
18103
18104                                         const buffer = attribute.buffer;
18105                                         const type = attribute.type;
18106                                         const bytesPerElement = attribute.bytesPerElement;
18107
18108                                         if ( geometryAttribute.isInterleavedBufferAttribute ) {
18109
18110                                                 const data = geometryAttribute.data;
18111                                                 const stride = data.stride;
18112                                                 const offset = geometryAttribute.offset;
18113
18114                                                 if ( data && data.isInstancedInterleavedBuffer ) {
18115
18116                                                         enableAttributeAndDivisor( programAttribute, data.meshPerAttribute );
18117
18118                                                         if ( geometry._maxInstanceCount === undefined ) {
18119
18120                                                                 geometry._maxInstanceCount = data.meshPerAttribute * data.count;
18121
18122                                                         }
18123
18124                                                 } else {
18125
18126                                                         enableAttribute( programAttribute );
18127
18128                                                 }
18129
18130                                                 gl.bindBuffer( 34962, buffer );
18131                                                 vertexAttribPointer( programAttribute, size, type, normalized, stride * bytesPerElement, offset * bytesPerElement );
18132
18133                                         } else {
18134
18135                                                 if ( geometryAttribute.isInstancedBufferAttribute ) {
18136
18137                                                         enableAttributeAndDivisor( programAttribute, geometryAttribute.meshPerAttribute );
18138
18139                                                         if ( geometry._maxInstanceCount === undefined ) {
18140
18141                                                                 geometry._maxInstanceCount = geometryAttribute.meshPerAttribute * geometryAttribute.count;
18142
18143                                                         }
18144
18145                                                 } else {
18146
18147                                                         enableAttribute( programAttribute );
18148
18149                                                 }
18150
18151                                                 gl.bindBuffer( 34962, buffer );
18152                                                 vertexAttribPointer( programAttribute, size, type, normalized, 0, 0 );
18153
18154                                         }
18155
18156                                 } else if ( name === 'instanceMatrix' ) {
18157
18158                                         const attribute = attributes.get( object.instanceMatrix );
18159
18160                                         // TODO Attribute may not be available on context restore
18161
18162                                         if ( attribute === undefined ) continue;
18163
18164                                         const buffer = attribute.buffer;
18165                                         const type = attribute.type;
18166
18167                                         enableAttributeAndDivisor( programAttribute + 0, 1 );
18168                                         enableAttributeAndDivisor( programAttribute + 1, 1 );
18169                                         enableAttributeAndDivisor( programAttribute + 2, 1 );
18170                                         enableAttributeAndDivisor( programAttribute + 3, 1 );
18171
18172                                         gl.bindBuffer( 34962, buffer );
18173
18174                                         gl.vertexAttribPointer( programAttribute + 0, 4, type, false, 64, 0 );
18175                                         gl.vertexAttribPointer( programAttribute + 1, 4, type, false, 64, 16 );
18176                                         gl.vertexAttribPointer( programAttribute + 2, 4, type, false, 64, 32 );
18177                                         gl.vertexAttribPointer( programAttribute + 3, 4, type, false, 64, 48 );
18178
18179                                 } else if ( name === 'instanceColor' ) {
18180
18181                                         const attribute = attributes.get( object.instanceColor );
18182
18183                                         // TODO Attribute may not be available on context restore
18184
18185                                         if ( attribute === undefined ) continue;
18186
18187                                         const buffer = attribute.buffer;
18188                                         const type = attribute.type;
18189
18190                                         enableAttributeAndDivisor( programAttribute, 1 );
18191
18192                                         gl.bindBuffer( 34962, buffer );
18193
18194                                         gl.vertexAttribPointer( programAttribute, 3, type, false, 12, 0 );
18195
18196                                 } else if ( materialDefaultAttributeValues !== undefined ) {
18197
18198                                         const value = materialDefaultAttributeValues[ name ];
18199
18200                                         if ( value !== undefined ) {
18201
18202                                                 switch ( value.length ) {
18203
18204                                                         case 2:
18205                                                                 gl.vertexAttrib2fv( programAttribute, value );
18206                                                                 break;
18207
18208                                                         case 3:
18209                                                                 gl.vertexAttrib3fv( programAttribute, value );
18210                                                                 break;
18211
18212                                                         case 4:
18213                                                                 gl.vertexAttrib4fv( programAttribute, value );
18214                                                                 break;
18215
18216                                                         default:
18217                                                                 gl.vertexAttrib1fv( programAttribute, value );
18218
18219                                                 }
18220
18221                                         }
18222
18223                                 }
18224
18225                         }
18226
18227                 }
18228
18229                 disableUnusedAttributes();
18230
18231         }
18232
18233         function dispose() {
18234
18235                 reset();
18236
18237                 for ( const geometryId in bindingStates ) {
18238
18239                         const programMap = bindingStates[ geometryId ];
18240
18241                         for ( const programId in programMap ) {
18242
18243                                 const stateMap = programMap[ programId ];
18244
18245                                 for ( const wireframe in stateMap ) {
18246
18247                                         deleteVertexArrayObject( stateMap[ wireframe ].object );
18248
18249                                         delete stateMap[ wireframe ];
18250
18251                                 }
18252
18253                                 delete programMap[ programId ];
18254
18255                         }
18256
18257                         delete bindingStates[ geometryId ];
18258
18259                 }
18260
18261         }
18262
18263         function releaseStatesOfGeometry( geometry ) {
18264
18265                 if ( bindingStates[ geometry.id ] === undefined ) return;
18266
18267                 const programMap = bindingStates[ geometry.id ];
18268
18269                 for ( const programId in programMap ) {
18270
18271                         const stateMap = programMap[ programId ];
18272
18273                         for ( const wireframe in stateMap ) {
18274
18275                                 deleteVertexArrayObject( stateMap[ wireframe ].object );
18276
18277                                 delete stateMap[ wireframe ];
18278
18279                         }
18280
18281                         delete programMap[ programId ];
18282
18283                 }
18284
18285                 delete bindingStates[ geometry.id ];
18286
18287         }
18288
18289         function releaseStatesOfProgram( program ) {
18290
18291                 for ( const geometryId in bindingStates ) {
18292
18293                         const programMap = bindingStates[ geometryId ];
18294
18295                         if ( programMap[ program.id ] === undefined ) continue;
18296
18297                         const stateMap = programMap[ program.id ];
18298
18299                         for ( const wireframe in stateMap ) {
18300
18301                                 deleteVertexArrayObject( stateMap[ wireframe ].object );
18302
18303                                 delete stateMap[ wireframe ];
18304
18305                         }
18306
18307                         delete programMap[ program.id ];
18308
18309                 }
18310
18311         }
18312
18313         function reset() {
18314
18315                 resetDefaultState();
18316
18317                 if ( currentState === defaultState ) return;
18318
18319                 currentState = defaultState;
18320                 bindVertexArrayObject( currentState.object );
18321
18322         }
18323
18324         // for backward-compatilibity
18325
18326         function resetDefaultState() {
18327
18328                 defaultState.geometry = null;
18329                 defaultState.program = null;
18330                 defaultState.wireframe = false;
18331
18332         }
18333
18334         return {
18335
18336                 setup: setup,
18337                 reset: reset,
18338                 resetDefaultState: resetDefaultState,
18339                 dispose: dispose,
18340                 releaseStatesOfGeometry: releaseStatesOfGeometry,
18341                 releaseStatesOfProgram: releaseStatesOfProgram,
18342
18343                 initAttributes: initAttributes,
18344                 enableAttribute: enableAttribute,
18345                 disableUnusedAttributes: disableUnusedAttributes
18346
18347         };
18348
18349 }
18350
18351 function WebGLBufferRenderer( gl, extensions, info, capabilities ) {
18352
18353         const isWebGL2 = capabilities.isWebGL2;
18354
18355         let mode;
18356
18357         function setMode( value ) {
18358
18359                 mode = value;
18360
18361         }
18362
18363         function render( start, count ) {
18364
18365                 gl.drawArrays( mode, start, count );
18366
18367                 info.update( count, mode, 1 );
18368
18369         }
18370
18371         function renderInstances( start, count, primcount ) {
18372
18373                 if ( primcount === 0 ) return;
18374
18375                 let extension, methodName;
18376
18377                 if ( isWebGL2 ) {
18378
18379                         extension = gl;
18380                         methodName = 'drawArraysInstanced';
18381
18382                 } else {
18383
18384                         extension = extensions.get( 'ANGLE_instanced_arrays' );
18385                         methodName = 'drawArraysInstancedANGLE';
18386
18387                         if ( extension === null ) {
18388
18389                                 console.error( 'THREE.WebGLBufferRenderer: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.' );
18390                                 return;
18391
18392                         }
18393
18394                 }
18395
18396                 extension[ methodName ]( mode, start, count, primcount );
18397
18398                 info.update( count, mode, primcount );
18399
18400         }
18401
18402         //
18403
18404         this.setMode = setMode;
18405         this.render = render;
18406         this.renderInstances = renderInstances;
18407
18408 }
18409
18410 function WebGLCapabilities( gl, extensions, parameters ) {
18411
18412         let maxAnisotropy;
18413
18414         function getMaxAnisotropy() {
18415
18416                 if ( maxAnisotropy !== undefined ) return maxAnisotropy;
18417
18418                 const extension = extensions.get( 'EXT_texture_filter_anisotropic' );
18419
18420                 if ( extension !== null ) {
18421
18422                         maxAnisotropy = gl.getParameter( extension.MAX_TEXTURE_MAX_ANISOTROPY_EXT );
18423
18424                 } else {
18425
18426                         maxAnisotropy = 0;
18427
18428                 }
18429
18430                 return maxAnisotropy;
18431
18432         }
18433
18434         function getMaxPrecision( precision ) {
18435
18436                 if ( precision === 'highp' ) {
18437
18438                         if ( gl.getShaderPrecisionFormat( 35633, 36338 ).precision > 0 &&
18439                                 gl.getShaderPrecisionFormat( 35632, 36338 ).precision > 0 ) {
18440
18441                                 return 'highp';
18442
18443                         }
18444
18445                         precision = 'mediump';
18446
18447                 }
18448
18449                 if ( precision === 'mediump' ) {
18450
18451                         if ( gl.getShaderPrecisionFormat( 35633, 36337 ).precision > 0 &&
18452                                 gl.getShaderPrecisionFormat( 35632, 36337 ).precision > 0 ) {
18453
18454                                 return 'mediump';
18455
18456                         }
18457
18458                 }
18459
18460                 return 'lowp';
18461
18462         }
18463
18464         /* eslint-disable no-undef */
18465         const isWebGL2 = ( typeof WebGL2RenderingContext !== 'undefined' && gl instanceof WebGL2RenderingContext ) ||
18466                 ( typeof WebGL2ComputeRenderingContext !== 'undefined' && gl instanceof WebGL2ComputeRenderingContext );
18467         /* eslint-enable no-undef */
18468
18469         let precision = parameters.precision !== undefined ? parameters.precision : 'highp';
18470         const maxPrecision = getMaxPrecision( precision );
18471
18472         if ( maxPrecision !== precision ) {
18473
18474                 console.warn( 'THREE.WebGLRenderer:', precision, 'not supported, using', maxPrecision, 'instead.' );
18475                 precision = maxPrecision;
18476
18477         }
18478
18479         const logarithmicDepthBuffer = parameters.logarithmicDepthBuffer === true;
18480
18481         const maxTextures = gl.getParameter( 34930 );
18482         const maxVertexTextures = gl.getParameter( 35660 );
18483         const maxTextureSize = gl.getParameter( 3379 );
18484         const maxCubemapSize = gl.getParameter( 34076 );
18485
18486         const maxAttributes = gl.getParameter( 34921 );
18487         const maxVertexUniforms = gl.getParameter( 36347 );
18488         const maxVaryings = gl.getParameter( 36348 );
18489         const maxFragmentUniforms = gl.getParameter( 36349 );
18490
18491         const vertexTextures = maxVertexTextures > 0;
18492         const floatFragmentTextures = isWebGL2 || !! extensions.get( 'OES_texture_float' );
18493         const floatVertexTextures = vertexTextures && floatFragmentTextures;
18494
18495         const maxSamples = isWebGL2 ? gl.getParameter( 36183 ) : 0;
18496
18497         return {
18498
18499                 isWebGL2: isWebGL2,
18500
18501                 getMaxAnisotropy: getMaxAnisotropy,
18502                 getMaxPrecision: getMaxPrecision,
18503
18504                 precision: precision,
18505                 logarithmicDepthBuffer: logarithmicDepthBuffer,
18506
18507                 maxTextures: maxTextures,
18508                 maxVertexTextures: maxVertexTextures,
18509                 maxTextureSize: maxTextureSize,
18510                 maxCubemapSize: maxCubemapSize,
18511
18512                 maxAttributes: maxAttributes,
18513                 maxVertexUniforms: maxVertexUniforms,
18514                 maxVaryings: maxVaryings,
18515                 maxFragmentUniforms: maxFragmentUniforms,
18516
18517                 vertexTextures: vertexTextures,
18518                 floatFragmentTextures: floatFragmentTextures,
18519                 floatVertexTextures: floatVertexTextures,
18520
18521                 maxSamples: maxSamples
18522
18523         };
18524
18525 }
18526
18527 function WebGLClipping( properties ) {
18528
18529         const scope = this;
18530
18531         let globalState = null,
18532                 numGlobalPlanes = 0,
18533                 localClippingEnabled = false,
18534                 renderingShadows = false;
18535
18536         const plane = new Plane(),
18537                 viewNormalMatrix = new Matrix3(),
18538
18539                 uniform = { value: null, needsUpdate: false };
18540
18541         this.uniform = uniform;
18542         this.numPlanes = 0;
18543         this.numIntersection = 0;
18544
18545         this.init = function ( planes, enableLocalClipping, camera ) {
18546
18547                 const enabled =
18548                         planes.length !== 0 ||
18549                         enableLocalClipping ||
18550                         // enable state of previous frame - the clipping code has to
18551                         // run another frame in order to reset the state:
18552                         numGlobalPlanes !== 0 ||
18553                         localClippingEnabled;
18554
18555                 localClippingEnabled = enableLocalClipping;
18556
18557                 globalState = projectPlanes( planes, camera, 0 );
18558                 numGlobalPlanes = planes.length;
18559
18560                 return enabled;
18561
18562         };
18563
18564         this.beginShadows = function () {
18565
18566                 renderingShadows = true;
18567                 projectPlanes( null );
18568
18569         };
18570
18571         this.endShadows = function () {
18572
18573                 renderingShadows = false;
18574                 resetGlobalState();
18575
18576         };
18577
18578         this.setState = function ( material, camera, useCache ) {
18579
18580                 const planes = material.clippingPlanes,
18581                         clipIntersection = material.clipIntersection,
18582                         clipShadows = material.clipShadows;
18583
18584                 const materialProperties = properties.get( material );
18585
18586                 if ( ! localClippingEnabled || planes === null || planes.length === 0 || renderingShadows && ! clipShadows ) {
18587
18588                         // there's no local clipping
18589
18590                         if ( renderingShadows ) {
18591
18592                                 // there's no global clipping
18593
18594                                 projectPlanes( null );
18595
18596                         } else {
18597
18598                                 resetGlobalState();
18599
18600                         }
18601
18602                 } else {
18603
18604                         const nGlobal = renderingShadows ? 0 : numGlobalPlanes,
18605                                 lGlobal = nGlobal * 4;
18606
18607                         let dstArray = materialProperties.clippingState || null;
18608
18609                         uniform.value = dstArray; // ensure unique state
18610
18611                         dstArray = projectPlanes( planes, camera, lGlobal, useCache );
18612
18613                         for ( let i = 0; i !== lGlobal; ++ i ) {
18614
18615                                 dstArray[ i ] = globalState[ i ];
18616
18617                         }
18618
18619                         materialProperties.clippingState = dstArray;
18620                         this.numIntersection = clipIntersection ? this.numPlanes : 0;
18621                         this.numPlanes += nGlobal;
18622
18623                 }
18624
18625
18626         };
18627
18628         function resetGlobalState() {
18629
18630                 if ( uniform.value !== globalState ) {
18631
18632                         uniform.value = globalState;
18633                         uniform.needsUpdate = numGlobalPlanes > 0;
18634
18635                 }
18636
18637                 scope.numPlanes = numGlobalPlanes;
18638                 scope.numIntersection = 0;
18639
18640         }
18641
18642         function projectPlanes( planes, camera, dstOffset, skipTransform ) {
18643
18644                 const nPlanes = planes !== null ? planes.length : 0;
18645                 let dstArray = null;
18646
18647                 if ( nPlanes !== 0 ) {
18648
18649                         dstArray = uniform.value;
18650
18651                         if ( skipTransform !== true || dstArray === null ) {
18652
18653                                 const flatSize = dstOffset + nPlanes * 4,
18654                                         viewMatrix = camera.matrixWorldInverse;
18655
18656                                 viewNormalMatrix.getNormalMatrix( viewMatrix );
18657
18658                                 if ( dstArray === null || dstArray.length < flatSize ) {
18659
18660                                         dstArray = new Float32Array( flatSize );
18661
18662                                 }
18663
18664                                 for ( let i = 0, i4 = dstOffset; i !== nPlanes; ++ i, i4 += 4 ) {
18665
18666                                         plane.copy( planes[ i ] ).applyMatrix4( viewMatrix, viewNormalMatrix );
18667
18668                                         plane.normal.toArray( dstArray, i4 );
18669                                         dstArray[ i4 + 3 ] = plane.constant;
18670
18671                                 }
18672
18673                         }
18674
18675                         uniform.value = dstArray;
18676                         uniform.needsUpdate = true;
18677
18678                 }
18679
18680                 scope.numPlanes = nPlanes;
18681                 scope.numIntersection = 0;
18682
18683                 return dstArray;
18684
18685         }
18686
18687 }
18688
18689 function WebGLCubeMaps( renderer ) {
18690
18691         let cubemaps = new WeakMap();
18692
18693         function mapTextureMapping( texture, mapping ) {
18694
18695                 if ( mapping === EquirectangularReflectionMapping ) {
18696
18697                         texture.mapping = CubeReflectionMapping;
18698
18699                 } else if ( mapping === EquirectangularRefractionMapping ) {
18700
18701                         texture.mapping = CubeRefractionMapping;
18702
18703                 }
18704
18705                 return texture;
18706
18707         }
18708
18709         function get( texture ) {
18710
18711                 if ( texture && texture.isTexture ) {
18712
18713                         const mapping = texture.mapping;
18714
18715                         if ( mapping === EquirectangularReflectionMapping || mapping === EquirectangularRefractionMapping ) {
18716
18717                                 if ( cubemaps.has( texture ) ) {
18718
18719                                         const cubemap = cubemaps.get( texture ).texture;
18720                                         return mapTextureMapping( cubemap, texture.mapping );
18721
18722                                 } else {
18723
18724                                         const image = texture.image;
18725
18726                                         if ( image && image.height > 0 ) {
18727
18728                                                 const currentRenderList = renderer.getRenderList();
18729                                                 const currentRenderTarget = renderer.getRenderTarget();
18730
18731                                                 const renderTarget = new WebGLCubeRenderTarget( image.height / 2 );
18732                                                 renderTarget.fromEquirectangularTexture( renderer, texture );
18733                                                 cubemaps.set( texture, renderTarget );
18734
18735                                                 renderer.setRenderTarget( currentRenderTarget );
18736                                                 renderer.setRenderList( currentRenderList );
18737
18738                                                 texture.addEventListener( 'dispose', onTextureDispose );
18739
18740                                                 return mapTextureMapping( renderTarget.texture, texture.mapping );
18741
18742                                         } else {
18743
18744                                                 // image not yet ready. try the conversion next frame
18745
18746                                                 return null;
18747
18748                                         }
18749
18750                                 }
18751
18752                         }
18753
18754                 }
18755
18756                 return texture;
18757
18758         }
18759
18760         function onTextureDispose( event ) {
18761
18762                 const texture = event.target;
18763
18764                 texture.removeEventListener( 'dispose', onTextureDispose );
18765
18766                 const cubemap = cubemaps.get( texture );
18767
18768                 if ( cubemap !== undefined ) {
18769
18770                         cubemaps.delete( texture );
18771                         cubemap.dispose();
18772
18773                 }
18774
18775         }
18776
18777         function dispose() {
18778
18779                 cubemaps = new WeakMap();
18780
18781         }
18782
18783         return {
18784                 get: get,
18785                 dispose: dispose
18786         };
18787
18788 }
18789
18790 function WebGLExtensions( gl ) {
18791
18792         const extensions = {};
18793
18794         function getExtension( name ) {
18795
18796                 if ( extensions[ name ] !== undefined ) {
18797
18798                         return extensions[ name ];
18799
18800                 }
18801
18802                 let extension;
18803
18804                 switch ( name ) {
18805
18806                         case 'WEBGL_depth_texture':
18807                                 extension = gl.getExtension( 'WEBGL_depth_texture' ) || gl.getExtension( 'MOZ_WEBGL_depth_texture' ) || gl.getExtension( 'WEBKIT_WEBGL_depth_texture' );
18808                                 break;
18809
18810                         case 'EXT_texture_filter_anisotropic':
18811                                 extension = gl.getExtension( 'EXT_texture_filter_anisotropic' ) || gl.getExtension( 'MOZ_EXT_texture_filter_anisotropic' ) || gl.getExtension( 'WEBKIT_EXT_texture_filter_anisotropic' );
18812                                 break;
18813
18814                         case 'WEBGL_compressed_texture_s3tc':
18815                                 extension = gl.getExtension( 'WEBGL_compressed_texture_s3tc' ) || gl.getExtension( 'MOZ_WEBGL_compressed_texture_s3tc' ) || gl.getExtension( 'WEBKIT_WEBGL_compressed_texture_s3tc' );
18816                                 break;
18817
18818                         case 'WEBGL_compressed_texture_pvrtc':
18819                                 extension = gl.getExtension( 'WEBGL_compressed_texture_pvrtc' ) || gl.getExtension( 'WEBKIT_WEBGL_compressed_texture_pvrtc' );
18820                                 break;
18821
18822                         default:
18823                                 extension = gl.getExtension( name );
18824
18825                 }
18826
18827                 extensions[ name ] = extension;
18828
18829                 return extension;
18830
18831         }
18832
18833         return {
18834
18835                 has: function ( name ) {
18836
18837                         return getExtension( name ) !== null;
18838
18839                 },
18840
18841                 init: function ( capabilities ) {
18842
18843                         if ( capabilities.isWebGL2 ) {
18844
18845                                 getExtension( 'EXT_color_buffer_float' );
18846
18847                         } else {
18848
18849                                 getExtension( 'WEBGL_depth_texture' );
18850                                 getExtension( 'OES_texture_float' );
18851                                 getExtension( 'OES_texture_half_float' );
18852                                 getExtension( 'OES_texture_half_float_linear' );
18853                                 getExtension( 'OES_standard_derivatives' );
18854                                 getExtension( 'OES_element_index_uint' );
18855                                 getExtension( 'OES_vertex_array_object' );
18856                                 getExtension( 'ANGLE_instanced_arrays' );
18857
18858                         }
18859
18860                         getExtension( 'OES_texture_float_linear' );
18861                         getExtension( 'EXT_color_buffer_half_float' );
18862
18863                 },
18864
18865                 get: function ( name ) {
18866
18867                         const extension = getExtension( name );
18868
18869                         if ( extension === null ) {
18870
18871                                 console.warn( 'THREE.WebGLRenderer: ' + name + ' extension not supported.' );
18872
18873                         }
18874
18875                         return extension;
18876
18877                 }
18878
18879         };
18880
18881 }
18882
18883 function WebGLGeometries( gl, attributes, info, bindingStates ) {
18884
18885         const geometries = {};
18886         const wireframeAttributes = new WeakMap();
18887
18888         function onGeometryDispose( event ) {
18889
18890                 const geometry = event.target;
18891
18892                 if ( geometry.index !== null ) {
18893
18894                         attributes.remove( geometry.index );
18895
18896                 }
18897
18898                 for ( const name in geometry.attributes ) {
18899
18900                         attributes.remove( geometry.attributes[ name ] );
18901
18902                 }
18903
18904                 geometry.removeEventListener( 'dispose', onGeometryDispose );
18905
18906                 delete geometries[ geometry.id ];
18907
18908                 const attribute = wireframeAttributes.get( geometry );
18909
18910                 if ( attribute ) {
18911
18912                         attributes.remove( attribute );
18913                         wireframeAttributes.delete( geometry );
18914
18915                 }
18916
18917                 bindingStates.releaseStatesOfGeometry( geometry );
18918
18919                 if ( geometry.isInstancedBufferGeometry === true ) {
18920
18921                         delete geometry._maxInstanceCount;
18922
18923                 }
18924
18925                 //
18926
18927                 info.memory.geometries --;
18928
18929         }
18930
18931         function get( object, geometry ) {
18932
18933                 if ( geometries[ geometry.id ] === true ) return geometry;
18934
18935                 geometry.addEventListener( 'dispose', onGeometryDispose );
18936
18937                 geometries[ geometry.id ] = true;
18938
18939                 info.memory.geometries ++;
18940
18941                 return geometry;
18942
18943         }
18944
18945         function update( geometry ) {
18946
18947                 const geometryAttributes = geometry.attributes;
18948
18949                 // Updating index buffer in VAO now. See WebGLBindingStates.
18950
18951                 for ( const name in geometryAttributes ) {
18952
18953                         attributes.update( geometryAttributes[ name ], 34962 );
18954
18955                 }
18956
18957                 // morph targets
18958
18959                 const morphAttributes = geometry.morphAttributes;
18960
18961                 for ( const name in morphAttributes ) {
18962
18963                         const array = morphAttributes[ name ];
18964
18965                         for ( let i = 0, l = array.length; i < l; i ++ ) {
18966
18967                                 attributes.update( array[ i ], 34962 );
18968
18969                         }
18970
18971                 }
18972
18973         }
18974
18975         function updateWireframeAttribute( geometry ) {
18976
18977                 const indices = [];
18978
18979                 const geometryIndex = geometry.index;
18980                 const geometryPosition = geometry.attributes.position;
18981                 let version = 0;
18982
18983                 if ( geometryIndex !== null ) {
18984
18985                         const array = geometryIndex.array;
18986                         version = geometryIndex.version;
18987
18988                         for ( let i = 0, l = array.length; i < l; i += 3 ) {
18989
18990                                 const a = array[ i + 0 ];
18991                                 const b = array[ i + 1 ];
18992                                 const c = array[ i + 2 ];
18993
18994                                 indices.push( a, b, b, c, c, a );
18995
18996                         }
18997
18998                 } else {
18999
19000                         const array = geometryPosition.array;
19001                         version = geometryPosition.version;
19002
19003                         for ( let i = 0, l = ( array.length / 3 ) - 1; i < l; i += 3 ) {
19004
19005                                 const a = i + 0;
19006                                 const b = i + 1;
19007                                 const c = i + 2;
19008
19009                                 indices.push( a, b, b, c, c, a );
19010
19011                         }
19012
19013                 }
19014
19015                 const attribute = new ( arrayMax( indices ) > 65535 ? Uint32BufferAttribute : Uint16BufferAttribute )( indices, 1 );
19016                 attribute.version = version;
19017
19018                 // Updating index buffer in VAO now. See WebGLBindingStates
19019
19020                 //
19021
19022                 const previousAttribute = wireframeAttributes.get( geometry );
19023
19024                 if ( previousAttribute ) attributes.remove( previousAttribute );
19025
19026                 //
19027
19028                 wireframeAttributes.set( geometry, attribute );
19029
19030         }
19031
19032         function getWireframeAttribute( geometry ) {
19033
19034                 const currentAttribute = wireframeAttributes.get( geometry );
19035
19036                 if ( currentAttribute ) {
19037
19038                         const geometryIndex = geometry.index;
19039
19040                         if ( geometryIndex !== null ) {
19041
19042                                 // if the attribute is obsolete, create a new one
19043
19044                                 if ( currentAttribute.version < geometryIndex.version ) {
19045
19046                                         updateWireframeAttribute( geometry );
19047
19048                                 }
19049
19050                         }
19051
19052                 } else {
19053
19054                         updateWireframeAttribute( geometry );
19055
19056                 }
19057
19058                 return wireframeAttributes.get( geometry );
19059
19060         }
19061
19062         return {
19063
19064                 get: get,
19065                 update: update,
19066
19067                 getWireframeAttribute: getWireframeAttribute
19068
19069         };
19070
19071 }
19072
19073 function WebGLIndexedBufferRenderer( gl, extensions, info, capabilities ) {
19074
19075         const isWebGL2 = capabilities.isWebGL2;
19076
19077         let mode;
19078
19079         function setMode( value ) {
19080
19081                 mode = value;
19082
19083         }
19084
19085         let type, bytesPerElement;
19086
19087         function setIndex( value ) {
19088
19089                 type = value.type;
19090                 bytesPerElement = value.bytesPerElement;
19091
19092         }
19093
19094         function render( start, count ) {
19095
19096                 gl.drawElements( mode, count, type, start * bytesPerElement );
19097
19098                 info.update( count, mode, 1 );
19099
19100         }
19101
19102         function renderInstances( start, count, primcount ) {
19103
19104                 if ( primcount === 0 ) return;
19105
19106                 let extension, methodName;
19107
19108                 if ( isWebGL2 ) {
19109
19110                         extension = gl;
19111                         methodName = 'drawElementsInstanced';
19112
19113                 } else {
19114
19115                         extension = extensions.get( 'ANGLE_instanced_arrays' );
19116                         methodName = 'drawElementsInstancedANGLE';
19117
19118                         if ( extension === null ) {
19119
19120                                 console.error( 'THREE.WebGLIndexedBufferRenderer: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.' );
19121                                 return;
19122
19123                         }
19124
19125                 }
19126
19127                 extension[ methodName ]( mode, count, type, start * bytesPerElement, primcount );
19128
19129                 info.update( count, mode, primcount );
19130
19131         }
19132
19133         //
19134
19135         this.setMode = setMode;
19136         this.setIndex = setIndex;
19137         this.render = render;
19138         this.renderInstances = renderInstances;
19139
19140 }
19141
19142 function WebGLInfo( gl ) {
19143
19144         const memory = {
19145                 geometries: 0,
19146                 textures: 0
19147         };
19148
19149         const render = {
19150                 frame: 0,
19151                 calls: 0,
19152                 triangles: 0,
19153                 points: 0,
19154                 lines: 0
19155         };
19156
19157         function update( count, mode, instanceCount ) {
19158
19159                 render.calls ++;
19160
19161                 switch ( mode ) {
19162
19163                         case 4:
19164                                 render.triangles += instanceCount * ( count / 3 );
19165                                 break;
19166
19167                         case 1:
19168                                 render.lines += instanceCount * ( count / 2 );
19169                                 break;
19170
19171                         case 3:
19172                                 render.lines += instanceCount * ( count - 1 );
19173                                 break;
19174
19175                         case 2:
19176                                 render.lines += instanceCount * count;
19177                                 break;
19178
19179                         case 0:
19180                                 render.points += instanceCount * count;
19181                                 break;
19182
19183                         default:
19184                                 console.error( 'THREE.WebGLInfo: Unknown draw mode:', mode );
19185                                 break;
19186
19187                 }
19188
19189         }
19190
19191         function reset() {
19192
19193                 render.frame ++;
19194                 render.calls = 0;
19195                 render.triangles = 0;
19196                 render.points = 0;
19197                 render.lines = 0;
19198
19199         }
19200
19201         return {
19202                 memory: memory,
19203                 render: render,
19204                 programs: null,
19205                 autoReset: true,
19206                 reset: reset,
19207                 update: update
19208         };
19209
19210 }
19211
19212 function numericalSort( a, b ) {
19213
19214         return a[ 0 ] - b[ 0 ];
19215
19216 }
19217
19218 function absNumericalSort( a, b ) {
19219
19220         return Math.abs( b[ 1 ] ) - Math.abs( a[ 1 ] );
19221
19222 }
19223
19224 function WebGLMorphtargets( gl ) {
19225
19226         const influencesList = {};
19227         const morphInfluences = new Float32Array( 8 );
19228
19229         const workInfluences = [];
19230
19231         for ( let i = 0; i < 8; i ++ ) {
19232
19233                 workInfluences[ i ] = [ i, 0 ];
19234
19235         }
19236
19237         function update( object, geometry, material, program ) {
19238
19239                 const objectInfluences = object.morphTargetInfluences;
19240
19241                 // When object doesn't have morph target influences defined, we treat it as a 0-length array
19242                 // This is important to make sure we set up morphTargetBaseInfluence / morphTargetInfluences
19243
19244                 const length = objectInfluences === undefined ? 0 : objectInfluences.length;
19245
19246                 let influences = influencesList[ geometry.id ];
19247
19248                 if ( influences === undefined ) {
19249
19250                         // initialise list
19251
19252                         influences = [];
19253
19254                         for ( let i = 0; i < length; i ++ ) {
19255
19256                                 influences[ i ] = [ i, 0 ];
19257
19258                         }
19259
19260                         influencesList[ geometry.id ] = influences;
19261
19262                 }
19263
19264                 // Collect influences
19265
19266                 for ( let i = 0; i < length; i ++ ) {
19267
19268                         const influence = influences[ i ];
19269
19270                         influence[ 0 ] = i;
19271                         influence[ 1 ] = objectInfluences[ i ];
19272
19273                 }
19274
19275                 influences.sort( absNumericalSort );
19276
19277                 for ( let i = 0; i < 8; i ++ ) {
19278
19279                         if ( i < length && influences[ i ][ 1 ] ) {
19280
19281                                 workInfluences[ i ][ 0 ] = influences[ i ][ 0 ];
19282                                 workInfluences[ i ][ 1 ] = influences[ i ][ 1 ];
19283
19284                         } else {
19285
19286                                 workInfluences[ i ][ 0 ] = Number.MAX_SAFE_INTEGER;
19287                                 workInfluences[ i ][ 1 ] = 0;
19288
19289                         }
19290
19291                 }
19292
19293                 workInfluences.sort( numericalSort );
19294
19295                 const morphTargets = material.morphTargets && geometry.morphAttributes.position;
19296                 const morphNormals = material.morphNormals && geometry.morphAttributes.normal;
19297
19298                 let morphInfluencesSum = 0;
19299
19300                 for ( let i = 0; i < 8; i ++ ) {
19301
19302                         const influence = workInfluences[ i ];
19303                         const index = influence[ 0 ];
19304                         const value = influence[ 1 ];
19305
19306                         if ( index !== Number.MAX_SAFE_INTEGER && value ) {
19307
19308                                 if ( morphTargets && geometry.getAttribute( 'morphTarget' + i ) !== morphTargets[ index ] ) {
19309
19310                                         geometry.setAttribute( 'morphTarget' + i, morphTargets[ index ] );
19311
19312                                 }
19313
19314                                 if ( morphNormals && geometry.getAttribute( 'morphNormal' + i ) !== morphNormals[ index ] ) {
19315
19316                                         geometry.setAttribute( 'morphNormal' + i, morphNormals[ index ] );
19317
19318                                 }
19319
19320                                 morphInfluences[ i ] = value;
19321                                 morphInfluencesSum += value;
19322
19323                         } else {
19324
19325                                 if ( morphTargets && geometry.hasAttribute( 'morphTarget' + i ) === true ) {
19326
19327                                         geometry.deleteAttribute( 'morphTarget' + i );
19328
19329                                 }
19330
19331                                 if ( morphNormals && geometry.hasAttribute( 'morphNormal' + i ) === true ) {
19332
19333                                         geometry.deleteAttribute( 'morphNormal' + i );
19334
19335                                 }
19336
19337                                 morphInfluences[ i ] = 0;
19338
19339                         }
19340
19341                 }
19342
19343                 // GLSL shader uses formula baseinfluence * base + sum(target * influence)
19344                 // This allows us to switch between absolute morphs and relative morphs without changing shader code
19345                 // When baseinfluence = 1 - sum(influence), the above is equivalent to sum((target - base) * influence)
19346                 const morphBaseInfluence = geometry.morphTargetsRelative ? 1 : 1 - morphInfluencesSum;
19347
19348                 program.getUniforms().setValue( gl, 'morphTargetBaseInfluence', morphBaseInfluence );
19349                 program.getUniforms().setValue( gl, 'morphTargetInfluences', morphInfluences );
19350
19351         }
19352
19353         return {
19354
19355                 update: update
19356
19357         };
19358
19359 }
19360
19361 function WebGLObjects( gl, geometries, attributes, info ) {
19362
19363         let updateMap = new WeakMap();
19364
19365         function update( object ) {
19366
19367                 const frame = info.render.frame;
19368
19369                 const geometry = object.geometry;
19370                 const buffergeometry = geometries.get( object, geometry );
19371
19372                 // Update once per frame
19373
19374                 if ( updateMap.get( buffergeometry ) !== frame ) {
19375
19376                         geometries.update( buffergeometry );
19377
19378                         updateMap.set( buffergeometry, frame );
19379
19380                 }
19381
19382                 if ( object.isInstancedMesh ) {
19383
19384                         if ( object.hasEventListener( 'dispose', onInstancedMeshDispose ) === false ) {
19385
19386                                 object.addEventListener( 'dispose', onInstancedMeshDispose );
19387
19388                         }
19389
19390                         attributes.update( object.instanceMatrix, 34962 );
19391
19392                         if ( object.instanceColor !== null ) {
19393
19394                                 attributes.update( object.instanceColor, 34962 );
19395
19396                         }
19397
19398                 }
19399
19400                 return buffergeometry;
19401
19402         }
19403
19404         function dispose() {
19405
19406                 updateMap = new WeakMap();
19407
19408         }
19409
19410         function onInstancedMeshDispose( event ) {
19411
19412                 const instancedMesh = event.target;
19413
19414                 instancedMesh.removeEventListener( 'dispose', onInstancedMeshDispose );
19415
19416                 attributes.remove( instancedMesh.instanceMatrix );
19417
19418                 if ( instancedMesh.instanceColor !== null ) attributes.remove( instancedMesh.instanceColor );
19419
19420         }
19421
19422         return {
19423
19424                 update: update,
19425                 dispose: dispose
19426
19427         };
19428
19429 }
19430
19431 function DataTexture2DArray( data = null, width = 1, height = 1, depth = 1 ) {
19432
19433         Texture.call( this, null );
19434
19435         this.image = { data, width, height, depth };
19436
19437         this.magFilter = NearestFilter;
19438         this.minFilter = NearestFilter;
19439
19440         this.wrapR = ClampToEdgeWrapping;
19441
19442         this.generateMipmaps = false;
19443         this.flipY = false;
19444
19445         this.needsUpdate = true;
19446
19447 }
19448
19449 DataTexture2DArray.prototype = Object.create( Texture.prototype );
19450 DataTexture2DArray.prototype.constructor = DataTexture2DArray;
19451 DataTexture2DArray.prototype.isDataTexture2DArray = true;
19452
19453 function DataTexture3D( data = null, width = 1, height = 1, depth = 1 ) {
19454
19455         // We're going to add .setXXX() methods for setting properties later.
19456         // Users can still set in DataTexture3D directly.
19457         //
19458         //      const texture = new THREE.DataTexture3D( data, width, height, depth );
19459         //      texture.anisotropy = 16;
19460         //
19461         // See #14839
19462
19463         Texture.call( this, null );
19464
19465         this.image = { data, width, height, depth };
19466
19467         this.magFilter = NearestFilter;
19468         this.minFilter = NearestFilter;
19469
19470         this.wrapR = ClampToEdgeWrapping;
19471
19472         this.generateMipmaps = false;
19473         this.flipY = false;
19474
19475         this.needsUpdate = true;
19476
19477
19478 }
19479
19480 DataTexture3D.prototype = Object.create( Texture.prototype );
19481 DataTexture3D.prototype.constructor = DataTexture3D;
19482 DataTexture3D.prototype.isDataTexture3D = true;
19483
19484 /**
19485  * Uniforms of a program.
19486  * Those form a tree structure with a special top-level container for the root,
19487  * which you get by calling 'new WebGLUniforms( gl, program )'.
19488  *
19489  *
19490  * Properties of inner nodes including the top-level container:
19491  *
19492  * .seq - array of nested uniforms
19493  * .map - nested uniforms by name
19494  *
19495  *
19496  * Methods of all nodes except the top-level container:
19497  *
19498  * .setValue( gl, value, [textures] )
19499  *
19500  *              uploads a uniform value(s)
19501  *      the 'textures' parameter is needed for sampler uniforms
19502  *
19503  *
19504  * Static methods of the top-level container (textures factorizations):
19505  *
19506  * .upload( gl, seq, values, textures )
19507  *
19508  *              sets uniforms in 'seq' to 'values[id].value'
19509  *
19510  * .seqWithValue( seq, values ) : filteredSeq
19511  *
19512  *              filters 'seq' entries with corresponding entry in values
19513  *
19514  *
19515  * Methods of the top-level container (textures factorizations):
19516  *
19517  * .setValue( gl, name, value, textures )
19518  *
19519  *              sets uniform with  name 'name' to 'value'
19520  *
19521  * .setOptional( gl, obj, prop )
19522  *
19523  *              like .set for an optional property of the object
19524  *
19525  */
19526
19527 const emptyTexture = new Texture();
19528 const emptyTexture2dArray = new DataTexture2DArray();
19529 const emptyTexture3d = new DataTexture3D();
19530 const emptyCubeTexture = new CubeTexture();
19531
19532 // --- Utilities ---
19533
19534 // Array Caches (provide typed arrays for temporary by size)
19535
19536 const arrayCacheF32 = [];
19537 const arrayCacheI32 = [];
19538
19539 // Float32Array caches used for uploading Matrix uniforms
19540
19541 const mat4array = new Float32Array( 16 );
19542 const mat3array = new Float32Array( 9 );
19543 const mat2array = new Float32Array( 4 );
19544
19545 // Flattening for arrays of vectors and matrices
19546
19547 function flatten( array, nBlocks, blockSize ) {
19548
19549         const firstElem = array[ 0 ];
19550
19551         if ( firstElem <= 0 || firstElem > 0 ) return array;
19552         // unoptimized: ! isNaN( firstElem )
19553         // see http://jacksondunstan.com/articles/983
19554
19555         const n = nBlocks * blockSize;
19556         let r = arrayCacheF32[ n ];
19557
19558         if ( r === undefined ) {
19559
19560                 r = new Float32Array( n );
19561                 arrayCacheF32[ n ] = r;
19562
19563         }
19564
19565         if ( nBlocks !== 0 ) {
19566
19567                 firstElem.toArray( r, 0 );
19568
19569                 for ( let i = 1, offset = 0; i !== nBlocks; ++ i ) {
19570
19571                         offset += blockSize;
19572                         array[ i ].toArray( r, offset );
19573
19574                 }
19575
19576         }
19577
19578         return r;
19579
19580 }
19581
19582 function arraysEqual( a, b ) {
19583
19584         if ( a.length !== b.length ) return false;
19585
19586         for ( let i = 0, l = a.length; i < l; i ++ ) {
19587
19588                 if ( a[ i ] !== b[ i ] ) return false;
19589
19590         }
19591
19592         return true;
19593
19594 }
19595
19596 function copyArray( a, b ) {
19597
19598         for ( let i = 0, l = b.length; i < l; i ++ ) {
19599
19600                 a[ i ] = b[ i ];
19601
19602         }
19603
19604 }
19605
19606 // Texture unit allocation
19607
19608 function allocTexUnits( textures, n ) {
19609
19610         let r = arrayCacheI32[ n ];
19611
19612         if ( r === undefined ) {
19613
19614                 r = new Int32Array( n );
19615                 arrayCacheI32[ n ] = r;
19616
19617         }
19618
19619         for ( let i = 0; i !== n; ++ i ) {
19620
19621                 r[ i ] = textures.allocateTextureUnit();
19622
19623         }
19624
19625         return r;
19626
19627 }
19628
19629 // --- Setters ---
19630
19631 // Note: Defining these methods externally, because they come in a bunch
19632 // and this way their names minify.
19633
19634 // Single scalar
19635
19636 function setValueV1f( gl, v ) {
19637
19638         const cache = this.cache;
19639
19640         if ( cache[ 0 ] === v ) return;
19641
19642         gl.uniform1f( this.addr, v );
19643
19644         cache[ 0 ] = v;
19645
19646 }
19647
19648 // Single float vector (from flat array or THREE.VectorN)
19649
19650 function setValueV2f( gl, v ) {
19651
19652         const cache = this.cache;
19653
19654         if ( v.x !== undefined ) {
19655
19656                 if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y ) {
19657
19658                         gl.uniform2f( this.addr, v.x, v.y );
19659
19660                         cache[ 0 ] = v.x;
19661                         cache[ 1 ] = v.y;
19662
19663                 }
19664
19665         } else {
19666
19667                 if ( arraysEqual( cache, v ) ) return;
19668
19669                 gl.uniform2fv( this.addr, v );
19670
19671                 copyArray( cache, v );
19672
19673         }
19674
19675 }
19676
19677 function setValueV3f( gl, v ) {
19678
19679         const cache = this.cache;
19680
19681         if ( v.x !== undefined ) {
19682
19683                 if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y || cache[ 2 ] !== v.z ) {
19684
19685                         gl.uniform3f( this.addr, v.x, v.y, v.z );
19686
19687                         cache[ 0 ] = v.x;
19688                         cache[ 1 ] = v.y;
19689                         cache[ 2 ] = v.z;
19690
19691                 }
19692
19693         } else if ( v.r !== undefined ) {
19694
19695                 if ( cache[ 0 ] !== v.r || cache[ 1 ] !== v.g || cache[ 2 ] !== v.b ) {
19696
19697                         gl.uniform3f( this.addr, v.r, v.g, v.b );
19698
19699                         cache[ 0 ] = v.r;
19700                         cache[ 1 ] = v.g;
19701                         cache[ 2 ] = v.b;
19702
19703                 }
19704
19705         } else {
19706
19707                 if ( arraysEqual( cache, v ) ) return;
19708
19709                 gl.uniform3fv( this.addr, v );
19710
19711                 copyArray( cache, v );
19712
19713         }
19714
19715 }
19716
19717 function setValueV4f( gl, v ) {
19718
19719         const cache = this.cache;
19720
19721         if ( v.x !== undefined ) {
19722
19723                 if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y || cache[ 2 ] !== v.z || cache[ 3 ] !== v.w ) {
19724
19725                         gl.uniform4f( this.addr, v.x, v.y, v.z, v.w );
19726
19727                         cache[ 0 ] = v.x;
19728                         cache[ 1 ] = v.y;
19729                         cache[ 2 ] = v.z;
19730                         cache[ 3 ] = v.w;
19731
19732                 }
19733
19734         } else {
19735
19736                 if ( arraysEqual( cache, v ) ) return;
19737
19738                 gl.uniform4fv( this.addr, v );
19739
19740                 copyArray( cache, v );
19741
19742         }
19743
19744 }
19745
19746 // Single matrix (from flat array or MatrixN)
19747
19748 function setValueM2( gl, v ) {
19749
19750         const cache = this.cache;
19751         const elements = v.elements;
19752
19753         if ( elements === undefined ) {
19754
19755                 if ( arraysEqual( cache, v ) ) return;
19756
19757                 gl.uniformMatrix2fv( this.addr, false, v );
19758
19759                 copyArray( cache, v );
19760
19761         } else {
19762
19763                 if ( arraysEqual( cache, elements ) ) return;
19764
19765                 mat2array.set( elements );
19766
19767                 gl.uniformMatrix2fv( this.addr, false, mat2array );
19768
19769                 copyArray( cache, elements );
19770
19771         }
19772
19773 }
19774
19775 function setValueM3( gl, v ) {
19776
19777         const cache = this.cache;
19778         const elements = v.elements;
19779
19780         if ( elements === undefined ) {
19781
19782                 if ( arraysEqual( cache, v ) ) return;
19783
19784                 gl.uniformMatrix3fv( this.addr, false, v );
19785
19786                 copyArray( cache, v );
19787
19788         } else {
19789
19790                 if ( arraysEqual( cache, elements ) ) return;
19791
19792                 mat3array.set( elements );
19793
19794                 gl.uniformMatrix3fv( this.addr, false, mat3array );
19795
19796                 copyArray( cache, elements );
19797
19798         }
19799
19800 }
19801
19802 function setValueM4( gl, v ) {
19803
19804         const cache = this.cache;
19805         const elements = v.elements;
19806
19807         if ( elements === undefined ) {
19808
19809                 if ( arraysEqual( cache, v ) ) return;
19810
19811                 gl.uniformMatrix4fv( this.addr, false, v );
19812
19813                 copyArray( cache, v );
19814
19815         } else {
19816
19817                 if ( arraysEqual( cache, elements ) ) return;
19818
19819                 mat4array.set( elements );
19820
19821                 gl.uniformMatrix4fv( this.addr, false, mat4array );
19822
19823                 copyArray( cache, elements );
19824
19825         }
19826
19827 }
19828
19829 // Single texture (2D / Cube)
19830
19831 function setValueT1( gl, v, textures ) {
19832
19833         const cache = this.cache;
19834         const unit = textures.allocateTextureUnit();
19835
19836         if ( cache[ 0 ] !== unit ) {
19837
19838                 gl.uniform1i( this.addr, unit );
19839                 cache[ 0 ] = unit;
19840
19841         }
19842
19843         textures.safeSetTexture2D( v || emptyTexture, unit );
19844
19845 }
19846
19847 function setValueT2DArray1( gl, v, textures ) {
19848
19849         const cache = this.cache;
19850         const unit = textures.allocateTextureUnit();
19851
19852         if ( cache[ 0 ] !== unit ) {
19853
19854                 gl.uniform1i( this.addr, unit );
19855                 cache[ 0 ] = unit;
19856
19857         }
19858
19859         textures.setTexture2DArray( v || emptyTexture2dArray, unit );
19860
19861 }
19862
19863 function setValueT3D1( gl, v, textures ) {
19864
19865         const cache = this.cache;
19866         const unit = textures.allocateTextureUnit();
19867
19868         if ( cache[ 0 ] !== unit ) {
19869
19870                 gl.uniform1i( this.addr, unit );
19871                 cache[ 0 ] = unit;
19872
19873         }
19874
19875         textures.setTexture3D( v || emptyTexture3d, unit );
19876
19877 }
19878
19879 function setValueT6( gl, v, textures ) {
19880
19881         const cache = this.cache;
19882         const unit = textures.allocateTextureUnit();
19883
19884         if ( cache[ 0 ] !== unit ) {
19885
19886                 gl.uniform1i( this.addr, unit );
19887                 cache[ 0 ] = unit;
19888
19889         }
19890
19891         textures.safeSetTextureCube( v || emptyCubeTexture, unit );
19892
19893 }
19894
19895 // Integer / Boolean vectors or arrays thereof (always flat arrays)
19896
19897 function setValueV1i( gl, v ) {
19898
19899         const cache = this.cache;
19900
19901         if ( cache[ 0 ] === v ) return;
19902
19903         gl.uniform1i( this.addr, v );
19904
19905         cache[ 0 ] = v;
19906
19907 }
19908
19909 function setValueV2i( gl, v ) {
19910
19911         const cache = this.cache;
19912
19913         if ( arraysEqual( cache, v ) ) return;
19914
19915         gl.uniform2iv( this.addr, v );
19916
19917         copyArray( cache, v );
19918
19919 }
19920
19921 function setValueV3i( gl, v ) {
19922
19923         const cache = this.cache;
19924
19925         if ( arraysEqual( cache, v ) ) return;
19926
19927         gl.uniform3iv( this.addr, v );
19928
19929         copyArray( cache, v );
19930
19931 }
19932
19933 function setValueV4i( gl, v ) {
19934
19935         const cache = this.cache;
19936
19937         if ( arraysEqual( cache, v ) ) return;
19938
19939         gl.uniform4iv( this.addr, v );
19940
19941         copyArray( cache, v );
19942
19943 }
19944
19945 // uint
19946
19947 function setValueV1ui( gl, v ) {
19948
19949         const cache = this.cache;
19950
19951         if ( cache[ 0 ] === v ) return;
19952
19953         gl.uniform1ui( this.addr, v );
19954
19955         cache[ 0 ] = v;
19956
19957 }
19958
19959 // Helper to pick the right setter for the singular case
19960
19961 function getSingularSetter( type ) {
19962
19963         switch ( type ) {
19964
19965                 case 0x1406: return setValueV1f; // FLOAT
19966                 case 0x8b50: return setValueV2f; // _VEC2
19967                 case 0x8b51: return setValueV3f; // _VEC3
19968                 case 0x8b52: return setValueV4f; // _VEC4
19969
19970                 case 0x8b5a: return setValueM2; // _MAT2
19971                 case 0x8b5b: return setValueM3; // _MAT3
19972                 case 0x8b5c: return setValueM4; // _MAT4
19973
19974                 case 0x1404: case 0x8b56: return setValueV1i; // INT, BOOL
19975                 case 0x8b53: case 0x8b57: return setValueV2i; // _VEC2
19976                 case 0x8b54: case 0x8b58: return setValueV3i; // _VEC3
19977                 case 0x8b55: case 0x8b59: return setValueV4i; // _VEC4
19978
19979                 case 0x1405: return setValueV1ui; // UINT
19980
19981                 case 0x8b5e: // SAMPLER_2D
19982                 case 0x8d66: // SAMPLER_EXTERNAL_OES
19983                 case 0x8dca: // INT_SAMPLER_2D
19984                 case 0x8dd2: // UNSIGNED_INT_SAMPLER_2D
19985                 case 0x8b62: // SAMPLER_2D_SHADOW
19986                         return setValueT1;
19987
19988                 case 0x8b5f: // SAMPLER_3D
19989                 case 0x8dcb: // INT_SAMPLER_3D
19990                 case 0x8dd3: // UNSIGNED_INT_SAMPLER_3D
19991                         return setValueT3D1;
19992
19993                 case 0x8b60: // SAMPLER_CUBE
19994                 case 0x8dcc: // INT_SAMPLER_CUBE
19995                 case 0x8dd4: // UNSIGNED_INT_SAMPLER_CUBE
19996                 case 0x8dc5: // SAMPLER_CUBE_SHADOW
19997                         return setValueT6;
19998
19999                 case 0x8dc1: // SAMPLER_2D_ARRAY
20000                 case 0x8dcf: // INT_SAMPLER_2D_ARRAY
20001                 case 0x8dd7: // UNSIGNED_INT_SAMPLER_2D_ARRAY
20002                 case 0x8dc4: // SAMPLER_2D_ARRAY_SHADOW
20003                         return setValueT2DArray1;
20004
20005         }
20006
20007 }
20008
20009 // Array of scalars
20010 function setValueV1fArray( gl, v ) {
20011
20012         gl.uniform1fv( this.addr, v );
20013
20014 }
20015
20016 // Integer / Boolean vectors or arrays thereof (always flat arrays)
20017 function setValueV1iArray( gl, v ) {
20018
20019         gl.uniform1iv( this.addr, v );
20020
20021 }
20022
20023 function setValueV2iArray( gl, v ) {
20024
20025         gl.uniform2iv( this.addr, v );
20026
20027 }
20028
20029 function setValueV3iArray( gl, v ) {
20030
20031         gl.uniform3iv( this.addr, v );
20032
20033 }
20034
20035 function setValueV4iArray( gl, v ) {
20036
20037         gl.uniform4iv( this.addr, v );
20038
20039 }
20040
20041
20042 // Array of vectors (flat or from THREE classes)
20043
20044 function setValueV2fArray( gl, v ) {
20045
20046         const data = flatten( v, this.size, 2 );
20047
20048         gl.uniform2fv( this.addr, data );
20049
20050 }
20051
20052 function setValueV3fArray( gl, v ) {
20053
20054         const data = flatten( v, this.size, 3 );
20055
20056         gl.uniform3fv( this.addr, data );
20057
20058 }
20059
20060 function setValueV4fArray( gl, v ) {
20061
20062         const data = flatten( v, this.size, 4 );
20063
20064         gl.uniform4fv( this.addr, data );
20065
20066 }
20067
20068 // Array of matrices (flat or from THREE clases)
20069
20070 function setValueM2Array( gl, v ) {
20071
20072         const data = flatten( v, this.size, 4 );
20073
20074         gl.uniformMatrix2fv( this.addr, false, data );
20075
20076 }
20077
20078 function setValueM3Array( gl, v ) {
20079
20080         const data = flatten( v, this.size, 9 );
20081
20082         gl.uniformMatrix3fv( this.addr, false, data );
20083
20084 }
20085
20086 function setValueM4Array( gl, v ) {
20087
20088         const data = flatten( v, this.size, 16 );
20089
20090         gl.uniformMatrix4fv( this.addr, false, data );
20091
20092 }
20093
20094 // Array of textures (2D / Cube)
20095
20096 function setValueT1Array( gl, v, textures ) {
20097
20098         const n = v.length;
20099
20100         const units = allocTexUnits( textures, n );
20101
20102         gl.uniform1iv( this.addr, units );
20103
20104         for ( let i = 0; i !== n; ++ i ) {
20105
20106                 textures.safeSetTexture2D( v[ i ] || emptyTexture, units[ i ] );
20107
20108         }
20109
20110 }
20111
20112 function setValueT6Array( gl, v, textures ) {
20113
20114         const n = v.length;
20115
20116         const units = allocTexUnits( textures, n );
20117
20118         gl.uniform1iv( this.addr, units );
20119
20120         for ( let i = 0; i !== n; ++ i ) {
20121
20122                 textures.safeSetTextureCube( v[ i ] || emptyCubeTexture, units[ i ] );
20123
20124         }
20125
20126 }
20127
20128 // Helper to pick the right setter for a pure (bottom-level) array
20129
20130 function getPureArraySetter( type ) {
20131
20132         switch ( type ) {
20133
20134                 case 0x1406: return setValueV1fArray; // FLOAT
20135                 case 0x8b50: return setValueV2fArray; // _VEC2
20136                 case 0x8b51: return setValueV3fArray; // _VEC3
20137                 case 0x8b52: return setValueV4fArray; // _VEC4
20138
20139                 case 0x8b5a: return setValueM2Array; // _MAT2
20140                 case 0x8b5b: return setValueM3Array; // _MAT3
20141                 case 0x8b5c: return setValueM4Array; // _MAT4
20142
20143                 case 0x1404: case 0x8b56: return setValueV1iArray; // INT, BOOL
20144                 case 0x8b53: case 0x8b57: return setValueV2iArray; // _VEC2
20145                 case 0x8b54: case 0x8b58: return setValueV3iArray; // _VEC3
20146                 case 0x8b55: case 0x8b59: return setValueV4iArray; // _VEC4
20147
20148                 case 0x8b5e: // SAMPLER_2D
20149                 case 0x8d66: // SAMPLER_EXTERNAL_OES
20150                 case 0x8dca: // INT_SAMPLER_2D
20151                 case 0x8dd2: // UNSIGNED_INT_SAMPLER_2D
20152                 case 0x8b62: // SAMPLER_2D_SHADOW
20153                         return setValueT1Array;
20154
20155                 case 0x8b60: // SAMPLER_CUBE
20156                 case 0x8dcc: // INT_SAMPLER_CUBE
20157                 case 0x8dd4: // UNSIGNED_INT_SAMPLER_CUBE
20158                 case 0x8dc5: // SAMPLER_CUBE_SHADOW
20159                         return setValueT6Array;
20160
20161         }
20162
20163 }
20164
20165 // --- Uniform Classes ---
20166
20167 function SingleUniform( id, activeInfo, addr ) {
20168
20169         this.id = id;
20170         this.addr = addr;
20171         this.cache = [];
20172         this.setValue = getSingularSetter( activeInfo.type );
20173
20174         // this.path = activeInfo.name; // DEBUG
20175
20176 }
20177
20178 function PureArrayUniform( id, activeInfo, addr ) {
20179
20180         this.id = id;
20181         this.addr = addr;
20182         this.cache = [];
20183         this.size = activeInfo.size;
20184         this.setValue = getPureArraySetter( activeInfo.type );
20185
20186         // this.path = activeInfo.name; // DEBUG
20187
20188 }
20189
20190 PureArrayUniform.prototype.updateCache = function ( data ) {
20191
20192         const cache = this.cache;
20193
20194         if ( data instanceof Float32Array && cache.length !== data.length ) {
20195
20196                 this.cache = new Float32Array( data.length );
20197
20198         }
20199
20200         copyArray( cache, data );
20201
20202 };
20203
20204 function StructuredUniform( id ) {
20205
20206         this.id = id;
20207
20208         this.seq = [];
20209         this.map = {};
20210
20211 }
20212
20213 StructuredUniform.prototype.setValue = function ( gl, value, textures ) {
20214
20215         const seq = this.seq;
20216
20217         for ( let i = 0, n = seq.length; i !== n; ++ i ) {
20218
20219                 const u = seq[ i ];
20220                 u.setValue( gl, value[ u.id ], textures );
20221
20222         }
20223
20224 };
20225
20226 // --- Top-level ---
20227
20228 // Parser - builds up the property tree from the path strings
20229
20230 const RePathPart = /(\w+)(\])?(\[|\.)?/g;
20231
20232 // extracts
20233 //      - the identifier (member name or array index)
20234 //  - followed by an optional right bracket (found when array index)
20235 //  - followed by an optional left bracket or dot (type of subscript)
20236 //
20237 // Note: These portions can be read in a non-overlapping fashion and
20238 // allow straightforward parsing of the hierarchy that WebGL encodes
20239 // in the uniform names.
20240
20241 function addUniform( container, uniformObject ) {
20242
20243         container.seq.push( uniformObject );
20244         container.map[ uniformObject.id ] = uniformObject;
20245
20246 }
20247
20248 function parseUniform( activeInfo, addr, container ) {
20249
20250         const path = activeInfo.name,
20251                 pathLength = path.length;
20252
20253         // reset RegExp object, because of the early exit of a previous run
20254         RePathPart.lastIndex = 0;
20255
20256         while ( true ) {
20257
20258                 const match = RePathPart.exec( path ),
20259                         matchEnd = RePathPart.lastIndex;
20260
20261                 let id = match[ 1 ];
20262                 const idIsIndex = match[ 2 ] === ']',
20263                         subscript = match[ 3 ];
20264
20265                 if ( idIsIndex ) id = id | 0; // convert to integer
20266
20267                 if ( subscript === undefined || subscript === '[' && matchEnd + 2 === pathLength ) {
20268
20269                         // bare name or "pure" bottom-level array "[0]" suffix
20270
20271                         addUniform( container, subscript === undefined ?
20272                                 new SingleUniform( id, activeInfo, addr ) :
20273                                 new PureArrayUniform( id, activeInfo, addr ) );
20274
20275                         break;
20276
20277                 } else {
20278
20279                         // step into inner node / create it in case it doesn't exist
20280
20281                         const map = container.map;
20282                         let next = map[ id ];
20283
20284                         if ( next === undefined ) {
20285
20286                                 next = new StructuredUniform( id );
20287                                 addUniform( container, next );
20288
20289                         }
20290
20291                         container = next;
20292
20293                 }
20294
20295         }
20296
20297 }
20298
20299 // Root Container
20300
20301 function WebGLUniforms( gl, program ) {
20302
20303         this.seq = [];
20304         this.map = {};
20305
20306         const n = gl.getProgramParameter( program, 35718 );
20307
20308         for ( let i = 0; i < n; ++ i ) {
20309
20310                 const info = gl.getActiveUniform( program, i ),
20311                         addr = gl.getUniformLocation( program, info.name );
20312
20313                 parseUniform( info, addr, this );
20314
20315         }
20316
20317 }
20318
20319 WebGLUniforms.prototype.setValue = function ( gl, name, value, textures ) {
20320
20321         const u = this.map[ name ];
20322
20323         if ( u !== undefined ) u.setValue( gl, value, textures );
20324
20325 };
20326
20327 WebGLUniforms.prototype.setOptional = function ( gl, object, name ) {
20328
20329         const v = object[ name ];
20330
20331         if ( v !== undefined ) this.setValue( gl, name, v );
20332
20333 };
20334
20335
20336 // Static interface
20337
20338 WebGLUniforms.upload = function ( gl, seq, values, textures ) {
20339
20340         for ( let i = 0, n = seq.length; i !== n; ++ i ) {
20341
20342                 const u = seq[ i ],
20343                         v = values[ u.id ];
20344
20345                 if ( v.needsUpdate !== false ) {
20346
20347                         // note: always updating when .needsUpdate is undefined
20348                         u.setValue( gl, v.value, textures );
20349
20350                 }
20351
20352         }
20353
20354 };
20355
20356 WebGLUniforms.seqWithValue = function ( seq, values ) {
20357
20358         const r = [];
20359
20360         for ( let i = 0, n = seq.length; i !== n; ++ i ) {
20361
20362                 const u = seq[ i ];
20363                 if ( u.id in values ) r.push( u );
20364
20365         }
20366
20367         return r;
20368
20369 };
20370
20371 function WebGLShader( gl, type, string ) {
20372
20373         const shader = gl.createShader( type );
20374
20375         gl.shaderSource( shader, string );
20376         gl.compileShader( shader );
20377
20378         return shader;
20379
20380 }
20381
20382 let programIdCount = 0;
20383
20384 function addLineNumbers( string ) {
20385
20386         const lines = string.split( '\n' );
20387
20388         for ( let i = 0; i < lines.length; i ++ ) {
20389
20390                 lines[ i ] = ( i + 1 ) + ': ' + lines[ i ];
20391
20392         }
20393
20394         return lines.join( '\n' );
20395
20396 }
20397
20398 function getEncodingComponents( encoding ) {
20399
20400         switch ( encoding ) {
20401
20402                 case LinearEncoding:
20403                         return [ 'Linear', '( value )' ];
20404                 case sRGBEncoding:
20405                         return [ 'sRGB', '( value )' ];
20406                 case RGBEEncoding:
20407                         return [ 'RGBE', '( value )' ];
20408                 case RGBM7Encoding:
20409                         return [ 'RGBM', '( value, 7.0 )' ];
20410                 case RGBM16Encoding:
20411                         return [ 'RGBM', '( value, 16.0 )' ];
20412                 case RGBDEncoding:
20413                         return [ 'RGBD', '( value, 256.0 )' ];
20414                 case GammaEncoding:
20415                         return [ 'Gamma', '( value, float( GAMMA_FACTOR ) )' ];
20416                 case LogLuvEncoding:
20417                         return [ 'LogLuv', '( value )' ];
20418                 default:
20419                         console.warn( 'THREE.WebGLProgram: Unsupported encoding:', encoding );
20420                         return [ 'Linear', '( value )' ];
20421
20422         }
20423
20424 }
20425
20426 function getShaderErrors( gl, shader, type ) {
20427
20428         const status = gl.getShaderParameter( shader, 35713 );
20429         const log = gl.getShaderInfoLog( shader ).trim();
20430
20431         if ( status && log === '' ) return '';
20432
20433         // --enable-privileged-webgl-extension
20434         // console.log( '**' + type + '**', gl.getExtension( 'WEBGL_debug_shaders' ).getTranslatedShaderSource( shader ) );
20435
20436         const source = gl.getShaderSource( shader );
20437
20438         return 'THREE.WebGLShader: gl.getShaderInfoLog() ' + type + '\n' + log + addLineNumbers( source );
20439
20440 }
20441
20442 function getTexelDecodingFunction( functionName, encoding ) {
20443
20444         const components = getEncodingComponents( encoding );
20445         return 'vec4 ' + functionName + '( vec4 value ) { return ' + components[ 0 ] + 'ToLinear' + components[ 1 ] + '; }';
20446
20447 }
20448
20449 function getTexelEncodingFunction( functionName, encoding ) {
20450
20451         const components = getEncodingComponents( encoding );
20452         return 'vec4 ' + functionName + '( vec4 value ) { return LinearTo' + components[ 0 ] + components[ 1 ] + '; }';
20453
20454 }
20455
20456 function getToneMappingFunction( functionName, toneMapping ) {
20457
20458         let toneMappingName;
20459
20460         switch ( toneMapping ) {
20461
20462                 case LinearToneMapping:
20463                         toneMappingName = 'Linear';
20464                         break;
20465
20466                 case ReinhardToneMapping:
20467                         toneMappingName = 'Reinhard';
20468                         break;
20469
20470                 case CineonToneMapping:
20471                         toneMappingName = 'OptimizedCineon';
20472                         break;
20473
20474                 case ACESFilmicToneMapping:
20475                         toneMappingName = 'ACESFilmic';
20476                         break;
20477
20478                 case CustomToneMapping:
20479                         toneMappingName = 'Custom';
20480                         break;
20481
20482                 default:
20483                         console.warn( 'THREE.WebGLProgram: Unsupported toneMapping:', toneMapping );
20484                         toneMappingName = 'Linear';
20485
20486         }
20487
20488         return 'vec3 ' + functionName + '( vec3 color ) { return ' + toneMappingName + 'ToneMapping( color ); }';
20489
20490 }
20491
20492 function generateExtensions( parameters ) {
20493
20494         const chunks = [
20495                 ( parameters.extensionDerivatives || parameters.envMapCubeUV || parameters.bumpMap || parameters.tangentSpaceNormalMap || parameters.clearcoatNormalMap || parameters.flatShading || parameters.shaderID === 'physical' ) ? '#extension GL_OES_standard_derivatives : enable' : '',
20496                 ( parameters.extensionFragDepth || parameters.logarithmicDepthBuffer ) && parameters.rendererExtensionFragDepth ? '#extension GL_EXT_frag_depth : enable' : '',
20497                 ( parameters.extensionDrawBuffers && parameters.rendererExtensionDrawBuffers ) ? '#extension GL_EXT_draw_buffers : require' : '',
20498                 ( parameters.extensionShaderTextureLOD || parameters.envMap ) && parameters.rendererExtensionShaderTextureLod ? '#extension GL_EXT_shader_texture_lod : enable' : ''
20499         ];
20500
20501         return chunks.filter( filterEmptyLine ).join( '\n' );
20502
20503 }
20504
20505 function generateDefines( defines ) {
20506
20507         const chunks = [];
20508
20509         for ( const name in defines ) {
20510
20511                 const value = defines[ name ];
20512
20513                 if ( value === false ) continue;
20514
20515                 chunks.push( '#define ' + name + ' ' + value );
20516
20517         }
20518
20519         return chunks.join( '\n' );
20520
20521 }
20522
20523 function fetchAttributeLocations( gl, program ) {
20524
20525         const attributes = {};
20526
20527         const n = gl.getProgramParameter( program, 35721 );
20528
20529         for ( let i = 0; i < n; i ++ ) {
20530
20531                 const info = gl.getActiveAttrib( program, i );
20532                 const name = info.name;
20533
20534                 // console.log( 'THREE.WebGLProgram: ACTIVE VERTEX ATTRIBUTE:', name, i );
20535
20536                 attributes[ name ] = gl.getAttribLocation( program, name );
20537
20538         }
20539
20540         return attributes;
20541
20542 }
20543
20544 function filterEmptyLine( string ) {
20545
20546         return string !== '';
20547
20548 }
20549
20550 function replaceLightNums( string, parameters ) {
20551
20552         return string
20553                 .replace( /NUM_DIR_LIGHTS/g, parameters.numDirLights )
20554                 .replace( /NUM_SPOT_LIGHTS/g, parameters.numSpotLights )
20555                 .replace( /NUM_RECT_AREA_LIGHTS/g, parameters.numRectAreaLights )
20556                 .replace( /NUM_POINT_LIGHTS/g, parameters.numPointLights )
20557                 .replace( /NUM_HEMI_LIGHTS/g, parameters.numHemiLights )
20558                 .replace( /NUM_DIR_LIGHT_SHADOWS/g, parameters.numDirLightShadows )
20559                 .replace( /NUM_SPOT_LIGHT_SHADOWS/g, parameters.numSpotLightShadows )
20560                 .replace( /NUM_POINT_LIGHT_SHADOWS/g, parameters.numPointLightShadows );
20561
20562 }
20563
20564 function replaceClippingPlaneNums( string, parameters ) {
20565
20566         return string
20567                 .replace( /NUM_CLIPPING_PLANES/g, parameters.numClippingPlanes )
20568                 .replace( /UNION_CLIPPING_PLANES/g, ( parameters.numClippingPlanes - parameters.numClipIntersection ) );
20569
20570 }
20571
20572 // Resolve Includes
20573
20574 const includePattern = /^[ \t]*#include +<([\w\d./]+)>/gm;
20575
20576 function resolveIncludes( string ) {
20577
20578         return string.replace( includePattern, includeReplacer );
20579
20580 }
20581
20582 function includeReplacer( match, include ) {
20583
20584         const string = ShaderChunk[ include ];
20585
20586         if ( string === undefined ) {
20587
20588                 throw new Error( 'Can not resolve #include <' + include + '>' );
20589
20590         }
20591
20592         return resolveIncludes( string );
20593
20594 }
20595
20596 // Unroll Loops
20597
20598 const deprecatedUnrollLoopPattern = /#pragma unroll_loop[\s]+?for \( int i \= (\d+)\; i < (\d+)\; i \+\+ \) \{([\s\S]+?)(?=\})\}/g;
20599 const unrollLoopPattern = /#pragma unroll_loop_start\s+for\s*\(\s*int\s+i\s*=\s*(\d+)\s*;\s*i\s*<\s*(\d+)\s*;\s*i\s*\+\+\s*\)\s*{([\s\S]+?)}\s+#pragma unroll_loop_end/g;
20600
20601 function unrollLoops( string ) {
20602
20603         return string
20604                 .replace( unrollLoopPattern, loopReplacer )
20605                 .replace( deprecatedUnrollLoopPattern, deprecatedLoopReplacer );
20606
20607 }
20608
20609 function deprecatedLoopReplacer( match, start, end, snippet ) {
20610
20611         console.warn( 'WebGLProgram: #pragma unroll_loop shader syntax is deprecated. Please use #pragma unroll_loop_start syntax instead.' );
20612         return loopReplacer( match, start, end, snippet );
20613
20614 }
20615
20616 function loopReplacer( match, start, end, snippet ) {
20617
20618         let string = '';
20619
20620         for ( let i = parseInt( start ); i < parseInt( end ); i ++ ) {
20621
20622                 string += snippet
20623                         .replace( /\[\s*i\s*\]/g, '[ ' + i + ' ]' )
20624                         .replace( /UNROLLED_LOOP_INDEX/g, i );
20625
20626         }
20627
20628         return string;
20629
20630 }
20631
20632 //
20633
20634 function generatePrecision( parameters ) {
20635
20636         let precisionstring = 'precision ' + parameters.precision + ' float;\nprecision ' + parameters.precision + ' int;';
20637
20638         if ( parameters.precision === 'highp' ) {
20639
20640                 precisionstring += '\n#define HIGH_PRECISION';
20641
20642         } else if ( parameters.precision === 'mediump' ) {
20643
20644                 precisionstring += '\n#define MEDIUM_PRECISION';
20645
20646         } else if ( parameters.precision === 'lowp' ) {
20647
20648                 precisionstring += '\n#define LOW_PRECISION';
20649
20650         }
20651
20652         return precisionstring;
20653
20654 }
20655
20656 function generateShadowMapTypeDefine( parameters ) {
20657
20658         let shadowMapTypeDefine = 'SHADOWMAP_TYPE_BASIC';
20659
20660         if ( parameters.shadowMapType === PCFShadowMap ) {
20661
20662                 shadowMapTypeDefine = 'SHADOWMAP_TYPE_PCF';
20663
20664         } else if ( parameters.shadowMapType === PCFSoftShadowMap ) {
20665
20666                 shadowMapTypeDefine = 'SHADOWMAP_TYPE_PCF_SOFT';
20667
20668         } else if ( parameters.shadowMapType === VSMShadowMap ) {
20669
20670                 shadowMapTypeDefine = 'SHADOWMAP_TYPE_VSM';
20671
20672         }
20673
20674         return shadowMapTypeDefine;
20675
20676 }
20677
20678 function generateEnvMapTypeDefine( parameters ) {
20679
20680         let envMapTypeDefine = 'ENVMAP_TYPE_CUBE';
20681
20682         if ( parameters.envMap ) {
20683
20684                 switch ( parameters.envMapMode ) {
20685
20686                         case CubeReflectionMapping:
20687                         case CubeRefractionMapping:
20688                                 envMapTypeDefine = 'ENVMAP_TYPE_CUBE';
20689                                 break;
20690
20691                         case CubeUVReflectionMapping:
20692                         case CubeUVRefractionMapping:
20693                                 envMapTypeDefine = 'ENVMAP_TYPE_CUBE_UV';
20694                                 break;
20695
20696                 }
20697
20698         }
20699
20700         return envMapTypeDefine;
20701
20702 }
20703
20704 function generateEnvMapModeDefine( parameters ) {
20705
20706         let envMapModeDefine = 'ENVMAP_MODE_REFLECTION';
20707
20708         if ( parameters.envMap ) {
20709
20710                 switch ( parameters.envMapMode ) {
20711
20712                         case CubeRefractionMapping:
20713                         case CubeUVRefractionMapping:
20714
20715                                 envMapModeDefine = 'ENVMAP_MODE_REFRACTION';
20716                                 break;
20717
20718                 }
20719
20720         }
20721
20722         return envMapModeDefine;
20723
20724 }
20725
20726 function generateEnvMapBlendingDefine( parameters ) {
20727
20728         let envMapBlendingDefine = 'ENVMAP_BLENDING_NONE';
20729
20730         if ( parameters.envMap ) {
20731
20732                 switch ( parameters.combine ) {
20733
20734                         case MultiplyOperation:
20735                                 envMapBlendingDefine = 'ENVMAP_BLENDING_MULTIPLY';
20736                                 break;
20737
20738                         case MixOperation:
20739                                 envMapBlendingDefine = 'ENVMAP_BLENDING_MIX';
20740                                 break;
20741
20742                         case AddOperation:
20743                                 envMapBlendingDefine = 'ENVMAP_BLENDING_ADD';
20744                                 break;
20745
20746                 }
20747
20748         }
20749
20750         return envMapBlendingDefine;
20751
20752 }
20753
20754 function WebGLProgram( renderer, cacheKey, parameters, bindingStates ) {
20755
20756         const gl = renderer.getContext();
20757
20758         const defines = parameters.defines;
20759
20760         let vertexShader = parameters.vertexShader;
20761         let fragmentShader = parameters.fragmentShader;
20762
20763         const shadowMapTypeDefine = generateShadowMapTypeDefine( parameters );
20764         const envMapTypeDefine = generateEnvMapTypeDefine( parameters );
20765         const envMapModeDefine = generateEnvMapModeDefine( parameters );
20766         const envMapBlendingDefine = generateEnvMapBlendingDefine( parameters );
20767
20768
20769         const gammaFactorDefine = ( renderer.gammaFactor > 0 ) ? renderer.gammaFactor : 1.0;
20770
20771         const customExtensions = parameters.isWebGL2 ? '' : generateExtensions( parameters );
20772
20773         const customDefines = generateDefines( defines );
20774
20775         const program = gl.createProgram();
20776
20777         let prefixVertex, prefixFragment;
20778         let versionString = parameters.glslVersion ? '#version ' + parameters.glslVersion + '\n' : '';
20779
20780         if ( parameters.isRawShaderMaterial ) {
20781
20782                 prefixVertex = [
20783
20784                         customDefines
20785
20786                 ].filter( filterEmptyLine ).join( '\n' );
20787
20788                 if ( prefixVertex.length > 0 ) {
20789
20790                         prefixVertex += '\n';
20791
20792                 }
20793
20794                 prefixFragment = [
20795
20796                         customExtensions,
20797                         customDefines
20798
20799                 ].filter( filterEmptyLine ).join( '\n' );
20800
20801                 if ( prefixFragment.length > 0 ) {
20802
20803                         prefixFragment += '\n';
20804
20805                 }
20806
20807         } else {
20808
20809                 prefixVertex = [
20810
20811                         generatePrecision( parameters ),
20812
20813                         '#define SHADER_NAME ' + parameters.shaderName,
20814
20815                         customDefines,
20816
20817                         parameters.instancing ? '#define USE_INSTANCING' : '',
20818                         parameters.instancingColor ? '#define USE_INSTANCING_COLOR' : '',
20819
20820                         parameters.supportsVertexTextures ? '#define VERTEX_TEXTURES' : '',
20821
20822                         '#define GAMMA_FACTOR ' + gammaFactorDefine,
20823
20824                         '#define MAX_BONES ' + parameters.maxBones,
20825                         ( parameters.useFog && parameters.fog ) ? '#define USE_FOG' : '',
20826                         ( parameters.useFog && parameters.fogExp2 ) ? '#define FOG_EXP2' : '',
20827
20828                         parameters.map ? '#define USE_MAP' : '',
20829                         parameters.envMap ? '#define USE_ENVMAP' : '',
20830                         parameters.envMap ? '#define ' + envMapModeDefine : '',
20831                         parameters.lightMap ? '#define USE_LIGHTMAP' : '',
20832                         parameters.aoMap ? '#define USE_AOMAP' : '',
20833                         parameters.emissiveMap ? '#define USE_EMISSIVEMAP' : '',
20834                         parameters.bumpMap ? '#define USE_BUMPMAP' : '',
20835                         parameters.normalMap ? '#define USE_NORMALMAP' : '',
20836                         ( parameters.normalMap && parameters.objectSpaceNormalMap ) ? '#define OBJECTSPACE_NORMALMAP' : '',
20837                         ( parameters.normalMap && parameters.tangentSpaceNormalMap ) ? '#define TANGENTSPACE_NORMALMAP' : '',
20838
20839                         parameters.clearcoatMap ? '#define USE_CLEARCOATMAP' : '',
20840                         parameters.clearcoatRoughnessMap ? '#define USE_CLEARCOAT_ROUGHNESSMAP' : '',
20841                         parameters.clearcoatNormalMap ? '#define USE_CLEARCOAT_NORMALMAP' : '',
20842                         parameters.displacementMap && parameters.supportsVertexTextures ? '#define USE_DISPLACEMENTMAP' : '',
20843                         parameters.specularMap ? '#define USE_SPECULARMAP' : '',
20844                         parameters.roughnessMap ? '#define USE_ROUGHNESSMAP' : '',
20845                         parameters.metalnessMap ? '#define USE_METALNESSMAP' : '',
20846                         parameters.alphaMap ? '#define USE_ALPHAMAP' : '',
20847                         parameters.transmissionMap ? '#define USE_TRANSMISSIONMAP' : '',
20848
20849                         parameters.vertexTangents ? '#define USE_TANGENT' : '',
20850                         parameters.vertexColors ? '#define USE_COLOR' : '',
20851                         parameters.vertexUvs ? '#define USE_UV' : '',
20852                         parameters.uvsVertexOnly ? '#define UVS_VERTEX_ONLY' : '',
20853
20854                         parameters.flatShading ? '#define FLAT_SHADED' : '',
20855
20856                         parameters.skinning ? '#define USE_SKINNING' : '',
20857                         parameters.useVertexTexture ? '#define BONE_TEXTURE' : '',
20858
20859                         parameters.morphTargets ? '#define USE_MORPHTARGETS' : '',
20860                         parameters.morphNormals && parameters.flatShading === false ? '#define USE_MORPHNORMALS' : '',
20861                         parameters.doubleSided ? '#define DOUBLE_SIDED' : '',
20862                         parameters.flipSided ? '#define FLIP_SIDED' : '',
20863
20864                         parameters.shadowMapEnabled ? '#define USE_SHADOWMAP' : '',
20865                         parameters.shadowMapEnabled ? '#define ' + shadowMapTypeDefine : '',
20866
20867                         parameters.sizeAttenuation ? '#define USE_SIZEATTENUATION' : '',
20868
20869                         parameters.logarithmicDepthBuffer ? '#define USE_LOGDEPTHBUF' : '',
20870                         ( parameters.logarithmicDepthBuffer && parameters.rendererExtensionFragDepth ) ? '#define USE_LOGDEPTHBUF_EXT' : '',
20871
20872                         'uniform mat4 modelMatrix;',
20873                         'uniform mat4 modelViewMatrix;',
20874                         'uniform mat4 projectionMatrix;',
20875                         'uniform mat4 viewMatrix;',
20876                         'uniform mat3 normalMatrix;',
20877                         'uniform vec3 cameraPosition;',
20878                         'uniform bool isOrthographic;',
20879
20880                         '#ifdef USE_INSTANCING',
20881
20882                         '       attribute mat4 instanceMatrix;',
20883
20884                         '#endif',
20885
20886                         '#ifdef USE_INSTANCING_COLOR',
20887
20888                         '       attribute vec3 instanceColor;',
20889
20890                         '#endif',
20891
20892                         'attribute vec3 position;',
20893                         'attribute vec3 normal;',
20894                         'attribute vec2 uv;',
20895
20896                         '#ifdef USE_TANGENT',
20897
20898                         '       attribute vec4 tangent;',
20899
20900                         '#endif',
20901
20902                         '#ifdef USE_COLOR',
20903
20904                         '       attribute vec3 color;',
20905
20906                         '#endif',
20907
20908                         '#ifdef USE_MORPHTARGETS',
20909
20910                         '       attribute vec3 morphTarget0;',
20911                         '       attribute vec3 morphTarget1;',
20912                         '       attribute vec3 morphTarget2;',
20913                         '       attribute vec3 morphTarget3;',
20914
20915                         '       #ifdef USE_MORPHNORMALS',
20916
20917                         '               attribute vec3 morphNormal0;',
20918                         '               attribute vec3 morphNormal1;',
20919                         '               attribute vec3 morphNormal2;',
20920                         '               attribute vec3 morphNormal3;',
20921
20922                         '       #else',
20923
20924                         '               attribute vec3 morphTarget4;',
20925                         '               attribute vec3 morphTarget5;',
20926                         '               attribute vec3 morphTarget6;',
20927                         '               attribute vec3 morphTarget7;',
20928
20929                         '       #endif',
20930
20931                         '#endif',
20932
20933                         '#ifdef USE_SKINNING',
20934
20935                         '       attribute vec4 skinIndex;',
20936                         '       attribute vec4 skinWeight;',
20937
20938                         '#endif',
20939
20940                         '\n'
20941
20942                 ].filter( filterEmptyLine ).join( '\n' );
20943
20944                 prefixFragment = [
20945
20946                         customExtensions,
20947
20948                         generatePrecision( parameters ),
20949
20950                         '#define SHADER_NAME ' + parameters.shaderName,
20951
20952                         customDefines,
20953
20954                         parameters.alphaTest ? '#define ALPHATEST ' + parameters.alphaTest + ( parameters.alphaTest % 1 ? '' : '.0' ) : '', // add '.0' if integer
20955
20956                         '#define GAMMA_FACTOR ' + gammaFactorDefine,
20957
20958                         ( parameters.useFog && parameters.fog ) ? '#define USE_FOG' : '',
20959                         ( parameters.useFog && parameters.fogExp2 ) ? '#define FOG_EXP2' : '',
20960
20961                         parameters.map ? '#define USE_MAP' : '',
20962                         parameters.matcap ? '#define USE_MATCAP' : '',
20963                         parameters.envMap ? '#define USE_ENVMAP' : '',
20964                         parameters.envMap ? '#define ' + envMapTypeDefine : '',
20965                         parameters.envMap ? '#define ' + envMapModeDefine : '',
20966                         parameters.envMap ? '#define ' + envMapBlendingDefine : '',
20967                         parameters.lightMap ? '#define USE_LIGHTMAP' : '',
20968                         parameters.aoMap ? '#define USE_AOMAP' : '',
20969                         parameters.emissiveMap ? '#define USE_EMISSIVEMAP' : '',
20970                         parameters.bumpMap ? '#define USE_BUMPMAP' : '',
20971                         parameters.normalMap ? '#define USE_NORMALMAP' : '',
20972                         ( parameters.normalMap && parameters.objectSpaceNormalMap ) ? '#define OBJECTSPACE_NORMALMAP' : '',
20973                         ( parameters.normalMap && parameters.tangentSpaceNormalMap ) ? '#define TANGENTSPACE_NORMALMAP' : '',
20974                         parameters.clearcoatMap ? '#define USE_CLEARCOATMAP' : '',
20975                         parameters.clearcoatRoughnessMap ? '#define USE_CLEARCOAT_ROUGHNESSMAP' : '',
20976                         parameters.clearcoatNormalMap ? '#define USE_CLEARCOAT_NORMALMAP' : '',
20977                         parameters.specularMap ? '#define USE_SPECULARMAP' : '',
20978                         parameters.roughnessMap ? '#define USE_ROUGHNESSMAP' : '',
20979                         parameters.metalnessMap ? '#define USE_METALNESSMAP' : '',
20980                         parameters.alphaMap ? '#define USE_ALPHAMAP' : '',
20981
20982                         parameters.sheen ? '#define USE_SHEEN' : '',
20983                         parameters.transmissionMap ? '#define USE_TRANSMISSIONMAP' : '',
20984
20985                         parameters.vertexTangents ? '#define USE_TANGENT' : '',
20986                         parameters.vertexColors || parameters.instancingColor ? '#define USE_COLOR' : '',
20987                         parameters.vertexUvs ? '#define USE_UV' : '',
20988                         parameters.uvsVertexOnly ? '#define UVS_VERTEX_ONLY' : '',
20989
20990                         parameters.gradientMap ? '#define USE_GRADIENTMAP' : '',
20991
20992                         parameters.flatShading ? '#define FLAT_SHADED' : '',
20993
20994                         parameters.doubleSided ? '#define DOUBLE_SIDED' : '',
20995                         parameters.flipSided ? '#define FLIP_SIDED' : '',
20996
20997                         parameters.shadowMapEnabled ? '#define USE_SHADOWMAP' : '',
20998                         parameters.shadowMapEnabled ? '#define ' + shadowMapTypeDefine : '',
20999
21000                         parameters.premultipliedAlpha ? '#define PREMULTIPLIED_ALPHA' : '',
21001
21002                         parameters.physicallyCorrectLights ? '#define PHYSICALLY_CORRECT_LIGHTS' : '',
21003
21004                         parameters.logarithmicDepthBuffer ? '#define USE_LOGDEPTHBUF' : '',
21005                         ( parameters.logarithmicDepthBuffer && parameters.rendererExtensionFragDepth ) ? '#define USE_LOGDEPTHBUF_EXT' : '',
21006
21007                         ( ( parameters.extensionShaderTextureLOD || parameters.envMap ) && parameters.rendererExtensionShaderTextureLod ) ? '#define TEXTURE_LOD_EXT' : '',
21008
21009                         'uniform mat4 viewMatrix;',
21010                         'uniform vec3 cameraPosition;',
21011                         'uniform bool isOrthographic;',
21012
21013                         ( parameters.toneMapping !== NoToneMapping ) ? '#define TONE_MAPPING' : '',
21014                         ( parameters.toneMapping !== NoToneMapping ) ? ShaderChunk[ 'tonemapping_pars_fragment' ] : '', // this code is required here because it is used by the toneMapping() function defined below
21015                         ( parameters.toneMapping !== NoToneMapping ) ? getToneMappingFunction( 'toneMapping', parameters.toneMapping ) : '',
21016
21017                         parameters.dithering ? '#define DITHERING' : '',
21018
21019                         ShaderChunk[ 'encodings_pars_fragment' ], // this code is required here because it is used by the various encoding/decoding function defined below
21020                         parameters.map ? getTexelDecodingFunction( 'mapTexelToLinear', parameters.mapEncoding ) : '',
21021                         parameters.matcap ? getTexelDecodingFunction( 'matcapTexelToLinear', parameters.matcapEncoding ) : '',
21022                         parameters.envMap ? getTexelDecodingFunction( 'envMapTexelToLinear', parameters.envMapEncoding ) : '',
21023                         parameters.emissiveMap ? getTexelDecodingFunction( 'emissiveMapTexelToLinear', parameters.emissiveMapEncoding ) : '',
21024                         parameters.lightMap ? getTexelDecodingFunction( 'lightMapTexelToLinear', parameters.lightMapEncoding ) : '',
21025                         getTexelEncodingFunction( 'linearToOutputTexel', parameters.outputEncoding ),
21026
21027                         parameters.depthPacking ? '#define DEPTH_PACKING ' + parameters.depthPacking : '',
21028
21029                         '\n'
21030
21031                 ].filter( filterEmptyLine ).join( '\n' );
21032
21033         }
21034
21035         vertexShader = resolveIncludes( vertexShader );
21036         vertexShader = replaceLightNums( vertexShader, parameters );
21037         vertexShader = replaceClippingPlaneNums( vertexShader, parameters );
21038
21039         fragmentShader = resolveIncludes( fragmentShader );
21040         fragmentShader = replaceLightNums( fragmentShader, parameters );
21041         fragmentShader = replaceClippingPlaneNums( fragmentShader, parameters );
21042
21043         vertexShader = unrollLoops( vertexShader );
21044         fragmentShader = unrollLoops( fragmentShader );
21045
21046         if ( parameters.isWebGL2 && parameters.isRawShaderMaterial !== true ) {
21047
21048                 // GLSL 3.0 conversion for built-in materials and ShaderMaterial
21049
21050                 versionString = '#version 300 es\n';
21051
21052                 prefixVertex = [
21053                         '#define attribute in',
21054                         '#define varying out',
21055                         '#define texture2D texture'
21056                 ].join( '\n' ) + '\n' + prefixVertex;
21057
21058                 prefixFragment = [
21059                         '#define varying in',
21060                         ( parameters.glslVersion === GLSL3 ) ? '' : 'out highp vec4 pc_fragColor;',
21061                         ( parameters.glslVersion === GLSL3 ) ? '' : '#define gl_FragColor pc_fragColor',
21062                         '#define gl_FragDepthEXT gl_FragDepth',
21063                         '#define texture2D texture',
21064                         '#define textureCube texture',
21065                         '#define texture2DProj textureProj',
21066                         '#define texture2DLodEXT textureLod',
21067                         '#define texture2DProjLodEXT textureProjLod',
21068                         '#define textureCubeLodEXT textureLod',
21069                         '#define texture2DGradEXT textureGrad',
21070                         '#define texture2DProjGradEXT textureProjGrad',
21071                         '#define textureCubeGradEXT textureGrad'
21072                 ].join( '\n' ) + '\n' + prefixFragment;
21073
21074         }
21075
21076         const vertexGlsl = versionString + prefixVertex + vertexShader;
21077         const fragmentGlsl = versionString + prefixFragment + fragmentShader;
21078
21079         // console.log( '*VERTEX*', vertexGlsl );
21080         // console.log( '*FRAGMENT*', fragmentGlsl );
21081
21082         const glVertexShader = WebGLShader( gl, 35633, vertexGlsl );
21083         const glFragmentShader = WebGLShader( gl, 35632, fragmentGlsl );
21084
21085         gl.attachShader( program, glVertexShader );
21086         gl.attachShader( program, glFragmentShader );
21087
21088         // Force a particular attribute to index 0.
21089
21090         if ( parameters.index0AttributeName !== undefined ) {
21091
21092                 gl.bindAttribLocation( program, 0, parameters.index0AttributeName );
21093
21094         } else if ( parameters.morphTargets === true ) {
21095
21096                 // programs with morphTargets displace position out of attribute 0
21097                 gl.bindAttribLocation( program, 0, 'position' );
21098
21099         }
21100
21101         gl.linkProgram( program );
21102
21103         // check for link errors
21104         if ( renderer.debug.checkShaderErrors ) {
21105
21106                 const programLog = gl.getProgramInfoLog( program ).trim();
21107                 const vertexLog = gl.getShaderInfoLog( glVertexShader ).trim();
21108                 const fragmentLog = gl.getShaderInfoLog( glFragmentShader ).trim();
21109
21110                 let runnable = true;
21111                 let haveDiagnostics = true;
21112
21113                 if ( gl.getProgramParameter( program, 35714 ) === false ) {
21114
21115                         runnable = false;
21116
21117                         const vertexErrors = getShaderErrors( gl, glVertexShader, 'vertex' );
21118                         const fragmentErrors = getShaderErrors( gl, glFragmentShader, 'fragment' );
21119
21120                         console.error( 'THREE.WebGLProgram: shader error: ', gl.getError(), '35715', gl.getProgramParameter( program, 35715 ), 'gl.getProgramInfoLog', programLog, vertexErrors, fragmentErrors );
21121
21122                 } else if ( programLog !== '' ) {
21123
21124                         console.warn( 'THREE.WebGLProgram: gl.getProgramInfoLog()', programLog );
21125
21126                 } else if ( vertexLog === '' || fragmentLog === '' ) {
21127
21128                         haveDiagnostics = false;
21129
21130                 }
21131
21132                 if ( haveDiagnostics ) {
21133
21134                         this.diagnostics = {
21135
21136                                 runnable: runnable,
21137
21138                                 programLog: programLog,
21139
21140                                 vertexShader: {
21141
21142                                         log: vertexLog,
21143                                         prefix: prefixVertex
21144
21145                                 },
21146
21147                                 fragmentShader: {
21148
21149                                         log: fragmentLog,
21150                                         prefix: prefixFragment
21151
21152                                 }
21153
21154                         };
21155
21156                 }
21157
21158         }
21159
21160         // Clean up
21161
21162         // Crashes in iOS9 and iOS10. #18402
21163         // gl.detachShader( program, glVertexShader );
21164         // gl.detachShader( program, glFragmentShader );
21165
21166         gl.deleteShader( glVertexShader );
21167         gl.deleteShader( glFragmentShader );
21168
21169         // set up caching for uniform locations
21170
21171         let cachedUniforms;
21172
21173         this.getUniforms = function () {
21174
21175                 if ( cachedUniforms === undefined ) {
21176
21177                         cachedUniforms = new WebGLUniforms( gl, program );
21178
21179                 }
21180
21181                 return cachedUniforms;
21182
21183         };
21184
21185         // set up caching for attribute locations
21186
21187         let cachedAttributes;
21188
21189         this.getAttributes = function () {
21190
21191                 if ( cachedAttributes === undefined ) {
21192
21193                         cachedAttributes = fetchAttributeLocations( gl, program );
21194
21195                 }
21196
21197                 return cachedAttributes;
21198
21199         };
21200
21201         // free resource
21202
21203         this.destroy = function () {
21204
21205                 bindingStates.releaseStatesOfProgram( this );
21206
21207                 gl.deleteProgram( program );
21208                 this.program = undefined;
21209
21210         };
21211
21212         //
21213
21214         this.name = parameters.shaderName;
21215         this.id = programIdCount ++;
21216         this.cacheKey = cacheKey;
21217         this.usedTimes = 1;
21218         this.program = program;
21219         this.vertexShader = glVertexShader;
21220         this.fragmentShader = glFragmentShader;
21221
21222         return this;
21223
21224 }
21225
21226 function WebGLPrograms( renderer, cubemaps, extensions, capabilities, bindingStates, clipping ) {
21227
21228         const programs = [];
21229
21230         const isWebGL2 = capabilities.isWebGL2;
21231         const logarithmicDepthBuffer = capabilities.logarithmicDepthBuffer;
21232         const floatVertexTextures = capabilities.floatVertexTextures;
21233         const maxVertexUniforms = capabilities.maxVertexUniforms;
21234         const vertexTextures = capabilities.vertexTextures;
21235
21236         let precision = capabilities.precision;
21237
21238         const shaderIDs = {
21239                 MeshDepthMaterial: 'depth',
21240                 MeshDistanceMaterial: 'distanceRGBA',
21241                 MeshNormalMaterial: 'normal',
21242                 MeshBasicMaterial: 'basic',
21243                 MeshLambertMaterial: 'lambert',
21244                 MeshPhongMaterial: 'phong',
21245                 MeshToonMaterial: 'toon',
21246                 MeshStandardMaterial: 'physical',
21247                 MeshPhysicalMaterial: 'physical',
21248                 MeshMatcapMaterial: 'matcap',
21249                 LineBasicMaterial: 'basic',
21250                 LineDashedMaterial: 'dashed',
21251                 PointsMaterial: 'points',
21252                 ShadowMaterial: 'shadow',
21253                 SpriteMaterial: 'sprite'
21254         };
21255
21256         const parameterNames = [
21257                 'precision', 'isWebGL2', 'supportsVertexTextures', 'outputEncoding', 'instancing', 'instancingColor',
21258                 'map', 'mapEncoding', 'matcap', 'matcapEncoding', 'envMap', 'envMapMode', 'envMapEncoding', 'envMapCubeUV',
21259                 'lightMap', 'lightMapEncoding', 'aoMap', 'emissiveMap', 'emissiveMapEncoding', 'bumpMap', 'normalMap', 'objectSpaceNormalMap', 'tangentSpaceNormalMap', 'clearcoatMap', 'clearcoatRoughnessMap', 'clearcoatNormalMap', 'displacementMap', 'specularMap',
21260                 'roughnessMap', 'metalnessMap', 'gradientMap',
21261                 'alphaMap', 'combine', 'vertexColors', 'vertexTangents', 'vertexUvs', 'uvsVertexOnly', 'fog', 'useFog', 'fogExp2',
21262                 'flatShading', 'sizeAttenuation', 'logarithmicDepthBuffer', 'skinning',
21263                 'maxBones', 'useVertexTexture', 'morphTargets', 'morphNormals',
21264                 'maxMorphTargets', 'maxMorphNormals', 'premultipliedAlpha',
21265                 'numDirLights', 'numPointLights', 'numSpotLights', 'numHemiLights', 'numRectAreaLights',
21266                 'numDirLightShadows', 'numPointLightShadows', 'numSpotLightShadows',
21267                 'shadowMapEnabled', 'shadowMapType', 'toneMapping', 'physicallyCorrectLights',
21268                 'alphaTest', 'doubleSided', 'flipSided', 'numClippingPlanes', 'numClipIntersection', 'depthPacking', 'dithering',
21269                 'sheen', 'transmissionMap'
21270         ];
21271
21272         function getMaxBones( object ) {
21273
21274                 const skeleton = object.skeleton;
21275                 const bones = skeleton.bones;
21276
21277                 if ( floatVertexTextures ) {
21278
21279                         return 1024;
21280
21281                 } else {
21282
21283                         // default for when object is not specified
21284                         // ( for example when prebuilding shader to be used with multiple objects )
21285                         //
21286                         //  - leave some extra space for other uniforms
21287                         //  - limit here is ANGLE's 254 max uniform vectors
21288                         //    (up to 54 should be safe)
21289
21290                         const nVertexUniforms = maxVertexUniforms;
21291                         const nVertexMatrices = Math.floor( ( nVertexUniforms - 20 ) / 4 );
21292
21293                         const maxBones = Math.min( nVertexMatrices, bones.length );
21294
21295                         if ( maxBones < bones.length ) {
21296
21297                                 console.warn( 'THREE.WebGLRenderer: Skeleton has ' + bones.length + ' bones. This GPU supports ' + maxBones + '.' );
21298                                 return 0;
21299
21300                         }
21301
21302                         return maxBones;
21303
21304                 }
21305
21306         }
21307
21308         function getTextureEncodingFromMap( map ) {
21309
21310                 let encoding;
21311
21312                 if ( map && map.isTexture ) {
21313
21314                         encoding = map.encoding;
21315
21316                 } else if ( map && map.isWebGLRenderTarget ) {
21317
21318                         console.warn( 'THREE.WebGLPrograms.getTextureEncodingFromMap: don\'t use render targets as textures. Use their .texture property instead.' );
21319                         encoding = map.texture.encoding;
21320
21321                 } else {
21322
21323                         encoding = LinearEncoding;
21324
21325                 }
21326
21327                 return encoding;
21328
21329         }
21330
21331         function getParameters( material, lights, shadows, scene, object ) {
21332
21333                 const fog = scene.fog;
21334                 const environment = material.isMeshStandardMaterial ? scene.environment : null;
21335
21336                 const envMap = cubemaps.get( material.envMap || environment );
21337
21338                 const shaderID = shaderIDs[ material.type ];
21339
21340                 // heuristics to create shader parameters according to lights in the scene
21341                 // (not to blow over maxLights budget)
21342
21343                 const maxBones = object.isSkinnedMesh ? getMaxBones( object ) : 0;
21344
21345                 if ( material.precision !== null ) {
21346
21347                         precision = capabilities.getMaxPrecision( material.precision );
21348
21349                         if ( precision !== material.precision ) {
21350
21351                                 console.warn( 'THREE.WebGLProgram.getParameters:', material.precision, 'not supported, using', precision, 'instead.' );
21352
21353                         }
21354
21355                 }
21356
21357                 let vertexShader, fragmentShader;
21358
21359                 if ( shaderID ) {
21360
21361                         const shader = ShaderLib[ shaderID ];
21362
21363                         vertexShader = shader.vertexShader;
21364                         fragmentShader = shader.fragmentShader;
21365
21366                 } else {
21367
21368                         vertexShader = material.vertexShader;
21369                         fragmentShader = material.fragmentShader;
21370
21371                 }
21372
21373                 const currentRenderTarget = renderer.getRenderTarget();
21374
21375                 const parameters = {
21376
21377                         isWebGL2: isWebGL2,
21378
21379                         shaderID: shaderID,
21380                         shaderName: material.type,
21381
21382                         vertexShader: vertexShader,
21383                         fragmentShader: fragmentShader,
21384                         defines: material.defines,
21385
21386                         isRawShaderMaterial: material.isRawShaderMaterial === true,
21387                         glslVersion: material.glslVersion,
21388
21389                         precision: precision,
21390
21391                         instancing: object.isInstancedMesh === true,
21392                         instancingColor: object.isInstancedMesh === true && object.instanceColor !== null,
21393
21394                         supportsVertexTextures: vertexTextures,
21395                         outputEncoding: ( currentRenderTarget !== null ) ? getTextureEncodingFromMap( currentRenderTarget.texture ) : renderer.outputEncoding,
21396                         map: !! material.map,
21397                         mapEncoding: getTextureEncodingFromMap( material.map ),
21398                         matcap: !! material.matcap,
21399                         matcapEncoding: getTextureEncodingFromMap( material.matcap ),
21400                         envMap: !! envMap,
21401                         envMapMode: envMap && envMap.mapping,
21402                         envMapEncoding: getTextureEncodingFromMap( envMap ),
21403                         envMapCubeUV: ( !! envMap ) && ( ( envMap.mapping === CubeUVReflectionMapping ) || ( envMap.mapping === CubeUVRefractionMapping ) ),
21404                         lightMap: !! material.lightMap,
21405                         lightMapEncoding: getTextureEncodingFromMap( material.lightMap ),
21406                         aoMap: !! material.aoMap,
21407                         emissiveMap: !! material.emissiveMap,
21408                         emissiveMapEncoding: getTextureEncodingFromMap( material.emissiveMap ),
21409                         bumpMap: !! material.bumpMap,
21410                         normalMap: !! material.normalMap,
21411                         objectSpaceNormalMap: material.normalMapType === ObjectSpaceNormalMap,
21412                         tangentSpaceNormalMap: material.normalMapType === TangentSpaceNormalMap,
21413                         clearcoatMap: !! material.clearcoatMap,
21414                         clearcoatRoughnessMap: !! material.clearcoatRoughnessMap,
21415                         clearcoatNormalMap: !! material.clearcoatNormalMap,
21416                         displacementMap: !! material.displacementMap,
21417                         roughnessMap: !! material.roughnessMap,
21418                         metalnessMap: !! material.metalnessMap,
21419                         specularMap: !! material.specularMap,
21420                         alphaMap: !! material.alphaMap,
21421
21422                         gradientMap: !! material.gradientMap,
21423
21424                         sheen: !! material.sheen,
21425
21426                         transmissionMap: !! material.transmissionMap,
21427
21428                         combine: material.combine,
21429
21430                         vertexTangents: ( material.normalMap && material.vertexTangents ),
21431                         vertexColors: material.vertexColors,
21432                         vertexUvs: !! material.map || !! material.bumpMap || !! material.normalMap || !! material.specularMap || !! material.alphaMap || !! material.emissiveMap || !! material.roughnessMap || !! material.metalnessMap || !! material.clearcoatMap || !! material.clearcoatRoughnessMap || !! material.clearcoatNormalMap || !! material.displacementMap || !! material.transmissionMap,
21433                         uvsVertexOnly: ! ( !! material.map || !! material.bumpMap || !! material.normalMap || !! material.specularMap || !! material.alphaMap || !! material.emissiveMap || !! material.roughnessMap || !! material.metalnessMap || !! material.clearcoatNormalMap || !! material.transmissionMap ) && !! material.displacementMap,
21434
21435                         fog: !! fog,
21436                         useFog: material.fog,
21437                         fogExp2: ( fog && fog.isFogExp2 ),
21438
21439                         flatShading: material.flatShading,
21440
21441                         sizeAttenuation: material.sizeAttenuation,
21442                         logarithmicDepthBuffer: logarithmicDepthBuffer,
21443
21444                         skinning: material.skinning && maxBones > 0,
21445                         maxBones: maxBones,
21446                         useVertexTexture: floatVertexTextures,
21447
21448                         morphTargets: material.morphTargets,
21449                         morphNormals: material.morphNormals,
21450                         maxMorphTargets: renderer.maxMorphTargets,
21451                         maxMorphNormals: renderer.maxMorphNormals,
21452
21453                         numDirLights: lights.directional.length,
21454                         numPointLights: lights.point.length,
21455                         numSpotLights: lights.spot.length,
21456                         numRectAreaLights: lights.rectArea.length,
21457                         numHemiLights: lights.hemi.length,
21458
21459                         numDirLightShadows: lights.directionalShadowMap.length,
21460                         numPointLightShadows: lights.pointShadowMap.length,
21461                         numSpotLightShadows: lights.spotShadowMap.length,
21462
21463                         numClippingPlanes: clipping.numPlanes,
21464                         numClipIntersection: clipping.numIntersection,
21465
21466                         dithering: material.dithering,
21467
21468                         shadowMapEnabled: renderer.shadowMap.enabled && shadows.length > 0,
21469                         shadowMapType: renderer.shadowMap.type,
21470
21471                         toneMapping: material.toneMapped ? renderer.toneMapping : NoToneMapping,
21472                         physicallyCorrectLights: renderer.physicallyCorrectLights,
21473
21474                         premultipliedAlpha: material.premultipliedAlpha,
21475
21476                         alphaTest: material.alphaTest,
21477                         doubleSided: material.side === DoubleSide,
21478                         flipSided: material.side === BackSide,
21479
21480                         depthPacking: ( material.depthPacking !== undefined ) ? material.depthPacking : false,
21481
21482                         index0AttributeName: material.index0AttributeName,
21483
21484                         extensionDerivatives: material.extensions && material.extensions.derivatives,
21485                         extensionFragDepth: material.extensions && material.extensions.fragDepth,
21486                         extensionDrawBuffers: material.extensions && material.extensions.drawBuffers,
21487                         extensionShaderTextureLOD: material.extensions && material.extensions.shaderTextureLOD,
21488
21489                         rendererExtensionFragDepth: isWebGL2 || extensions.has( 'EXT_frag_depth' ),
21490                         rendererExtensionDrawBuffers: isWebGL2 || extensions.has( 'WEBGL_draw_buffers' ),
21491                         rendererExtensionShaderTextureLod: isWebGL2 || extensions.has( 'EXT_shader_texture_lod' ),
21492
21493                         customProgramCacheKey: material.customProgramCacheKey()
21494
21495                 };
21496
21497                 return parameters;
21498
21499         }
21500
21501         function getProgramCacheKey( parameters ) {
21502
21503                 const array = [];
21504
21505                 if ( parameters.shaderID ) {
21506
21507                         array.push( parameters.shaderID );
21508
21509                 } else {
21510
21511                         array.push( parameters.fragmentShader );
21512                         array.push( parameters.vertexShader );
21513
21514                 }
21515
21516                 if ( parameters.defines !== undefined ) {
21517
21518                         for ( const name in parameters.defines ) {
21519
21520                                 array.push( name );
21521                                 array.push( parameters.defines[ name ] );
21522
21523                         }
21524
21525                 }
21526
21527                 if ( parameters.isRawShaderMaterial === false ) {
21528
21529                         for ( let i = 0; i < parameterNames.length; i ++ ) {
21530
21531                                 array.push( parameters[ parameterNames[ i ] ] );
21532
21533                         }
21534
21535                         array.push( renderer.outputEncoding );
21536                         array.push( renderer.gammaFactor );
21537
21538                 }
21539
21540                 array.push( parameters.customProgramCacheKey );
21541
21542                 return array.join();
21543
21544         }
21545
21546         function getUniforms( material ) {
21547
21548                 const shaderID = shaderIDs[ material.type ];
21549                 let uniforms;
21550
21551                 if ( shaderID ) {
21552
21553                         const shader = ShaderLib[ shaderID ];
21554                         uniforms = UniformsUtils.clone( shader.uniforms );
21555
21556                 } else {
21557
21558                         uniforms = material.uniforms;
21559
21560                 }
21561
21562                 return uniforms;
21563
21564         }
21565
21566         function acquireProgram( parameters, cacheKey ) {
21567
21568                 let program;
21569
21570                 // Check if code has been already compiled
21571                 for ( let p = 0, pl = programs.length; p < pl; p ++ ) {
21572
21573                         const preexistingProgram = programs[ p ];
21574
21575                         if ( preexistingProgram.cacheKey === cacheKey ) {
21576
21577                                 program = preexistingProgram;
21578                                 ++ program.usedTimes;
21579
21580                                 break;
21581
21582                         }
21583
21584                 }
21585
21586                 if ( program === undefined ) {
21587
21588                         program = new WebGLProgram( renderer, cacheKey, parameters, bindingStates );
21589                         programs.push( program );
21590
21591                 }
21592
21593                 return program;
21594
21595         }
21596
21597         function releaseProgram( program ) {
21598
21599                 if ( -- program.usedTimes === 0 ) {
21600
21601                         // Remove from unordered set
21602                         const i = programs.indexOf( program );
21603                         programs[ i ] = programs[ programs.length - 1 ];
21604                         programs.pop();
21605
21606                         // Free WebGL resources
21607                         program.destroy();
21608
21609                 }
21610
21611         }
21612
21613         return {
21614                 getParameters: getParameters,
21615                 getProgramCacheKey: getProgramCacheKey,
21616                 getUniforms: getUniforms,
21617                 acquireProgram: acquireProgram,
21618                 releaseProgram: releaseProgram,
21619                 // Exposed for resource monitoring & error feedback via renderer.info:
21620                 programs: programs
21621         };
21622
21623 }
21624
21625 function WebGLProperties() {
21626
21627         let properties = new WeakMap();
21628
21629         function get( object ) {
21630
21631                 let map = properties.get( object );
21632
21633                 if ( map === undefined ) {
21634
21635                         map = {};
21636                         properties.set( object, map );
21637
21638                 }
21639
21640                 return map;
21641
21642         }
21643
21644         function remove( object ) {
21645
21646                 properties.delete( object );
21647
21648         }
21649
21650         function update( object, key, value ) {
21651
21652                 properties.get( object )[ key ] = value;
21653
21654         }
21655
21656         function dispose() {
21657
21658                 properties = new WeakMap();
21659
21660         }
21661
21662         return {
21663                 get: get,
21664                 remove: remove,
21665                 update: update,
21666                 dispose: dispose
21667         };
21668
21669 }
21670
21671 function painterSortStable( a, b ) {
21672
21673         if ( a.groupOrder !== b.groupOrder ) {
21674
21675                 return a.groupOrder - b.groupOrder;
21676
21677         } else if ( a.renderOrder !== b.renderOrder ) {
21678
21679                 return a.renderOrder - b.renderOrder;
21680
21681         } else if ( a.program !== b.program ) {
21682
21683                 return a.program.id - b.program.id;
21684
21685         } else if ( a.material.id !== b.material.id ) {
21686
21687                 return a.material.id - b.material.id;
21688
21689         } else if ( a.z !== b.z ) {
21690
21691                 return a.z - b.z;
21692
21693         } else {
21694
21695                 return a.id - b.id;
21696
21697         }
21698
21699 }
21700
21701 function reversePainterSortStable( a, b ) {
21702
21703         if ( a.groupOrder !== b.groupOrder ) {
21704
21705                 return a.groupOrder - b.groupOrder;
21706
21707         } else if ( a.renderOrder !== b.renderOrder ) {
21708
21709                 return a.renderOrder - b.renderOrder;
21710
21711         } else if ( a.z !== b.z ) {
21712
21713                 return b.z - a.z;
21714
21715         } else {
21716
21717                 return a.id - b.id;
21718
21719         }
21720
21721 }
21722
21723
21724 function WebGLRenderList( properties ) {
21725
21726         const renderItems = [];
21727         let renderItemsIndex = 0;
21728
21729         const opaque = [];
21730         const transparent = [];
21731
21732         const defaultProgram = { id: - 1 };
21733
21734         function init() {
21735
21736                 renderItemsIndex = 0;
21737
21738                 opaque.length = 0;
21739                 transparent.length = 0;
21740
21741         }
21742
21743         function getNextRenderItem( object, geometry, material, groupOrder, z, group ) {
21744
21745                 let renderItem = renderItems[ renderItemsIndex ];
21746                 const materialProperties = properties.get( material );
21747
21748                 if ( renderItem === undefined ) {
21749
21750                         renderItem = {
21751                                 id: object.id,
21752                                 object: object,
21753                                 geometry: geometry,
21754                                 material: material,
21755                                 program: materialProperties.program || defaultProgram,
21756                                 groupOrder: groupOrder,
21757                                 renderOrder: object.renderOrder,
21758                                 z: z,
21759                                 group: group
21760                         };
21761
21762                         renderItems[ renderItemsIndex ] = renderItem;
21763
21764                 } else {
21765
21766                         renderItem.id = object.id;
21767                         renderItem.object = object;
21768                         renderItem.geometry = geometry;
21769                         renderItem.material = material;
21770                         renderItem.program = materialProperties.program || defaultProgram;
21771                         renderItem.groupOrder = groupOrder;
21772                         renderItem.renderOrder = object.renderOrder;
21773                         renderItem.z = z;
21774                         renderItem.group = group;
21775
21776                 }
21777
21778                 renderItemsIndex ++;
21779
21780                 return renderItem;
21781
21782         }
21783
21784         function push( object, geometry, material, groupOrder, z, group ) {
21785
21786                 const renderItem = getNextRenderItem( object, geometry, material, groupOrder, z, group );
21787
21788                 ( material.transparent === true ? transparent : opaque ).push( renderItem );
21789
21790         }
21791
21792         function unshift( object, geometry, material, groupOrder, z, group ) {
21793
21794                 const renderItem = getNextRenderItem( object, geometry, material, groupOrder, z, group );
21795
21796                 ( material.transparent === true ? transparent : opaque ).unshift( renderItem );
21797
21798         }
21799
21800         function sort( customOpaqueSort, customTransparentSort ) {
21801
21802                 if ( opaque.length > 1 ) opaque.sort( customOpaqueSort || painterSortStable );
21803                 if ( transparent.length > 1 ) transparent.sort( customTransparentSort || reversePainterSortStable );
21804
21805         }
21806
21807         function finish() {
21808
21809                 // Clear references from inactive renderItems in the list
21810
21811                 for ( let i = renderItemsIndex, il = renderItems.length; i < il; i ++ ) {
21812
21813                         const renderItem = renderItems[ i ];
21814
21815                         if ( renderItem.id === null ) break;
21816
21817                         renderItem.id = null;
21818                         renderItem.object = null;
21819                         renderItem.geometry = null;
21820                         renderItem.material = null;
21821                         renderItem.program = null;
21822                         renderItem.group = null;
21823
21824                 }
21825
21826         }
21827
21828         return {
21829
21830                 opaque: opaque,
21831                 transparent: transparent,
21832
21833                 init: init,
21834                 push: push,
21835                 unshift: unshift,
21836                 finish: finish,
21837
21838                 sort: sort
21839         };
21840
21841 }
21842
21843 function WebGLRenderLists( properties ) {
21844
21845         let lists = new WeakMap();
21846
21847         function get( scene, camera ) {
21848
21849                 const cameras = lists.get( scene );
21850                 let list;
21851
21852                 if ( cameras === undefined ) {
21853
21854                         list = new WebGLRenderList( properties );
21855                         lists.set( scene, new WeakMap() );
21856                         lists.get( scene ).set( camera, list );
21857
21858                 } else {
21859
21860                         list = cameras.get( camera );
21861                         if ( list === undefined ) {
21862
21863                                 list = new WebGLRenderList( properties );
21864                                 cameras.set( camera, list );
21865
21866                         }
21867
21868                 }
21869
21870                 return list;
21871
21872         }
21873
21874         function dispose() {
21875
21876                 lists = new WeakMap();
21877
21878         }
21879
21880         return {
21881                 get: get,
21882                 dispose: dispose
21883         };
21884
21885 }
21886
21887 function UniformsCache() {
21888
21889         const lights = {};
21890
21891         return {
21892
21893                 get: function ( light ) {
21894
21895                         if ( lights[ light.id ] !== undefined ) {
21896
21897                                 return lights[ light.id ];
21898
21899                         }
21900
21901                         let uniforms;
21902
21903                         switch ( light.type ) {
21904
21905                                 case 'DirectionalLight':
21906                                         uniforms = {
21907                                                 direction: new Vector3(),
21908                                                 color: new Color()
21909                                         };
21910                                         break;
21911
21912                                 case 'SpotLight':
21913                                         uniforms = {
21914                                                 position: new Vector3(),
21915                                                 direction: new Vector3(),
21916                                                 color: new Color(),
21917                                                 distance: 0,
21918                                                 coneCos: 0,
21919                                                 penumbraCos: 0,
21920                                                 decay: 0
21921                                         };
21922                                         break;
21923
21924                                 case 'PointLight':
21925                                         uniforms = {
21926                                                 position: new Vector3(),
21927                                                 color: new Color(),
21928                                                 distance: 0,
21929                                                 decay: 0
21930                                         };
21931                                         break;
21932
21933                                 case 'HemisphereLight':
21934                                         uniforms = {
21935                                                 direction: new Vector3(),
21936                                                 skyColor: new Color(),
21937                                                 groundColor: new Color()
21938                                         };
21939                                         break;
21940
21941                                 case 'RectAreaLight':
21942                                         uniforms = {
21943                                                 color: new Color(),
21944                                                 position: new Vector3(),
21945                                                 halfWidth: new Vector3(),
21946                                                 halfHeight: new Vector3()
21947                                         };
21948                                         break;
21949
21950                         }
21951
21952                         lights[ light.id ] = uniforms;
21953
21954                         return uniforms;
21955
21956                 }
21957
21958         };
21959
21960 }
21961
21962 function ShadowUniformsCache() {
21963
21964         const lights = {};
21965
21966         return {
21967
21968                 get: function ( light ) {
21969
21970                         if ( lights[ light.id ] !== undefined ) {
21971
21972                                 return lights[ light.id ];
21973
21974                         }
21975
21976                         let uniforms;
21977
21978                         switch ( light.type ) {
21979
21980                                 case 'DirectionalLight':
21981                                         uniforms = {
21982                                                 shadowBias: 0,
21983                                                 shadowNormalBias: 0,
21984                                                 shadowRadius: 1,
21985                                                 shadowMapSize: new Vector2()
21986                                         };
21987                                         break;
21988
21989                                 case 'SpotLight':
21990                                         uniforms = {
21991                                                 shadowBias: 0,
21992                                                 shadowNormalBias: 0,
21993                                                 shadowRadius: 1,
21994                                                 shadowMapSize: new Vector2()
21995                                         };
21996                                         break;
21997
21998                                 case 'PointLight':
21999                                         uniforms = {
22000                                                 shadowBias: 0,
22001                                                 shadowNormalBias: 0,
22002                                                 shadowRadius: 1,
22003                                                 shadowMapSize: new Vector2(),
22004                                                 shadowCameraNear: 1,
22005                                                 shadowCameraFar: 1000
22006                                         };
22007                                         break;
22008
22009                                 // TODO (abelnation): set RectAreaLight shadow uniforms
22010
22011                         }
22012
22013                         lights[ light.id ] = uniforms;
22014
22015                         return uniforms;
22016
22017                 }
22018
22019         };
22020
22021 }
22022
22023
22024
22025 let nextVersion = 0;
22026
22027 function shadowCastingLightsFirst( lightA, lightB ) {
22028
22029         return ( lightB.castShadow ? 1 : 0 ) - ( lightA.castShadow ? 1 : 0 );
22030
22031 }
22032
22033 function WebGLLights( extensions, capabilities ) {
22034
22035         const cache = new UniformsCache();
22036
22037         const shadowCache = ShadowUniformsCache();
22038
22039         const state = {
22040
22041                 version: 0,
22042
22043                 hash: {
22044                         directionalLength: - 1,
22045                         pointLength: - 1,
22046                         spotLength: - 1,
22047                         rectAreaLength: - 1,
22048                         hemiLength: - 1,
22049
22050                         numDirectionalShadows: - 1,
22051                         numPointShadows: - 1,
22052                         numSpotShadows: - 1
22053                 },
22054
22055                 ambient: [ 0, 0, 0 ],
22056                 probe: [],
22057                 directional: [],
22058                 directionalShadow: [],
22059                 directionalShadowMap: [],
22060                 directionalShadowMatrix: [],
22061                 spot: [],
22062                 spotShadow: [],
22063                 spotShadowMap: [],
22064                 spotShadowMatrix: [],
22065                 rectArea: [],
22066                 rectAreaLTC1: null,
22067                 rectAreaLTC2: null,
22068                 point: [],
22069                 pointShadow: [],
22070                 pointShadowMap: [],
22071                 pointShadowMatrix: [],
22072                 hemi: []
22073
22074         };
22075
22076         for ( let i = 0; i < 9; i ++ ) state.probe.push( new Vector3() );
22077
22078         const vector3 = new Vector3();
22079         const matrix4 = new Matrix4();
22080         const matrix42 = new Matrix4();
22081
22082         function setup( lights ) {
22083
22084                 let r = 0, g = 0, b = 0;
22085
22086                 for ( let i = 0; i < 9; i ++ ) state.probe[ i ].set( 0, 0, 0 );
22087
22088                 let directionalLength = 0;
22089                 let pointLength = 0;
22090                 let spotLength = 0;
22091                 let rectAreaLength = 0;
22092                 let hemiLength = 0;
22093
22094                 let numDirectionalShadows = 0;
22095                 let numPointShadows = 0;
22096                 let numSpotShadows = 0;
22097
22098                 lights.sort( shadowCastingLightsFirst );
22099
22100                 for ( let i = 0, l = lights.length; i < l; i ++ ) {
22101
22102                         const light = lights[ i ];
22103
22104                         const color = light.color;
22105                         const intensity = light.intensity;
22106                         const distance = light.distance;
22107
22108                         const shadowMap = ( light.shadow && light.shadow.map ) ? light.shadow.map.texture : null;
22109
22110                         if ( light.isAmbientLight ) {
22111
22112                                 r += color.r * intensity;
22113                                 g += color.g * intensity;
22114                                 b += color.b * intensity;
22115
22116                         } else if ( light.isLightProbe ) {
22117
22118                                 for ( let j = 0; j < 9; j ++ ) {
22119
22120                                         state.probe[ j ].addScaledVector( light.sh.coefficients[ j ], intensity );
22121
22122                                 }
22123
22124                         } else if ( light.isDirectionalLight ) {
22125
22126                                 const uniforms = cache.get( light );
22127
22128                                 uniforms.color.copy( light.color ).multiplyScalar( light.intensity );
22129
22130                                 if ( light.castShadow ) {
22131
22132                                         const shadow = light.shadow;
22133
22134                                         const shadowUniforms = shadowCache.get( light );
22135
22136                                         shadowUniforms.shadowBias = shadow.bias;
22137                                         shadowUniforms.shadowNormalBias = shadow.normalBias;
22138                                         shadowUniforms.shadowRadius = shadow.radius;
22139                                         shadowUniforms.shadowMapSize = shadow.mapSize;
22140
22141                                         state.directionalShadow[ directionalLength ] = shadowUniforms;
22142                                         state.directionalShadowMap[ directionalLength ] = shadowMap;
22143                                         state.directionalShadowMatrix[ directionalLength ] = light.shadow.matrix;
22144
22145                                         numDirectionalShadows ++;
22146
22147                                 }
22148
22149                                 state.directional[ directionalLength ] = uniforms;
22150
22151                                 directionalLength ++;
22152
22153                         } else if ( light.isSpotLight ) {
22154
22155                                 const uniforms = cache.get( light );
22156
22157                                 uniforms.position.setFromMatrixPosition( light.matrixWorld );
22158
22159                                 uniforms.color.copy( color ).multiplyScalar( intensity );
22160                                 uniforms.distance = distance;
22161
22162                                 uniforms.coneCos = Math.cos( light.angle );
22163                                 uniforms.penumbraCos = Math.cos( light.angle * ( 1 - light.penumbra ) );
22164                                 uniforms.decay = light.decay;
22165
22166                                 if ( light.castShadow ) {
22167
22168                                         const shadow = light.shadow;
22169
22170                                         const shadowUniforms = shadowCache.get( light );
22171
22172                                         shadowUniforms.shadowBias = shadow.bias;
22173                                         shadowUniforms.shadowNormalBias = shadow.normalBias;
22174                                         shadowUniforms.shadowRadius = shadow.radius;
22175                                         shadowUniforms.shadowMapSize = shadow.mapSize;
22176
22177                                         state.spotShadow[ spotLength ] = shadowUniforms;
22178                                         state.spotShadowMap[ spotLength ] = shadowMap;
22179                                         state.spotShadowMatrix[ spotLength ] = light.shadow.matrix;
22180
22181                                         numSpotShadows ++;
22182
22183                                 }
22184
22185                                 state.spot[ spotLength ] = uniforms;
22186
22187                                 spotLength ++;
22188
22189                         } else if ( light.isRectAreaLight ) {
22190
22191                                 const uniforms = cache.get( light );
22192
22193                                 // (a) intensity is the total visible light emitted
22194                                 //uniforms.color.copy( color ).multiplyScalar( intensity / ( light.width * light.height * Math.PI ) );
22195
22196                                 // (b) intensity is the brightness of the light
22197                                 uniforms.color.copy( color ).multiplyScalar( intensity );
22198
22199                                 uniforms.halfWidth.set( light.width * 0.5, 0.0, 0.0 );
22200                                 uniforms.halfHeight.set( 0.0, light.height * 0.5, 0.0 );
22201
22202                                 state.rectArea[ rectAreaLength ] = uniforms;
22203
22204                                 rectAreaLength ++;
22205
22206                         } else if ( light.isPointLight ) {
22207
22208                                 const uniforms = cache.get( light );
22209
22210                                 uniforms.color.copy( light.color ).multiplyScalar( light.intensity );
22211                                 uniforms.distance = light.distance;
22212                                 uniforms.decay = light.decay;
22213
22214                                 if ( light.castShadow ) {
22215
22216                                         const shadow = light.shadow;
22217
22218                                         const shadowUniforms = shadowCache.get( light );
22219
22220                                         shadowUniforms.shadowBias = shadow.bias;
22221                                         shadowUniforms.shadowNormalBias = shadow.normalBias;
22222                                         shadowUniforms.shadowRadius = shadow.radius;
22223                                         shadowUniforms.shadowMapSize = shadow.mapSize;
22224                                         shadowUniforms.shadowCameraNear = shadow.camera.near;
22225                                         shadowUniforms.shadowCameraFar = shadow.camera.far;
22226
22227                                         state.pointShadow[ pointLength ] = shadowUniforms;
22228                                         state.pointShadowMap[ pointLength ] = shadowMap;
22229                                         state.pointShadowMatrix[ pointLength ] = light.shadow.matrix;
22230
22231                                         numPointShadows ++;
22232
22233                                 }
22234
22235                                 state.point[ pointLength ] = uniforms;
22236
22237                                 pointLength ++;
22238
22239                         } else if ( light.isHemisphereLight ) {
22240
22241                                 const uniforms = cache.get( light );
22242
22243                                 uniforms.skyColor.copy( light.color ).multiplyScalar( intensity );
22244                                 uniforms.groundColor.copy( light.groundColor ).multiplyScalar( intensity );
22245
22246                                 state.hemi[ hemiLength ] = uniforms;
22247
22248                                 hemiLength ++;
22249
22250                         }
22251
22252                 }
22253
22254                 if ( rectAreaLength > 0 ) {
22255
22256                         if ( capabilities.isWebGL2 ) {
22257
22258                                 // WebGL 2
22259
22260                                 state.rectAreaLTC1 = UniformsLib.LTC_FLOAT_1;
22261                                 state.rectAreaLTC2 = UniformsLib.LTC_FLOAT_2;
22262
22263                         } else {
22264
22265                                 // WebGL 1
22266
22267                                 if ( extensions.has( 'OES_texture_float_linear' ) === true ) {
22268
22269                                         state.rectAreaLTC1 = UniformsLib.LTC_FLOAT_1;
22270                                         state.rectAreaLTC2 = UniformsLib.LTC_FLOAT_2;
22271
22272                                 } else if ( extensions.has( 'OES_texture_half_float_linear' ) === true ) {
22273
22274                                         state.rectAreaLTC1 = UniformsLib.LTC_HALF_1;
22275                                         state.rectAreaLTC2 = UniformsLib.LTC_HALF_2;
22276
22277                                 } else {
22278
22279                                         console.error( 'THREE.WebGLRenderer: Unable to use RectAreaLight. Missing WebGL extensions.' );
22280
22281                                 }
22282
22283                         }
22284
22285                 }
22286
22287                 state.ambient[ 0 ] = r;
22288                 state.ambient[ 1 ] = g;
22289                 state.ambient[ 2 ] = b;
22290
22291                 const hash = state.hash;
22292
22293                 if ( hash.directionalLength !== directionalLength ||
22294                         hash.pointLength !== pointLength ||
22295                         hash.spotLength !== spotLength ||
22296                         hash.rectAreaLength !== rectAreaLength ||
22297                         hash.hemiLength !== hemiLength ||
22298                         hash.numDirectionalShadows !== numDirectionalShadows ||
22299                         hash.numPointShadows !== numPointShadows ||
22300                         hash.numSpotShadows !== numSpotShadows ) {
22301
22302                         state.directional.length = directionalLength;
22303                         state.spot.length = spotLength;
22304                         state.rectArea.length = rectAreaLength;
22305                         state.point.length = pointLength;
22306                         state.hemi.length = hemiLength;
22307
22308                         state.directionalShadow.length = numDirectionalShadows;
22309                         state.directionalShadowMap.length = numDirectionalShadows;
22310                         state.pointShadow.length = numPointShadows;
22311                         state.pointShadowMap.length = numPointShadows;
22312                         state.spotShadow.length = numSpotShadows;
22313                         state.spotShadowMap.length = numSpotShadows;
22314                         state.directionalShadowMatrix.length = numDirectionalShadows;
22315                         state.pointShadowMatrix.length = numPointShadows;
22316                         state.spotShadowMatrix.length = numSpotShadows;
22317
22318                         hash.directionalLength = directionalLength;
22319                         hash.pointLength = pointLength;
22320                         hash.spotLength = spotLength;
22321                         hash.rectAreaLength = rectAreaLength;
22322                         hash.hemiLength = hemiLength;
22323
22324                         hash.numDirectionalShadows = numDirectionalShadows;
22325                         hash.numPointShadows = numPointShadows;
22326                         hash.numSpotShadows = numSpotShadows;
22327
22328                         state.version = nextVersion ++;
22329
22330                 }
22331
22332         }
22333
22334         function setupView( lights, camera ) {
22335
22336                 let directionalLength = 0;
22337                 let pointLength = 0;
22338                 let spotLength = 0;
22339                 let rectAreaLength = 0;
22340                 let hemiLength = 0;
22341
22342                 const viewMatrix = camera.matrixWorldInverse;
22343
22344                 for ( let i = 0, l = lights.length; i < l; i ++ ) {
22345
22346                         const light = lights[ i ];
22347
22348                         if ( light.isDirectionalLight ) {
22349
22350                                 const uniforms = state.directional[ directionalLength ];
22351
22352                                 uniforms.direction.setFromMatrixPosition( light.matrixWorld );
22353                                 vector3.setFromMatrixPosition( light.target.matrixWorld );
22354                                 uniforms.direction.sub( vector3 );
22355                                 uniforms.direction.transformDirection( viewMatrix );
22356
22357                                 directionalLength ++;
22358
22359                         } else if ( light.isSpotLight ) {
22360
22361                                 const uniforms = state.spot[ spotLength ];
22362
22363                                 uniforms.position.setFromMatrixPosition( light.matrixWorld );
22364                                 uniforms.position.applyMatrix4( viewMatrix );
22365
22366                                 uniforms.direction.setFromMatrixPosition( light.matrixWorld );
22367                                 vector3.setFromMatrixPosition( light.target.matrixWorld );
22368                                 uniforms.direction.sub( vector3 );
22369                                 uniforms.direction.transformDirection( viewMatrix );
22370
22371                                 spotLength ++;
22372
22373                         } else if ( light.isRectAreaLight ) {
22374
22375                                 const uniforms = state.rectArea[ rectAreaLength ];
22376
22377                                 uniforms.position.setFromMatrixPosition( light.matrixWorld );
22378                                 uniforms.position.applyMatrix4( viewMatrix );
22379
22380                                 // extract local rotation of light to derive width/height half vectors
22381                                 matrix42.identity();
22382                                 matrix4.copy( light.matrixWorld );
22383                                 matrix4.premultiply( viewMatrix );
22384                                 matrix42.extractRotation( matrix4 );
22385
22386                                 uniforms.halfWidth.set( light.width * 0.5, 0.0, 0.0 );
22387                                 uniforms.halfHeight.set( 0.0, light.height * 0.5, 0.0 );
22388
22389                                 uniforms.halfWidth.applyMatrix4( matrix42 );
22390                                 uniforms.halfHeight.applyMatrix4( matrix42 );
22391
22392                                 rectAreaLength ++;
22393
22394                         } else if ( light.isPointLight ) {
22395
22396                                 const uniforms = state.point[ pointLength ];
22397
22398                                 uniforms.position.setFromMatrixPosition( light.matrixWorld );
22399                                 uniforms.position.applyMatrix4( viewMatrix );
22400
22401                                 pointLength ++;
22402
22403                         } else if ( light.isHemisphereLight ) {
22404
22405                                 const uniforms = state.hemi[ hemiLength ];
22406
22407                                 uniforms.direction.setFromMatrixPosition( light.matrixWorld );
22408                                 uniforms.direction.transformDirection( viewMatrix );
22409                                 uniforms.direction.normalize();
22410
22411                                 hemiLength ++;
22412
22413                         }
22414
22415                 }
22416
22417         }
22418
22419         return {
22420                 setup: setup,
22421                 setupView: setupView,
22422                 state: state
22423         };
22424
22425 }
22426
22427 function WebGLRenderState( extensions, capabilities ) {
22428
22429         const lights = new WebGLLights( extensions, capabilities );
22430
22431         const lightsArray = [];
22432         const shadowsArray = [];
22433
22434         function init() {
22435
22436                 lightsArray.length = 0;
22437                 shadowsArray.length = 0;
22438
22439         }
22440
22441         function pushLight( light ) {
22442
22443                 lightsArray.push( light );
22444
22445         }
22446
22447         function pushShadow( shadowLight ) {
22448
22449                 shadowsArray.push( shadowLight );
22450
22451         }
22452
22453         function setupLights() {
22454
22455                 lights.setup( lightsArray );
22456
22457         }
22458
22459         function setupLightsView( camera ) {
22460
22461                 lights.setupView( lightsArray, camera );
22462
22463         }
22464
22465         const state = {
22466                 lightsArray: lightsArray,
22467                 shadowsArray: shadowsArray,
22468
22469                 lights: lights
22470         };
22471
22472         return {
22473                 init: init,
22474                 state: state,
22475                 setupLights: setupLights,
22476                 setupLightsView: setupLightsView,
22477
22478                 pushLight: pushLight,
22479                 pushShadow: pushShadow
22480         };
22481
22482 }
22483
22484 function WebGLRenderStates( extensions, capabilities ) {
22485
22486         let renderStates = new WeakMap();
22487
22488         function get( scene, renderCallDepth = 0 ) {
22489
22490                 let renderState;
22491
22492                 if ( renderStates.has( scene ) === false ) {
22493
22494                         renderState = new WebGLRenderState( extensions, capabilities );
22495                         renderStates.set( scene, [] );
22496                         renderStates.get( scene ).push( renderState );
22497
22498                 } else {
22499
22500                         if ( renderCallDepth >= renderStates.get( scene ).length ) {
22501
22502                                 renderState = new WebGLRenderState( extensions, capabilities );
22503                                 renderStates.get( scene ).push( renderState );
22504
22505                         } else {
22506
22507                                 renderState = renderStates.get( scene )[ renderCallDepth ];
22508
22509                         }
22510
22511                 }
22512
22513                 return renderState;
22514
22515         }
22516
22517         function dispose() {
22518
22519                 renderStates = new WeakMap();
22520
22521         }
22522
22523         return {
22524                 get: get,
22525                 dispose: dispose
22526         };
22527
22528 }
22529
22530 /**
22531  * parameters = {
22532  *
22533  *  opacity: <float>,
22534  *
22535  *  map: new THREE.Texture( <Image> ),
22536  *
22537  *  alphaMap: new THREE.Texture( <Image> ),
22538  *
22539  *  displacementMap: new THREE.Texture( <Image> ),
22540  *  displacementScale: <float>,
22541  *  displacementBias: <float>,
22542  *
22543  *  wireframe: <boolean>,
22544  *  wireframeLinewidth: <float>
22545  * }
22546  */
22547
22548 function MeshDepthMaterial( parameters ) {
22549
22550         Material.call( this );
22551
22552         this.type = 'MeshDepthMaterial';
22553
22554         this.depthPacking = BasicDepthPacking;
22555
22556         this.skinning = false;
22557         this.morphTargets = false;
22558
22559         this.map = null;
22560
22561         this.alphaMap = null;
22562
22563         this.displacementMap = null;
22564         this.displacementScale = 1;
22565         this.displacementBias = 0;
22566
22567         this.wireframe = false;
22568         this.wireframeLinewidth = 1;
22569
22570         this.fog = false;
22571
22572         this.setValues( parameters );
22573
22574 }
22575
22576 MeshDepthMaterial.prototype = Object.create( Material.prototype );
22577 MeshDepthMaterial.prototype.constructor = MeshDepthMaterial;
22578
22579 MeshDepthMaterial.prototype.isMeshDepthMaterial = true;
22580
22581 MeshDepthMaterial.prototype.copy = function ( source ) {
22582
22583         Material.prototype.copy.call( this, source );
22584
22585         this.depthPacking = source.depthPacking;
22586
22587         this.skinning = source.skinning;
22588         this.morphTargets = source.morphTargets;
22589
22590         this.map = source.map;
22591
22592         this.alphaMap = source.alphaMap;
22593
22594         this.displacementMap = source.displacementMap;
22595         this.displacementScale = source.displacementScale;
22596         this.displacementBias = source.displacementBias;
22597
22598         this.wireframe = source.wireframe;
22599         this.wireframeLinewidth = source.wireframeLinewidth;
22600
22601         return this;
22602
22603 };
22604
22605 /**
22606  * parameters = {
22607  *
22608  *  referencePosition: <float>,
22609  *  nearDistance: <float>,
22610  *  farDistance: <float>,
22611  *
22612  *  skinning: <bool>,
22613  *  morphTargets: <bool>,
22614  *
22615  *  map: new THREE.Texture( <Image> ),
22616  *
22617  *  alphaMap: new THREE.Texture( <Image> ),
22618  *
22619  *  displacementMap: new THREE.Texture( <Image> ),
22620  *  displacementScale: <float>,
22621  *  displacementBias: <float>
22622  *
22623  * }
22624  */
22625
22626 function MeshDistanceMaterial( parameters ) {
22627
22628         Material.call( this );
22629
22630         this.type = 'MeshDistanceMaterial';
22631
22632         this.referencePosition = new Vector3();
22633         this.nearDistance = 1;
22634         this.farDistance = 1000;
22635
22636         this.skinning = false;
22637         this.morphTargets = false;
22638
22639         this.map = null;
22640
22641         this.alphaMap = null;
22642
22643         this.displacementMap = null;
22644         this.displacementScale = 1;
22645         this.displacementBias = 0;
22646
22647         this.fog = false;
22648
22649         this.setValues( parameters );
22650
22651 }
22652
22653 MeshDistanceMaterial.prototype = Object.create( Material.prototype );
22654 MeshDistanceMaterial.prototype.constructor = MeshDistanceMaterial;
22655
22656 MeshDistanceMaterial.prototype.isMeshDistanceMaterial = true;
22657
22658 MeshDistanceMaterial.prototype.copy = function ( source ) {
22659
22660         Material.prototype.copy.call( this, source );
22661
22662         this.referencePosition.copy( source.referencePosition );
22663         this.nearDistance = source.nearDistance;
22664         this.farDistance = source.farDistance;
22665
22666         this.skinning = source.skinning;
22667         this.morphTargets = source.morphTargets;
22668
22669         this.map = source.map;
22670
22671         this.alphaMap = source.alphaMap;
22672
22673         this.displacementMap = source.displacementMap;
22674         this.displacementScale = source.displacementScale;
22675         this.displacementBias = source.displacementBias;
22676
22677         return this;
22678
22679 };
22680
22681 var vsm_frag = "uniform sampler2D shadow_pass;\nuniform vec2 resolution;\nuniform float radius;\n#include <packing>\nvoid main() {\n\tfloat mean = 0.0;\n\tfloat squared_mean = 0.0;\n\tfloat depth = unpackRGBAToDepth( texture2D( shadow_pass, ( gl_FragCoord.xy ) / resolution ) );\n\tfor ( float i = -1.0; i < 1.0 ; i += SAMPLE_RATE) {\n\t\t#ifdef HORIZONTAL_PASS\n\t\t\tvec2 distribution = unpackRGBATo2Half( texture2D( shadow_pass, ( gl_FragCoord.xy + vec2( i, 0.0 ) * radius ) / resolution ) );\n\t\t\tmean += distribution.x;\n\t\t\tsquared_mean += distribution.y * distribution.y + distribution.x * distribution.x;\n\t\t#else\n\t\t\tfloat depth = unpackRGBAToDepth( texture2D( shadow_pass, ( gl_FragCoord.xy + vec2( 0.0, i ) * radius ) / resolution ) );\n\t\t\tmean += depth;\n\t\t\tsquared_mean += depth * depth;\n\t\t#endif\n\t}\n\tmean = mean * HALF_SAMPLE_RATE;\n\tsquared_mean = squared_mean * HALF_SAMPLE_RATE;\n\tfloat std_dev = sqrt( squared_mean - mean * mean );\n\tgl_FragColor = pack2HalfToRGBA( vec2( mean, std_dev ) );\n}";
22682
22683 var vsm_vert = "void main() {\n\tgl_Position = vec4( position, 1.0 );\n}";
22684
22685 function WebGLShadowMap( _renderer, _objects, maxTextureSize ) {
22686
22687         let _frustum = new Frustum();
22688
22689         const _shadowMapSize = new Vector2(),
22690                 _viewportSize = new Vector2(),
22691
22692                 _viewport = new Vector4(),
22693
22694                 _depthMaterials = [],
22695                 _distanceMaterials = [],
22696
22697                 _materialCache = {};
22698
22699         const shadowSide = { 0: BackSide, 1: FrontSide, 2: DoubleSide };
22700
22701         const shadowMaterialVertical = new ShaderMaterial( {
22702
22703                 defines: {
22704                         SAMPLE_RATE: 2.0 / 8.0,
22705                         HALF_SAMPLE_RATE: 1.0 / 8.0
22706                 },
22707
22708                 uniforms: {
22709                         shadow_pass: { value: null },
22710                         resolution: { value: new Vector2() },
22711                         radius: { value: 4.0 }
22712                 },
22713
22714                 vertexShader: vsm_vert,
22715
22716                 fragmentShader: vsm_frag
22717
22718         } );
22719
22720         const shadowMaterialHorizontal = shadowMaterialVertical.clone();
22721         shadowMaterialHorizontal.defines.HORIZONTAL_PASS = 1;
22722
22723         const fullScreenTri = new BufferGeometry();
22724         fullScreenTri.setAttribute(
22725                 'position',
22726                 new BufferAttribute(
22727                         new Float32Array( [ - 1, - 1, 0.5, 3, - 1, 0.5, - 1, 3, 0.5 ] ),
22728                         3
22729                 )
22730         );
22731
22732         const fullScreenMesh = new Mesh( fullScreenTri, shadowMaterialVertical );
22733
22734         const scope = this;
22735
22736         this.enabled = false;
22737
22738         this.autoUpdate = true;
22739         this.needsUpdate = false;
22740
22741         this.type = PCFShadowMap;
22742
22743         this.render = function ( lights, scene, camera ) {
22744
22745                 if ( scope.enabled === false ) return;
22746                 if ( scope.autoUpdate === false && scope.needsUpdate === false ) return;
22747
22748                 if ( lights.length === 0 ) return;
22749
22750                 const currentRenderTarget = _renderer.getRenderTarget();
22751                 const activeCubeFace = _renderer.getActiveCubeFace();
22752                 const activeMipmapLevel = _renderer.getActiveMipmapLevel();
22753
22754                 const _state = _renderer.state;
22755
22756                 // Set GL state for depth map.
22757                 _state.setBlending( NoBlending );
22758                 _state.buffers.color.setClear( 1, 1, 1, 1 );
22759                 _state.buffers.depth.setTest( true );
22760                 _state.setScissorTest( false );
22761
22762                 // render depth map
22763
22764                 for ( let i = 0, il = lights.length; i < il; i ++ ) {
22765
22766                         const light = lights[ i ];
22767                         const shadow = light.shadow;
22768
22769                         if ( shadow === undefined ) {
22770
22771                                 console.warn( 'THREE.WebGLShadowMap:', light, 'has no shadow.' );
22772                                 continue;
22773
22774                         }
22775
22776                         if ( shadow.autoUpdate === false && shadow.needsUpdate === false ) continue;
22777
22778                         _shadowMapSize.copy( shadow.mapSize );
22779
22780                         const shadowFrameExtents = shadow.getFrameExtents();
22781
22782                         _shadowMapSize.multiply( shadowFrameExtents );
22783
22784                         _viewportSize.copy( shadow.mapSize );
22785
22786                         if ( _shadowMapSize.x > maxTextureSize || _shadowMapSize.y > maxTextureSize ) {
22787
22788                                 if ( _shadowMapSize.x > maxTextureSize ) {
22789
22790                                         _viewportSize.x = Math.floor( maxTextureSize / shadowFrameExtents.x );
22791                                         _shadowMapSize.x = _viewportSize.x * shadowFrameExtents.x;
22792                                         shadow.mapSize.x = _viewportSize.x;
22793
22794                                 }
22795
22796                                 if ( _shadowMapSize.y > maxTextureSize ) {
22797
22798                                         _viewportSize.y = Math.floor( maxTextureSize / shadowFrameExtents.y );
22799                                         _shadowMapSize.y = _viewportSize.y * shadowFrameExtents.y;
22800                                         shadow.mapSize.y = _viewportSize.y;
22801
22802                                 }
22803
22804                         }
22805
22806                         if ( shadow.map === null && ! shadow.isPointLightShadow && this.type === VSMShadowMap ) {
22807
22808                                 const pars = { minFilter: LinearFilter, magFilter: LinearFilter, format: RGBAFormat };
22809
22810                                 shadow.map = new WebGLRenderTarget( _shadowMapSize.x, _shadowMapSize.y, pars );
22811                                 shadow.map.texture.name = light.name + '.shadowMap';
22812
22813                                 shadow.mapPass = new WebGLRenderTarget( _shadowMapSize.x, _shadowMapSize.y, pars );
22814
22815                                 shadow.camera.updateProjectionMatrix();
22816
22817                         }
22818
22819                         if ( shadow.map === null ) {
22820
22821                                 const pars = { minFilter: NearestFilter, magFilter: NearestFilter, format: RGBAFormat };
22822
22823                                 shadow.map = new WebGLRenderTarget( _shadowMapSize.x, _shadowMapSize.y, pars );
22824                                 shadow.map.texture.name = light.name + '.shadowMap';
22825
22826                                 shadow.camera.updateProjectionMatrix();
22827
22828                         }
22829
22830                         _renderer.setRenderTarget( shadow.map );
22831                         _renderer.clear();
22832
22833                         const viewportCount = shadow.getViewportCount();
22834
22835                         for ( let vp = 0; vp < viewportCount; vp ++ ) {
22836
22837                                 const viewport = shadow.getViewport( vp );
22838
22839                                 _viewport.set(
22840                                         _viewportSize.x * viewport.x,
22841                                         _viewportSize.y * viewport.y,
22842                                         _viewportSize.x * viewport.z,
22843                                         _viewportSize.y * viewport.w
22844                                 );
22845
22846                                 _state.viewport( _viewport );
22847
22848                                 shadow.updateMatrices( light, vp );
22849
22850                                 _frustum = shadow.getFrustum();
22851
22852                                 renderObject( scene, camera, shadow.camera, light, this.type );
22853
22854                         }
22855
22856                         // do blur pass for VSM
22857
22858                         if ( ! shadow.isPointLightShadow && this.type === VSMShadowMap ) {
22859
22860                                 VSMPass( shadow, camera );
22861
22862                         }
22863
22864                         shadow.needsUpdate = false;
22865
22866                 }
22867
22868                 scope.needsUpdate = false;
22869
22870                 _renderer.setRenderTarget( currentRenderTarget, activeCubeFace, activeMipmapLevel );
22871
22872         };
22873
22874         function VSMPass( shadow, camera ) {
22875
22876                 const geometry = _objects.update( fullScreenMesh );
22877
22878                 // vertical pass
22879
22880                 shadowMaterialVertical.uniforms.shadow_pass.value = shadow.map.texture;
22881                 shadowMaterialVertical.uniforms.resolution.value = shadow.mapSize;
22882                 shadowMaterialVertical.uniforms.radius.value = shadow.radius;
22883                 _renderer.setRenderTarget( shadow.mapPass );
22884                 _renderer.clear();
22885                 _renderer.renderBufferDirect( camera, null, geometry, shadowMaterialVertical, fullScreenMesh, null );
22886
22887                 // horizontal pass
22888
22889                 shadowMaterialHorizontal.uniforms.shadow_pass.value = shadow.mapPass.texture;
22890                 shadowMaterialHorizontal.uniforms.resolution.value = shadow.mapSize;
22891                 shadowMaterialHorizontal.uniforms.radius.value = shadow.radius;
22892                 _renderer.setRenderTarget( shadow.map );
22893                 _renderer.clear();
22894                 _renderer.renderBufferDirect( camera, null, geometry, shadowMaterialHorizontal, fullScreenMesh, null );
22895
22896         }
22897
22898         function getDepthMaterialVariant( useMorphing, useSkinning, useInstancing ) {
22899
22900                 const index = useMorphing << 0 | useSkinning << 1 | useInstancing << 2;
22901
22902                 let material = _depthMaterials[ index ];
22903
22904                 if ( material === undefined ) {
22905
22906                         material = new MeshDepthMaterial( {
22907
22908                                 depthPacking: RGBADepthPacking,
22909
22910                                 morphTargets: useMorphing,
22911                                 skinning: useSkinning
22912
22913                         } );
22914
22915                         _depthMaterials[ index ] = material;
22916
22917                 }
22918
22919                 return material;
22920
22921         }
22922
22923         function getDistanceMaterialVariant( useMorphing, useSkinning, useInstancing ) {
22924
22925                 const index = useMorphing << 0 | useSkinning << 1 | useInstancing << 2;
22926
22927                 let material = _distanceMaterials[ index ];
22928
22929                 if ( material === undefined ) {
22930
22931                         material = new MeshDistanceMaterial( {
22932
22933                                 morphTargets: useMorphing,
22934                                 skinning: useSkinning
22935
22936                         } );
22937
22938                         _distanceMaterials[ index ] = material;
22939
22940                 }
22941
22942                 return material;
22943
22944         }
22945
22946         function getDepthMaterial( object, geometry, material, light, shadowCameraNear, shadowCameraFar, type ) {
22947
22948                 let result = null;
22949
22950                 let getMaterialVariant = getDepthMaterialVariant;
22951                 let customMaterial = object.customDepthMaterial;
22952
22953                 if ( light.isPointLight === true ) {
22954
22955                         getMaterialVariant = getDistanceMaterialVariant;
22956                         customMaterial = object.customDistanceMaterial;
22957
22958                 }
22959
22960                 if ( customMaterial === undefined ) {
22961
22962                         let useMorphing = false;
22963
22964                         if ( material.morphTargets === true ) {
22965
22966                                 useMorphing = geometry.morphAttributes && geometry.morphAttributes.position && geometry.morphAttributes.position.length > 0;
22967
22968                         }
22969
22970                         let useSkinning = false;
22971
22972                         if ( object.isSkinnedMesh === true ) {
22973
22974                                 if ( material.skinning === true ) {
22975
22976                                         useSkinning = true;
22977
22978                                 } else {
22979
22980                                         console.warn( 'THREE.WebGLShadowMap: THREE.SkinnedMesh with material.skinning set to false:', object );
22981
22982                                 }
22983
22984                         }
22985
22986                         const useInstancing = object.isInstancedMesh === true;
22987
22988                         result = getMaterialVariant( useMorphing, useSkinning, useInstancing );
22989
22990                 } else {
22991
22992                         result = customMaterial;
22993
22994                 }
22995
22996                 if ( _renderer.localClippingEnabled &&
22997                                 material.clipShadows === true &&
22998                                 material.clippingPlanes.length !== 0 ) {
22999
23000                         // in this case we need a unique material instance reflecting the
23001                         // appropriate state
23002
23003                         const keyA = result.uuid, keyB = material.uuid;
23004
23005                         let materialsForVariant = _materialCache[ keyA ];
23006
23007                         if ( materialsForVariant === undefined ) {
23008
23009                                 materialsForVariant = {};
23010                                 _materialCache[ keyA ] = materialsForVariant;
23011
23012                         }
23013
23014                         let cachedMaterial = materialsForVariant[ keyB ];
23015
23016                         if ( cachedMaterial === undefined ) {
23017
23018                                 cachedMaterial = result.clone();
23019                                 materialsForVariant[ keyB ] = cachedMaterial;
23020
23021                         }
23022
23023                         result = cachedMaterial;
23024
23025                 }
23026
23027                 result.visible = material.visible;
23028                 result.wireframe = material.wireframe;
23029
23030                 if ( type === VSMShadowMap ) {
23031
23032                         result.side = ( material.shadowSide !== null ) ? material.shadowSide : material.side;
23033
23034                 } else {
23035
23036                         result.side = ( material.shadowSide !== null ) ? material.shadowSide : shadowSide[ material.side ];
23037
23038                 }
23039
23040                 result.clipShadows = material.clipShadows;
23041                 result.clippingPlanes = material.clippingPlanes;
23042                 result.clipIntersection = material.clipIntersection;
23043
23044                 result.wireframeLinewidth = material.wireframeLinewidth;
23045                 result.linewidth = material.linewidth;
23046
23047                 if ( light.isPointLight === true && result.isMeshDistanceMaterial === true ) {
23048
23049                         result.referencePosition.setFromMatrixPosition( light.matrixWorld );
23050                         result.nearDistance = shadowCameraNear;
23051                         result.farDistance = shadowCameraFar;
23052
23053                 }
23054
23055                 return result;
23056
23057         }
23058
23059         function renderObject( object, camera, shadowCamera, light, type ) {
23060
23061                 if ( object.visible === false ) return;
23062
23063                 const visible = object.layers.test( camera.layers );
23064
23065                 if ( visible && ( object.isMesh || object.isLine || object.isPoints ) ) {
23066
23067                         if ( ( object.castShadow || ( object.receiveShadow && type === VSMShadowMap ) ) && ( ! object.frustumCulled || _frustum.intersectsObject( object ) ) ) {
23068
23069                                 object.modelViewMatrix.multiplyMatrices( shadowCamera.matrixWorldInverse, object.matrixWorld );
23070
23071                                 const geometry = _objects.update( object );
23072                                 const material = object.material;
23073
23074                                 if ( Array.isArray( material ) ) {
23075
23076                                         const groups = geometry.groups;
23077
23078                                         for ( let k = 0, kl = groups.length; k < kl; k ++ ) {
23079
23080                                                 const group = groups[ k ];
23081                                                 const groupMaterial = material[ group.materialIndex ];
23082
23083                                                 if ( groupMaterial && groupMaterial.visible ) {
23084
23085                                                         const depthMaterial = getDepthMaterial( object, geometry, groupMaterial, light, shadowCamera.near, shadowCamera.far, type );
23086
23087                                                         _renderer.renderBufferDirect( shadowCamera, null, geometry, depthMaterial, object, group );
23088
23089                                                 }
23090
23091                                         }
23092
23093                                 } else if ( material.visible ) {
23094
23095                                         const depthMaterial = getDepthMaterial( object, geometry, material, light, shadowCamera.near, shadowCamera.far, type );
23096
23097                                         _renderer.renderBufferDirect( shadowCamera, null, geometry, depthMaterial, object, null );
23098
23099                                 }
23100
23101                         }
23102
23103                 }
23104
23105                 const children = object.children;
23106
23107                 for ( let i = 0, l = children.length; i < l; i ++ ) {
23108
23109                         renderObject( children[ i ], camera, shadowCamera, light, type );
23110
23111                 }
23112
23113         }
23114
23115 }
23116
23117 function WebGLState( gl, extensions, capabilities ) {
23118
23119         const isWebGL2 = capabilities.isWebGL2;
23120
23121         function ColorBuffer() {
23122
23123                 let locked = false;
23124
23125                 const color = new Vector4();
23126                 let currentColorMask = null;
23127                 const currentColorClear = new Vector4( 0, 0, 0, 0 );
23128
23129                 return {
23130
23131                         setMask: function ( colorMask ) {
23132
23133                                 if ( currentColorMask !== colorMask && ! locked ) {
23134
23135                                         gl.colorMask( colorMask, colorMask, colorMask, colorMask );
23136                                         currentColorMask = colorMask;
23137
23138                                 }
23139
23140                         },
23141
23142                         setLocked: function ( lock ) {
23143
23144                                 locked = lock;
23145
23146                         },
23147
23148                         setClear: function ( r, g, b, a, premultipliedAlpha ) {
23149
23150                                 if ( premultipliedAlpha === true ) {
23151
23152                                         r *= a; g *= a; b *= a;
23153
23154                                 }
23155
23156                                 color.set( r, g, b, a );
23157
23158                                 if ( currentColorClear.equals( color ) === false ) {
23159
23160                                         gl.clearColor( r, g, b, a );
23161                                         currentColorClear.copy( color );
23162
23163                                 }
23164
23165                         },
23166
23167                         reset: function () {
23168
23169                                 locked = false;
23170
23171                                 currentColorMask = null;
23172                                 currentColorClear.set( - 1, 0, 0, 0 ); // set to invalid state
23173
23174                         }
23175
23176                 };
23177
23178         }
23179
23180         function DepthBuffer() {
23181
23182                 let locked = false;
23183
23184                 let currentDepthMask = null;
23185                 let currentDepthFunc = null;
23186                 let currentDepthClear = null;
23187
23188                 return {
23189
23190                         setTest: function ( depthTest ) {
23191
23192                                 if ( depthTest ) {
23193
23194                                         enable( 2929 );
23195
23196                                 } else {
23197
23198                                         disable( 2929 );
23199
23200                                 }
23201
23202                         },
23203
23204                         setMask: function ( depthMask ) {
23205
23206                                 if ( currentDepthMask !== depthMask && ! locked ) {
23207
23208                                         gl.depthMask( depthMask );
23209                                         currentDepthMask = depthMask;
23210
23211                                 }
23212
23213                         },
23214
23215                         setFunc: function ( depthFunc ) {
23216
23217                                 if ( currentDepthFunc !== depthFunc ) {
23218
23219                                         if ( depthFunc ) {
23220
23221                                                 switch ( depthFunc ) {
23222
23223                                                         case NeverDepth:
23224
23225                                                                 gl.depthFunc( 512 );
23226                                                                 break;
23227
23228                                                         case AlwaysDepth:
23229
23230                                                                 gl.depthFunc( 519 );
23231                                                                 break;
23232
23233                                                         case LessDepth:
23234
23235                                                                 gl.depthFunc( 513 );
23236                                                                 break;
23237
23238                                                         case LessEqualDepth:
23239
23240                                                                 gl.depthFunc( 515 );
23241                                                                 break;
23242
23243                                                         case EqualDepth:
23244
23245                                                                 gl.depthFunc( 514 );
23246                                                                 break;
23247
23248                                                         case GreaterEqualDepth:
23249
23250                                                                 gl.depthFunc( 518 );
23251                                                                 break;
23252
23253                                                         case GreaterDepth:
23254
23255                                                                 gl.depthFunc( 516 );
23256                                                                 break;
23257
23258                                                         case NotEqualDepth:
23259
23260                                                                 gl.depthFunc( 517 );
23261                                                                 break;
23262
23263                                                         default:
23264
23265                                                                 gl.depthFunc( 515 );
23266
23267                                                 }
23268
23269                                         } else {
23270
23271                                                 gl.depthFunc( 515 );
23272
23273                                         }
23274
23275                                         currentDepthFunc = depthFunc;
23276
23277                                 }
23278
23279                         },
23280
23281                         setLocked: function ( lock ) {
23282
23283                                 locked = lock;
23284
23285                         },
23286
23287                         setClear: function ( depth ) {
23288
23289                                 if ( currentDepthClear !== depth ) {
23290
23291                                         gl.clearDepth( depth );
23292                                         currentDepthClear = depth;
23293
23294                                 }
23295
23296                         },
23297
23298                         reset: function () {
23299
23300                                 locked = false;
23301
23302                                 currentDepthMask = null;
23303                                 currentDepthFunc = null;
23304                                 currentDepthClear = null;
23305
23306                         }
23307
23308                 };
23309
23310         }
23311
23312         function StencilBuffer() {
23313
23314                 let locked = false;
23315
23316                 let currentStencilMask = null;
23317                 let currentStencilFunc = null;
23318                 let currentStencilRef = null;
23319                 let currentStencilFuncMask = null;
23320                 let currentStencilFail = null;
23321                 let currentStencilZFail = null;
23322                 let currentStencilZPass = null;
23323                 let currentStencilClear = null;
23324
23325                 return {
23326
23327                         setTest: function ( stencilTest ) {
23328
23329                                 if ( ! locked ) {
23330
23331                                         if ( stencilTest ) {
23332
23333                                                 enable( 2960 );
23334
23335                                         } else {
23336
23337                                                 disable( 2960 );
23338
23339                                         }
23340
23341                                 }
23342
23343                         },
23344
23345                         setMask: function ( stencilMask ) {
23346
23347                                 if ( currentStencilMask !== stencilMask && ! locked ) {
23348
23349                                         gl.stencilMask( stencilMask );
23350                                         currentStencilMask = stencilMask;
23351
23352                                 }
23353
23354                         },
23355
23356                         setFunc: function ( stencilFunc, stencilRef, stencilMask ) {
23357
23358                                 if ( currentStencilFunc !== stencilFunc ||
23359                                      currentStencilRef !== stencilRef ||
23360                                      currentStencilFuncMask !== stencilMask ) {
23361
23362                                         gl.stencilFunc( stencilFunc, stencilRef, stencilMask );
23363
23364                                         currentStencilFunc = stencilFunc;
23365                                         currentStencilRef = stencilRef;
23366                                         currentStencilFuncMask = stencilMask;
23367
23368                                 }
23369
23370                         },
23371
23372                         setOp: function ( stencilFail, stencilZFail, stencilZPass ) {
23373
23374                                 if ( currentStencilFail !== stencilFail ||
23375                                      currentStencilZFail !== stencilZFail ||
23376                                      currentStencilZPass !== stencilZPass ) {
23377
23378                                         gl.stencilOp( stencilFail, stencilZFail, stencilZPass );
23379
23380                                         currentStencilFail = stencilFail;
23381                                         currentStencilZFail = stencilZFail;
23382                                         currentStencilZPass = stencilZPass;
23383
23384                                 }
23385
23386                         },
23387
23388                         setLocked: function ( lock ) {
23389
23390                                 locked = lock;
23391
23392                         },
23393
23394                         setClear: function ( stencil ) {
23395
23396                                 if ( currentStencilClear !== stencil ) {
23397
23398                                         gl.clearStencil( stencil );
23399                                         currentStencilClear = stencil;
23400
23401                                 }
23402
23403                         },
23404
23405                         reset: function () {
23406
23407                                 locked = false;
23408
23409                                 currentStencilMask = null;
23410                                 currentStencilFunc = null;
23411                                 currentStencilRef = null;
23412                                 currentStencilFuncMask = null;
23413                                 currentStencilFail = null;
23414                                 currentStencilZFail = null;
23415                                 currentStencilZPass = null;
23416                                 currentStencilClear = null;
23417
23418                         }
23419
23420                 };
23421
23422         }
23423
23424         //
23425
23426         const colorBuffer = new ColorBuffer();
23427         const depthBuffer = new DepthBuffer();
23428         const stencilBuffer = new StencilBuffer();
23429
23430         let enabledCapabilities = {};
23431
23432         let currentProgram = null;
23433
23434         let currentBlendingEnabled = null;
23435         let currentBlending = null;
23436         let currentBlendEquation = null;
23437         let currentBlendSrc = null;
23438         let currentBlendDst = null;
23439         let currentBlendEquationAlpha = null;
23440         let currentBlendSrcAlpha = null;
23441         let currentBlendDstAlpha = null;
23442         let currentPremultipledAlpha = false;
23443
23444         let currentFlipSided = null;
23445         let currentCullFace = null;
23446
23447         let currentLineWidth = null;
23448
23449         let currentPolygonOffsetFactor = null;
23450         let currentPolygonOffsetUnits = null;
23451
23452         const maxTextures = gl.getParameter( 35661 );
23453
23454         let lineWidthAvailable = false;
23455         let version = 0;
23456         const glVersion = gl.getParameter( 7938 );
23457
23458         if ( glVersion.indexOf( 'WebGL' ) !== - 1 ) {
23459
23460                 version = parseFloat( /^WebGL (\d)/.exec( glVersion )[ 1 ] );
23461                 lineWidthAvailable = ( version >= 1.0 );
23462
23463         } else if ( glVersion.indexOf( 'OpenGL ES' ) !== - 1 ) {
23464
23465                 version = parseFloat( /^OpenGL ES (\d)/.exec( glVersion )[ 1 ] );
23466                 lineWidthAvailable = ( version >= 2.0 );
23467
23468         }
23469
23470         let currentTextureSlot = null;
23471         let currentBoundTextures = {};
23472
23473         const currentScissor = new Vector4();
23474         const currentViewport = new Vector4();
23475
23476         function createTexture( type, target, count ) {
23477
23478                 const data = new Uint8Array( 4 ); // 4 is required to match default unpack alignment of 4.
23479                 const texture = gl.createTexture();
23480
23481                 gl.bindTexture( type, texture );
23482                 gl.texParameteri( type, 10241, 9728 );
23483                 gl.texParameteri( type, 10240, 9728 );
23484
23485                 for ( let i = 0; i < count; i ++ ) {
23486
23487                         gl.texImage2D( target + i, 0, 6408, 1, 1, 0, 6408, 5121, data );
23488
23489                 }
23490
23491                 return texture;
23492
23493         }
23494
23495         const emptyTextures = {};
23496         emptyTextures[ 3553 ] = createTexture( 3553, 3553, 1 );
23497         emptyTextures[ 34067 ] = createTexture( 34067, 34069, 6 );
23498
23499         // init
23500
23501         colorBuffer.setClear( 0, 0, 0, 1 );
23502         depthBuffer.setClear( 1 );
23503         stencilBuffer.setClear( 0 );
23504
23505         enable( 2929 );
23506         depthBuffer.setFunc( LessEqualDepth );
23507
23508         setFlipSided( false );
23509         setCullFace( CullFaceBack );
23510         enable( 2884 );
23511
23512         setBlending( NoBlending );
23513
23514         //
23515
23516         function enable( id ) {
23517
23518                 if ( enabledCapabilities[ id ] !== true ) {
23519
23520                         gl.enable( id );
23521                         enabledCapabilities[ id ] = true;
23522
23523                 }
23524
23525         }
23526
23527         function disable( id ) {
23528
23529                 if ( enabledCapabilities[ id ] !== false ) {
23530
23531                         gl.disable( id );
23532                         enabledCapabilities[ id ] = false;
23533
23534                 }
23535
23536         }
23537
23538         function useProgram( program ) {
23539
23540                 if ( currentProgram !== program ) {
23541
23542                         gl.useProgram( program );
23543
23544                         currentProgram = program;
23545
23546                         return true;
23547
23548                 }
23549
23550                 return false;
23551
23552         }
23553
23554         const equationToGL = {
23555                 [ AddEquation ]: 32774,
23556                 [ SubtractEquation ]: 32778,
23557                 [ ReverseSubtractEquation ]: 32779
23558         };
23559
23560         if ( isWebGL2 ) {
23561
23562                 equationToGL[ MinEquation ] = 32775;
23563                 equationToGL[ MaxEquation ] = 32776;
23564
23565         } else {
23566
23567                 const extension = extensions.get( 'EXT_blend_minmax' );
23568
23569                 if ( extension !== null ) {
23570
23571                         equationToGL[ MinEquation ] = extension.MIN_EXT;
23572                         equationToGL[ MaxEquation ] = extension.MAX_EXT;
23573
23574                 }
23575
23576         }
23577
23578         const factorToGL = {
23579                 [ ZeroFactor ]: 0,
23580                 [ OneFactor ]: 1,
23581                 [ SrcColorFactor ]: 768,
23582                 [ SrcAlphaFactor ]: 770,
23583                 [ SrcAlphaSaturateFactor ]: 776,
23584                 [ DstColorFactor ]: 774,
23585                 [ DstAlphaFactor ]: 772,
23586                 [ OneMinusSrcColorFactor ]: 769,
23587                 [ OneMinusSrcAlphaFactor ]: 771,
23588                 [ OneMinusDstColorFactor ]: 775,
23589                 [ OneMinusDstAlphaFactor ]: 773
23590         };
23591
23592         function setBlending( blending, blendEquation, blendSrc, blendDst, blendEquationAlpha, blendSrcAlpha, blendDstAlpha, premultipliedAlpha ) {
23593
23594                 if ( blending === NoBlending ) {
23595
23596                         if ( currentBlendingEnabled ) {
23597
23598                                 disable( 3042 );
23599                                 currentBlendingEnabled = false;
23600
23601                         }
23602
23603                         return;
23604
23605                 }
23606
23607                 if ( ! currentBlendingEnabled ) {
23608
23609                         enable( 3042 );
23610                         currentBlendingEnabled = true;
23611
23612                 }
23613
23614                 if ( blending !== CustomBlending ) {
23615
23616                         if ( blending !== currentBlending || premultipliedAlpha !== currentPremultipledAlpha ) {
23617
23618                                 if ( currentBlendEquation !== AddEquation || currentBlendEquationAlpha !== AddEquation ) {
23619
23620                                         gl.blendEquation( 32774 );
23621
23622                                         currentBlendEquation = AddEquation;
23623                                         currentBlendEquationAlpha = AddEquation;
23624
23625                                 }
23626
23627                                 if ( premultipliedAlpha ) {
23628
23629                                         switch ( blending ) {
23630
23631                                                 case NormalBlending:
23632                                                         gl.blendFuncSeparate( 1, 771, 1, 771 );
23633                                                         break;
23634
23635                                                 case AdditiveBlending:
23636                                                         gl.blendFunc( 1, 1 );
23637                                                         break;
23638
23639                                                 case SubtractiveBlending:
23640                                                         gl.blendFuncSeparate( 0, 0, 769, 771 );
23641                                                         break;
23642
23643                                                 case MultiplyBlending:
23644                                                         gl.blendFuncSeparate( 0, 768, 0, 770 );
23645                                                         break;
23646
23647                                                 default:
23648                                                         console.error( 'THREE.WebGLState: Invalid blending: ', blending );
23649                                                         break;
23650
23651                                         }
23652
23653                                 } else {
23654
23655                                         switch ( blending ) {
23656
23657                                                 case NormalBlending:
23658                                                         gl.blendFuncSeparate( 770, 771, 1, 771 );
23659                                                         break;
23660
23661                                                 case AdditiveBlending:
23662                                                         gl.blendFunc( 770, 1 );
23663                                                         break;
23664
23665                                                 case SubtractiveBlending:
23666                                                         gl.blendFunc( 0, 769 );
23667                                                         break;
23668
23669                                                 case MultiplyBlending:
23670                                                         gl.blendFunc( 0, 768 );
23671                                                         break;
23672
23673                                                 default:
23674                                                         console.error( 'THREE.WebGLState: Invalid blending: ', blending );
23675                                                         break;
23676
23677                                         }
23678
23679                                 }
23680
23681                                 currentBlendSrc = null;
23682                                 currentBlendDst = null;
23683                                 currentBlendSrcAlpha = null;
23684                                 currentBlendDstAlpha = null;
23685
23686                                 currentBlending = blending;
23687                                 currentPremultipledAlpha = premultipliedAlpha;
23688
23689                         }
23690
23691                         return;
23692
23693                 }
23694
23695                 // custom blending
23696
23697                 blendEquationAlpha = blendEquationAlpha || blendEquation;
23698                 blendSrcAlpha = blendSrcAlpha || blendSrc;
23699                 blendDstAlpha = blendDstAlpha || blendDst;
23700
23701                 if ( blendEquation !== currentBlendEquation || blendEquationAlpha !== currentBlendEquationAlpha ) {
23702
23703                         gl.blendEquationSeparate( equationToGL[ blendEquation ], equationToGL[ blendEquationAlpha ] );
23704
23705                         currentBlendEquation = blendEquation;
23706                         currentBlendEquationAlpha = blendEquationAlpha;
23707
23708                 }
23709
23710                 if ( blendSrc !== currentBlendSrc || blendDst !== currentBlendDst || blendSrcAlpha !== currentBlendSrcAlpha || blendDstAlpha !== currentBlendDstAlpha ) {
23711
23712                         gl.blendFuncSeparate( factorToGL[ blendSrc ], factorToGL[ blendDst ], factorToGL[ blendSrcAlpha ], factorToGL[ blendDstAlpha ] );
23713
23714                         currentBlendSrc = blendSrc;
23715                         currentBlendDst = blendDst;
23716                         currentBlendSrcAlpha = blendSrcAlpha;
23717                         currentBlendDstAlpha = blendDstAlpha;
23718
23719                 }
23720
23721                 currentBlending = blending;
23722                 currentPremultipledAlpha = null;
23723
23724         }
23725
23726         function setMaterial( material, frontFaceCW ) {
23727
23728                 material.side === DoubleSide
23729                         ? disable( 2884 )
23730                         : enable( 2884 );
23731
23732                 let flipSided = ( material.side === BackSide );
23733                 if ( frontFaceCW ) flipSided = ! flipSided;
23734
23735                 setFlipSided( flipSided );
23736
23737                 ( material.blending === NormalBlending && material.transparent === false )
23738                         ? setBlending( NoBlending )
23739                         : setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst, material.blendEquationAlpha, material.blendSrcAlpha, material.blendDstAlpha, material.premultipliedAlpha );
23740
23741                 depthBuffer.setFunc( material.depthFunc );
23742                 depthBuffer.setTest( material.depthTest );
23743                 depthBuffer.setMask( material.depthWrite );
23744                 colorBuffer.setMask( material.colorWrite );
23745
23746                 const stencilWrite = material.stencilWrite;
23747                 stencilBuffer.setTest( stencilWrite );
23748                 if ( stencilWrite ) {
23749
23750                         stencilBuffer.setMask( material.stencilWriteMask );
23751                         stencilBuffer.setFunc( material.stencilFunc, material.stencilRef, material.stencilFuncMask );
23752                         stencilBuffer.setOp( material.stencilFail, material.stencilZFail, material.stencilZPass );
23753
23754                 }
23755
23756                 setPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits );
23757
23758         }
23759
23760         //
23761
23762         function setFlipSided( flipSided ) {
23763
23764                 if ( currentFlipSided !== flipSided ) {
23765
23766                         if ( flipSided ) {
23767
23768                                 gl.frontFace( 2304 );
23769
23770                         } else {
23771
23772                                 gl.frontFace( 2305 );
23773
23774                         }
23775
23776                         currentFlipSided = flipSided;
23777
23778                 }
23779
23780         }
23781
23782         function setCullFace( cullFace ) {
23783
23784                 if ( cullFace !== CullFaceNone ) {
23785
23786                         enable( 2884 );
23787
23788                         if ( cullFace !== currentCullFace ) {
23789
23790                                 if ( cullFace === CullFaceBack ) {
23791
23792                                         gl.cullFace( 1029 );
23793
23794                                 } else if ( cullFace === CullFaceFront ) {
23795
23796                                         gl.cullFace( 1028 );
23797
23798                                 } else {
23799
23800                                         gl.cullFace( 1032 );
23801
23802                                 }
23803
23804                         }
23805
23806                 } else {
23807
23808                         disable( 2884 );
23809
23810                 }
23811
23812                 currentCullFace = cullFace;
23813
23814         }
23815
23816         function setLineWidth( width ) {
23817
23818                 if ( width !== currentLineWidth ) {
23819
23820                         if ( lineWidthAvailable ) gl.lineWidth( width );
23821
23822                         currentLineWidth = width;
23823
23824                 }
23825
23826         }
23827
23828         function setPolygonOffset( polygonOffset, factor, units ) {
23829
23830                 if ( polygonOffset ) {
23831
23832                         enable( 32823 );
23833
23834                         if ( currentPolygonOffsetFactor !== factor || currentPolygonOffsetUnits !== units ) {
23835
23836                                 gl.polygonOffset( factor, units );
23837
23838                                 currentPolygonOffsetFactor = factor;
23839                                 currentPolygonOffsetUnits = units;
23840
23841                         }
23842
23843                 } else {
23844
23845                         disable( 32823 );
23846
23847                 }
23848
23849         }
23850
23851         function setScissorTest( scissorTest ) {
23852
23853                 if ( scissorTest ) {
23854
23855                         enable( 3089 );
23856
23857                 } else {
23858
23859                         disable( 3089 );
23860
23861                 }
23862
23863         }
23864
23865         // texture
23866
23867         function activeTexture( webglSlot ) {
23868
23869                 if ( webglSlot === undefined ) webglSlot = 33984 + maxTextures - 1;
23870
23871                 if ( currentTextureSlot !== webglSlot ) {
23872
23873                         gl.activeTexture( webglSlot );
23874                         currentTextureSlot = webglSlot;
23875
23876                 }
23877
23878         }
23879
23880         function bindTexture( webglType, webglTexture ) {
23881
23882                 if ( currentTextureSlot === null ) {
23883
23884                         activeTexture();
23885
23886                 }
23887
23888                 let boundTexture = currentBoundTextures[ currentTextureSlot ];
23889
23890                 if ( boundTexture === undefined ) {
23891
23892                         boundTexture = { type: undefined, texture: undefined };
23893                         currentBoundTextures[ currentTextureSlot ] = boundTexture;
23894
23895                 }
23896
23897                 if ( boundTexture.type !== webglType || boundTexture.texture !== webglTexture ) {
23898
23899                         gl.bindTexture( webglType, webglTexture || emptyTextures[ webglType ] );
23900
23901                         boundTexture.type = webglType;
23902                         boundTexture.texture = webglTexture;
23903
23904                 }
23905
23906         }
23907
23908         function unbindTexture() {
23909
23910                 const boundTexture = currentBoundTextures[ currentTextureSlot ];
23911
23912                 if ( boundTexture !== undefined && boundTexture.type !== undefined ) {
23913
23914                         gl.bindTexture( boundTexture.type, null );
23915
23916                         boundTexture.type = undefined;
23917                         boundTexture.texture = undefined;
23918
23919                 }
23920
23921         }
23922
23923         function compressedTexImage2D() {
23924
23925                 try {
23926
23927                         gl.compressedTexImage2D.apply( gl, arguments );
23928
23929                 } catch ( error ) {
23930
23931                         console.error( 'THREE.WebGLState:', error );
23932
23933                 }
23934
23935         }
23936
23937         function texImage2D() {
23938
23939                 try {
23940
23941                         gl.texImage2D.apply( gl, arguments );
23942
23943                 } catch ( error ) {
23944
23945                         console.error( 'THREE.WebGLState:', error );
23946
23947                 }
23948
23949         }
23950
23951         function texImage3D() {
23952
23953                 try {
23954
23955                         gl.texImage3D.apply( gl, arguments );
23956
23957                 } catch ( error ) {
23958
23959                         console.error( 'THREE.WebGLState:', error );
23960
23961                 }
23962
23963         }
23964
23965         //
23966
23967         function scissor( scissor ) {
23968
23969                 if ( currentScissor.equals( scissor ) === false ) {
23970
23971                         gl.scissor( scissor.x, scissor.y, scissor.z, scissor.w );
23972                         currentScissor.copy( scissor );
23973
23974                 }
23975
23976         }
23977
23978         function viewport( viewport ) {
23979
23980                 if ( currentViewport.equals( viewport ) === false ) {
23981
23982                         gl.viewport( viewport.x, viewport.y, viewport.z, viewport.w );
23983                         currentViewport.copy( viewport );
23984
23985                 }
23986
23987         }
23988
23989         //
23990
23991         function reset() {
23992
23993                 enabledCapabilities = {};
23994
23995                 currentTextureSlot = null;
23996                 currentBoundTextures = {};
23997
23998                 currentProgram = null;
23999
24000                 currentBlendingEnabled = null;
24001                 currentBlending = null;
24002                 currentBlendEquation = null;
24003                 currentBlendSrc = null;
24004                 currentBlendDst = null;
24005                 currentBlendEquationAlpha = null;
24006                 currentBlendSrcAlpha = null;
24007                 currentBlendDstAlpha = null;
24008                 currentPremultipledAlpha = false;
24009
24010                 currentFlipSided = null;
24011                 currentCullFace = null;
24012
24013                 currentLineWidth = null;
24014
24015                 currentPolygonOffsetFactor = null;
24016                 currentPolygonOffsetUnits = null;
24017
24018                 colorBuffer.reset();
24019                 depthBuffer.reset();
24020                 stencilBuffer.reset();
24021
24022         }
24023
24024         return {
24025
24026                 buffers: {
24027                         color: colorBuffer,
24028                         depth: depthBuffer,
24029                         stencil: stencilBuffer
24030                 },
24031
24032                 enable: enable,
24033                 disable: disable,
24034
24035                 useProgram: useProgram,
24036
24037                 setBlending: setBlending,
24038                 setMaterial: setMaterial,
24039
24040                 setFlipSided: setFlipSided,
24041                 setCullFace: setCullFace,
24042
24043                 setLineWidth: setLineWidth,
24044                 setPolygonOffset: setPolygonOffset,
24045
24046                 setScissorTest: setScissorTest,
24047
24048                 activeTexture: activeTexture,
24049                 bindTexture: bindTexture,
24050                 unbindTexture: unbindTexture,
24051                 compressedTexImage2D: compressedTexImage2D,
24052                 texImage2D: texImage2D,
24053                 texImage3D: texImage3D,
24054
24055                 scissor: scissor,
24056                 viewport: viewport,
24057
24058                 reset: reset
24059
24060         };
24061
24062 }
24063
24064 function WebGLTextures( _gl, extensions, state, properties, capabilities, utils, info ) {
24065
24066         const isWebGL2 = capabilities.isWebGL2;
24067         const maxTextures = capabilities.maxTextures;
24068         const maxCubemapSize = capabilities.maxCubemapSize;
24069         const maxTextureSize = capabilities.maxTextureSize;
24070         const maxSamples = capabilities.maxSamples;
24071
24072         const _videoTextures = new WeakMap();
24073         let _canvas;
24074
24075         // cordova iOS (as of 5.0) still uses UIWebView, which provides OffscreenCanvas,
24076         // also OffscreenCanvas.getContext("webgl"), but not OffscreenCanvas.getContext("2d")!
24077         // Some implementations may only implement OffscreenCanvas partially (e.g. lacking 2d).
24078
24079         let useOffscreenCanvas = false;
24080
24081         try {
24082
24083                 useOffscreenCanvas = typeof OffscreenCanvas !== 'undefined'
24084                         && ( new OffscreenCanvas( 1, 1 ).getContext( '2d' ) ) !== null;
24085
24086         } catch ( err ) {
24087
24088                 // Ignore any errors
24089
24090         }
24091
24092         function createCanvas( width, height ) {
24093
24094                 // Use OffscreenCanvas when available. Specially needed in web workers
24095
24096                 return useOffscreenCanvas ?
24097                         new OffscreenCanvas( width, height ) :
24098                         document.createElementNS( 'http://www.w3.org/1999/xhtml', 'canvas' );
24099
24100         }
24101
24102         function resizeImage( image, needsPowerOfTwo, needsNewCanvas, maxSize ) {
24103
24104                 let scale = 1;
24105
24106                 // handle case if texture exceeds max size
24107
24108                 if ( image.width > maxSize || image.height > maxSize ) {
24109
24110                         scale = maxSize / Math.max( image.width, image.height );
24111
24112                 }
24113
24114                 // only perform resize if necessary
24115
24116                 if ( scale < 1 || needsPowerOfTwo === true ) {
24117
24118                         // only perform resize for certain image types
24119
24120                         if ( ( typeof HTMLImageElement !== 'undefined' && image instanceof HTMLImageElement ) ||
24121                                 ( typeof HTMLCanvasElement !== 'undefined' && image instanceof HTMLCanvasElement ) ||
24122                                 ( typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap ) ) {
24123
24124                                 const floor = needsPowerOfTwo ? MathUtils.floorPowerOfTwo : Math.floor;
24125
24126                                 const width = floor( scale * image.width );
24127                                 const height = floor( scale * image.height );
24128
24129                                 if ( _canvas === undefined ) _canvas = createCanvas( width, height );
24130
24131                                 // cube textures can't reuse the same canvas
24132
24133                                 const canvas = needsNewCanvas ? createCanvas( width, height ) : _canvas;
24134
24135                                 canvas.width = width;
24136                                 canvas.height = height;
24137
24138                                 const context = canvas.getContext( '2d' );
24139                                 context.drawImage( image, 0, 0, width, height );
24140
24141                                 console.warn( 'THREE.WebGLRenderer: Texture has been resized from (' + image.width + 'x' + image.height + ') to (' + width + 'x' + height + ').' );
24142
24143                                 return canvas;
24144
24145                         } else {
24146
24147                                 if ( 'data' in image ) {
24148
24149                                         console.warn( 'THREE.WebGLRenderer: Image in DataTexture is too big (' + image.width + 'x' + image.height + ').' );
24150
24151                                 }
24152
24153                                 return image;
24154
24155                         }
24156
24157                 }
24158
24159                 return image;
24160
24161         }
24162
24163         function isPowerOfTwo( image ) {
24164
24165                 return MathUtils.isPowerOfTwo( image.width ) && MathUtils.isPowerOfTwo( image.height );
24166
24167         }
24168
24169         function textureNeedsPowerOfTwo( texture ) {
24170
24171                 if ( isWebGL2 ) return false;
24172
24173                 return ( texture.wrapS !== ClampToEdgeWrapping || texture.wrapT !== ClampToEdgeWrapping ) ||
24174                         ( texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter );
24175
24176         }
24177
24178         function textureNeedsGenerateMipmaps( texture, supportsMips ) {
24179
24180                 return texture.generateMipmaps && supportsMips &&
24181                         texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter;
24182
24183         }
24184
24185         function generateMipmap( target, texture, width, height ) {
24186
24187                 _gl.generateMipmap( target );
24188
24189                 const textureProperties = properties.get( texture );
24190
24191                 // Note: Math.log( x ) * Math.LOG2E used instead of Math.log2( x ) which is not supported by IE11
24192                 textureProperties.__maxMipLevel = Math.log( Math.max( width, height ) ) * Math.LOG2E;
24193
24194         }
24195
24196         function getInternalFormat( internalFormatName, glFormat, glType ) {
24197
24198                 if ( isWebGL2 === false ) return glFormat;
24199
24200                 if ( internalFormatName !== null ) {
24201
24202                         if ( _gl[ internalFormatName ] !== undefined ) return _gl[ internalFormatName ];
24203
24204                         console.warn( 'THREE.WebGLRenderer: Attempt to use non-existing WebGL internal format \'' + internalFormatName + '\'' );
24205
24206                 }
24207
24208                 let internalFormat = glFormat;
24209
24210                 if ( glFormat === 6403 ) {
24211
24212                         if ( glType === 5126 ) internalFormat = 33326;
24213                         if ( glType === 5131 ) internalFormat = 33325;
24214                         if ( glType === 5121 ) internalFormat = 33321;
24215
24216                 }
24217
24218                 if ( glFormat === 6407 ) {
24219
24220                         if ( glType === 5126 ) internalFormat = 34837;
24221                         if ( glType === 5131 ) internalFormat = 34843;
24222                         if ( glType === 5121 ) internalFormat = 32849;
24223
24224                 }
24225
24226                 if ( glFormat === 6408 ) {
24227
24228                         if ( glType === 5126 ) internalFormat = 34836;
24229                         if ( glType === 5131 ) internalFormat = 34842;
24230                         if ( glType === 5121 ) internalFormat = 32856;
24231
24232                 }
24233
24234                 if ( internalFormat === 33325 || internalFormat === 33326 ||
24235                         internalFormat === 34842 || internalFormat === 34836 ) {
24236
24237                         extensions.get( 'EXT_color_buffer_float' );
24238
24239                 }
24240
24241                 return internalFormat;
24242
24243         }
24244
24245         // Fallback filters for non-power-of-2 textures
24246
24247         function filterFallback( f ) {
24248
24249                 if ( f === NearestFilter || f === NearestMipmapNearestFilter || f === NearestMipmapLinearFilter ) {
24250
24251                         return 9728;
24252
24253                 }
24254
24255                 return 9729;
24256
24257         }
24258
24259         //
24260
24261         function onTextureDispose( event ) {
24262
24263                 const texture = event.target;
24264
24265                 texture.removeEventListener( 'dispose', onTextureDispose );
24266
24267                 deallocateTexture( texture );
24268
24269                 if ( texture.isVideoTexture ) {
24270
24271                         _videoTextures.delete( texture );
24272
24273                 }
24274
24275                 info.memory.textures --;
24276
24277         }
24278
24279         function onRenderTargetDispose( event ) {
24280
24281                 const renderTarget = event.target;
24282
24283                 renderTarget.removeEventListener( 'dispose', onRenderTargetDispose );
24284
24285                 deallocateRenderTarget( renderTarget );
24286
24287                 info.memory.textures --;
24288
24289         }
24290
24291         //
24292
24293         function deallocateTexture( texture ) {
24294
24295                 const textureProperties = properties.get( texture );
24296
24297                 if ( textureProperties.__webglInit === undefined ) return;
24298
24299                 _gl.deleteTexture( textureProperties.__webglTexture );
24300
24301                 properties.remove( texture );
24302
24303         }
24304
24305         function deallocateRenderTarget( renderTarget ) {
24306
24307                 const renderTargetProperties = properties.get( renderTarget );
24308                 const textureProperties = properties.get( renderTarget.texture );
24309
24310                 if ( ! renderTarget ) return;
24311
24312                 if ( textureProperties.__webglTexture !== undefined ) {
24313
24314                         _gl.deleteTexture( textureProperties.__webglTexture );
24315
24316                 }
24317
24318                 if ( renderTarget.depthTexture ) {
24319
24320                         renderTarget.depthTexture.dispose();
24321
24322                 }
24323
24324                 if ( renderTarget.isWebGLCubeRenderTarget ) {
24325
24326                         for ( let i = 0; i < 6; i ++ ) {
24327
24328                                 _gl.deleteFramebuffer( renderTargetProperties.__webglFramebuffer[ i ] );
24329                                 if ( renderTargetProperties.__webglDepthbuffer ) _gl.deleteRenderbuffer( renderTargetProperties.__webglDepthbuffer[ i ] );
24330
24331                         }
24332
24333                 } else {
24334
24335                         _gl.deleteFramebuffer( renderTargetProperties.__webglFramebuffer );
24336                         if ( renderTargetProperties.__webglDepthbuffer ) _gl.deleteRenderbuffer( renderTargetProperties.__webglDepthbuffer );
24337                         if ( renderTargetProperties.__webglMultisampledFramebuffer ) _gl.deleteFramebuffer( renderTargetProperties.__webglMultisampledFramebuffer );
24338                         if ( renderTargetProperties.__webglColorRenderbuffer ) _gl.deleteRenderbuffer( renderTargetProperties.__webglColorRenderbuffer );
24339                         if ( renderTargetProperties.__webglDepthRenderbuffer ) _gl.deleteRenderbuffer( renderTargetProperties.__webglDepthRenderbuffer );
24340
24341                 }
24342
24343                 properties.remove( renderTarget.texture );
24344                 properties.remove( renderTarget );
24345
24346         }
24347
24348         //
24349
24350         let textureUnits = 0;
24351
24352         function resetTextureUnits() {
24353
24354                 textureUnits = 0;
24355
24356         }
24357
24358         function allocateTextureUnit() {
24359
24360                 const textureUnit = textureUnits;
24361
24362                 if ( textureUnit >= maxTextures ) {
24363
24364                         console.warn( 'THREE.WebGLTextures: Trying to use ' + textureUnit + ' texture units while this GPU supports only ' + maxTextures );
24365
24366                 }
24367
24368                 textureUnits += 1;
24369
24370                 return textureUnit;
24371
24372         }
24373
24374         //
24375
24376         function setTexture2D( texture, slot ) {
24377
24378                 const textureProperties = properties.get( texture );
24379
24380                 if ( texture.isVideoTexture ) updateVideoTexture( texture );
24381
24382                 if ( texture.version > 0 && textureProperties.__version !== texture.version ) {
24383
24384                         const image = texture.image;
24385
24386                         if ( image === undefined ) {
24387
24388                                 console.warn( 'THREE.WebGLRenderer: Texture marked for update but image is undefined' );
24389
24390                         } else if ( image.complete === false ) {
24391
24392                                 console.warn( 'THREE.WebGLRenderer: Texture marked for update but image is incomplete' );
24393
24394                         } else {
24395
24396                                 uploadTexture( textureProperties, texture, slot );
24397                                 return;
24398
24399                         }
24400
24401                 }
24402
24403                 state.activeTexture( 33984 + slot );
24404                 state.bindTexture( 3553, textureProperties.__webglTexture );
24405
24406         }
24407
24408         function setTexture2DArray( texture, slot ) {
24409
24410                 const textureProperties = properties.get( texture );
24411
24412                 if ( texture.version > 0 && textureProperties.__version !== texture.version ) {
24413
24414                         uploadTexture( textureProperties, texture, slot );
24415                         return;
24416
24417                 }
24418
24419                 state.activeTexture( 33984 + slot );
24420                 state.bindTexture( 35866, textureProperties.__webglTexture );
24421
24422         }
24423
24424         function setTexture3D( texture, slot ) {
24425
24426                 const textureProperties = properties.get( texture );
24427
24428                 if ( texture.version > 0 && textureProperties.__version !== texture.version ) {
24429
24430                         uploadTexture( textureProperties, texture, slot );
24431                         return;
24432
24433                 }
24434
24435                 state.activeTexture( 33984 + slot );
24436                 state.bindTexture( 32879, textureProperties.__webglTexture );
24437
24438         }
24439
24440         function setTextureCube( texture, slot ) {
24441
24442                 const textureProperties = properties.get( texture );
24443
24444                 if ( texture.version > 0 && textureProperties.__version !== texture.version ) {
24445
24446                         uploadCubeTexture( textureProperties, texture, slot );
24447                         return;
24448
24449                 }
24450
24451                 state.activeTexture( 33984 + slot );
24452                 state.bindTexture( 34067, textureProperties.__webglTexture );
24453
24454         }
24455
24456         const wrappingToGL = {
24457                 [ RepeatWrapping ]: 10497,
24458                 [ ClampToEdgeWrapping ]: 33071,
24459                 [ MirroredRepeatWrapping ]: 33648
24460         };
24461
24462         const filterToGL = {
24463                 [ NearestFilter ]: 9728,
24464                 [ NearestMipmapNearestFilter ]: 9984,
24465                 [ NearestMipmapLinearFilter ]: 9986,
24466
24467                 [ LinearFilter ]: 9729,
24468                 [ LinearMipmapNearestFilter ]: 9985,
24469                 [ LinearMipmapLinearFilter ]: 9987
24470         };
24471
24472         function setTextureParameters( textureType, texture, supportsMips ) {
24473
24474                 if ( supportsMips ) {
24475
24476                         _gl.texParameteri( textureType, 10242, wrappingToGL[ texture.wrapS ] );
24477                         _gl.texParameteri( textureType, 10243, wrappingToGL[ texture.wrapT ] );
24478
24479                         if ( textureType === 32879 || textureType === 35866 ) {
24480
24481                                 _gl.texParameteri( textureType, 32882, wrappingToGL[ texture.wrapR ] );
24482
24483                         }
24484
24485                         _gl.texParameteri( textureType, 10240, filterToGL[ texture.magFilter ] );
24486                         _gl.texParameteri( textureType, 10241, filterToGL[ texture.minFilter ] );
24487
24488                 } else {
24489
24490                         _gl.texParameteri( textureType, 10242, 33071 );
24491                         _gl.texParameteri( textureType, 10243, 33071 );
24492
24493                         if ( textureType === 32879 || textureType === 35866 ) {
24494
24495                                 _gl.texParameteri( textureType, 32882, 33071 );
24496
24497                         }
24498
24499                         if ( texture.wrapS !== ClampToEdgeWrapping || texture.wrapT !== ClampToEdgeWrapping ) {
24500
24501                                 console.warn( 'THREE.WebGLRenderer: Texture is not power of two. Texture.wrapS and Texture.wrapT should be set to THREE.ClampToEdgeWrapping.' );
24502
24503                         }
24504
24505                         _gl.texParameteri( textureType, 10240, filterFallback( texture.magFilter ) );
24506                         _gl.texParameteri( textureType, 10241, filterFallback( texture.minFilter ) );
24507
24508                         if ( texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter ) {
24509
24510                                 console.warn( 'THREE.WebGLRenderer: Texture is not power of two. Texture.minFilter should be set to THREE.NearestFilter or THREE.LinearFilter.' );
24511
24512                         }
24513
24514                 }
24515
24516                 const extension = extensions.get( 'EXT_texture_filter_anisotropic' );
24517
24518                 if ( extension ) {
24519
24520                         if ( texture.type === FloatType && extensions.get( 'OES_texture_float_linear' ) === null ) return;
24521                         if ( texture.type === HalfFloatType && ( isWebGL2 || extensions.get( 'OES_texture_half_float_linear' ) ) === null ) return;
24522
24523                         if ( texture.anisotropy > 1 || properties.get( texture ).__currentAnisotropy ) {
24524
24525                                 _gl.texParameterf( textureType, extension.TEXTURE_MAX_ANISOTROPY_EXT, Math.min( texture.anisotropy, capabilities.getMaxAnisotropy() ) );
24526                                 properties.get( texture ).__currentAnisotropy = texture.anisotropy;
24527
24528                         }
24529
24530                 }
24531
24532         }
24533
24534         function initTexture( textureProperties, texture ) {
24535
24536                 if ( textureProperties.__webglInit === undefined ) {
24537
24538                         textureProperties.__webglInit = true;
24539
24540                         texture.addEventListener( 'dispose', onTextureDispose );
24541
24542                         textureProperties.__webglTexture = _gl.createTexture();
24543
24544                         info.memory.textures ++;
24545
24546                 }
24547
24548         }
24549
24550         function uploadTexture( textureProperties, texture, slot ) {
24551
24552                 let textureType = 3553;
24553
24554                 if ( texture.isDataTexture2DArray ) textureType = 35866;
24555                 if ( texture.isDataTexture3D ) textureType = 32879;
24556
24557                 initTexture( textureProperties, texture );
24558
24559                 state.activeTexture( 33984 + slot );
24560                 state.bindTexture( textureType, textureProperties.__webglTexture );
24561
24562                 _gl.pixelStorei( 37440, texture.flipY );
24563                 _gl.pixelStorei( 37441, texture.premultiplyAlpha );
24564                 _gl.pixelStorei( 3317, texture.unpackAlignment );
24565
24566                 const needsPowerOfTwo = textureNeedsPowerOfTwo( texture ) && isPowerOfTwo( texture.image ) === false;
24567                 const image = resizeImage( texture.image, needsPowerOfTwo, false, maxTextureSize );
24568
24569                 const supportsMips = isPowerOfTwo( image ) || isWebGL2,
24570                         glFormat = utils.convert( texture.format );
24571
24572                 let glType = utils.convert( texture.type ),
24573                         glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType );
24574
24575                 setTextureParameters( textureType, texture, supportsMips );
24576
24577                 let mipmap;
24578                 const mipmaps = texture.mipmaps;
24579
24580                 if ( texture.isDepthTexture ) {
24581
24582                         // populate depth texture with dummy data
24583
24584                         glInternalFormat = 6402;
24585
24586                         if ( isWebGL2 ) {
24587
24588                                 if ( texture.type === FloatType ) {
24589
24590                                         glInternalFormat = 36012;
24591
24592                                 } else if ( texture.type === UnsignedIntType ) {
24593
24594                                         glInternalFormat = 33190;
24595
24596                                 } else if ( texture.type === UnsignedInt248Type ) {
24597
24598                                         glInternalFormat = 35056;
24599
24600                                 } else {
24601
24602                                         glInternalFormat = 33189; // WebGL2 requires sized internalformat for glTexImage2D
24603
24604                                 }
24605
24606                         } else {
24607
24608                                 if ( texture.type === FloatType ) {
24609
24610                                         console.error( 'WebGLRenderer: Floating point depth texture requires WebGL2.' );
24611
24612                                 }
24613
24614                         }
24615
24616                         // validation checks for WebGL 1
24617
24618                         if ( texture.format === DepthFormat && glInternalFormat === 6402 ) {
24619
24620                                 // The error INVALID_OPERATION is generated by texImage2D if format and internalformat are
24621                                 // DEPTH_COMPONENT and type is not UNSIGNED_SHORT or UNSIGNED_INT
24622                                 // (https://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/)
24623                                 if ( texture.type !== UnsignedShortType && texture.type !== UnsignedIntType ) {
24624
24625                                         console.warn( 'THREE.WebGLRenderer: Use UnsignedShortType or UnsignedIntType for DepthFormat DepthTexture.' );
24626
24627                                         texture.type = UnsignedShortType;
24628                                         glType = utils.convert( texture.type );
24629
24630                                 }
24631
24632                         }
24633
24634                         if ( texture.format === DepthStencilFormat && glInternalFormat === 6402 ) {
24635
24636                                 // Depth stencil textures need the DEPTH_STENCIL internal format
24637                                 // (https://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/)
24638                                 glInternalFormat = 34041;
24639
24640                                 // The error INVALID_OPERATION is generated by texImage2D if format and internalformat are
24641                                 // DEPTH_STENCIL and type is not UNSIGNED_INT_24_8_WEBGL.
24642                                 // (https://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/)
24643                                 if ( texture.type !== UnsignedInt248Type ) {
24644
24645                                         console.warn( 'THREE.WebGLRenderer: Use UnsignedInt248Type for DepthStencilFormat DepthTexture.' );
24646
24647                                         texture.type = UnsignedInt248Type;
24648                                         glType = utils.convert( texture.type );
24649
24650                                 }
24651
24652                         }
24653
24654                         //
24655
24656                         state.texImage2D( 3553, 0, glInternalFormat, image.width, image.height, 0, glFormat, glType, null );
24657
24658                 } else if ( texture.isDataTexture ) {
24659
24660                         // use manually created mipmaps if available
24661                         // if there are no manual mipmaps
24662                         // set 0 level mipmap and then use GL to generate other mipmap levels
24663
24664                         if ( mipmaps.length > 0 && supportsMips ) {
24665
24666                                 for ( let i = 0, il = mipmaps.length; i < il; i ++ ) {
24667
24668                                         mipmap = mipmaps[ i ];
24669                                         state.texImage2D( 3553, i, glInternalFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data );
24670
24671                                 }
24672
24673                                 texture.generateMipmaps = false;
24674                                 textureProperties.__maxMipLevel = mipmaps.length - 1;
24675
24676                         } else {
24677
24678                                 state.texImage2D( 3553, 0, glInternalFormat, image.width, image.height, 0, glFormat, glType, image.data );
24679                                 textureProperties.__maxMipLevel = 0;
24680
24681                         }
24682
24683                 } else if ( texture.isCompressedTexture ) {
24684
24685                         for ( let i = 0, il = mipmaps.length; i < il; i ++ ) {
24686
24687                                 mipmap = mipmaps[ i ];
24688
24689                                 if ( texture.format !== RGBAFormat && texture.format !== RGBFormat ) {
24690
24691                                         if ( glFormat !== null ) {
24692
24693                                                 state.compressedTexImage2D( 3553, i, glInternalFormat, mipmap.width, mipmap.height, 0, mipmap.data );
24694
24695                                         } else {
24696
24697                                                 console.warn( 'THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .uploadTexture()' );
24698
24699                                         }
24700
24701                                 } else {
24702
24703                                         state.texImage2D( 3553, i, glInternalFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data );
24704
24705                                 }
24706
24707                         }
24708
24709                         textureProperties.__maxMipLevel = mipmaps.length - 1;
24710
24711                 } else if ( texture.isDataTexture2DArray ) {
24712
24713                         state.texImage3D( 35866, 0, glInternalFormat, image.width, image.height, image.depth, 0, glFormat, glType, image.data );
24714                         textureProperties.__maxMipLevel = 0;
24715
24716                 } else if ( texture.isDataTexture3D ) {
24717
24718                         state.texImage3D( 32879, 0, glInternalFormat, image.width, image.height, image.depth, 0, glFormat, glType, image.data );
24719                         textureProperties.__maxMipLevel = 0;
24720
24721                 } else {
24722
24723                         // regular Texture (image, video, canvas)
24724
24725                         // use manually created mipmaps if available
24726                         // if there are no manual mipmaps
24727                         // set 0 level mipmap and then use GL to generate other mipmap levels
24728
24729                         if ( mipmaps.length > 0 && supportsMips ) {
24730
24731                                 for ( let i = 0, il = mipmaps.length; i < il; i ++ ) {
24732
24733                                         mipmap = mipmaps[ i ];
24734                                         state.texImage2D( 3553, i, glInternalFormat, glFormat, glType, mipmap );
24735
24736                                 }
24737
24738                                 texture.generateMipmaps = false;
24739                                 textureProperties.__maxMipLevel = mipmaps.length - 1;
24740
24741                         } else {
24742
24743                                 state.texImage2D( 3553, 0, glInternalFormat, glFormat, glType, image );
24744                                 textureProperties.__maxMipLevel = 0;
24745
24746                         }
24747
24748                 }
24749
24750                 if ( textureNeedsGenerateMipmaps( texture, supportsMips ) ) {
24751
24752                         generateMipmap( textureType, texture, image.width, image.height );
24753
24754                 }
24755
24756                 textureProperties.__version = texture.version;
24757
24758                 if ( texture.onUpdate ) texture.onUpdate( texture );
24759
24760         }
24761
24762         function uploadCubeTexture( textureProperties, texture, slot ) {
24763
24764                 if ( texture.image.length !== 6 ) return;
24765
24766                 initTexture( textureProperties, texture );
24767
24768                 state.activeTexture( 33984 + slot );
24769                 state.bindTexture( 34067, textureProperties.__webglTexture );
24770
24771                 _gl.pixelStorei( 37440, texture.flipY );
24772                 _gl.pixelStorei( 37441, texture.premultiplyAlpha );
24773                 _gl.pixelStorei( 3317, texture.unpackAlignment );
24774
24775                 const isCompressed = ( texture && ( texture.isCompressedTexture || texture.image[ 0 ].isCompressedTexture ) );
24776                 const isDataTexture = ( texture.image[ 0 ] && texture.image[ 0 ].isDataTexture );
24777
24778                 const cubeImage = [];
24779
24780                 for ( let i = 0; i < 6; i ++ ) {
24781
24782                         if ( ! isCompressed && ! isDataTexture ) {
24783
24784                                 cubeImage[ i ] = resizeImage( texture.image[ i ], false, true, maxCubemapSize );
24785
24786                         } else {
24787
24788                                 cubeImage[ i ] = isDataTexture ? texture.image[ i ].image : texture.image[ i ];
24789
24790                         }
24791
24792                 }
24793
24794                 const image = cubeImage[ 0 ],
24795                         supportsMips = isPowerOfTwo( image ) || isWebGL2,
24796                         glFormat = utils.convert( texture.format ),
24797                         glType = utils.convert( texture.type ),
24798                         glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType );
24799
24800                 setTextureParameters( 34067, texture, supportsMips );
24801
24802                 let mipmaps;
24803
24804                 if ( isCompressed ) {
24805
24806                         for ( let i = 0; i < 6; i ++ ) {
24807
24808                                 mipmaps = cubeImage[ i ].mipmaps;
24809
24810                                 for ( let j = 0; j < mipmaps.length; j ++ ) {
24811
24812                                         const mipmap = mipmaps[ j ];
24813
24814                                         if ( texture.format !== RGBAFormat && texture.format !== RGBFormat ) {
24815
24816                                                 if ( glFormat !== null ) {
24817
24818                                                         state.compressedTexImage2D( 34069 + i, j, glInternalFormat, mipmap.width, mipmap.height, 0, mipmap.data );
24819
24820                                                 } else {
24821
24822                                                         console.warn( 'THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .setTextureCube()' );
24823
24824                                                 }
24825
24826                                         } else {
24827
24828                                                 state.texImage2D( 34069 + i, j, glInternalFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data );
24829
24830                                         }
24831
24832                                 }
24833
24834                         }
24835
24836                         textureProperties.__maxMipLevel = mipmaps.length - 1;
24837
24838                 } else {
24839
24840                         mipmaps = texture.mipmaps;
24841
24842                         for ( let i = 0; i < 6; i ++ ) {
24843
24844                                 if ( isDataTexture ) {
24845
24846                                         state.texImage2D( 34069 + i, 0, glInternalFormat, cubeImage[ i ].width, cubeImage[ i ].height, 0, glFormat, glType, cubeImage[ i ].data );
24847
24848                                         for ( let j = 0; j < mipmaps.length; j ++ ) {
24849
24850                                                 const mipmap = mipmaps[ j ];
24851                                                 const mipmapImage = mipmap.image[ i ].image;
24852
24853                                                 state.texImage2D( 34069 + i, j + 1, glInternalFormat, mipmapImage.width, mipmapImage.height, 0, glFormat, glType, mipmapImage.data );
24854
24855                                         }
24856
24857                                 } else {
24858
24859                                         state.texImage2D( 34069 + i, 0, glInternalFormat, glFormat, glType, cubeImage[ i ] );
24860
24861                                         for ( let j = 0; j < mipmaps.length; j ++ ) {
24862
24863                                                 const mipmap = mipmaps[ j ];
24864
24865                                                 state.texImage2D( 34069 + i, j + 1, glInternalFormat, glFormat, glType, mipmap.image[ i ] );
24866
24867                                         }
24868
24869                                 }
24870
24871                         }
24872
24873                         textureProperties.__maxMipLevel = mipmaps.length;
24874
24875                 }
24876
24877                 if ( textureNeedsGenerateMipmaps( texture, supportsMips ) ) {
24878
24879                         // We assume images for cube map have the same size.
24880                         generateMipmap( 34067, texture, image.width, image.height );
24881
24882                 }
24883
24884                 textureProperties.__version = texture.version;
24885
24886                 if ( texture.onUpdate ) texture.onUpdate( texture );
24887
24888         }
24889
24890         // Render targets
24891
24892         // Setup storage for target texture and bind it to correct framebuffer
24893         function setupFrameBufferTexture( framebuffer, renderTarget, attachment, textureTarget ) {
24894
24895                 const glFormat = utils.convert( renderTarget.texture.format );
24896                 const glType = utils.convert( renderTarget.texture.type );
24897                 const glInternalFormat = getInternalFormat( renderTarget.texture.internalFormat, glFormat, glType );
24898                 state.texImage2D( textureTarget, 0, glInternalFormat, renderTarget.width, renderTarget.height, 0, glFormat, glType, null );
24899                 _gl.bindFramebuffer( 36160, framebuffer );
24900                 _gl.framebufferTexture2D( 36160, attachment, textureTarget, properties.get( renderTarget.texture ).__webglTexture, 0 );
24901                 _gl.bindFramebuffer( 36160, null );
24902
24903         }
24904
24905         // Setup storage for internal depth/stencil buffers and bind to correct framebuffer
24906         function setupRenderBufferStorage( renderbuffer, renderTarget, isMultisample ) {
24907
24908                 _gl.bindRenderbuffer( 36161, renderbuffer );
24909
24910                 if ( renderTarget.depthBuffer && ! renderTarget.stencilBuffer ) {
24911
24912                         let glInternalFormat = 33189;
24913
24914                         if ( isMultisample ) {
24915
24916                                 const depthTexture = renderTarget.depthTexture;
24917
24918                                 if ( depthTexture && depthTexture.isDepthTexture ) {
24919
24920                                         if ( depthTexture.type === FloatType ) {
24921
24922                                                 glInternalFormat = 36012;
24923
24924                                         } else if ( depthTexture.type === UnsignedIntType ) {
24925
24926                                                 glInternalFormat = 33190;
24927
24928                                         }
24929
24930                                 }
24931
24932                                 const samples = getRenderTargetSamples( renderTarget );
24933
24934                                 _gl.renderbufferStorageMultisample( 36161, samples, glInternalFormat, renderTarget.width, renderTarget.height );
24935
24936                         } else {
24937
24938                                 _gl.renderbufferStorage( 36161, glInternalFormat, renderTarget.width, renderTarget.height );
24939
24940                         }
24941
24942                         _gl.framebufferRenderbuffer( 36160, 36096, 36161, renderbuffer );
24943
24944                 } else if ( renderTarget.depthBuffer && renderTarget.stencilBuffer ) {
24945
24946                         if ( isMultisample ) {
24947
24948                                 const samples = getRenderTargetSamples( renderTarget );
24949
24950                                 _gl.renderbufferStorageMultisample( 36161, samples, 35056, renderTarget.width, renderTarget.height );
24951
24952                         } else {
24953
24954                                 _gl.renderbufferStorage( 36161, 34041, renderTarget.width, renderTarget.height );
24955
24956                         }
24957
24958
24959                         _gl.framebufferRenderbuffer( 36160, 33306, 36161, renderbuffer );
24960
24961                 } else {
24962
24963                         const glFormat = utils.convert( renderTarget.texture.format );
24964                         const glType = utils.convert( renderTarget.texture.type );
24965                         const glInternalFormat = getInternalFormat( renderTarget.texture.internalFormat, glFormat, glType );
24966
24967                         if ( isMultisample ) {
24968
24969                                 const samples = getRenderTargetSamples( renderTarget );
24970
24971                                 _gl.renderbufferStorageMultisample( 36161, samples, glInternalFormat, renderTarget.width, renderTarget.height );
24972
24973                         } else {
24974
24975                                 _gl.renderbufferStorage( 36161, glInternalFormat, renderTarget.width, renderTarget.height );
24976
24977                         }
24978
24979                 }
24980
24981                 _gl.bindRenderbuffer( 36161, null );
24982
24983         }
24984
24985         // Setup resources for a Depth Texture for a FBO (needs an extension)
24986         function setupDepthTexture( framebuffer, renderTarget ) {
24987
24988                 const isCube = ( renderTarget && renderTarget.isWebGLCubeRenderTarget );
24989                 if ( isCube ) throw new Error( 'Depth Texture with cube render targets is not supported' );
24990
24991                 _gl.bindFramebuffer( 36160, framebuffer );
24992
24993                 if ( ! ( renderTarget.depthTexture && renderTarget.depthTexture.isDepthTexture ) ) {
24994
24995                         throw new Error( 'renderTarget.depthTexture must be an instance of THREE.DepthTexture' );
24996
24997                 }
24998
24999                 // upload an empty depth texture with framebuffer size
25000                 if ( ! properties.get( renderTarget.depthTexture ).__webglTexture ||
25001                                 renderTarget.depthTexture.image.width !== renderTarget.width ||
25002                                 renderTarget.depthTexture.image.height !== renderTarget.height ) {
25003
25004                         renderTarget.depthTexture.image.width = renderTarget.width;
25005                         renderTarget.depthTexture.image.height = renderTarget.height;
25006                         renderTarget.depthTexture.needsUpdate = true;
25007
25008                 }
25009
25010                 setTexture2D( renderTarget.depthTexture, 0 );
25011
25012                 const webglDepthTexture = properties.get( renderTarget.depthTexture ).__webglTexture;
25013
25014                 if ( renderTarget.depthTexture.format === DepthFormat ) {
25015
25016                         _gl.framebufferTexture2D( 36160, 36096, 3553, webglDepthTexture, 0 );
25017
25018                 } else if ( renderTarget.depthTexture.format === DepthStencilFormat ) {
25019
25020                         _gl.framebufferTexture2D( 36160, 33306, 3553, webglDepthTexture, 0 );
25021
25022                 } else {
25023
25024                         throw new Error( 'Unknown depthTexture format' );
25025
25026                 }
25027
25028         }
25029
25030         // Setup GL resources for a non-texture depth buffer
25031         function setupDepthRenderbuffer( renderTarget ) {
25032
25033                 const renderTargetProperties = properties.get( renderTarget );
25034
25035                 const isCube = ( renderTarget.isWebGLCubeRenderTarget === true );
25036
25037                 if ( renderTarget.depthTexture ) {
25038
25039                         if ( isCube ) throw new Error( 'target.depthTexture not supported in Cube render targets' );
25040
25041                         setupDepthTexture( renderTargetProperties.__webglFramebuffer, renderTarget );
25042
25043                 } else {
25044
25045                         if ( isCube ) {
25046
25047                                 renderTargetProperties.__webglDepthbuffer = [];
25048
25049                                 for ( let i = 0; i < 6; i ++ ) {
25050
25051                                         _gl.bindFramebuffer( 36160, renderTargetProperties.__webglFramebuffer[ i ] );
25052                                         renderTargetProperties.__webglDepthbuffer[ i ] = _gl.createRenderbuffer();
25053                                         setupRenderBufferStorage( renderTargetProperties.__webglDepthbuffer[ i ], renderTarget, false );
25054
25055                                 }
25056
25057                         } else {
25058
25059                                 _gl.bindFramebuffer( 36160, renderTargetProperties.__webglFramebuffer );
25060                                 renderTargetProperties.__webglDepthbuffer = _gl.createRenderbuffer();
25061                                 setupRenderBufferStorage( renderTargetProperties.__webglDepthbuffer, renderTarget, false );
25062
25063                         }
25064
25065                 }
25066
25067                 _gl.bindFramebuffer( 36160, null );
25068
25069         }
25070
25071         // Set up GL resources for the render target
25072         function setupRenderTarget( renderTarget ) {
25073
25074                 const renderTargetProperties = properties.get( renderTarget );
25075                 const textureProperties = properties.get( renderTarget.texture );
25076
25077                 renderTarget.addEventListener( 'dispose', onRenderTargetDispose );
25078
25079                 textureProperties.__webglTexture = _gl.createTexture();
25080
25081                 info.memory.textures ++;
25082
25083                 const isCube = ( renderTarget.isWebGLCubeRenderTarget === true );
25084                 const isMultisample = ( renderTarget.isWebGLMultisampleRenderTarget === true );
25085                 const supportsMips = isPowerOfTwo( renderTarget ) || isWebGL2;
25086
25087                 // Handles WebGL2 RGBFormat fallback - #18858
25088
25089                 if ( isWebGL2 && renderTarget.texture.format === RGBFormat && ( renderTarget.texture.type === FloatType || renderTarget.texture.type === HalfFloatType ) ) {
25090
25091                         renderTarget.texture.format = RGBAFormat;
25092
25093                         console.warn( 'THREE.WebGLRenderer: Rendering to textures with RGB format is not supported. Using RGBA format instead.' );
25094
25095                 }
25096
25097                 // Setup framebuffer
25098
25099                 if ( isCube ) {
25100
25101                         renderTargetProperties.__webglFramebuffer = [];
25102
25103                         for ( let i = 0; i < 6; i ++ ) {
25104
25105                                 renderTargetProperties.__webglFramebuffer[ i ] = _gl.createFramebuffer();
25106
25107                         }
25108
25109                 } else {
25110
25111                         renderTargetProperties.__webglFramebuffer = _gl.createFramebuffer();
25112
25113                         if ( isMultisample ) {
25114
25115                                 if ( isWebGL2 ) {
25116
25117                                         renderTargetProperties.__webglMultisampledFramebuffer = _gl.createFramebuffer();
25118                                         renderTargetProperties.__webglColorRenderbuffer = _gl.createRenderbuffer();
25119
25120                                         _gl.bindRenderbuffer( 36161, renderTargetProperties.__webglColorRenderbuffer );
25121
25122                                         const glFormat = utils.convert( renderTarget.texture.format );
25123                                         const glType = utils.convert( renderTarget.texture.type );
25124                                         const glInternalFormat = getInternalFormat( renderTarget.texture.internalFormat, glFormat, glType );
25125                                         const samples = getRenderTargetSamples( renderTarget );
25126                                         _gl.renderbufferStorageMultisample( 36161, samples, glInternalFormat, renderTarget.width, renderTarget.height );
25127
25128                                         _gl.bindFramebuffer( 36160, renderTargetProperties.__webglMultisampledFramebuffer );
25129                                         _gl.framebufferRenderbuffer( 36160, 36064, 36161, renderTargetProperties.__webglColorRenderbuffer );
25130                                         _gl.bindRenderbuffer( 36161, null );
25131
25132                                         if ( renderTarget.depthBuffer ) {
25133
25134                                                 renderTargetProperties.__webglDepthRenderbuffer = _gl.createRenderbuffer();
25135                                                 setupRenderBufferStorage( renderTargetProperties.__webglDepthRenderbuffer, renderTarget, true );
25136
25137                                         }
25138
25139                                         _gl.bindFramebuffer( 36160, null );
25140
25141
25142                                 } else {
25143
25144                                         console.warn( 'THREE.WebGLRenderer: WebGLMultisampleRenderTarget can only be used with WebGL2.' );
25145
25146                                 }
25147
25148                         }
25149
25150                 }
25151
25152                 // Setup color buffer
25153
25154                 if ( isCube ) {
25155
25156                         state.bindTexture( 34067, textureProperties.__webglTexture );
25157                         setTextureParameters( 34067, renderTarget.texture, supportsMips );
25158
25159                         for ( let i = 0; i < 6; i ++ ) {
25160
25161                                 setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer[ i ], renderTarget, 36064, 34069 + i );
25162
25163                         }
25164
25165                         if ( textureNeedsGenerateMipmaps( renderTarget.texture, supportsMips ) ) {
25166
25167                                 generateMipmap( 34067, renderTarget.texture, renderTarget.width, renderTarget.height );
25168
25169                         }
25170
25171                         state.bindTexture( 34067, null );
25172
25173                 } else {
25174
25175                         state.bindTexture( 3553, textureProperties.__webglTexture );
25176                         setTextureParameters( 3553, renderTarget.texture, supportsMips );
25177                         setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer, renderTarget, 36064, 3553 );
25178
25179                         if ( textureNeedsGenerateMipmaps( renderTarget.texture, supportsMips ) ) {
25180
25181                                 generateMipmap( 3553, renderTarget.texture, renderTarget.width, renderTarget.height );
25182
25183                         }
25184
25185                         state.bindTexture( 3553, null );
25186
25187                 }
25188
25189                 // Setup depth and stencil buffers
25190
25191                 if ( renderTarget.depthBuffer ) {
25192
25193                         setupDepthRenderbuffer( renderTarget );
25194
25195                 }
25196
25197         }
25198
25199         function updateRenderTargetMipmap( renderTarget ) {
25200
25201                 const texture = renderTarget.texture;
25202                 const supportsMips = isPowerOfTwo( renderTarget ) || isWebGL2;
25203
25204                 if ( textureNeedsGenerateMipmaps( texture, supportsMips ) ) {
25205
25206                         const target = renderTarget.isWebGLCubeRenderTarget ? 34067 : 3553;
25207                         const webglTexture = properties.get( texture ).__webglTexture;
25208
25209                         state.bindTexture( target, webglTexture );
25210                         generateMipmap( target, texture, renderTarget.width, renderTarget.height );
25211                         state.bindTexture( target, null );
25212
25213                 }
25214
25215         }
25216
25217         function updateMultisampleRenderTarget( renderTarget ) {
25218
25219                 if ( renderTarget.isWebGLMultisampleRenderTarget ) {
25220
25221                         if ( isWebGL2 ) {
25222
25223                                 const renderTargetProperties = properties.get( renderTarget );
25224
25225                                 _gl.bindFramebuffer( 36008, renderTargetProperties.__webglMultisampledFramebuffer );
25226                                 _gl.bindFramebuffer( 36009, renderTargetProperties.__webglFramebuffer );
25227
25228                                 const width = renderTarget.width;
25229                                 const height = renderTarget.height;
25230                                 let mask = 16384;
25231
25232                                 if ( renderTarget.depthBuffer ) mask |= 256;
25233                                 if ( renderTarget.stencilBuffer ) mask |= 1024;
25234
25235                                 _gl.blitFramebuffer( 0, 0, width, height, 0, 0, width, height, mask, 9728 );
25236
25237                                 _gl.bindFramebuffer( 36160, renderTargetProperties.__webglMultisampledFramebuffer ); // see #18905
25238
25239                         } else {
25240
25241                                 console.warn( 'THREE.WebGLRenderer: WebGLMultisampleRenderTarget can only be used with WebGL2.' );
25242
25243                         }
25244
25245                 }
25246
25247         }
25248
25249         function getRenderTargetSamples( renderTarget ) {
25250
25251                 return ( isWebGL2 && renderTarget.isWebGLMultisampleRenderTarget ) ?
25252                         Math.min( maxSamples, renderTarget.samples ) : 0;
25253
25254         }
25255
25256         function updateVideoTexture( texture ) {
25257
25258                 const frame = info.render.frame;
25259
25260                 // Check the last frame we updated the VideoTexture
25261
25262                 if ( _videoTextures.get( texture ) !== frame ) {
25263
25264                         _videoTextures.set( texture, frame );
25265                         texture.update();
25266
25267                 }
25268
25269         }
25270
25271         // backwards compatibility
25272
25273         let warnedTexture2D = false;
25274         let warnedTextureCube = false;
25275
25276         function safeSetTexture2D( texture, slot ) {
25277
25278                 if ( texture && texture.isWebGLRenderTarget ) {
25279
25280                         if ( warnedTexture2D === false ) {
25281
25282                                 console.warn( 'THREE.WebGLTextures.safeSetTexture2D: don\'t use render targets as textures. Use their .texture property instead.' );
25283                                 warnedTexture2D = true;
25284
25285                         }
25286
25287                         texture = texture.texture;
25288
25289                 }
25290
25291                 setTexture2D( texture, slot );
25292
25293         }
25294
25295         function safeSetTextureCube( texture, slot ) {
25296
25297                 if ( texture && texture.isWebGLCubeRenderTarget ) {
25298
25299                         if ( warnedTextureCube === false ) {
25300
25301                                 console.warn( 'THREE.WebGLTextures.safeSetTextureCube: don\'t use cube render targets as textures. Use their .texture property instead.' );
25302                                 warnedTextureCube = true;
25303
25304                         }
25305
25306                         texture = texture.texture;
25307
25308                 }
25309
25310
25311                 setTextureCube( texture, slot );
25312
25313         }
25314
25315         //
25316
25317         this.allocateTextureUnit = allocateTextureUnit;
25318         this.resetTextureUnits = resetTextureUnits;
25319
25320         this.setTexture2D = setTexture2D;
25321         this.setTexture2DArray = setTexture2DArray;
25322         this.setTexture3D = setTexture3D;
25323         this.setTextureCube = setTextureCube;
25324         this.setupRenderTarget = setupRenderTarget;
25325         this.updateRenderTargetMipmap = updateRenderTargetMipmap;
25326         this.updateMultisampleRenderTarget = updateMultisampleRenderTarget;
25327
25328         this.safeSetTexture2D = safeSetTexture2D;
25329         this.safeSetTextureCube = safeSetTextureCube;
25330
25331 }
25332
25333 function WebGLUtils( gl, extensions, capabilities ) {
25334
25335         const isWebGL2 = capabilities.isWebGL2;
25336
25337         function convert( p ) {
25338
25339                 let extension;
25340
25341                 if ( p === UnsignedByteType ) return 5121;
25342                 if ( p === UnsignedShort4444Type ) return 32819;
25343                 if ( p === UnsignedShort5551Type ) return 32820;
25344                 if ( p === UnsignedShort565Type ) return 33635;
25345
25346                 if ( p === ByteType ) return 5120;
25347                 if ( p === ShortType ) return 5122;
25348                 if ( p === UnsignedShortType ) return 5123;
25349                 if ( p === IntType ) return 5124;
25350                 if ( p === UnsignedIntType ) return 5125;
25351                 if ( p === FloatType ) return 5126;
25352
25353                 if ( p === HalfFloatType ) {
25354
25355                         if ( isWebGL2 ) return 5131;
25356
25357                         extension = extensions.get( 'OES_texture_half_float' );
25358
25359                         if ( extension !== null ) {
25360
25361                                 return extension.HALF_FLOAT_OES;
25362
25363                         } else {
25364
25365                                 return null;
25366
25367                         }
25368
25369                 }
25370
25371                 if ( p === AlphaFormat ) return 6406;
25372                 if ( p === RGBFormat ) return 6407;
25373                 if ( p === RGBAFormat ) return 6408;
25374                 if ( p === LuminanceFormat ) return 6409;
25375                 if ( p === LuminanceAlphaFormat ) return 6410;
25376                 if ( p === DepthFormat ) return 6402;
25377                 if ( p === DepthStencilFormat ) return 34041;
25378                 if ( p === RedFormat ) return 6403;
25379
25380                 // WebGL2 formats.
25381
25382                 if ( p === RedIntegerFormat ) return 36244;
25383                 if ( p === RGFormat ) return 33319;
25384                 if ( p === RGIntegerFormat ) return 33320;
25385                 if ( p === RGBIntegerFormat ) return 36248;
25386                 if ( p === RGBAIntegerFormat ) return 36249;
25387
25388                 if ( p === RGB_S3TC_DXT1_Format || p === RGBA_S3TC_DXT1_Format ||
25389                         p === RGBA_S3TC_DXT3_Format || p === RGBA_S3TC_DXT5_Format ) {
25390
25391                         extension = extensions.get( 'WEBGL_compressed_texture_s3tc' );
25392
25393                         if ( extension !== null ) {
25394
25395                                 if ( p === RGB_S3TC_DXT1_Format ) return extension.COMPRESSED_RGB_S3TC_DXT1_EXT;
25396                                 if ( p === RGBA_S3TC_DXT1_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT1_EXT;
25397                                 if ( p === RGBA_S3TC_DXT3_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT3_EXT;
25398                                 if ( p === RGBA_S3TC_DXT5_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT5_EXT;
25399
25400                         } else {
25401
25402                                 return null;
25403
25404                         }
25405
25406                 }
25407
25408                 if ( p === RGB_PVRTC_4BPPV1_Format || p === RGB_PVRTC_2BPPV1_Format ||
25409                         p === RGBA_PVRTC_4BPPV1_Format || p === RGBA_PVRTC_2BPPV1_Format ) {
25410
25411                         extension = extensions.get( 'WEBGL_compressed_texture_pvrtc' );
25412
25413                         if ( extension !== null ) {
25414
25415                                 if ( p === RGB_PVRTC_4BPPV1_Format ) return extension.COMPRESSED_RGB_PVRTC_4BPPV1_IMG;
25416                                 if ( p === RGB_PVRTC_2BPPV1_Format ) return extension.COMPRESSED_RGB_PVRTC_2BPPV1_IMG;
25417                                 if ( p === RGBA_PVRTC_4BPPV1_Format ) return extension.COMPRESSED_RGBA_PVRTC_4BPPV1_IMG;
25418                                 if ( p === RGBA_PVRTC_2BPPV1_Format ) return extension.COMPRESSED_RGBA_PVRTC_2BPPV1_IMG;
25419
25420                         } else {
25421
25422                                 return null;
25423
25424                         }
25425
25426                 }
25427
25428                 if ( p === RGB_ETC1_Format ) {
25429
25430                         extension = extensions.get( 'WEBGL_compressed_texture_etc1' );
25431
25432                         if ( extension !== null ) {
25433
25434                                 return extension.COMPRESSED_RGB_ETC1_WEBGL;
25435
25436                         } else {
25437
25438                                 return null;
25439
25440                         }
25441
25442                 }
25443
25444                 if ( p === RGB_ETC2_Format || p === RGBA_ETC2_EAC_Format ) {
25445
25446                         extension = extensions.get( 'WEBGL_compressed_texture_etc' );
25447
25448                         if ( extension !== null ) {
25449
25450                                 if ( p === RGB_ETC2_Format ) return extension.COMPRESSED_RGB8_ETC2;
25451                                 if ( p === RGBA_ETC2_EAC_Format ) return extension.COMPRESSED_RGBA8_ETC2_EAC;
25452
25453                         }
25454
25455                 }
25456
25457                 if ( p === RGBA_ASTC_4x4_Format || p === RGBA_ASTC_5x4_Format || p === RGBA_ASTC_5x5_Format ||
25458                         p === RGBA_ASTC_6x5_Format || p === RGBA_ASTC_6x6_Format || p === RGBA_ASTC_8x5_Format ||
25459                         p === RGBA_ASTC_8x6_Format || p === RGBA_ASTC_8x8_Format || p === RGBA_ASTC_10x5_Format ||
25460                         p === RGBA_ASTC_10x6_Format || p === RGBA_ASTC_10x8_Format || p === RGBA_ASTC_10x10_Format ||
25461                         p === RGBA_ASTC_12x10_Format || p === RGBA_ASTC_12x12_Format ||
25462                         p === SRGB8_ALPHA8_ASTC_4x4_Format || p === SRGB8_ALPHA8_ASTC_5x4_Format || p === SRGB8_ALPHA8_ASTC_5x5_Format ||
25463                         p === SRGB8_ALPHA8_ASTC_6x5_Format || p === SRGB8_ALPHA8_ASTC_6x6_Format || p === SRGB8_ALPHA8_ASTC_8x5_Format ||
25464                         p === SRGB8_ALPHA8_ASTC_8x6_Format || p === SRGB8_ALPHA8_ASTC_8x8_Format || p === SRGB8_ALPHA8_ASTC_10x5_Format ||
25465                         p === SRGB8_ALPHA8_ASTC_10x6_Format || p === SRGB8_ALPHA8_ASTC_10x8_Format || p === SRGB8_ALPHA8_ASTC_10x10_Format ||
25466                         p === SRGB8_ALPHA8_ASTC_12x10_Format || p === SRGB8_ALPHA8_ASTC_12x12_Format ) {
25467
25468                         extension = extensions.get( 'WEBGL_compressed_texture_astc' );
25469
25470                         if ( extension !== null ) {
25471
25472                                 // TODO Complete?
25473
25474                                 return p;
25475
25476                         } else {
25477
25478                                 return null;
25479
25480                         }
25481
25482                 }
25483
25484                 if ( p === RGBA_BPTC_Format ) {
25485
25486                         extension = extensions.get( 'EXT_texture_compression_bptc' );
25487
25488                         if ( extension !== null ) {
25489
25490                                 // TODO Complete?
25491
25492                                 return p;
25493
25494                         } else {
25495
25496                                 return null;
25497
25498                         }
25499
25500                 }
25501
25502                 if ( p === UnsignedInt248Type ) {
25503
25504                         if ( isWebGL2 ) return 34042;
25505
25506                         extension = extensions.get( 'WEBGL_depth_texture' );
25507
25508                         if ( extension !== null ) {
25509
25510                                 return extension.UNSIGNED_INT_24_8_WEBGL;
25511
25512                         } else {
25513
25514                                 return null;
25515
25516                         }
25517
25518                 }
25519
25520         }
25521
25522         return { convert: convert };
25523
25524 }
25525
25526 function ArrayCamera( array = [] ) {
25527
25528         PerspectiveCamera.call( this );
25529
25530         this.cameras = array;
25531
25532 }
25533
25534 ArrayCamera.prototype = Object.assign( Object.create( PerspectiveCamera.prototype ), {
25535
25536         constructor: ArrayCamera,
25537
25538         isArrayCamera: true
25539
25540 } );
25541
25542 function Group() {
25543
25544         Object3D.call( this );
25545
25546         this.type = 'Group';
25547
25548 }
25549
25550 Group.prototype = Object.assign( Object.create( Object3D.prototype ), {
25551
25552         constructor: Group,
25553
25554         isGroup: true
25555
25556 } );
25557
25558 function WebXRController() {
25559
25560         this._targetRay = null;
25561         this._grip = null;
25562         this._hand = null;
25563
25564 }
25565
25566 Object.assign( WebXRController.prototype, {
25567
25568         constructor: WebXRController,
25569
25570         getHandSpace: function () {
25571
25572                 if ( this._hand === null ) {
25573
25574                         this._hand = new Group();
25575                         this._hand.matrixAutoUpdate = false;
25576                         this._hand.visible = false;
25577
25578                         this._hand.joints = {};
25579                         this._hand.inputState = { pinching: false };
25580
25581                 }
25582
25583                 return this._hand;
25584
25585         },
25586
25587         getTargetRaySpace: function () {
25588
25589                 if ( this._targetRay === null ) {
25590
25591                         this._targetRay = new Group();
25592                         this._targetRay.matrixAutoUpdate = false;
25593                         this._targetRay.visible = false;
25594
25595                 }
25596
25597                 return this._targetRay;
25598
25599         },
25600
25601         getGripSpace: function () {
25602
25603                 if ( this._grip === null ) {
25604
25605                         this._grip = new Group();
25606                         this._grip.matrixAutoUpdate = false;
25607                         this._grip.visible = false;
25608
25609                 }
25610
25611                 return this._grip;
25612
25613         },
25614
25615         dispatchEvent: function ( event ) {
25616
25617                 if ( this._targetRay !== null ) {
25618
25619                         this._targetRay.dispatchEvent( event );
25620
25621                 }
25622
25623                 if ( this._grip !== null ) {
25624
25625                         this._grip.dispatchEvent( event );
25626
25627                 }
25628
25629                 if ( this._hand !== null ) {
25630
25631                         this._hand.dispatchEvent( event );
25632
25633                 }
25634
25635                 return this;
25636
25637         },
25638
25639         disconnect: function ( inputSource ) {
25640
25641                 this.dispatchEvent( { type: 'disconnected', data: inputSource } );
25642
25643                 if ( this._targetRay !== null ) {
25644
25645                         this._targetRay.visible = false;
25646
25647                 }
25648
25649                 if ( this._grip !== null ) {
25650
25651                         this._grip.visible = false;
25652
25653                 }
25654
25655                 if ( this._hand !== null ) {
25656
25657                         this._hand.visible = false;
25658
25659                 }
25660
25661                 return this;
25662
25663         },
25664
25665         update: function ( inputSource, frame, referenceSpace ) {
25666
25667                 let inputPose = null;
25668                 let gripPose = null;
25669                 let handPose = null;
25670
25671                 const targetRay = this._targetRay;
25672                 const grip = this._grip;
25673                 const hand = this._hand;
25674
25675                 if ( inputSource && frame.session.visibilityState !== 'visible-blurred' ) {
25676
25677                         if ( hand && inputSource.hand ) {
25678
25679                                 handPose = true;
25680
25681                                 for ( const inputjoint of inputSource.hand.values() ) {
25682
25683                                         // Update the joints groups with the XRJoint poses
25684                                         const jointPose = frame.getJointPose( inputjoint, referenceSpace );
25685
25686                                         if ( hand.joints[ inputjoint.jointName ] === undefined ) {
25687
25688                                                 // The transform of this joint will be updated with the joint pose on each frame
25689                                                 const joint = new Group();
25690                                                 joint.matrixAutoUpdate = false;
25691                                                 joint.visible = false;
25692                                                 hand.joints[ inputjoint.jointName ] = joint;
25693                                                 // ??
25694                                                 hand.add( joint );
25695
25696                                         }
25697
25698                                         const joint = hand.joints[ inputjoint.jointName ];
25699
25700                                         if ( jointPose !== null ) {
25701
25702                                                 joint.matrix.fromArray( jointPose.transform.matrix );
25703                                                 joint.matrix.decompose( joint.position, joint.rotation, joint.scale );
25704                                                 joint.jointRadius = jointPose.radius;
25705
25706                                         }
25707
25708                                         joint.visible = jointPose !== null;
25709
25710                                 }
25711
25712                                 // Custom events
25713
25714                                 // Check pinchz
25715                                 const indexTip = hand.joints[ 'index-finger-tip' ];
25716                                 const thumbTip = hand.joints[ 'thumb-tip' ];
25717                                 const distance = indexTip.position.distanceTo( thumbTip.position );
25718
25719                                 const distanceToPinch = 0.02;
25720                                 const threshold = 0.005;
25721
25722                                 if ( hand.inputState.pinching && distance > distanceToPinch + threshold ) {
25723
25724                                         hand.inputState.pinching = false;
25725                                         this.dispatchEvent( {
25726                                                 type: 'pinchend',
25727                                                 handedness: inputSource.handedness,
25728                                                 target: this
25729                                         } );
25730
25731                                 } else if ( ! hand.inputState.pinching && distance <= distanceToPinch - threshold ) {
25732
25733                                         hand.inputState.pinching = true;
25734                                         this.dispatchEvent( {
25735                                                 type: 'pinchstart',
25736                                                 handedness: inputSource.handedness,
25737                                                 target: this
25738                                         } );
25739
25740                                 }
25741
25742                         } else {
25743
25744                                 if ( targetRay !== null ) {
25745
25746                                         inputPose = frame.getPose( inputSource.targetRaySpace, referenceSpace );
25747
25748                                         if ( inputPose !== null ) {
25749
25750                                                 targetRay.matrix.fromArray( inputPose.transform.matrix );
25751                                                 targetRay.matrix.decompose( targetRay.position, targetRay.rotation, targetRay.scale );
25752
25753                                         }
25754
25755                                 }
25756
25757                                 if ( grip !== null && inputSource.gripSpace ) {
25758
25759                                         gripPose = frame.getPose( inputSource.gripSpace, referenceSpace );
25760
25761                                         if ( gripPose !== null ) {
25762
25763                                                 grip.matrix.fromArray( gripPose.transform.matrix );
25764                                                 grip.matrix.decompose( grip.position, grip.rotation, grip.scale );
25765
25766                                         }
25767
25768                                 }
25769
25770                         }
25771
25772                 }
25773
25774                 if ( targetRay !== null ) {
25775
25776                         targetRay.visible = ( inputPose !== null );
25777
25778                 }
25779
25780                 if ( grip !== null ) {
25781
25782                         grip.visible = ( gripPose !== null );
25783
25784                 }
25785
25786                 if ( hand !== null ) {
25787
25788                         hand.visible = ( handPose !== null );
25789
25790                 }
25791
25792                 return this;
25793
25794         }
25795
25796 } );
25797
25798 function WebXRManager( renderer, gl ) {
25799
25800         const scope = this;
25801
25802         let session = null;
25803
25804         let framebufferScaleFactor = 1.0;
25805
25806         let referenceSpace = null;
25807         let referenceSpaceType = 'local-floor';
25808
25809         let pose = null;
25810
25811         const controllers = [];
25812         const inputSourcesMap = new Map();
25813
25814         //
25815
25816         const cameraL = new PerspectiveCamera();
25817         cameraL.layers.enable( 1 );
25818         cameraL.viewport = new Vector4();
25819
25820         const cameraR = new PerspectiveCamera();
25821         cameraR.layers.enable( 2 );
25822         cameraR.viewport = new Vector4();
25823
25824         const cameras = [ cameraL, cameraR ];
25825
25826         const cameraVR = new ArrayCamera();
25827         cameraVR.layers.enable( 1 );
25828         cameraVR.layers.enable( 2 );
25829
25830         let _currentDepthNear = null;
25831         let _currentDepthFar = null;
25832
25833         //
25834
25835         this.enabled = false;
25836
25837         this.isPresenting = false;
25838
25839         this.getController = function ( index ) {
25840
25841                 let controller = controllers[ index ];
25842
25843                 if ( controller === undefined ) {
25844
25845                         controller = new WebXRController();
25846                         controllers[ index ] = controller;
25847
25848                 }
25849
25850                 return controller.getTargetRaySpace();
25851
25852         };
25853
25854         this.getControllerGrip = function ( index ) {
25855
25856                 let controller = controllers[ index ];
25857
25858                 if ( controller === undefined ) {
25859
25860                         controller = new WebXRController();
25861                         controllers[ index ] = controller;
25862
25863                 }
25864
25865                 return controller.getGripSpace();
25866
25867         };
25868
25869         this.getHand = function ( index ) {
25870
25871                 let controller = controllers[ index ];
25872
25873                 if ( controller === undefined ) {
25874
25875                         controller = new WebXRController();
25876                         controllers[ index ] = controller;
25877
25878                 }
25879
25880                 return controller.getHandSpace();
25881
25882         };
25883
25884         //
25885
25886         function onSessionEvent( event ) {
25887
25888                 const controller = inputSourcesMap.get( event.inputSource );
25889
25890                 if ( controller ) {
25891
25892                         controller.dispatchEvent( { type: event.type, data: event.inputSource } );
25893
25894                 }
25895
25896         }
25897
25898         function onSessionEnd() {
25899
25900                 inputSourcesMap.forEach( function ( controller, inputSource ) {
25901
25902                         controller.disconnect( inputSource );
25903
25904                 } );
25905
25906                 inputSourcesMap.clear();
25907
25908                 _currentDepthNear = null;
25909                 _currentDepthFar = null;
25910
25911                 //
25912
25913                 renderer.setFramebuffer( null );
25914                 renderer.setRenderTarget( renderer.getRenderTarget() ); // Hack #15830
25915                 animation.stop();
25916
25917                 scope.isPresenting = false;
25918
25919                 scope.dispatchEvent( { type: 'sessionend' } );
25920
25921         }
25922
25923         this.setFramebufferScaleFactor = function ( value ) {
25924
25925                 framebufferScaleFactor = value;
25926
25927                 if ( scope.isPresenting === true ) {
25928
25929                         console.warn( 'THREE.WebXRManager: Cannot change framebuffer scale while presenting.' );
25930
25931                 }
25932
25933         };
25934
25935         this.setReferenceSpaceType = function ( value ) {
25936
25937                 referenceSpaceType = value;
25938
25939                 if ( scope.isPresenting === true ) {
25940
25941                         console.warn( 'THREE.WebXRManager: Cannot change reference space type while presenting.' );
25942
25943                 }
25944
25945         };
25946
25947         this.getReferenceSpace = function () {
25948
25949                 return referenceSpace;
25950
25951         };
25952
25953         this.getSession = function () {
25954
25955                 return session;
25956
25957         };
25958
25959         this.setSession = async function ( value ) {
25960
25961                 session = value;
25962
25963                 if ( session !== null ) {
25964
25965                         session.addEventListener( 'select', onSessionEvent );
25966                         session.addEventListener( 'selectstart', onSessionEvent );
25967                         session.addEventListener( 'selectend', onSessionEvent );
25968                         session.addEventListener( 'squeeze', onSessionEvent );
25969                         session.addEventListener( 'squeezestart', onSessionEvent );
25970                         session.addEventListener( 'squeezeend', onSessionEvent );
25971                         session.addEventListener( 'end', onSessionEnd );
25972                         session.addEventListener( 'inputsourceschange', onInputSourcesChange );
25973
25974                         const attributes = gl.getContextAttributes();
25975
25976                         if ( attributes.xrCompatible !== true ) {
25977
25978                                 await gl.makeXRCompatible();
25979
25980                         }
25981
25982                         const layerInit = {
25983                                 antialias: attributes.antialias,
25984                                 alpha: attributes.alpha,
25985                                 depth: attributes.depth,
25986                                 stencil: attributes.stencil,
25987                                 framebufferScaleFactor: framebufferScaleFactor
25988                         };
25989
25990                         // eslint-disable-next-line no-undef
25991                         const baseLayer = new XRWebGLLayer( session, gl, layerInit );
25992
25993                         session.updateRenderState( { baseLayer: baseLayer } );
25994
25995                         referenceSpace = await session.requestReferenceSpace( referenceSpaceType );
25996
25997                         animation.setContext( session );
25998                         animation.start();
25999
26000                         scope.isPresenting = true;
26001
26002                         scope.dispatchEvent( { type: 'sessionstart' } );
26003
26004                 }
26005
26006         };
26007
26008         function onInputSourcesChange( event ) {
26009
26010                 const inputSources = session.inputSources;
26011
26012                 // Assign inputSources to available controllers
26013
26014                 for ( let i = 0; i < controllers.length; i ++ ) {
26015
26016                         inputSourcesMap.set( inputSources[ i ], controllers[ i ] );
26017
26018                 }
26019
26020                 // Notify disconnected
26021
26022                 for ( let i = 0; i < event.removed.length; i ++ ) {
26023
26024                         const inputSource = event.removed[ i ];
26025                         const controller = inputSourcesMap.get( inputSource );
26026
26027                         if ( controller ) {
26028
26029                                 controller.dispatchEvent( { type: 'disconnected', data: inputSource } );
26030                                 inputSourcesMap.delete( inputSource );
26031
26032                         }
26033
26034                 }
26035
26036                 // Notify connected
26037
26038                 for ( let i = 0; i < event.added.length; i ++ ) {
26039
26040                         const inputSource = event.added[ i ];
26041                         const controller = inputSourcesMap.get( inputSource );
26042
26043                         if ( controller ) {
26044
26045                                 controller.dispatchEvent( { type: 'connected', data: inputSource } );
26046
26047                         }
26048
26049                 }
26050
26051         }
26052
26053         //
26054
26055         const cameraLPos = new Vector3();
26056         const cameraRPos = new Vector3();
26057
26058         /**
26059          * Assumes 2 cameras that are parallel and share an X-axis, and that
26060          * the cameras' projection and world matrices have already been set.
26061          * And that near and far planes are identical for both cameras.
26062          * Visualization of this technique: https://computergraphics.stackexchange.com/a/4765
26063          */
26064         function setProjectionFromUnion( camera, cameraL, cameraR ) {
26065
26066                 cameraLPos.setFromMatrixPosition( cameraL.matrixWorld );
26067                 cameraRPos.setFromMatrixPosition( cameraR.matrixWorld );
26068
26069                 const ipd = cameraLPos.distanceTo( cameraRPos );
26070
26071                 const projL = cameraL.projectionMatrix.elements;
26072                 const projR = cameraR.projectionMatrix.elements;
26073
26074                 // VR systems will have identical far and near planes, and
26075                 // most likely identical top and bottom frustum extents.
26076                 // Use the left camera for these values.
26077                 const near = projL[ 14 ] / ( projL[ 10 ] - 1 );
26078                 const far = projL[ 14 ] / ( projL[ 10 ] + 1 );
26079                 const topFov = ( projL[ 9 ] + 1 ) / projL[ 5 ];
26080                 const bottomFov = ( projL[ 9 ] - 1 ) / projL[ 5 ];
26081
26082                 const leftFov = ( projL[ 8 ] - 1 ) / projL[ 0 ];
26083                 const rightFov = ( projR[ 8 ] + 1 ) / projR[ 0 ];
26084                 const left = near * leftFov;
26085                 const right = near * rightFov;
26086
26087                 // Calculate the new camera's position offset from the
26088                 // left camera. xOffset should be roughly half `ipd`.
26089                 const zOffset = ipd / ( - leftFov + rightFov );
26090                 const xOffset = zOffset * - leftFov;
26091
26092                 // TODO: Better way to apply this offset?
26093                 cameraL.matrixWorld.decompose( camera.position, camera.quaternion, camera.scale );
26094                 camera.translateX( xOffset );
26095                 camera.translateZ( zOffset );
26096                 camera.matrixWorld.compose( camera.position, camera.quaternion, camera.scale );
26097                 camera.matrixWorldInverse.copy( camera.matrixWorld ).invert();
26098
26099                 // Find the union of the frustum values of the cameras and scale
26100                 // the values so that the near plane's position does not change in world space,
26101                 // although must now be relative to the new union camera.
26102                 const near2 = near + zOffset;
26103                 const far2 = far + zOffset;
26104                 const left2 = left - xOffset;
26105                 const right2 = right + ( ipd - xOffset );
26106                 const top2 = topFov * far / far2 * near2;
26107                 const bottom2 = bottomFov * far / far2 * near2;
26108
26109                 camera.projectionMatrix.makePerspective( left2, right2, top2, bottom2, near2, far2 );
26110
26111         }
26112
26113         function updateCamera( camera, parent ) {
26114
26115                 if ( parent === null ) {
26116
26117                         camera.matrixWorld.copy( camera.matrix );
26118
26119                 } else {
26120
26121                         camera.matrixWorld.multiplyMatrices( parent.matrixWorld, camera.matrix );
26122
26123                 }
26124
26125                 camera.matrixWorldInverse.copy( camera.matrixWorld ).invert();
26126
26127         }
26128
26129         this.getCamera = function ( camera ) {
26130
26131                 cameraVR.near = cameraR.near = cameraL.near = camera.near;
26132                 cameraVR.far = cameraR.far = cameraL.far = camera.far;
26133
26134                 if ( _currentDepthNear !== cameraVR.near || _currentDepthFar !== cameraVR.far ) {
26135
26136                         // Note that the new renderState won't apply until the next frame. See #18320
26137
26138                         session.updateRenderState( {
26139                                 depthNear: cameraVR.near,
26140                                 depthFar: cameraVR.far
26141                         } );
26142
26143                         _currentDepthNear = cameraVR.near;
26144                         _currentDepthFar = cameraVR.far;
26145
26146                 }
26147
26148                 const parent = camera.parent;
26149                 const cameras = cameraVR.cameras;
26150
26151                 updateCamera( cameraVR, parent );
26152
26153                 for ( let i = 0; i < cameras.length; i ++ ) {
26154
26155                         updateCamera( cameras[ i ], parent );
26156
26157                 }
26158
26159                 // update camera and its children
26160
26161                 camera.matrixWorld.copy( cameraVR.matrixWorld );
26162                 camera.matrix.copy( cameraVR.matrix );
26163                 camera.matrix.decompose( camera.position, camera.quaternion, camera.scale );
26164
26165                 const children = camera.children;
26166
26167                 for ( let i = 0, l = children.length; i < l; i ++ ) {
26168
26169                         children[ i ].updateMatrixWorld( true );
26170
26171                 }
26172
26173                 // update projection matrix for proper view frustum culling
26174
26175                 if ( cameras.length === 2 ) {
26176
26177                         setProjectionFromUnion( cameraVR, cameraL, cameraR );
26178
26179                 } else {
26180
26181                         // assume single camera setup (AR)
26182
26183                         cameraVR.projectionMatrix.copy( cameraL.projectionMatrix );
26184
26185                 }
26186
26187                 return cameraVR;
26188
26189         };
26190
26191         // Animation Loop
26192
26193         let onAnimationFrameCallback = null;
26194
26195         function onAnimationFrame( time, frame ) {
26196
26197                 pose = frame.getViewerPose( referenceSpace );
26198
26199                 if ( pose !== null ) {
26200
26201                         const views = pose.views;
26202                         const baseLayer = session.renderState.baseLayer;
26203
26204                         renderer.setFramebuffer( baseLayer.framebuffer );
26205
26206                         let cameraVRNeedsUpdate = false;
26207
26208                         // check if it's necessary to rebuild cameraVR's camera list
26209
26210                         if ( views.length !== cameraVR.cameras.length ) {
26211
26212                                 cameraVR.cameras.length = 0;
26213                                 cameraVRNeedsUpdate = true;
26214
26215                         }
26216
26217                         for ( let i = 0; i < views.length; i ++ ) {
26218
26219                                 const view = views[ i ];
26220                                 const viewport = baseLayer.getViewport( view );
26221
26222                                 const camera = cameras[ i ];
26223                                 camera.matrix.fromArray( view.transform.matrix );
26224                                 camera.projectionMatrix.fromArray( view.projectionMatrix );
26225                                 camera.viewport.set( viewport.x, viewport.y, viewport.width, viewport.height );
26226
26227                                 if ( i === 0 ) {
26228
26229                                         cameraVR.matrix.copy( camera.matrix );
26230
26231                                 }
26232
26233                                 if ( cameraVRNeedsUpdate === true ) {
26234
26235                                         cameraVR.cameras.push( camera );
26236
26237                                 }
26238
26239                         }
26240
26241                 }
26242
26243                 //
26244
26245                 const inputSources = session.inputSources;
26246
26247                 for ( let i = 0; i < controllers.length; i ++ ) {
26248
26249                         const controller = controllers[ i ];
26250                         const inputSource = inputSources[ i ];
26251
26252                         controller.update( inputSource, frame, referenceSpace );
26253
26254                 }
26255
26256                 if ( onAnimationFrameCallback ) onAnimationFrameCallback( time, frame );
26257
26258         }
26259
26260         const animation = new WebGLAnimation();
26261         animation.setAnimationLoop( onAnimationFrame );
26262
26263         this.setAnimationLoop = function ( callback ) {
26264
26265                 onAnimationFrameCallback = callback;
26266
26267         };
26268
26269         this.dispose = function () {};
26270
26271 }
26272
26273 Object.assign( WebXRManager.prototype, EventDispatcher.prototype );
26274
26275 function WebGLMaterials( properties ) {
26276
26277         function refreshFogUniforms( uniforms, fog ) {
26278
26279                 uniforms.fogColor.value.copy( fog.color );
26280
26281                 if ( fog.isFog ) {
26282
26283                         uniforms.fogNear.value = fog.near;
26284                         uniforms.fogFar.value = fog.far;
26285
26286                 } else if ( fog.isFogExp2 ) {
26287
26288                         uniforms.fogDensity.value = fog.density;
26289
26290                 }
26291
26292         }
26293
26294         function refreshMaterialUniforms( uniforms, material, pixelRatio, height ) {
26295
26296                 if ( material.isMeshBasicMaterial ) {
26297
26298                         refreshUniformsCommon( uniforms, material );
26299
26300                 } else if ( material.isMeshLambertMaterial ) {
26301
26302                         refreshUniformsCommon( uniforms, material );
26303                         refreshUniformsLambert( uniforms, material );
26304
26305                 } else if ( material.isMeshToonMaterial ) {
26306
26307                         refreshUniformsCommon( uniforms, material );
26308                         refreshUniformsToon( uniforms, material );
26309
26310                 } else if ( material.isMeshPhongMaterial ) {
26311
26312                         refreshUniformsCommon( uniforms, material );
26313                         refreshUniformsPhong( uniforms, material );
26314
26315                 } else if ( material.isMeshStandardMaterial ) {
26316
26317                         refreshUniformsCommon( uniforms, material );
26318
26319                         if ( material.isMeshPhysicalMaterial ) {
26320
26321                                 refreshUniformsPhysical( uniforms, material );
26322
26323                         } else {
26324
26325                                 refreshUniformsStandard( uniforms, material );
26326
26327                         }
26328
26329                 } else if ( material.isMeshMatcapMaterial ) {
26330
26331                         refreshUniformsCommon( uniforms, material );
26332                         refreshUniformsMatcap( uniforms, material );
26333
26334                 } else if ( material.isMeshDepthMaterial ) {
26335
26336                         refreshUniformsCommon( uniforms, material );
26337                         refreshUniformsDepth( uniforms, material );
26338
26339                 } else if ( material.isMeshDistanceMaterial ) {
26340
26341                         refreshUniformsCommon( uniforms, material );
26342                         refreshUniformsDistance( uniforms, material );
26343
26344                 } else if ( material.isMeshNormalMaterial ) {
26345
26346                         refreshUniformsCommon( uniforms, material );
26347                         refreshUniformsNormal( uniforms, material );
26348
26349                 } else if ( material.isLineBasicMaterial ) {
26350
26351                         refreshUniformsLine( uniforms, material );
26352
26353                         if ( material.isLineDashedMaterial ) {
26354
26355                                 refreshUniformsDash( uniforms, material );
26356
26357                         }
26358
26359                 } else if ( material.isPointsMaterial ) {
26360
26361                         refreshUniformsPoints( uniforms, material, pixelRatio, height );
26362
26363                 } else if ( material.isSpriteMaterial ) {
26364
26365                         refreshUniformsSprites( uniforms, material );
26366
26367                 } else if ( material.isShadowMaterial ) {
26368
26369                         uniforms.color.value.copy( material.color );
26370                         uniforms.opacity.value = material.opacity;
26371
26372                 } else if ( material.isShaderMaterial ) {
26373
26374                         material.uniformsNeedUpdate = false; // #15581
26375
26376                 }
26377
26378         }
26379
26380         function refreshUniformsCommon( uniforms, material ) {
26381
26382                 uniforms.opacity.value = material.opacity;
26383
26384                 if ( material.color ) {
26385
26386                         uniforms.diffuse.value.copy( material.color );
26387
26388                 }
26389
26390                 if ( material.emissive ) {
26391
26392                         uniforms.emissive.value.copy( material.emissive ).multiplyScalar( material.emissiveIntensity );
26393
26394                 }
26395
26396                 if ( material.map ) {
26397
26398                         uniforms.map.value = material.map;
26399
26400                 }
26401
26402                 if ( material.alphaMap ) {
26403
26404                         uniforms.alphaMap.value = material.alphaMap;
26405
26406                 }
26407
26408                 if ( material.specularMap ) {
26409
26410                         uniforms.specularMap.value = material.specularMap;
26411
26412                 }
26413
26414                 const envMap = properties.get( material ).envMap;
26415
26416                 if ( envMap ) {
26417
26418                         uniforms.envMap.value = envMap;
26419
26420                         uniforms.flipEnvMap.value = ( envMap.isCubeTexture && envMap._needsFlipEnvMap ) ? - 1 : 1;
26421
26422                         uniforms.reflectivity.value = material.reflectivity;
26423                         uniforms.refractionRatio.value = material.refractionRatio;
26424
26425                         const maxMipLevel = properties.get( envMap ).__maxMipLevel;
26426
26427                         if ( maxMipLevel !== undefined ) {
26428
26429                                 uniforms.maxMipLevel.value = maxMipLevel;
26430
26431                         }
26432
26433                 }
26434
26435                 if ( material.lightMap ) {
26436
26437                         uniforms.lightMap.value = material.lightMap;
26438                         uniforms.lightMapIntensity.value = material.lightMapIntensity;
26439
26440                 }
26441
26442                 if ( material.aoMap ) {
26443
26444                         uniforms.aoMap.value = material.aoMap;
26445                         uniforms.aoMapIntensity.value = material.aoMapIntensity;
26446
26447                 }
26448
26449                 // uv repeat and offset setting priorities
26450                 // 1. color map
26451                 // 2. specular map
26452                 // 3. displacementMap map
26453                 // 4. normal map
26454                 // 5. bump map
26455                 // 6. roughnessMap map
26456                 // 7. metalnessMap map
26457                 // 8. alphaMap map
26458                 // 9. emissiveMap map
26459                 // 10. clearcoat map
26460                 // 11. clearcoat normal map
26461                 // 12. clearcoat roughnessMap map
26462
26463                 let uvScaleMap;
26464
26465                 if ( material.map ) {
26466
26467                         uvScaleMap = material.map;
26468
26469                 } else if ( material.specularMap ) {
26470
26471                         uvScaleMap = material.specularMap;
26472
26473                 } else if ( material.displacementMap ) {
26474
26475                         uvScaleMap = material.displacementMap;
26476
26477                 } else if ( material.normalMap ) {
26478
26479                         uvScaleMap = material.normalMap;
26480
26481                 } else if ( material.bumpMap ) {
26482
26483                         uvScaleMap = material.bumpMap;
26484
26485                 } else if ( material.roughnessMap ) {
26486
26487                         uvScaleMap = material.roughnessMap;
26488
26489                 } else if ( material.metalnessMap ) {
26490
26491                         uvScaleMap = material.metalnessMap;
26492
26493                 } else if ( material.alphaMap ) {
26494
26495                         uvScaleMap = material.alphaMap;
26496
26497                 } else if ( material.emissiveMap ) {
26498
26499                         uvScaleMap = material.emissiveMap;
26500
26501                 } else if ( material.clearcoatMap ) {
26502
26503                         uvScaleMap = material.clearcoatMap;
26504
26505                 } else if ( material.clearcoatNormalMap ) {
26506
26507                         uvScaleMap = material.clearcoatNormalMap;
26508
26509                 } else if ( material.clearcoatRoughnessMap ) {
26510
26511                         uvScaleMap = material.clearcoatRoughnessMap;
26512
26513                 }
26514
26515                 if ( uvScaleMap !== undefined ) {
26516
26517                         // backwards compatibility
26518                         if ( uvScaleMap.isWebGLRenderTarget ) {
26519
26520                                 uvScaleMap = uvScaleMap.texture;
26521
26522                         }
26523
26524                         if ( uvScaleMap.matrixAutoUpdate === true ) {
26525
26526                                 uvScaleMap.updateMatrix();
26527
26528                         }
26529
26530                         uniforms.uvTransform.value.copy( uvScaleMap.matrix );
26531
26532                 }
26533
26534                 // uv repeat and offset setting priorities for uv2
26535                 // 1. ao map
26536                 // 2. light map
26537
26538                 let uv2ScaleMap;
26539
26540                 if ( material.aoMap ) {
26541
26542                         uv2ScaleMap = material.aoMap;
26543
26544                 } else if ( material.lightMap ) {
26545
26546                         uv2ScaleMap = material.lightMap;
26547
26548                 }
26549
26550                 if ( uv2ScaleMap !== undefined ) {
26551
26552                         // backwards compatibility
26553                         if ( uv2ScaleMap.isWebGLRenderTarget ) {
26554
26555                                 uv2ScaleMap = uv2ScaleMap.texture;
26556
26557                         }
26558
26559                         if ( uv2ScaleMap.matrixAutoUpdate === true ) {
26560
26561                                 uv2ScaleMap.updateMatrix();
26562
26563                         }
26564
26565                         uniforms.uv2Transform.value.copy( uv2ScaleMap.matrix );
26566
26567                 }
26568
26569         }
26570
26571         function refreshUniformsLine( uniforms, material ) {
26572
26573                 uniforms.diffuse.value.copy( material.color );
26574                 uniforms.opacity.value = material.opacity;
26575
26576         }
26577
26578         function refreshUniformsDash( uniforms, material ) {
26579
26580                 uniforms.dashSize.value = material.dashSize;
26581                 uniforms.totalSize.value = material.dashSize + material.gapSize;
26582                 uniforms.scale.value = material.scale;
26583
26584         }
26585
26586         function refreshUniformsPoints( uniforms, material, pixelRatio, height ) {
26587
26588                 uniforms.diffuse.value.copy( material.color );
26589                 uniforms.opacity.value = material.opacity;
26590                 uniforms.size.value = material.size * pixelRatio;
26591                 uniforms.scale.value = height * 0.5;
26592
26593                 if ( material.map ) {
26594
26595                         uniforms.map.value = material.map;
26596
26597                 }
26598
26599                 if ( material.alphaMap ) {
26600
26601                         uniforms.alphaMap.value = material.alphaMap;
26602
26603                 }
26604
26605                 // uv repeat and offset setting priorities
26606                 // 1. color map
26607                 // 2. alpha map
26608
26609                 let uvScaleMap;
26610
26611                 if ( material.map ) {
26612
26613                         uvScaleMap = material.map;
26614
26615                 } else if ( material.alphaMap ) {
26616
26617                         uvScaleMap = material.alphaMap;
26618
26619                 }
26620
26621                 if ( uvScaleMap !== undefined ) {
26622
26623                         if ( uvScaleMap.matrixAutoUpdate === true ) {
26624
26625                                 uvScaleMap.updateMatrix();
26626
26627                         }
26628
26629                         uniforms.uvTransform.value.copy( uvScaleMap.matrix );
26630
26631                 }
26632
26633         }
26634
26635         function refreshUniformsSprites( uniforms, material ) {
26636
26637                 uniforms.diffuse.value.copy( material.color );
26638                 uniforms.opacity.value = material.opacity;
26639                 uniforms.rotation.value = material.rotation;
26640
26641                 if ( material.map ) {
26642
26643                         uniforms.map.value = material.map;
26644
26645                 }
26646
26647                 if ( material.alphaMap ) {
26648
26649                         uniforms.alphaMap.value = material.alphaMap;
26650
26651                 }
26652
26653                 // uv repeat and offset setting priorities
26654                 // 1. color map
26655                 // 2. alpha map
26656
26657                 let uvScaleMap;
26658
26659                 if ( material.map ) {
26660
26661                         uvScaleMap = material.map;
26662
26663                 } else if ( material.alphaMap ) {
26664
26665                         uvScaleMap = material.alphaMap;
26666
26667                 }
26668
26669                 if ( uvScaleMap !== undefined ) {
26670
26671                         if ( uvScaleMap.matrixAutoUpdate === true ) {
26672
26673                                 uvScaleMap.updateMatrix();
26674
26675                         }
26676
26677                         uniforms.uvTransform.value.copy( uvScaleMap.matrix );
26678
26679                 }
26680
26681         }
26682
26683         function refreshUniformsLambert( uniforms, material ) {
26684
26685                 if ( material.emissiveMap ) {
26686
26687                         uniforms.emissiveMap.value = material.emissiveMap;
26688
26689                 }
26690
26691         }
26692
26693         function refreshUniformsPhong( uniforms, material ) {
26694
26695                 uniforms.specular.value.copy( material.specular );
26696                 uniforms.shininess.value = Math.max( material.shininess, 1e-4 ); // to prevent pow( 0.0, 0.0 )
26697
26698                 if ( material.emissiveMap ) {
26699
26700                         uniforms.emissiveMap.value = material.emissiveMap;
26701
26702                 }
26703
26704                 if ( material.bumpMap ) {
26705
26706                         uniforms.bumpMap.value = material.bumpMap;
26707                         uniforms.bumpScale.value = material.bumpScale;
26708                         if ( material.side === BackSide ) uniforms.bumpScale.value *= - 1;
26709
26710                 }
26711
26712                 if ( material.normalMap ) {
26713
26714                         uniforms.normalMap.value = material.normalMap;
26715                         uniforms.normalScale.value.copy( material.normalScale );
26716                         if ( material.side === BackSide ) uniforms.normalScale.value.negate();
26717
26718                 }
26719
26720                 if ( material.displacementMap ) {
26721
26722                         uniforms.displacementMap.value = material.displacementMap;
26723                         uniforms.displacementScale.value = material.displacementScale;
26724                         uniforms.displacementBias.value = material.displacementBias;
26725
26726                 }
26727
26728         }
26729
26730         function refreshUniformsToon( uniforms, material ) {
26731
26732                 if ( material.gradientMap ) {
26733
26734                         uniforms.gradientMap.value = material.gradientMap;
26735
26736                 }
26737
26738                 if ( material.emissiveMap ) {
26739
26740                         uniforms.emissiveMap.value = material.emissiveMap;
26741
26742                 }
26743
26744                 if ( material.bumpMap ) {
26745
26746                         uniforms.bumpMap.value = material.bumpMap;
26747                         uniforms.bumpScale.value = material.bumpScale;
26748                         if ( material.side === BackSide ) uniforms.bumpScale.value *= - 1;
26749
26750                 }
26751
26752                 if ( material.normalMap ) {
26753
26754                         uniforms.normalMap.value = material.normalMap;
26755                         uniforms.normalScale.value.copy( material.normalScale );
26756                         if ( material.side === BackSide ) uniforms.normalScale.value.negate();
26757
26758                 }
26759
26760                 if ( material.displacementMap ) {
26761
26762                         uniforms.displacementMap.value = material.displacementMap;
26763                         uniforms.displacementScale.value = material.displacementScale;
26764                         uniforms.displacementBias.value = material.displacementBias;
26765
26766                 }
26767
26768         }
26769
26770         function refreshUniformsStandard( uniforms, material ) {
26771
26772                 uniforms.roughness.value = material.roughness;
26773                 uniforms.metalness.value = material.metalness;
26774
26775                 if ( material.roughnessMap ) {
26776
26777                         uniforms.roughnessMap.value = material.roughnessMap;
26778
26779                 }
26780
26781                 if ( material.metalnessMap ) {
26782
26783                         uniforms.metalnessMap.value = material.metalnessMap;
26784
26785                 }
26786
26787                 if ( material.emissiveMap ) {
26788
26789                         uniforms.emissiveMap.value = material.emissiveMap;
26790
26791                 }
26792
26793                 if ( material.bumpMap ) {
26794
26795                         uniforms.bumpMap.value = material.bumpMap;
26796                         uniforms.bumpScale.value = material.bumpScale;
26797                         if ( material.side === BackSide ) uniforms.bumpScale.value *= - 1;
26798
26799                 }
26800
26801                 if ( material.normalMap ) {
26802
26803                         uniforms.normalMap.value = material.normalMap;
26804                         uniforms.normalScale.value.copy( material.normalScale );
26805                         if ( material.side === BackSide ) uniforms.normalScale.value.negate();
26806
26807                 }
26808
26809                 if ( material.displacementMap ) {
26810
26811                         uniforms.displacementMap.value = material.displacementMap;
26812                         uniforms.displacementScale.value = material.displacementScale;
26813                         uniforms.displacementBias.value = material.displacementBias;
26814
26815                 }
26816
26817                 const envMap = properties.get( material ).envMap;
26818
26819                 if ( envMap ) {
26820
26821                         //uniforms.envMap.value = material.envMap; // part of uniforms common
26822                         uniforms.envMapIntensity.value = material.envMapIntensity;
26823
26824                 }
26825
26826         }
26827
26828         function refreshUniformsPhysical( uniforms, material ) {
26829
26830                 refreshUniformsStandard( uniforms, material );
26831
26832                 uniforms.reflectivity.value = material.reflectivity; // also part of uniforms common
26833
26834                 uniforms.clearcoat.value = material.clearcoat;
26835                 uniforms.clearcoatRoughness.value = material.clearcoatRoughness;
26836                 if ( material.sheen ) uniforms.sheen.value.copy( material.sheen );
26837
26838                 if ( material.clearcoatMap ) {
26839
26840                         uniforms.clearcoatMap.value = material.clearcoatMap;
26841
26842                 }
26843
26844                 if ( material.clearcoatRoughnessMap ) {
26845
26846                         uniforms.clearcoatRoughnessMap.value = material.clearcoatRoughnessMap;
26847
26848                 }
26849
26850                 if ( material.clearcoatNormalMap ) {
26851
26852                         uniforms.clearcoatNormalScale.value.copy( material.clearcoatNormalScale );
26853                         uniforms.clearcoatNormalMap.value = material.clearcoatNormalMap;
26854
26855                         if ( material.side === BackSide ) {
26856
26857                                 uniforms.clearcoatNormalScale.value.negate();
26858
26859                         }
26860
26861                 }
26862
26863                 uniforms.transmission.value = material.transmission;
26864
26865                 if ( material.transmissionMap ) {
26866
26867                         uniforms.transmissionMap.value = material.transmissionMap;
26868
26869                 }
26870
26871         }
26872
26873         function refreshUniformsMatcap( uniforms, material ) {
26874
26875                 if ( material.matcap ) {
26876
26877                         uniforms.matcap.value = material.matcap;
26878
26879                 }
26880
26881                 if ( material.bumpMap ) {
26882
26883                         uniforms.bumpMap.value = material.bumpMap;
26884                         uniforms.bumpScale.value = material.bumpScale;
26885                         if ( material.side === BackSide ) uniforms.bumpScale.value *= - 1;
26886
26887                 }
26888
26889                 if ( material.normalMap ) {
26890
26891                         uniforms.normalMap.value = material.normalMap;
26892                         uniforms.normalScale.value.copy( material.normalScale );
26893                         if ( material.side === BackSide ) uniforms.normalScale.value.negate();
26894
26895                 }
26896
26897                 if ( material.displacementMap ) {
26898
26899                         uniforms.displacementMap.value = material.displacementMap;
26900                         uniforms.displacementScale.value = material.displacementScale;
26901                         uniforms.displacementBias.value = material.displacementBias;
26902
26903                 }
26904
26905         }
26906
26907         function refreshUniformsDepth( uniforms, material ) {
26908
26909                 if ( material.displacementMap ) {
26910
26911                         uniforms.displacementMap.value = material.displacementMap;
26912                         uniforms.displacementScale.value = material.displacementScale;
26913                         uniforms.displacementBias.value = material.displacementBias;
26914
26915                 }
26916
26917         }
26918
26919         function refreshUniformsDistance( uniforms, material ) {
26920
26921                 if ( material.displacementMap ) {
26922
26923                         uniforms.displacementMap.value = material.displacementMap;
26924                         uniforms.displacementScale.value = material.displacementScale;
26925                         uniforms.displacementBias.value = material.displacementBias;
26926
26927                 }
26928
26929                 uniforms.referencePosition.value.copy( material.referencePosition );
26930                 uniforms.nearDistance.value = material.nearDistance;
26931                 uniforms.farDistance.value = material.farDistance;
26932
26933         }
26934
26935         function refreshUniformsNormal( uniforms, material ) {
26936
26937                 if ( material.bumpMap ) {
26938
26939                         uniforms.bumpMap.value = material.bumpMap;
26940                         uniforms.bumpScale.value = material.bumpScale;
26941                         if ( material.side === BackSide ) uniforms.bumpScale.value *= - 1;
26942
26943                 }
26944
26945                 if ( material.normalMap ) {
26946
26947                         uniforms.normalMap.value = material.normalMap;
26948                         uniforms.normalScale.value.copy( material.normalScale );
26949                         if ( material.side === BackSide ) uniforms.normalScale.value.negate();
26950
26951                 }
26952
26953                 if ( material.displacementMap ) {
26954
26955                         uniforms.displacementMap.value = material.displacementMap;
26956                         uniforms.displacementScale.value = material.displacementScale;
26957                         uniforms.displacementBias.value = material.displacementBias;
26958
26959                 }
26960
26961         }
26962
26963         return {
26964                 refreshFogUniforms: refreshFogUniforms,
26965                 refreshMaterialUniforms: refreshMaterialUniforms
26966         };
26967
26968 }
26969
26970 function createCanvasElement() {
26971
26972         const canvas = document.createElementNS( 'http://www.w3.org/1999/xhtml', 'canvas' );
26973         canvas.style.display = 'block';
26974         return canvas;
26975
26976 }
26977
26978 function WebGLRenderer( parameters ) {
26979
26980         parameters = parameters || {};
26981
26982         const _canvas = parameters.canvas !== undefined ? parameters.canvas : createCanvasElement(),
26983                 _context = parameters.context !== undefined ? parameters.context : null,
26984
26985                 _alpha = parameters.alpha !== undefined ? parameters.alpha : false,
26986                 _depth = parameters.depth !== undefined ? parameters.depth : true,
26987                 _stencil = parameters.stencil !== undefined ? parameters.stencil : true,
26988                 _antialias = parameters.antialias !== undefined ? parameters.antialias : false,
26989                 _premultipliedAlpha = parameters.premultipliedAlpha !== undefined ? parameters.premultipliedAlpha : true,
26990                 _preserveDrawingBuffer = parameters.preserveDrawingBuffer !== undefined ? parameters.preserveDrawingBuffer : false,
26991                 _powerPreference = parameters.powerPreference !== undefined ? parameters.powerPreference : 'default',
26992                 _failIfMajorPerformanceCaveat = parameters.failIfMajorPerformanceCaveat !== undefined ? parameters.failIfMajorPerformanceCaveat : false;
26993
26994         let currentRenderList = null;
26995         let currentRenderState = null;
26996
26997         // render() can be called from within a callback triggered by another render.
26998         // We track this so that the nested render call gets its state isolated from the parent render call.
26999
27000         const renderStateStack = [];
27001
27002         // public properties
27003
27004         this.domElement = _canvas;
27005
27006         // Debug configuration container
27007         this.debug = {
27008
27009                 /**
27010                  * Enables error checking and reporting when shader programs are being compiled
27011                  * @type {boolean}
27012                  */
27013                 checkShaderErrors: true
27014         };
27015
27016         // clearing
27017
27018         this.autoClear = true;
27019         this.autoClearColor = true;
27020         this.autoClearDepth = true;
27021         this.autoClearStencil = true;
27022
27023         // scene graph
27024
27025         this.sortObjects = true;
27026
27027         // user-defined clipping
27028
27029         this.clippingPlanes = [];
27030         this.localClippingEnabled = false;
27031
27032         // physically based shading
27033
27034         this.gammaFactor = 2.0; // for backwards compatibility
27035         this.outputEncoding = LinearEncoding;
27036
27037         // physical lights
27038
27039         this.physicallyCorrectLights = false;
27040
27041         // tone mapping
27042
27043         this.toneMapping = NoToneMapping;
27044         this.toneMappingExposure = 1.0;
27045
27046         // morphs
27047
27048         this.maxMorphTargets = 8;
27049         this.maxMorphNormals = 4;
27050
27051         // internal properties
27052
27053         const _this = this;
27054
27055         let _isContextLost = false;
27056
27057         // internal state cache
27058
27059         let _framebuffer = null;
27060
27061         let _currentActiveCubeFace = 0;
27062         let _currentActiveMipmapLevel = 0;
27063         let _currentRenderTarget = null;
27064         let _currentFramebuffer = null;
27065         let _currentMaterialId = - 1;
27066
27067         let _currentCamera = null;
27068
27069         const _currentViewport = new Vector4();
27070         const _currentScissor = new Vector4();
27071         let _currentScissorTest = null;
27072
27073         //
27074
27075         let _width = _canvas.width;
27076         let _height = _canvas.height;
27077
27078         let _pixelRatio = 1;
27079         let _opaqueSort = null;
27080         let _transparentSort = null;
27081
27082         const _viewport = new Vector4( 0, 0, _width, _height );
27083         const _scissor = new Vector4( 0, 0, _width, _height );
27084         let _scissorTest = false;
27085
27086         // frustum
27087
27088         const _frustum = new Frustum();
27089
27090         // clipping
27091
27092         let _clippingEnabled = false;
27093         let _localClippingEnabled = false;
27094
27095         // camera matrices cache
27096
27097         const _projScreenMatrix = new Matrix4();
27098
27099         const _vector3 = new Vector3();
27100
27101         const _emptyScene = { background: null, fog: null, environment: null, overrideMaterial: null, isScene: true };
27102
27103         function getTargetPixelRatio() {
27104
27105                 return _currentRenderTarget === null ? _pixelRatio : 1;
27106
27107         }
27108
27109         // initialize
27110
27111         let _gl = _context;
27112
27113         function getContext( contextNames, contextAttributes ) {
27114
27115                 for ( let i = 0; i < contextNames.length; i ++ ) {
27116
27117                         const contextName = contextNames[ i ];
27118                         const context = _canvas.getContext( contextName, contextAttributes );
27119                         if ( context !== null ) return context;
27120
27121                 }
27122
27123                 return null;
27124
27125         }
27126
27127         try {
27128
27129                 const contextAttributes = {
27130                         alpha: _alpha,
27131                         depth: _depth,
27132                         stencil: _stencil,
27133                         antialias: _antialias,
27134                         premultipliedAlpha: _premultipliedAlpha,
27135                         preserveDrawingBuffer: _preserveDrawingBuffer,
27136                         powerPreference: _powerPreference,
27137                         failIfMajorPerformanceCaveat: _failIfMajorPerformanceCaveat
27138                 };
27139
27140                 // event listeners must be registered before WebGL context is created, see #12753
27141
27142                 _canvas.addEventListener( 'webglcontextlost', onContextLost, false );
27143                 _canvas.addEventListener( 'webglcontextrestored', onContextRestore, false );
27144
27145                 if ( _gl === null ) {
27146
27147                         const contextNames = [ 'webgl2', 'webgl', 'experimental-webgl' ];
27148
27149                         if ( _this.isWebGL1Renderer === true ) {
27150
27151                                 contextNames.shift();
27152
27153                         }
27154
27155                         _gl = getContext( contextNames, contextAttributes );
27156
27157                         if ( _gl === null ) {
27158
27159                                 if ( getContext( contextNames ) ) {
27160
27161                                         throw new Error( 'Error creating WebGL context with your selected attributes.' );
27162
27163                                 } else {
27164
27165                                         throw new Error( 'Error creating WebGL context.' );
27166
27167                                 }
27168
27169                         }
27170
27171                 }
27172
27173                 // Some experimental-webgl implementations do not have getShaderPrecisionFormat
27174
27175                 if ( _gl.getShaderPrecisionFormat === undefined ) {
27176
27177                         _gl.getShaderPrecisionFormat = function () {
27178
27179                                 return { 'rangeMin': 1, 'rangeMax': 1, 'precision': 1 };
27180
27181                         };
27182
27183                 }
27184
27185         } catch ( error ) {
27186
27187                 console.error( 'THREE.WebGLRenderer: ' + error.message );
27188                 throw error;
27189
27190         }
27191
27192         let extensions, capabilities, state, info;
27193         let properties, textures, cubemaps, attributes, geometries, objects;
27194         let programCache, materials, renderLists, renderStates, clipping;
27195
27196         let background, morphtargets, bufferRenderer, indexedBufferRenderer;
27197
27198         let utils, bindingStates;
27199
27200         function initGLContext() {
27201
27202                 extensions = new WebGLExtensions( _gl );
27203
27204                 capabilities = new WebGLCapabilities( _gl, extensions, parameters );
27205
27206                 extensions.init( capabilities );
27207
27208                 utils = new WebGLUtils( _gl, extensions, capabilities );
27209
27210                 state = new WebGLState( _gl, extensions, capabilities );
27211                 state.scissor( _currentScissor.copy( _scissor ).multiplyScalar( _pixelRatio ).floor() );
27212                 state.viewport( _currentViewport.copy( _viewport ).multiplyScalar( _pixelRatio ).floor() );
27213
27214                 info = new WebGLInfo( _gl );
27215                 properties = new WebGLProperties();
27216                 textures = new WebGLTextures( _gl, extensions, state, properties, capabilities, utils, info );
27217                 cubemaps = new WebGLCubeMaps( _this );
27218                 attributes = new WebGLAttributes( _gl, capabilities );
27219                 bindingStates = new WebGLBindingStates( _gl, extensions, attributes, capabilities );
27220                 geometries = new WebGLGeometries( _gl, attributes, info, bindingStates );
27221                 objects = new WebGLObjects( _gl, geometries, attributes, info );
27222                 morphtargets = new WebGLMorphtargets( _gl );
27223                 clipping = new WebGLClipping( properties );
27224                 programCache = new WebGLPrograms( _this, cubemaps, extensions, capabilities, bindingStates, clipping );
27225                 materials = new WebGLMaterials( properties );
27226                 renderLists = new WebGLRenderLists( properties );
27227                 renderStates = new WebGLRenderStates( extensions, capabilities );
27228                 background = new WebGLBackground( _this, cubemaps, state, objects, _premultipliedAlpha );
27229
27230                 bufferRenderer = new WebGLBufferRenderer( _gl, extensions, info, capabilities );
27231                 indexedBufferRenderer = new WebGLIndexedBufferRenderer( _gl, extensions, info, capabilities );
27232
27233                 info.programs = programCache.programs;
27234
27235                 _this.capabilities = capabilities;
27236                 _this.extensions = extensions;
27237                 _this.properties = properties;
27238                 _this.renderLists = renderLists;
27239                 _this.state = state;
27240                 _this.info = info;
27241
27242         }
27243
27244         initGLContext();
27245
27246         // xr
27247
27248         const xr = new WebXRManager( _this, _gl );
27249
27250         this.xr = xr;
27251
27252         // shadow map
27253
27254         const shadowMap = new WebGLShadowMap( _this, objects, capabilities.maxTextureSize );
27255
27256         this.shadowMap = shadowMap;
27257
27258         // API
27259
27260         this.getContext = function () {
27261
27262                 return _gl;
27263
27264         };
27265
27266         this.getContextAttributes = function () {
27267
27268                 return _gl.getContextAttributes();
27269
27270         };
27271
27272         this.forceContextLoss = function () {
27273
27274                 const extension = extensions.get( 'WEBGL_lose_context' );
27275                 if ( extension ) extension.loseContext();
27276
27277         };
27278
27279         this.forceContextRestore = function () {
27280
27281                 const extension = extensions.get( 'WEBGL_lose_context' );
27282                 if ( extension ) extension.restoreContext();
27283
27284         };
27285
27286         this.getPixelRatio = function () {
27287
27288                 return _pixelRatio;
27289
27290         };
27291
27292         this.setPixelRatio = function ( value ) {
27293
27294                 if ( value === undefined ) return;
27295
27296                 _pixelRatio = value;
27297
27298                 this.setSize( _width, _height, false );
27299
27300         };
27301
27302         this.getSize = function ( target ) {
27303
27304                 if ( target === undefined ) {
27305
27306                         console.warn( 'WebGLRenderer: .getsize() now requires a Vector2 as an argument' );
27307
27308                         target = new Vector2();
27309
27310                 }
27311
27312                 return target.set( _width, _height );
27313
27314         };
27315
27316         this.setSize = function ( width, height, updateStyle ) {
27317
27318                 if ( xr.isPresenting ) {
27319
27320                         console.warn( 'THREE.WebGLRenderer: Can\'t change size while VR device is presenting.' );
27321                         return;
27322
27323                 }
27324
27325                 _width = width;
27326                 _height = height;
27327
27328                 _canvas.width = Math.floor( width * _pixelRatio );
27329                 _canvas.height = Math.floor( height * _pixelRatio );
27330
27331                 if ( updateStyle !== false ) {
27332
27333                         _canvas.style.width = width + 'px';
27334                         _canvas.style.height = height + 'px';
27335
27336                 }
27337
27338                 this.setViewport( 0, 0, width, height );
27339
27340         };
27341
27342         this.getDrawingBufferSize = function ( target ) {
27343
27344                 if ( target === undefined ) {
27345
27346                         console.warn( 'WebGLRenderer: .getdrawingBufferSize() now requires a Vector2 as an argument' );
27347
27348                         target = new Vector2();
27349
27350                 }
27351
27352                 return target.set( _width * _pixelRatio, _height * _pixelRatio ).floor();
27353
27354         };
27355
27356         this.setDrawingBufferSize = function ( width, height, pixelRatio ) {
27357
27358                 _width = width;
27359                 _height = height;
27360
27361                 _pixelRatio = pixelRatio;
27362
27363                 _canvas.width = Math.floor( width * pixelRatio );
27364                 _canvas.height = Math.floor( height * pixelRatio );
27365
27366                 this.setViewport( 0, 0, width, height );
27367
27368         };
27369
27370         this.getCurrentViewport = function ( target ) {
27371
27372                 if ( target === undefined ) {
27373
27374                         console.warn( 'WebGLRenderer: .getCurrentViewport() now requires a Vector4 as an argument' );
27375
27376                         target = new Vector4();
27377
27378                 }
27379
27380                 return target.copy( _currentViewport );
27381
27382         };
27383
27384         this.getViewport = function ( target ) {
27385
27386                 return target.copy( _viewport );
27387
27388         };
27389
27390         this.setViewport = function ( x, y, width, height ) {
27391
27392                 if ( x.isVector4 ) {
27393
27394                         _viewport.set( x.x, x.y, x.z, x.w );
27395
27396                 } else {
27397
27398                         _viewport.set( x, y, width, height );
27399
27400                 }
27401
27402                 state.viewport( _currentViewport.copy( _viewport ).multiplyScalar( _pixelRatio ).floor() );
27403
27404         };
27405
27406         this.getScissor = function ( target ) {
27407
27408                 return target.copy( _scissor );
27409
27410         };
27411
27412         this.setScissor = function ( x, y, width, height ) {
27413
27414                 if ( x.isVector4 ) {
27415
27416                         _scissor.set( x.x, x.y, x.z, x.w );
27417
27418                 } else {
27419
27420                         _scissor.set( x, y, width, height );
27421
27422                 }
27423
27424                 state.scissor( _currentScissor.copy( _scissor ).multiplyScalar( _pixelRatio ).floor() );
27425
27426         };
27427
27428         this.getScissorTest = function () {
27429
27430                 return _scissorTest;
27431
27432         };
27433
27434         this.setScissorTest = function ( boolean ) {
27435
27436                 state.setScissorTest( _scissorTest = boolean );
27437
27438         };
27439
27440         this.setOpaqueSort = function ( method ) {
27441
27442                 _opaqueSort = method;
27443
27444         };
27445
27446         this.setTransparentSort = function ( method ) {
27447
27448                 _transparentSort = method;
27449
27450         };
27451
27452         // Clearing
27453
27454         this.getClearColor = function ( target ) {
27455
27456                 if ( target === undefined ) {
27457
27458                         console.warn( 'WebGLRenderer: .getClearColor() now requires a Color as an argument' );
27459
27460                         target = new Color();
27461
27462                 }
27463
27464                 return target.copy( background.getClearColor() );
27465
27466         };
27467
27468         this.setClearColor = function () {
27469
27470                 background.setClearColor.apply( background, arguments );
27471
27472         };
27473
27474         this.getClearAlpha = function () {
27475
27476                 return background.getClearAlpha();
27477
27478         };
27479
27480         this.setClearAlpha = function () {
27481
27482                 background.setClearAlpha.apply( background, arguments );
27483
27484         };
27485
27486         this.clear = function ( color, depth, stencil ) {
27487
27488                 let bits = 0;
27489
27490                 if ( color === undefined || color ) bits |= 16384;
27491                 if ( depth === undefined || depth ) bits |= 256;
27492                 if ( stencil === undefined || stencil ) bits |= 1024;
27493
27494                 _gl.clear( bits );
27495
27496         };
27497
27498         this.clearColor = function () {
27499
27500                 this.clear( true, false, false );
27501
27502         };
27503
27504         this.clearDepth = function () {
27505
27506                 this.clear( false, true, false );
27507
27508         };
27509
27510         this.clearStencil = function () {
27511
27512                 this.clear( false, false, true );
27513
27514         };
27515
27516         //
27517
27518         this.dispose = function () {
27519
27520                 _canvas.removeEventListener( 'webglcontextlost', onContextLost, false );
27521                 _canvas.removeEventListener( 'webglcontextrestored', onContextRestore, false );
27522
27523                 renderLists.dispose();
27524                 renderStates.dispose();
27525                 properties.dispose();
27526                 cubemaps.dispose();
27527                 objects.dispose();
27528                 bindingStates.dispose();
27529
27530                 xr.dispose();
27531
27532                 animation.stop();
27533
27534         };
27535
27536         // Events
27537
27538         function onContextLost( event ) {
27539
27540                 event.preventDefault();
27541
27542                 console.log( 'THREE.WebGLRenderer: Context Lost.' );
27543
27544                 _isContextLost = true;
27545
27546         }
27547
27548         function onContextRestore( /* event */ ) {
27549
27550                 console.log( 'THREE.WebGLRenderer: Context Restored.' );
27551
27552                 _isContextLost = false;
27553
27554                 initGLContext();
27555
27556         }
27557
27558         function onMaterialDispose( event ) {
27559
27560                 const material = event.target;
27561
27562                 material.removeEventListener( 'dispose', onMaterialDispose );
27563
27564                 deallocateMaterial( material );
27565
27566         }
27567
27568         // Buffer deallocation
27569
27570         function deallocateMaterial( material ) {
27571
27572                 releaseMaterialProgramReference( material );
27573
27574                 properties.remove( material );
27575
27576         }
27577
27578
27579         function releaseMaterialProgramReference( material ) {
27580
27581                 const programInfo = properties.get( material ).program;
27582
27583                 if ( programInfo !== undefined ) {
27584
27585                         programCache.releaseProgram( programInfo );
27586
27587                 }
27588
27589         }
27590
27591         // Buffer rendering
27592
27593         function renderObjectImmediate( object, program ) {
27594
27595                 object.render( function ( object ) {
27596
27597                         _this.renderBufferImmediate( object, program );
27598
27599                 } );
27600
27601         }
27602
27603         this.renderBufferImmediate = function ( object, program ) {
27604
27605                 bindingStates.initAttributes();
27606
27607                 const buffers = properties.get( object );
27608
27609                 if ( object.hasPositions && ! buffers.position ) buffers.position = _gl.createBuffer();
27610                 if ( object.hasNormals && ! buffers.normal ) buffers.normal = _gl.createBuffer();
27611                 if ( object.hasUvs && ! buffers.uv ) buffers.uv = _gl.createBuffer();
27612                 if ( object.hasColors && ! buffers.color ) buffers.color = _gl.createBuffer();
27613
27614                 const programAttributes = program.getAttributes();
27615
27616                 if ( object.hasPositions ) {
27617
27618                         _gl.bindBuffer( 34962, buffers.position );
27619                         _gl.bufferData( 34962, object.positionArray, 35048 );
27620
27621                         bindingStates.enableAttribute( programAttributes.position );
27622                         _gl.vertexAttribPointer( programAttributes.position, 3, 5126, false, 0, 0 );
27623
27624                 }
27625
27626                 if ( object.hasNormals ) {
27627
27628                         _gl.bindBuffer( 34962, buffers.normal );
27629                         _gl.bufferData( 34962, object.normalArray, 35048 );
27630
27631                         bindingStates.enableAttribute( programAttributes.normal );
27632                         _gl.vertexAttribPointer( programAttributes.normal, 3, 5126, false, 0, 0 );
27633
27634                 }
27635
27636                 if ( object.hasUvs ) {
27637
27638                         _gl.bindBuffer( 34962, buffers.uv );
27639                         _gl.bufferData( 34962, object.uvArray, 35048 );
27640
27641                         bindingStates.enableAttribute( programAttributes.uv );
27642                         _gl.vertexAttribPointer( programAttributes.uv, 2, 5126, false, 0, 0 );
27643
27644                 }
27645
27646                 if ( object.hasColors ) {
27647
27648                         _gl.bindBuffer( 34962, buffers.color );
27649                         _gl.bufferData( 34962, object.colorArray, 35048 );
27650
27651                         bindingStates.enableAttribute( programAttributes.color );
27652                         _gl.vertexAttribPointer( programAttributes.color, 3, 5126, false, 0, 0 );
27653
27654                 }
27655
27656                 bindingStates.disableUnusedAttributes();
27657
27658                 _gl.drawArrays( 4, 0, object.count );
27659
27660                 object.count = 0;
27661
27662         };
27663
27664         this.renderBufferDirect = function ( camera, scene, geometry, material, object, group ) {
27665
27666                 if ( scene === null ) scene = _emptyScene; // renderBufferDirect second parameter used to be fog (could be null)
27667
27668                 const frontFaceCW = ( object.isMesh && object.matrixWorld.determinant() < 0 );
27669
27670                 const program = setProgram( camera, scene, material, object );
27671
27672                 state.setMaterial( material, frontFaceCW );
27673
27674                 //
27675
27676                 let index = geometry.index;
27677                 const position = geometry.attributes.position;
27678
27679                 //
27680
27681                 if ( index === null ) {
27682
27683                         if ( position === undefined || position.count === 0 ) return;
27684
27685                 } else if ( index.count === 0 ) {
27686
27687                         return;
27688
27689                 }
27690
27691                 //
27692
27693                 let rangeFactor = 1;
27694
27695                 if ( material.wireframe === true ) {
27696
27697                         index = geometries.getWireframeAttribute( geometry );
27698                         rangeFactor = 2;
27699
27700                 }
27701
27702                 if ( material.morphTargets || material.morphNormals ) {
27703
27704                         morphtargets.update( object, geometry, material, program );
27705
27706                 }
27707
27708                 bindingStates.setup( object, material, program, geometry, index );
27709
27710                 let attribute;
27711                 let renderer = bufferRenderer;
27712
27713                 if ( index !== null ) {
27714
27715                         attribute = attributes.get( index );
27716
27717                         renderer = indexedBufferRenderer;
27718                         renderer.setIndex( attribute );
27719
27720                 }
27721
27722                 //
27723
27724                 const dataCount = ( index !== null ) ? index.count : position.count;
27725
27726                 const rangeStart = geometry.drawRange.start * rangeFactor;
27727                 const rangeCount = geometry.drawRange.count * rangeFactor;
27728
27729                 const groupStart = group !== null ? group.start * rangeFactor : 0;
27730                 const groupCount = group !== null ? group.count * rangeFactor : Infinity;
27731
27732                 const drawStart = Math.max( rangeStart, groupStart );
27733                 const drawEnd = Math.min( dataCount, rangeStart + rangeCount, groupStart + groupCount ) - 1;
27734
27735                 const drawCount = Math.max( 0, drawEnd - drawStart + 1 );
27736
27737                 if ( drawCount === 0 ) return;
27738
27739                 //
27740
27741                 if ( object.isMesh ) {
27742
27743                         if ( material.wireframe === true ) {
27744
27745                                 state.setLineWidth( material.wireframeLinewidth * getTargetPixelRatio() );
27746                                 renderer.setMode( 1 );
27747
27748                         } else {
27749
27750                                 renderer.setMode( 4 );
27751
27752                         }
27753
27754                 } else if ( object.isLine ) {
27755
27756                         let lineWidth = material.linewidth;
27757
27758                         if ( lineWidth === undefined ) lineWidth = 1; // Not using Line*Material
27759
27760                         state.setLineWidth( lineWidth * getTargetPixelRatio() );
27761
27762                         if ( object.isLineSegments ) {
27763
27764                                 renderer.setMode( 1 );
27765
27766                         } else if ( object.isLineLoop ) {
27767
27768                                 renderer.setMode( 2 );
27769
27770                         } else {
27771
27772                                 renderer.setMode( 3 );
27773
27774                         }
27775
27776                 } else if ( object.isPoints ) {
27777
27778                         renderer.setMode( 0 );
27779
27780                 } else if ( object.isSprite ) {
27781
27782                         renderer.setMode( 4 );
27783
27784                 }
27785
27786                 if ( object.isInstancedMesh ) {
27787
27788                         renderer.renderInstances( drawStart, drawCount, object.count );
27789
27790                 } else if ( geometry.isInstancedBufferGeometry ) {
27791
27792                         const instanceCount = Math.min( geometry.instanceCount, geometry._maxInstanceCount );
27793
27794                         renderer.renderInstances( drawStart, drawCount, instanceCount );
27795
27796                 } else {
27797
27798                         renderer.render( drawStart, drawCount );
27799
27800                 }
27801
27802         };
27803
27804         // Compile
27805
27806         this.compile = function ( scene, camera ) {
27807
27808                 currentRenderState = renderStates.get( scene );
27809                 currentRenderState.init();
27810
27811                 scene.traverseVisible( function ( object ) {
27812
27813                         if ( object.isLight && object.layers.test( camera.layers ) ) {
27814
27815                                 currentRenderState.pushLight( object );
27816
27817                                 if ( object.castShadow ) {
27818
27819                                         currentRenderState.pushShadow( object );
27820
27821                                 }
27822
27823                         }
27824
27825                 } );
27826
27827                 currentRenderState.setupLights();
27828
27829                 const compiled = new WeakMap();
27830
27831                 scene.traverse( function ( object ) {
27832
27833                         const material = object.material;
27834
27835                         if ( material ) {
27836
27837                                 if ( Array.isArray( material ) ) {
27838
27839                                         for ( let i = 0; i < material.length; i ++ ) {
27840
27841                                                 const material2 = material[ i ];
27842
27843                                                 if ( compiled.has( material2 ) === false ) {
27844
27845                                                         initMaterial( material2, scene, object );
27846                                                         compiled.set( material2 );
27847
27848                                                 }
27849
27850                                         }
27851
27852                                 } else if ( compiled.has( material ) === false ) {
27853
27854                                         initMaterial( material, scene, object );
27855                                         compiled.set( material );
27856
27857                                 }
27858
27859                         }
27860
27861                 } );
27862
27863         };
27864
27865         // Animation Loop
27866
27867         let onAnimationFrameCallback = null;
27868
27869         function onAnimationFrame( time ) {
27870
27871                 if ( xr.isPresenting ) return;
27872                 if ( onAnimationFrameCallback ) onAnimationFrameCallback( time );
27873
27874         }
27875
27876         const animation = new WebGLAnimation();
27877         animation.setAnimationLoop( onAnimationFrame );
27878
27879         if ( typeof window !== 'undefined' ) animation.setContext( window );
27880
27881         this.setAnimationLoop = function ( callback ) {
27882
27883                 onAnimationFrameCallback = callback;
27884                 xr.setAnimationLoop( callback );
27885
27886                 ( callback === null ) ? animation.stop() : animation.start();
27887
27888         };
27889
27890         // Rendering
27891
27892         this.render = function ( scene, camera ) {
27893
27894                 let renderTarget, forceClear;
27895
27896                 if ( arguments[ 2 ] !== undefined ) {
27897
27898                         console.warn( 'THREE.WebGLRenderer.render(): the renderTarget argument has been removed. Use .setRenderTarget() instead.' );
27899                         renderTarget = arguments[ 2 ];
27900
27901                 }
27902
27903                 if ( arguments[ 3 ] !== undefined ) {
27904
27905                         console.warn( 'THREE.WebGLRenderer.render(): the forceClear argument has been removed. Use .clear() instead.' );
27906                         forceClear = arguments[ 3 ];
27907
27908                 }
27909
27910                 if ( camera !== undefined && camera.isCamera !== true ) {
27911
27912                         console.error( 'THREE.WebGLRenderer.render: camera is not an instance of THREE.Camera.' );
27913                         return;
27914
27915                 }
27916
27917                 if ( _isContextLost === true ) return;
27918
27919                 // reset caching for this frame
27920
27921                 bindingStates.resetDefaultState();
27922                 _currentMaterialId = - 1;
27923                 _currentCamera = null;
27924
27925                 // update scene graph
27926
27927                 if ( scene.autoUpdate === true ) scene.updateMatrixWorld();
27928
27929                 // update camera matrices and frustum
27930
27931                 if ( camera.parent === null ) camera.updateMatrixWorld();
27932
27933                 if ( xr.enabled === true && xr.isPresenting === true ) {
27934
27935                         camera = xr.getCamera( camera );
27936
27937                 }
27938
27939                 //
27940                 if ( scene.isScene === true ) scene.onBeforeRender( _this, scene, camera, renderTarget || _currentRenderTarget );
27941
27942                 currentRenderState = renderStates.get( scene, renderStateStack.length );
27943                 currentRenderState.init();
27944
27945                 renderStateStack.push( currentRenderState );
27946
27947                 _projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse );
27948                 _frustum.setFromProjectionMatrix( _projScreenMatrix );
27949
27950                 _localClippingEnabled = this.localClippingEnabled;
27951                 _clippingEnabled = clipping.init( this.clippingPlanes, _localClippingEnabled, camera );
27952
27953                 currentRenderList = renderLists.get( scene, camera );
27954                 currentRenderList.init();
27955
27956                 projectObject( scene, camera, 0, _this.sortObjects );
27957
27958                 currentRenderList.finish();
27959
27960                 if ( _this.sortObjects === true ) {
27961
27962                         currentRenderList.sort( _opaqueSort, _transparentSort );
27963
27964                 }
27965
27966                 //
27967
27968                 if ( _clippingEnabled === true ) clipping.beginShadows();
27969
27970                 const shadowsArray = currentRenderState.state.shadowsArray;
27971
27972                 shadowMap.render( shadowsArray, scene, camera );
27973
27974                 currentRenderState.setupLights();
27975                 currentRenderState.setupLightsView( camera );
27976
27977                 if ( _clippingEnabled === true ) clipping.endShadows();
27978
27979                 //
27980
27981                 if ( this.info.autoReset === true ) this.info.reset();
27982
27983                 if ( renderTarget !== undefined ) {
27984
27985                         this.setRenderTarget( renderTarget );
27986
27987                 }
27988
27989                 //
27990
27991                 background.render( currentRenderList, scene, camera, forceClear );
27992
27993                 // render scene
27994
27995                 const opaqueObjects = currentRenderList.opaque;
27996                 const transparentObjects = currentRenderList.transparent;
27997
27998                 if ( opaqueObjects.length > 0 ) renderObjects( opaqueObjects, scene, camera );
27999                 if ( transparentObjects.length > 0 ) renderObjects( transparentObjects, scene, camera );
28000
28001                 //
28002
28003                 if ( scene.isScene === true ) scene.onAfterRender( _this, scene, camera );
28004
28005                 //
28006
28007                 if ( _currentRenderTarget !== null ) {
28008
28009                         // Generate mipmap if we're using any kind of mipmap filtering
28010
28011                         textures.updateRenderTargetMipmap( _currentRenderTarget );
28012
28013                         // resolve multisample renderbuffers to a single-sample texture if necessary
28014
28015                         textures.updateMultisampleRenderTarget( _currentRenderTarget );
28016
28017                 }
28018
28019                 // Ensure depth buffer writing is enabled so it can be cleared on next render
28020
28021                 state.buffers.depth.setTest( true );
28022                 state.buffers.depth.setMask( true );
28023                 state.buffers.color.setMask( true );
28024
28025                 state.setPolygonOffset( false );
28026
28027                 // _gl.finish();
28028
28029                 renderStateStack.pop();
28030                 if ( renderStateStack.length > 0 ) {
28031
28032                         currentRenderState = renderStateStack[ renderStateStack.length - 1 ];
28033
28034                 } else {
28035
28036                         currentRenderState = null;
28037
28038                 }
28039
28040                 currentRenderList = null;
28041
28042         };
28043
28044         function projectObject( object, camera, groupOrder, sortObjects ) {
28045
28046                 if ( object.visible === false ) return;
28047
28048                 const visible = object.layers.test( camera.layers );
28049
28050                 if ( visible ) {
28051
28052                         if ( object.isGroup ) {
28053
28054                                 groupOrder = object.renderOrder;
28055
28056                         } else if ( object.isLOD ) {
28057
28058                                 if ( object.autoUpdate === true ) object.update( camera );
28059
28060                         } else if ( object.isLight ) {
28061
28062                                 currentRenderState.pushLight( object );
28063
28064                                 if ( object.castShadow ) {
28065
28066                                         currentRenderState.pushShadow( object );
28067
28068                                 }
28069
28070                         } else if ( object.isSprite ) {
28071
28072                                 if ( ! object.frustumCulled || _frustum.intersectsSprite( object ) ) {
28073
28074                                         if ( sortObjects ) {
28075
28076                                                 _vector3.setFromMatrixPosition( object.matrixWorld )
28077                                                         .applyMatrix4( _projScreenMatrix );
28078
28079                                         }
28080
28081                                         const geometry = objects.update( object );
28082                                         const material = object.material;
28083
28084                                         if ( material.visible ) {
28085
28086                                                 currentRenderList.push( object, geometry, material, groupOrder, _vector3.z, null );
28087
28088                                         }
28089
28090                                 }
28091
28092                         } else if ( object.isImmediateRenderObject ) {
28093
28094                                 if ( sortObjects ) {
28095
28096                                         _vector3.setFromMatrixPosition( object.matrixWorld )
28097                                                 .applyMatrix4( _projScreenMatrix );
28098
28099                                 }
28100
28101                                 currentRenderList.push( object, null, object.material, groupOrder, _vector3.z, null );
28102
28103                         } else if ( object.isMesh || object.isLine || object.isPoints ) {
28104
28105                                 if ( object.isSkinnedMesh ) {
28106
28107                                         // update skeleton only once in a frame
28108
28109                                         if ( object.skeleton.frame !== info.render.frame ) {
28110
28111                                                 object.skeleton.update();
28112                                                 object.skeleton.frame = info.render.frame;
28113
28114                                         }
28115
28116                                 }
28117
28118                                 if ( ! object.frustumCulled || _frustum.intersectsObject( object ) ) {
28119
28120                                         if ( sortObjects ) {
28121
28122                                                 _vector3.setFromMatrixPosition( object.matrixWorld )
28123                                                         .applyMatrix4( _projScreenMatrix );
28124
28125                                         }
28126
28127                                         const geometry = objects.update( object );
28128                                         const material = object.material;
28129
28130                                         if ( Array.isArray( material ) ) {
28131
28132                                                 const groups = geometry.groups;
28133
28134                                                 for ( let i = 0, l = groups.length; i < l; i ++ ) {
28135
28136                                                         const group = groups[ i ];
28137                                                         const groupMaterial = material[ group.materialIndex ];
28138
28139                                                         if ( groupMaterial && groupMaterial.visible ) {
28140
28141                                                                 currentRenderList.push( object, geometry, groupMaterial, groupOrder, _vector3.z, group );
28142
28143                                                         }
28144
28145                                                 }
28146
28147                                         } else if ( material.visible ) {
28148
28149                                                 currentRenderList.push( object, geometry, material, groupOrder, _vector3.z, null );
28150
28151                                         }
28152
28153                                 }
28154
28155                         }
28156
28157                 }
28158
28159                 const children = object.children;
28160
28161                 for ( let i = 0, l = children.length; i < l; i ++ ) {
28162
28163                         projectObject( children[ i ], camera, groupOrder, sortObjects );
28164
28165                 }
28166
28167         }
28168
28169         function renderObjects( renderList, scene, camera ) {
28170
28171                 const overrideMaterial = scene.isScene === true ? scene.overrideMaterial : null;
28172
28173                 for ( let i = 0, l = renderList.length; i < l; i ++ ) {
28174
28175                         const renderItem = renderList[ i ];
28176
28177                         const object = renderItem.object;
28178                         const geometry = renderItem.geometry;
28179                         const material = overrideMaterial === null ? renderItem.material : overrideMaterial;
28180                         const group = renderItem.group;
28181
28182                         if ( camera.isArrayCamera ) {
28183
28184                                 const cameras = camera.cameras;
28185
28186                                 for ( let j = 0, jl = cameras.length; j < jl; j ++ ) {
28187
28188                                         const camera2 = cameras[ j ];
28189
28190                                         if ( object.layers.test( camera2.layers ) ) {
28191
28192                                                 state.viewport( _currentViewport.copy( camera2.viewport ) );
28193
28194                                                 currentRenderState.setupLightsView( camera2 );
28195
28196                                                 renderObject( object, scene, camera2, geometry, material, group );
28197
28198                                         }
28199
28200                                 }
28201
28202                         } else {
28203
28204                                 renderObject( object, scene, camera, geometry, material, group );
28205
28206                         }
28207
28208                 }
28209
28210         }
28211
28212         function renderObject( object, scene, camera, geometry, material, group ) {
28213
28214                 object.onBeforeRender( _this, scene, camera, geometry, material, group );
28215
28216                 object.modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld );
28217                 object.normalMatrix.getNormalMatrix( object.modelViewMatrix );
28218
28219                 if ( object.isImmediateRenderObject ) {
28220
28221                         const program = setProgram( camera, scene, material, object );
28222
28223                         state.setMaterial( material );
28224
28225                         bindingStates.reset();
28226
28227                         renderObjectImmediate( object, program );
28228
28229                 } else {
28230
28231                         _this.renderBufferDirect( camera, scene, geometry, material, object, group );
28232
28233                 }
28234
28235                 object.onAfterRender( _this, scene, camera, geometry, material, group );
28236
28237         }
28238
28239         function initMaterial( material, scene, object ) {
28240
28241                 if ( scene.isScene !== true ) scene = _emptyScene; // scene could be a Mesh, Line, Points, ...
28242
28243                 const materialProperties = properties.get( material );
28244
28245                 const lights = currentRenderState.state.lights;
28246                 const shadowsArray = currentRenderState.state.shadowsArray;
28247
28248                 const lightsStateVersion = lights.state.version;
28249
28250                 const parameters = programCache.getParameters( material, lights.state, shadowsArray, scene, object );
28251                 const programCacheKey = programCache.getProgramCacheKey( parameters );
28252
28253                 let program = materialProperties.program;
28254                 let programChange = true;
28255
28256                 // always update environment and fog - changing these trigger an initMaterial call, but it's possible that the program doesn't change
28257
28258                 materialProperties.environment = material.isMeshStandardMaterial ? scene.environment : null;
28259                 materialProperties.fog = scene.fog;
28260                 materialProperties.envMap = cubemaps.get( material.envMap || materialProperties.environment );
28261
28262                 if ( program === undefined ) {
28263
28264                         // new material
28265                         material.addEventListener( 'dispose', onMaterialDispose );
28266
28267                 } else if ( program.cacheKey !== programCacheKey ) {
28268
28269                         // changed glsl or parameters
28270                         releaseMaterialProgramReference( material );
28271
28272                 } else if ( materialProperties.lightsStateVersion !== lightsStateVersion ) {
28273
28274                         programChange = false;
28275
28276                 } else if ( parameters.shaderID !== undefined ) {
28277
28278                         // same glsl and uniform list
28279                         return;
28280
28281                 } else {
28282
28283                         // only rebuild uniform list
28284                         programChange = false;
28285
28286                 }
28287
28288                 if ( programChange ) {
28289
28290                         parameters.uniforms = programCache.getUniforms( material );
28291
28292                         material.onBeforeCompile( parameters, _this );
28293
28294                         program = programCache.acquireProgram( parameters, programCacheKey );
28295
28296                         materialProperties.program = program;
28297                         materialProperties.uniforms = parameters.uniforms;
28298                         materialProperties.outputEncoding = parameters.outputEncoding;
28299
28300                 }
28301
28302                 const uniforms = materialProperties.uniforms;
28303
28304                 if ( ! material.isShaderMaterial &&
28305                         ! material.isRawShaderMaterial ||
28306                         material.clipping === true ) {
28307
28308                         materialProperties.numClippingPlanes = clipping.numPlanes;
28309                         materialProperties.numIntersection = clipping.numIntersection;
28310                         uniforms.clippingPlanes = clipping.uniform;
28311
28312                 }
28313
28314                 // store the light setup it was created for
28315
28316                 materialProperties.needsLights = materialNeedsLights( material );
28317                 materialProperties.lightsStateVersion = lightsStateVersion;
28318
28319                 if ( materialProperties.needsLights ) {
28320
28321                         // wire up the material to this renderer's lighting state
28322
28323                         uniforms.ambientLightColor.value = lights.state.ambient;
28324                         uniforms.lightProbe.value = lights.state.probe;
28325                         uniforms.directionalLights.value = lights.state.directional;
28326                         uniforms.directionalLightShadows.value = lights.state.directionalShadow;
28327                         uniforms.spotLights.value = lights.state.spot;
28328                         uniforms.spotLightShadows.value = lights.state.spotShadow;
28329                         uniforms.rectAreaLights.value = lights.state.rectArea;
28330                         uniforms.ltc_1.value = lights.state.rectAreaLTC1;
28331                         uniforms.ltc_2.value = lights.state.rectAreaLTC2;
28332                         uniforms.pointLights.value = lights.state.point;
28333                         uniforms.pointLightShadows.value = lights.state.pointShadow;
28334                         uniforms.hemisphereLights.value = lights.state.hemi;
28335
28336                         uniforms.directionalShadowMap.value = lights.state.directionalShadowMap;
28337                         uniforms.directionalShadowMatrix.value = lights.state.directionalShadowMatrix;
28338                         uniforms.spotShadowMap.value = lights.state.spotShadowMap;
28339                         uniforms.spotShadowMatrix.value = lights.state.spotShadowMatrix;
28340                         uniforms.pointShadowMap.value = lights.state.pointShadowMap;
28341                         uniforms.pointShadowMatrix.value = lights.state.pointShadowMatrix;
28342                         // TODO (abelnation): add area lights shadow info to uniforms
28343
28344                 }
28345
28346                 const progUniforms = materialProperties.program.getUniforms();
28347                 const uniformsList = WebGLUniforms.seqWithValue( progUniforms.seq, uniforms );
28348
28349                 materialProperties.uniformsList = uniformsList;
28350
28351         }
28352
28353         function setProgram( camera, scene, material, object ) {
28354
28355                 if ( scene.isScene !== true ) scene = _emptyScene; // scene could be a Mesh, Line, Points, ...
28356
28357                 textures.resetTextureUnits();
28358
28359                 const fog = scene.fog;
28360                 const environment = material.isMeshStandardMaterial ? scene.environment : null;
28361                 const encoding = ( _currentRenderTarget === null ) ? _this.outputEncoding : _currentRenderTarget.texture.encoding;
28362                 const envMap = cubemaps.get( material.envMap || environment );
28363
28364                 const materialProperties = properties.get( material );
28365                 const lights = currentRenderState.state.lights;
28366
28367                 if ( _clippingEnabled === true ) {
28368
28369                         if ( _localClippingEnabled === true || camera !== _currentCamera ) {
28370
28371                                 const useCache =
28372                                         camera === _currentCamera &&
28373                                         material.id === _currentMaterialId;
28374
28375                                 // we might want to call this function with some ClippingGroup
28376                                 // object instead of the material, once it becomes feasible
28377                                 // (#8465, #8379)
28378                                 clipping.setState( material, camera, useCache );
28379
28380                         }
28381
28382                 }
28383
28384                 if ( material.version === materialProperties.__version ) {
28385
28386                         if ( material.fog && materialProperties.fog !== fog ) {
28387
28388                                 initMaterial( material, scene, object );
28389
28390                         } else if ( materialProperties.environment !== environment ) {
28391
28392                                 initMaterial( material, scene, object );
28393
28394                         } else if ( materialProperties.needsLights && ( materialProperties.lightsStateVersion !== lights.state.version ) ) {
28395
28396                                 initMaterial( material, scene, object );
28397
28398                         } else if ( materialProperties.numClippingPlanes !== undefined &&
28399                                 ( materialProperties.numClippingPlanes !== clipping.numPlanes ||
28400                                 materialProperties.numIntersection !== clipping.numIntersection ) ) {
28401
28402                                 initMaterial( material, scene, object );
28403
28404                         } else if ( materialProperties.outputEncoding !== encoding ) {
28405
28406                                 initMaterial( material, scene, object );
28407
28408                         } else if ( materialProperties.envMap !== envMap ) {
28409
28410                                 initMaterial( material, scene, object );
28411
28412                         }
28413
28414                 } else {
28415
28416                         initMaterial( material, scene, object );
28417                         materialProperties.__version = material.version;
28418
28419                 }
28420
28421                 let refreshProgram = false;
28422                 let refreshMaterial = false;
28423                 let refreshLights = false;
28424
28425                 const program = materialProperties.program,
28426                         p_uniforms = program.getUniforms(),
28427                         m_uniforms = materialProperties.uniforms;
28428
28429                 if ( state.useProgram( program.program ) ) {
28430
28431                         refreshProgram = true;
28432                         refreshMaterial = true;
28433                         refreshLights = true;
28434
28435                 }
28436
28437                 if ( material.id !== _currentMaterialId ) {
28438
28439                         _currentMaterialId = material.id;
28440
28441                         refreshMaterial = true;
28442
28443                 }
28444
28445                 if ( refreshProgram || _currentCamera !== camera ) {
28446
28447                         p_uniforms.setValue( _gl, 'projectionMatrix', camera.projectionMatrix );
28448
28449                         if ( capabilities.logarithmicDepthBuffer ) {
28450
28451                                 p_uniforms.setValue( _gl, 'logDepthBufFC',
28452                                         2.0 / ( Math.log( camera.far + 1.0 ) / Math.LN2 ) );
28453
28454                         }
28455
28456                         if ( _currentCamera !== camera ) {
28457
28458                                 _currentCamera = camera;
28459
28460                                 // lighting uniforms depend on the camera so enforce an update
28461                                 // now, in case this material supports lights - or later, when
28462                                 // the next material that does gets activated:
28463
28464                                 refreshMaterial = true;         // set to true on material change
28465                                 refreshLights = true;           // remains set until update done
28466
28467                         }
28468
28469                         // load material specific uniforms
28470                         // (shader material also gets them for the sake of genericity)
28471
28472                         if ( material.isShaderMaterial ||
28473                                 material.isMeshPhongMaterial ||
28474                                 material.isMeshToonMaterial ||
28475                                 material.isMeshStandardMaterial ||
28476                                 material.envMap ) {
28477
28478                                 const uCamPos = p_uniforms.map.cameraPosition;
28479
28480                                 if ( uCamPos !== undefined ) {
28481
28482                                         uCamPos.setValue( _gl,
28483                                                 _vector3.setFromMatrixPosition( camera.matrixWorld ) );
28484
28485                                 }
28486
28487                         }
28488
28489                         if ( material.isMeshPhongMaterial ||
28490                                 material.isMeshToonMaterial ||
28491                                 material.isMeshLambertMaterial ||
28492                                 material.isMeshBasicMaterial ||
28493                                 material.isMeshStandardMaterial ||
28494                                 material.isShaderMaterial ) {
28495
28496                                 p_uniforms.setValue( _gl, 'isOrthographic', camera.isOrthographicCamera === true );
28497
28498                         }
28499
28500                         if ( material.isMeshPhongMaterial ||
28501                                 material.isMeshToonMaterial ||
28502                                 material.isMeshLambertMaterial ||
28503                                 material.isMeshBasicMaterial ||
28504                                 material.isMeshStandardMaterial ||
28505                                 material.isShaderMaterial ||
28506                                 material.isShadowMaterial ||
28507                                 material.skinning ) {
28508
28509                                 p_uniforms.setValue( _gl, 'viewMatrix', camera.matrixWorldInverse );
28510
28511                         }
28512
28513                 }
28514
28515                 // skinning uniforms must be set even if material didn't change
28516                 // auto-setting of texture unit for bone texture must go before other textures
28517                 // otherwise textures used for skinning can take over texture units reserved for other material textures
28518
28519                 if ( material.skinning ) {
28520
28521                         p_uniforms.setOptional( _gl, object, 'bindMatrix' );
28522                         p_uniforms.setOptional( _gl, object, 'bindMatrixInverse' );
28523
28524                         const skeleton = object.skeleton;
28525
28526                         if ( skeleton ) {
28527
28528                                 const bones = skeleton.bones;
28529
28530                                 if ( capabilities.floatVertexTextures ) {
28531
28532                                         if ( skeleton.boneTexture === null ) {
28533
28534                                                 // layout (1 matrix = 4 pixels)
28535                                                 //      RGBA RGBA RGBA RGBA (=> column1, column2, column3, column4)
28536                                                 //  with  8x8  pixel texture max   16 bones * 4 pixels =  (8 * 8)
28537                                                 //       16x16 pixel texture max   64 bones * 4 pixels = (16 * 16)
28538                                                 //       32x32 pixel texture max  256 bones * 4 pixels = (32 * 32)
28539                                                 //       64x64 pixel texture max 1024 bones * 4 pixels = (64 * 64)
28540
28541
28542                                                 let size = Math.sqrt( bones.length * 4 ); // 4 pixels needed for 1 matrix
28543                                                 size = MathUtils.ceilPowerOfTwo( size );
28544                                                 size = Math.max( size, 4 );
28545
28546                                                 const boneMatrices = new Float32Array( size * size * 4 ); // 4 floats per RGBA pixel
28547                                                 boneMatrices.set( skeleton.boneMatrices ); // copy current values
28548
28549                                                 const boneTexture = new DataTexture( boneMatrices, size, size, RGBAFormat, FloatType );
28550
28551                                                 skeleton.boneMatrices = boneMatrices;
28552                                                 skeleton.boneTexture = boneTexture;
28553                                                 skeleton.boneTextureSize = size;
28554
28555                                         }
28556
28557                                         p_uniforms.setValue( _gl, 'boneTexture', skeleton.boneTexture, textures );
28558                                         p_uniforms.setValue( _gl, 'boneTextureSize', skeleton.boneTextureSize );
28559
28560                                 } else {
28561
28562                                         p_uniforms.setOptional( _gl, skeleton, 'boneMatrices' );
28563
28564                                 }
28565
28566                         }
28567
28568                 }
28569
28570                 if ( refreshMaterial || materialProperties.receiveShadow !== object.receiveShadow ) {
28571
28572                         materialProperties.receiveShadow = object.receiveShadow;
28573                         p_uniforms.setValue( _gl, 'receiveShadow', object.receiveShadow );
28574
28575                 }
28576
28577                 if ( refreshMaterial ) {
28578
28579                         p_uniforms.setValue( _gl, 'toneMappingExposure', _this.toneMappingExposure );
28580
28581                         if ( materialProperties.needsLights ) {
28582
28583                                 // the current material requires lighting info
28584
28585                                 // note: all lighting uniforms are always set correctly
28586                                 // they simply reference the renderer's state for their
28587                                 // values
28588                                 //
28589                                 // use the current material's .needsUpdate flags to set
28590                                 // the GL state when required
28591
28592                                 markUniformsLightsNeedsUpdate( m_uniforms, refreshLights );
28593
28594                         }
28595
28596                         // refresh uniforms common to several materials
28597
28598                         if ( fog && material.fog ) {
28599
28600                                 materials.refreshFogUniforms( m_uniforms, fog );
28601
28602                         }
28603
28604                         materials.refreshMaterialUniforms( m_uniforms, material, _pixelRatio, _height );
28605
28606                         WebGLUniforms.upload( _gl, materialProperties.uniformsList, m_uniforms, textures );
28607
28608                 }
28609
28610                 if ( material.isShaderMaterial && material.uniformsNeedUpdate === true ) {
28611
28612                         WebGLUniforms.upload( _gl, materialProperties.uniformsList, m_uniforms, textures );
28613                         material.uniformsNeedUpdate = false;
28614
28615                 }
28616
28617                 if ( material.isSpriteMaterial ) {
28618
28619                         p_uniforms.setValue( _gl, 'center', object.center );
28620
28621                 }
28622
28623                 // common matrices
28624
28625                 p_uniforms.setValue( _gl, 'modelViewMatrix', object.modelViewMatrix );
28626                 p_uniforms.setValue( _gl, 'normalMatrix', object.normalMatrix );
28627                 p_uniforms.setValue( _gl, 'modelMatrix', object.matrixWorld );
28628
28629                 return program;
28630
28631         }
28632
28633         // If uniforms are marked as clean, they don't need to be loaded to the GPU.
28634
28635         function markUniformsLightsNeedsUpdate( uniforms, value ) {
28636
28637                 uniforms.ambientLightColor.needsUpdate = value;
28638                 uniforms.lightProbe.needsUpdate = value;
28639
28640                 uniforms.directionalLights.needsUpdate = value;
28641                 uniforms.directionalLightShadows.needsUpdate = value;
28642                 uniforms.pointLights.needsUpdate = value;
28643                 uniforms.pointLightShadows.needsUpdate = value;
28644                 uniforms.spotLights.needsUpdate = value;
28645                 uniforms.spotLightShadows.needsUpdate = value;
28646                 uniforms.rectAreaLights.needsUpdate = value;
28647                 uniforms.hemisphereLights.needsUpdate = value;
28648
28649         }
28650
28651         function materialNeedsLights( material ) {
28652
28653                 return material.isMeshLambertMaterial || material.isMeshToonMaterial || material.isMeshPhongMaterial ||
28654                         material.isMeshStandardMaterial || material.isShadowMaterial ||
28655                         ( material.isShaderMaterial && material.lights === true );
28656
28657         }
28658
28659         //
28660         this.setFramebuffer = function ( value ) {
28661
28662                 if ( _framebuffer !== value && _currentRenderTarget === null ) _gl.bindFramebuffer( 36160, value );
28663
28664                 _framebuffer = value;
28665
28666         };
28667
28668         this.getActiveCubeFace = function () {
28669
28670                 return _currentActiveCubeFace;
28671
28672         };
28673
28674         this.getActiveMipmapLevel = function () {
28675
28676                 return _currentActiveMipmapLevel;
28677
28678         };
28679
28680         this.getRenderList = function () {
28681
28682                 return currentRenderList;
28683
28684         };
28685
28686         this.setRenderList = function ( renderList ) {
28687
28688                 currentRenderList = renderList;
28689
28690         };
28691
28692         this.getRenderTarget = function () {
28693
28694                 return _currentRenderTarget;
28695
28696         };
28697
28698         this.setRenderTarget = function ( renderTarget, activeCubeFace = 0, activeMipmapLevel = 0 ) {
28699
28700                 _currentRenderTarget = renderTarget;
28701                 _currentActiveCubeFace = activeCubeFace;
28702                 _currentActiveMipmapLevel = activeMipmapLevel;
28703
28704                 if ( renderTarget && properties.get( renderTarget ).__webglFramebuffer === undefined ) {
28705
28706                         textures.setupRenderTarget( renderTarget );
28707
28708                 }
28709
28710                 let framebuffer = _framebuffer;
28711                 let isCube = false;
28712
28713                 if ( renderTarget ) {
28714
28715                         const __webglFramebuffer = properties.get( renderTarget ).__webglFramebuffer;
28716
28717                         if ( renderTarget.isWebGLCubeRenderTarget ) {
28718
28719                                 framebuffer = __webglFramebuffer[ activeCubeFace ];
28720                                 isCube = true;
28721
28722                         } else if ( renderTarget.isWebGLMultisampleRenderTarget ) {
28723
28724                                 framebuffer = properties.get( renderTarget ).__webglMultisampledFramebuffer;
28725
28726                         } else {
28727
28728                                 framebuffer = __webglFramebuffer;
28729
28730                         }
28731
28732                         _currentViewport.copy( renderTarget.viewport );
28733                         _currentScissor.copy( renderTarget.scissor );
28734                         _currentScissorTest = renderTarget.scissorTest;
28735
28736                 } else {
28737
28738                         _currentViewport.copy( _viewport ).multiplyScalar( _pixelRatio ).floor();
28739                         _currentScissor.copy( _scissor ).multiplyScalar( _pixelRatio ).floor();
28740                         _currentScissorTest = _scissorTest;
28741
28742                 }
28743
28744                 if ( _currentFramebuffer !== framebuffer ) {
28745
28746                         _gl.bindFramebuffer( 36160, framebuffer );
28747                         _currentFramebuffer = framebuffer;
28748
28749                 }
28750
28751                 state.viewport( _currentViewport );
28752                 state.scissor( _currentScissor );
28753                 state.setScissorTest( _currentScissorTest );
28754
28755                 if ( isCube ) {
28756
28757                         const textureProperties = properties.get( renderTarget.texture );
28758                         _gl.framebufferTexture2D( 36160, 36064, 34069 + activeCubeFace, textureProperties.__webglTexture, activeMipmapLevel );
28759
28760                 }
28761
28762         };
28763
28764         this.readRenderTargetPixels = function ( renderTarget, x, y, width, height, buffer, activeCubeFaceIndex ) {
28765
28766                 if ( ! ( renderTarget && renderTarget.isWebGLRenderTarget ) ) {
28767
28768                         console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.' );
28769                         return;
28770
28771                 }
28772
28773                 let framebuffer = properties.get( renderTarget ).__webglFramebuffer;
28774
28775                 if ( renderTarget.isWebGLCubeRenderTarget && activeCubeFaceIndex !== undefined ) {
28776
28777                         framebuffer = framebuffer[ activeCubeFaceIndex ];
28778
28779                 }
28780
28781                 if ( framebuffer ) {
28782
28783                         let restore = false;
28784
28785                         if ( framebuffer !== _currentFramebuffer ) {
28786
28787                                 _gl.bindFramebuffer( 36160, framebuffer );
28788
28789                                 restore = true;
28790
28791                         }
28792
28793                         try {
28794
28795                                 const texture = renderTarget.texture;
28796                                 const textureFormat = texture.format;
28797                                 const textureType = texture.type;
28798
28799                                 if ( textureFormat !== RGBAFormat && utils.convert( textureFormat ) !== _gl.getParameter( 35739 ) ) {
28800
28801                                         console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in RGBA or implementation defined format.' );
28802                                         return;
28803
28804                                 }
28805
28806                                 const halfFloatSupportedByExt = ( textureType === HalfFloatType ) && ( extensions.has( 'EXT_color_buffer_half_float' ) || ( capabilities.isWebGL2 && extensions.has( 'EXT_color_buffer_float' ) ) );
28807
28808                                 if ( textureType !== UnsignedByteType && utils.convert( textureType ) !== _gl.getParameter( 35738 ) && // IE11, Edge and Chrome Mac < 52 (#9513)
28809                                         ! ( textureType === FloatType && ( capabilities.isWebGL2 || extensions.has( 'OES_texture_float' ) || extensions.has( 'WEBGL_color_buffer_float' ) ) ) && // Chrome Mac >= 52 and Firefox
28810                                         ! halfFloatSupportedByExt ) {
28811
28812                                         console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in UnsignedByteType or implementation defined type.' );
28813                                         return;
28814
28815                                 }
28816
28817                                 if ( _gl.checkFramebufferStatus( 36160 ) === 36053 ) {
28818
28819                                         // the following if statement ensures valid read requests (no out-of-bounds pixels, see #8604)
28820
28821                                         if ( ( x >= 0 && x <= ( renderTarget.width - width ) ) && ( y >= 0 && y <= ( renderTarget.height - height ) ) ) {
28822
28823                                                 _gl.readPixels( x, y, width, height, utils.convert( textureFormat ), utils.convert( textureType ), buffer );
28824
28825                                         }
28826
28827                                 } else {
28828
28829                                         console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: readPixels from renderTarget failed. Framebuffer not complete.' );
28830
28831                                 }
28832
28833                         } finally {
28834
28835                                 if ( restore ) {
28836
28837                                         _gl.bindFramebuffer( 36160, _currentFramebuffer );
28838
28839                                 }
28840
28841                         }
28842
28843                 }
28844
28845         };
28846
28847         this.copyFramebufferToTexture = function ( position, texture, level = 0 ) {
28848
28849                 const levelScale = Math.pow( 2, - level );
28850                 const width = Math.floor( texture.image.width * levelScale );
28851                 const height = Math.floor( texture.image.height * levelScale );
28852                 const glFormat = utils.convert( texture.format );
28853
28854                 textures.setTexture2D( texture, 0 );
28855
28856                 _gl.copyTexImage2D( 3553, level, glFormat, position.x, position.y, width, height, 0 );
28857
28858                 state.unbindTexture();
28859
28860         };
28861
28862         this.copyTextureToTexture = function ( position, srcTexture, dstTexture, level = 0 ) {
28863
28864                 const width = srcTexture.image.width;
28865                 const height = srcTexture.image.height;
28866                 const glFormat = utils.convert( dstTexture.format );
28867                 const glType = utils.convert( dstTexture.type );
28868
28869                 textures.setTexture2D( dstTexture, 0 );
28870
28871                 // As another texture upload may have changed pixelStorei
28872                 // parameters, make sure they are correct for the dstTexture
28873                 _gl.pixelStorei( 37440, dstTexture.flipY );
28874                 _gl.pixelStorei( 37441, dstTexture.premultiplyAlpha );
28875                 _gl.pixelStorei( 3317, dstTexture.unpackAlignment );
28876
28877                 if ( srcTexture.isDataTexture ) {
28878
28879                         _gl.texSubImage2D( 3553, level, position.x, position.y, width, height, glFormat, glType, srcTexture.image.data );
28880
28881                 } else {
28882
28883                         if ( srcTexture.isCompressedTexture ) {
28884
28885                                 _gl.compressedTexSubImage2D( 3553, level, position.x, position.y, srcTexture.mipmaps[ 0 ].width, srcTexture.mipmaps[ 0 ].height, glFormat, srcTexture.mipmaps[ 0 ].data );
28886
28887                         } else {
28888
28889                                 _gl.texSubImage2D( 3553, level, position.x, position.y, glFormat, glType, srcTexture.image );
28890
28891                         }
28892
28893                 }
28894
28895                 // Generate mipmaps only when copying level 0
28896                 if ( level === 0 && dstTexture.generateMipmaps ) _gl.generateMipmap( 3553 );
28897
28898                 state.unbindTexture();
28899
28900         };
28901
28902         this.initTexture = function ( texture ) {
28903
28904                 textures.setTexture2D( texture, 0 );
28905
28906                 state.unbindTexture();
28907
28908         };
28909
28910         this.resetState = function () {
28911
28912                 state.reset();
28913                 bindingStates.reset();
28914
28915         };
28916
28917         if ( typeof __THREE_DEVTOOLS__ !== 'undefined' ) {
28918
28919                 __THREE_DEVTOOLS__.dispatchEvent( new CustomEvent( 'observe', { detail: this } ) ); // eslint-disable-line no-undef
28920
28921         }
28922
28923 }
28924
28925 function WebGL1Renderer( parameters ) {
28926
28927         WebGLRenderer.call( this, parameters );
28928
28929 }
28930
28931 WebGL1Renderer.prototype = Object.assign( Object.create( WebGLRenderer.prototype ), {
28932
28933         constructor: WebGL1Renderer,
28934
28935         isWebGL1Renderer: true
28936
28937 } );
28938
28939 class Scene extends Object3D {
28940
28941         constructor() {
28942
28943                 super();
28944
28945                 Object.defineProperty( this, 'isScene', { value: true } );
28946
28947                 this.type = 'Scene';
28948
28949                 this.background = null;
28950                 this.environment = null;
28951                 this.fog = null;
28952
28953                 this.overrideMaterial = null;
28954
28955                 this.autoUpdate = true; // checked by the renderer
28956
28957                 if ( typeof __THREE_DEVTOOLS__ !== 'undefined' ) {
28958
28959                         __THREE_DEVTOOLS__.dispatchEvent( new CustomEvent( 'observe', { detail: this } ) ); // eslint-disable-line no-undef
28960
28961                 }
28962
28963         }
28964
28965         copy( source, recursive ) {
28966
28967                 super.copy( source, recursive );
28968
28969                 if ( source.background !== null ) this.background = source.background.clone();
28970                 if ( source.environment !== null ) this.environment = source.environment.clone();
28971                 if ( source.fog !== null ) this.fog = source.fog.clone();
28972
28973                 if ( source.overrideMaterial !== null ) this.overrideMaterial = source.overrideMaterial.clone();
28974
28975                 this.autoUpdate = source.autoUpdate;
28976                 this.matrixAutoUpdate = source.matrixAutoUpdate;
28977
28978                 return this;
28979
28980         }
28981
28982         toJSON( meta ) {
28983
28984                 const data = super.toJSON( meta );
28985
28986                 if ( this.background !== null ) data.object.background = this.background.toJSON( meta );
28987                 if ( this.environment !== null ) data.object.environment = this.environment.toJSON( meta );
28988                 if ( this.fog !== null ) data.object.fog = this.fog.toJSON();
28989
28990                 return data;
28991
28992         }
28993
28994 }
28995
28996 function InterleavedBuffer( array, stride ) {
28997
28998         this.array = array;
28999         this.stride = stride;
29000         this.count = array !== undefined ? array.length / stride : 0;
29001
29002         this.usage = StaticDrawUsage;
29003         this.updateRange = { offset: 0, count: - 1 };
29004
29005         this.version = 0;
29006
29007         this.uuid = MathUtils.generateUUID();
29008
29009 }
29010
29011 Object.defineProperty( InterleavedBuffer.prototype, 'needsUpdate', {
29012
29013         set: function ( value ) {
29014
29015                 if ( value === true ) this.version ++;
29016
29017         }
29018
29019 } );
29020
29021 Object.assign( InterleavedBuffer.prototype, {
29022
29023         isInterleavedBuffer: true,
29024
29025         onUploadCallback: function () {},
29026
29027         setUsage: function ( value ) {
29028
29029                 this.usage = value;
29030
29031                 return this;
29032
29033         },
29034
29035         copy: function ( source ) {
29036
29037                 this.array = new source.array.constructor( source.array );
29038                 this.count = source.count;
29039                 this.stride = source.stride;
29040                 this.usage = source.usage;
29041
29042                 return this;
29043
29044         },
29045
29046         copyAt: function ( index1, attribute, index2 ) {
29047
29048                 index1 *= this.stride;
29049                 index2 *= attribute.stride;
29050
29051                 for ( let i = 0, l = this.stride; i < l; i ++ ) {
29052
29053                         this.array[ index1 + i ] = attribute.array[ index2 + i ];
29054
29055                 }
29056
29057                 return this;
29058
29059         },
29060
29061         set: function ( value, offset = 0 ) {
29062
29063                 this.array.set( value, offset );
29064
29065                 return this;
29066
29067         },
29068
29069         clone: function ( data ) {
29070
29071                 if ( data.arrayBuffers === undefined ) {
29072
29073                         data.arrayBuffers = {};
29074
29075                 }
29076
29077                 if ( this.array.buffer._uuid === undefined ) {
29078
29079                         this.array.buffer._uuid = MathUtils.generateUUID();
29080
29081                 }
29082
29083                 if ( data.arrayBuffers[ this.array.buffer._uuid ] === undefined ) {
29084
29085                         data.arrayBuffers[ this.array.buffer._uuid ] = this.array.slice( 0 ).buffer;
29086
29087                 }
29088
29089                 const array = new this.array.constructor( data.arrayBuffers[ this.array.buffer._uuid ] );
29090
29091                 const ib = new InterleavedBuffer( array, this.stride );
29092                 ib.setUsage( this.usage );
29093
29094                 return ib;
29095
29096         },
29097
29098         onUpload: function ( callback ) {
29099
29100                 this.onUploadCallback = callback;
29101
29102                 return this;
29103
29104         },
29105
29106         toJSON: function ( data ) {
29107
29108                 if ( data.arrayBuffers === undefined ) {
29109
29110                         data.arrayBuffers = {};
29111
29112                 }
29113
29114                 // generate UUID for array buffer if necessary
29115
29116                 if ( this.array.buffer._uuid === undefined ) {
29117
29118                         this.array.buffer._uuid = MathUtils.generateUUID();
29119
29120                 }
29121
29122                 if ( data.arrayBuffers[ this.array.buffer._uuid ] === undefined ) {
29123
29124                         data.arrayBuffers[ this.array.buffer._uuid ] = Array.prototype.slice.call( new Uint32Array( this.array.buffer ) );
29125
29126                 }
29127
29128                 //
29129
29130                 return {
29131                         uuid: this.uuid,
29132                         buffer: this.array.buffer._uuid,
29133                         type: this.array.constructor.name,
29134                         stride: this.stride
29135                 };
29136
29137         }
29138
29139 } );
29140
29141 const _vector$6 = new Vector3();
29142
29143 function InterleavedBufferAttribute( interleavedBuffer, itemSize, offset, normalized ) {
29144
29145         this.name = '';
29146
29147         this.data = interleavedBuffer;
29148         this.itemSize = itemSize;
29149         this.offset = offset;
29150
29151         this.normalized = normalized === true;
29152
29153 }
29154
29155 Object.defineProperties( InterleavedBufferAttribute.prototype, {
29156
29157         count: {
29158
29159                 get: function () {
29160
29161                         return this.data.count;
29162
29163                 }
29164
29165         },
29166
29167         array: {
29168
29169                 get: function () {
29170
29171                         return this.data.array;
29172
29173                 }
29174
29175         },
29176
29177         needsUpdate: {
29178
29179                 set: function ( value ) {
29180
29181                         this.data.needsUpdate = value;
29182
29183                 }
29184
29185         }
29186
29187 } );
29188
29189 Object.assign( InterleavedBufferAttribute.prototype, {
29190
29191         isInterleavedBufferAttribute: true,
29192
29193         applyMatrix4: function ( m ) {
29194
29195                 for ( let i = 0, l = this.data.count; i < l; i ++ ) {
29196
29197                         _vector$6.x = this.getX( i );
29198                         _vector$6.y = this.getY( i );
29199                         _vector$6.z = this.getZ( i );
29200
29201                         _vector$6.applyMatrix4( m );
29202
29203                         this.setXYZ( i, _vector$6.x, _vector$6.y, _vector$6.z );
29204
29205                 }
29206
29207                 return this;
29208
29209         },
29210
29211         setX: function ( index, x ) {
29212
29213                 this.data.array[ index * this.data.stride + this.offset ] = x;
29214
29215                 return this;
29216
29217         },
29218
29219         setY: function ( index, y ) {
29220
29221                 this.data.array[ index * this.data.stride + this.offset + 1 ] = y;
29222
29223                 return this;
29224
29225         },
29226
29227         setZ: function ( index, z ) {
29228
29229                 this.data.array[ index * this.data.stride + this.offset + 2 ] = z;
29230
29231                 return this;
29232
29233         },
29234
29235         setW: function ( index, w ) {
29236
29237                 this.data.array[ index * this.data.stride + this.offset + 3 ] = w;
29238
29239                 return this;
29240
29241         },
29242
29243         getX: function ( index ) {
29244
29245                 return this.data.array[ index * this.data.stride + this.offset ];
29246
29247         },
29248
29249         getY: function ( index ) {
29250
29251                 return this.data.array[ index * this.data.stride + this.offset + 1 ];
29252
29253         },
29254
29255         getZ: function ( index ) {
29256
29257                 return this.data.array[ index * this.data.stride + this.offset + 2 ];
29258
29259         },
29260
29261         getW: function ( index ) {
29262
29263                 return this.data.array[ index * this.data.stride + this.offset + 3 ];
29264
29265         },
29266
29267         setXY: function ( index, x, y ) {
29268
29269                 index = index * this.data.stride + this.offset;
29270
29271                 this.data.array[ index + 0 ] = x;
29272                 this.data.array[ index + 1 ] = y;
29273
29274                 return this;
29275
29276         },
29277
29278         setXYZ: function ( index, x, y, z ) {
29279
29280                 index = index * this.data.stride + this.offset;
29281
29282                 this.data.array[ index + 0 ] = x;
29283                 this.data.array[ index + 1 ] = y;
29284                 this.data.array[ index + 2 ] = z;
29285
29286                 return this;
29287
29288         },
29289
29290         setXYZW: function ( index, x, y, z, w ) {
29291
29292                 index = index * this.data.stride + this.offset;
29293
29294                 this.data.array[ index + 0 ] = x;
29295                 this.data.array[ index + 1 ] = y;
29296                 this.data.array[ index + 2 ] = z;
29297                 this.data.array[ index + 3 ] = w;
29298
29299                 return this;
29300
29301         },
29302
29303         clone: function ( data ) {
29304
29305                 if ( data === undefined ) {
29306
29307                         console.log( 'THREE.InterleavedBufferAttribute.clone(): Cloning an interlaved buffer attribute will deinterleave buffer data.' );
29308
29309                         const array = [];
29310
29311                         for ( let i = 0; i < this.count; i ++ ) {
29312
29313                                 const index = i * this.data.stride + this.offset;
29314
29315                                 for ( let j = 0; j < this.itemSize; j ++ ) {
29316
29317                                         array.push( this.data.array[ index + j ] );
29318
29319                                 }
29320
29321                         }
29322
29323                         return new BufferAttribute( new this.array.constructor( array ), this.itemSize, this.normalized );
29324
29325                 } else {
29326
29327                         if ( data.interleavedBuffers === undefined ) {
29328
29329                                 data.interleavedBuffers = {};
29330
29331                         }
29332
29333                         if ( data.interleavedBuffers[ this.data.uuid ] === undefined ) {
29334
29335                                 data.interleavedBuffers[ this.data.uuid ] = this.data.clone( data );
29336
29337                         }
29338
29339                         return new InterleavedBufferAttribute( data.interleavedBuffers[ this.data.uuid ], this.itemSize, this.offset, this.normalized );
29340
29341                 }
29342
29343         },
29344
29345         toJSON: function ( data ) {
29346
29347                 if ( data === undefined ) {
29348
29349                         console.log( 'THREE.InterleavedBufferAttribute.toJSON(): Serializing an interlaved buffer attribute will deinterleave buffer data.' );
29350
29351                         const array = [];
29352
29353                         for ( let i = 0; i < this.count; i ++ ) {
29354
29355                                 const index = i * this.data.stride + this.offset;
29356
29357                                 for ( let j = 0; j < this.itemSize; j ++ ) {
29358
29359                                         array.push( this.data.array[ index + j ] );
29360
29361                                 }
29362
29363                         }
29364
29365                         // deinterleave data and save it as an ordinary buffer attribute for now
29366
29367                         return {
29368                                 itemSize: this.itemSize,
29369                                 type: this.array.constructor.name,
29370                                 array: array,
29371                                 normalized: this.normalized
29372                         };
29373
29374                 } else {
29375
29376                         // save as true interlaved attribtue
29377
29378                         if ( data.interleavedBuffers === undefined ) {
29379
29380                                 data.interleavedBuffers = {};
29381
29382                         }
29383
29384                         if ( data.interleavedBuffers[ this.data.uuid ] === undefined ) {
29385
29386                                 data.interleavedBuffers[ this.data.uuid ] = this.data.toJSON( data );
29387
29388                         }
29389
29390                         return {
29391                                 isInterleavedBufferAttribute: true,
29392                                 itemSize: this.itemSize,
29393                                 data: this.data.uuid,
29394                                 offset: this.offset,
29395                                 normalized: this.normalized
29396                         };
29397
29398                 }
29399
29400         }
29401
29402 } );
29403
29404 /**
29405  * parameters = {
29406  *  color: <hex>,
29407  *  map: new THREE.Texture( <Image> ),
29408  *  alphaMap: new THREE.Texture( <Image> ),
29409  *  rotation: <float>,
29410  *  sizeAttenuation: <bool>
29411  * }
29412  */
29413
29414 function SpriteMaterial( parameters ) {
29415
29416         Material.call( this );
29417
29418         this.type = 'SpriteMaterial';
29419
29420         this.color = new Color( 0xffffff );
29421
29422         this.map = null;
29423
29424         this.alphaMap = null;
29425
29426         this.rotation = 0;
29427
29428         this.sizeAttenuation = true;
29429
29430         this.transparent = true;
29431
29432         this.setValues( parameters );
29433
29434 }
29435
29436 SpriteMaterial.prototype = Object.create( Material.prototype );
29437 SpriteMaterial.prototype.constructor = SpriteMaterial;
29438 SpriteMaterial.prototype.isSpriteMaterial = true;
29439
29440 SpriteMaterial.prototype.copy = function ( source ) {
29441
29442         Material.prototype.copy.call( this, source );
29443
29444         this.color.copy( source.color );
29445
29446         this.map = source.map;
29447
29448         this.alphaMap = source.alphaMap;
29449
29450         this.rotation = source.rotation;
29451
29452         this.sizeAttenuation = source.sizeAttenuation;
29453
29454         return this;
29455
29456 };
29457
29458 let _geometry;
29459
29460 const _intersectPoint = new Vector3();
29461 const _worldScale = new Vector3();
29462 const _mvPosition = new Vector3();
29463
29464 const _alignedPosition = new Vector2();
29465 const _rotatedPosition = new Vector2();
29466 const _viewWorldMatrix = new Matrix4();
29467
29468 const _vA$1 = new Vector3();
29469 const _vB$1 = new Vector3();
29470 const _vC$1 = new Vector3();
29471
29472 const _uvA$1 = new Vector2();
29473 const _uvB$1 = new Vector2();
29474 const _uvC$1 = new Vector2();
29475
29476 function Sprite( material ) {
29477
29478         Object3D.call( this );
29479
29480         this.type = 'Sprite';
29481
29482         if ( _geometry === undefined ) {
29483
29484                 _geometry = new BufferGeometry();
29485
29486                 const float32Array = new Float32Array( [
29487                         - 0.5, - 0.5, 0, 0, 0,
29488                         0.5, - 0.5, 0, 1, 0,
29489                         0.5, 0.5, 0, 1, 1,
29490                         - 0.5, 0.5, 0, 0, 1
29491                 ] );
29492
29493                 const interleavedBuffer = new InterleavedBuffer( float32Array, 5 );
29494
29495                 _geometry.setIndex( [ 0, 1, 2,  0, 2, 3 ] );
29496                 _geometry.setAttribute( 'position', new InterleavedBufferAttribute( interleavedBuffer, 3, 0, false ) );
29497                 _geometry.setAttribute( 'uv', new InterleavedBufferAttribute( interleavedBuffer, 2, 3, false ) );
29498
29499         }
29500
29501         this.geometry = _geometry;
29502         this.material = ( material !== undefined ) ? material : new SpriteMaterial();
29503
29504         this.center = new Vector2( 0.5, 0.5 );
29505
29506 }
29507
29508 Sprite.prototype = Object.assign( Object.create( Object3D.prototype ), {
29509
29510         constructor: Sprite,
29511
29512         isSprite: true,
29513
29514         raycast: function ( raycaster, intersects ) {
29515
29516                 if ( raycaster.camera === null ) {
29517
29518                         console.error( 'THREE.Sprite: "Raycaster.camera" needs to be set in order to raycast against sprites.' );
29519
29520                 }
29521
29522                 _worldScale.setFromMatrixScale( this.matrixWorld );
29523
29524                 _viewWorldMatrix.copy( raycaster.camera.matrixWorld );
29525                 this.modelViewMatrix.multiplyMatrices( raycaster.camera.matrixWorldInverse, this.matrixWorld );
29526
29527                 _mvPosition.setFromMatrixPosition( this.modelViewMatrix );
29528
29529                 if ( raycaster.camera.isPerspectiveCamera && this.material.sizeAttenuation === false ) {
29530
29531                         _worldScale.multiplyScalar( - _mvPosition.z );
29532
29533                 }
29534
29535                 const rotation = this.material.rotation;
29536                 let sin, cos;
29537
29538                 if ( rotation !== 0 ) {
29539
29540                         cos = Math.cos( rotation );
29541                         sin = Math.sin( rotation );
29542
29543                 }
29544
29545                 const center = this.center;
29546
29547                 transformVertex( _vA$1.set( - 0.5, - 0.5, 0 ), _mvPosition, center, _worldScale, sin, cos );
29548                 transformVertex( _vB$1.set( 0.5, - 0.5, 0 ), _mvPosition, center, _worldScale, sin, cos );
29549                 transformVertex( _vC$1.set( 0.5, 0.5, 0 ), _mvPosition, center, _worldScale, sin, cos );
29550
29551                 _uvA$1.set( 0, 0 );
29552                 _uvB$1.set( 1, 0 );
29553                 _uvC$1.set( 1, 1 );
29554
29555                 // check first triangle
29556                 let intersect = raycaster.ray.intersectTriangle( _vA$1, _vB$1, _vC$1, false, _intersectPoint );
29557
29558                 if ( intersect === null ) {
29559
29560                         // check second triangle
29561                         transformVertex( _vB$1.set( - 0.5, 0.5, 0 ), _mvPosition, center, _worldScale, sin, cos );
29562                         _uvB$1.set( 0, 1 );
29563
29564                         intersect = raycaster.ray.intersectTriangle( _vA$1, _vC$1, _vB$1, false, _intersectPoint );
29565                         if ( intersect === null ) {
29566
29567                                 return;
29568
29569                         }
29570
29571                 }
29572
29573                 const distance = raycaster.ray.origin.distanceTo( _intersectPoint );
29574
29575                 if ( distance < raycaster.near || distance > raycaster.far ) return;
29576
29577                 intersects.push( {
29578
29579                         distance: distance,
29580                         point: _intersectPoint.clone(),
29581                         uv: Triangle.getUV( _intersectPoint, _vA$1, _vB$1, _vC$1, _uvA$1, _uvB$1, _uvC$1, new Vector2() ),
29582                         face: null,
29583                         object: this
29584
29585                 } );
29586
29587         },
29588
29589         copy: function ( source ) {
29590
29591                 Object3D.prototype.copy.call( this, source );
29592
29593                 if ( source.center !== undefined ) this.center.copy( source.center );
29594
29595                 this.material = source.material;
29596
29597                 return this;
29598
29599         }
29600
29601 } );
29602
29603 function transformVertex( vertexPosition, mvPosition, center, scale, sin, cos ) {
29604
29605         // compute position in camera space
29606         _alignedPosition.subVectors( vertexPosition, center ).addScalar( 0.5 ).multiply( scale );
29607
29608         // to check if rotation is not zero
29609         if ( sin !== undefined ) {
29610
29611                 _rotatedPosition.x = ( cos * _alignedPosition.x ) - ( sin * _alignedPosition.y );
29612                 _rotatedPosition.y = ( sin * _alignedPosition.x ) + ( cos * _alignedPosition.y );
29613
29614         } else {
29615
29616                 _rotatedPosition.copy( _alignedPosition );
29617
29618         }
29619
29620
29621         vertexPosition.copy( mvPosition );
29622         vertexPosition.x += _rotatedPosition.x;
29623         vertexPosition.y += _rotatedPosition.y;
29624
29625         // transform to world space
29626         vertexPosition.applyMatrix4( _viewWorldMatrix );
29627
29628 }
29629
29630 const _v1$4 = new Vector3();
29631 const _v2$2 = new Vector3();
29632
29633 function LOD() {
29634
29635         Object3D.call( this );
29636
29637         this._currentLevel = 0;
29638
29639         this.type = 'LOD';
29640
29641         Object.defineProperties( this, {
29642                 levels: {
29643                         enumerable: true,
29644                         value: []
29645                 }
29646         } );
29647
29648         this.autoUpdate = true;
29649
29650 }
29651
29652 LOD.prototype = Object.assign( Object.create( Object3D.prototype ), {
29653
29654         constructor: LOD,
29655
29656         isLOD: true,
29657
29658         copy: function ( source ) {
29659
29660                 Object3D.prototype.copy.call( this, source, false );
29661
29662                 const levels = source.levels;
29663
29664                 for ( let i = 0, l = levels.length; i < l; i ++ ) {
29665
29666                         const level = levels[ i ];
29667
29668                         this.addLevel( level.object.clone(), level.distance );
29669
29670                 }
29671
29672                 this.autoUpdate = source.autoUpdate;
29673
29674                 return this;
29675
29676         },
29677
29678         addLevel: function ( object, distance = 0 ) {
29679
29680                 distance = Math.abs( distance );
29681
29682                 const levels = this.levels;
29683
29684                 let l;
29685
29686                 for ( l = 0; l < levels.length; l ++ ) {
29687
29688                         if ( distance < levels[ l ].distance ) {
29689
29690                                 break;
29691
29692                         }
29693
29694                 }
29695
29696                 levels.splice( l, 0, { distance: distance, object: object } );
29697
29698                 this.add( object );
29699
29700                 return this;
29701
29702         },
29703
29704         getCurrentLevel: function () {
29705
29706                 return this._currentLevel;
29707
29708         },
29709
29710         getObjectForDistance: function ( distance ) {
29711
29712                 const levels = this.levels;
29713
29714                 if ( levels.length > 0 ) {
29715
29716                         let i, l;
29717
29718                         for ( i = 1, l = levels.length; i < l; i ++ ) {
29719
29720                                 if ( distance < levels[ i ].distance ) {
29721
29722                                         break;
29723
29724                                 }
29725
29726                         }
29727
29728                         return levels[ i - 1 ].object;
29729
29730                 }
29731
29732                 return null;
29733
29734         },
29735
29736         raycast: function ( raycaster, intersects ) {
29737
29738                 const levels = this.levels;
29739
29740                 if ( levels.length > 0 ) {
29741
29742                         _v1$4.setFromMatrixPosition( this.matrixWorld );
29743
29744                         const distance = raycaster.ray.origin.distanceTo( _v1$4 );
29745
29746                         this.getObjectForDistance( distance ).raycast( raycaster, intersects );
29747
29748                 }
29749
29750         },
29751
29752         update: function ( camera ) {
29753
29754                 const levels = this.levels;
29755
29756                 if ( levels.length > 1 ) {
29757
29758                         _v1$4.setFromMatrixPosition( camera.matrixWorld );
29759                         _v2$2.setFromMatrixPosition( this.matrixWorld );
29760
29761                         const distance = _v1$4.distanceTo( _v2$2 ) / camera.zoom;
29762
29763                         levels[ 0 ].object.visible = true;
29764
29765                         let i, l;
29766
29767                         for ( i = 1, l = levels.length; i < l; i ++ ) {
29768
29769                                 if ( distance >= levels[ i ].distance ) {
29770
29771                                         levels[ i - 1 ].object.visible = false;
29772                                         levels[ i ].object.visible = true;
29773
29774                                 } else {
29775
29776                                         break;
29777
29778                                 }
29779
29780                         }
29781
29782                         this._currentLevel = i - 1;
29783
29784                         for ( ; i < l; i ++ ) {
29785
29786                                 levels[ i ].object.visible = false;
29787
29788                         }
29789
29790                 }
29791
29792         },
29793
29794         toJSON: function ( meta ) {
29795
29796                 const data = Object3D.prototype.toJSON.call( this, meta );
29797
29798                 if ( this.autoUpdate === false ) data.object.autoUpdate = false;
29799
29800                 data.object.levels = [];
29801
29802                 const levels = this.levels;
29803
29804                 for ( let i = 0, l = levels.length; i < l; i ++ ) {
29805
29806                         const level = levels[ i ];
29807
29808                         data.object.levels.push( {
29809                                 object: level.object.uuid,
29810                                 distance: level.distance
29811                         } );
29812
29813                 }
29814
29815                 return data;
29816
29817         }
29818
29819 } );
29820
29821 const _basePosition = new Vector3();
29822
29823 const _skinIndex = new Vector4();
29824 const _skinWeight = new Vector4();
29825
29826 const _vector$7 = new Vector3();
29827 const _matrix$1 = new Matrix4();
29828
29829 function SkinnedMesh( geometry, material ) {
29830
29831         if ( geometry && geometry.isGeometry ) {
29832
29833                 console.error( 'THREE.SkinnedMesh no longer supports THREE.Geometry. Use THREE.BufferGeometry instead.' );
29834
29835         }
29836
29837         Mesh.call( this, geometry, material );
29838
29839         this.type = 'SkinnedMesh';
29840
29841         this.bindMode = 'attached';
29842         this.bindMatrix = new Matrix4();
29843         this.bindMatrixInverse = new Matrix4();
29844
29845 }
29846
29847 SkinnedMesh.prototype = Object.assign( Object.create( Mesh.prototype ), {
29848
29849         constructor: SkinnedMesh,
29850
29851         isSkinnedMesh: true,
29852
29853         copy: function ( source ) {
29854
29855                 Mesh.prototype.copy.call( this, source );
29856
29857                 this.bindMode = source.bindMode;
29858                 this.bindMatrix.copy( source.bindMatrix );
29859                 this.bindMatrixInverse.copy( source.bindMatrixInverse );
29860
29861                 this.skeleton = source.skeleton;
29862
29863                 return this;
29864
29865         },
29866
29867         bind: function ( skeleton, bindMatrix ) {
29868
29869                 this.skeleton = skeleton;
29870
29871                 if ( bindMatrix === undefined ) {
29872
29873                         this.updateMatrixWorld( true );
29874
29875                         this.skeleton.calculateInverses();
29876
29877                         bindMatrix = this.matrixWorld;
29878
29879                 }
29880
29881                 this.bindMatrix.copy( bindMatrix );
29882                 this.bindMatrixInverse.copy( bindMatrix ).invert();
29883
29884         },
29885
29886         pose: function () {
29887
29888                 this.skeleton.pose();
29889
29890         },
29891
29892         normalizeSkinWeights: function () {
29893
29894                 const vector = new Vector4();
29895
29896                 const skinWeight = this.geometry.attributes.skinWeight;
29897
29898                 for ( let i = 0, l = skinWeight.count; i < l; i ++ ) {
29899
29900                         vector.x = skinWeight.getX( i );
29901                         vector.y = skinWeight.getY( i );
29902                         vector.z = skinWeight.getZ( i );
29903                         vector.w = skinWeight.getW( i );
29904
29905                         const scale = 1.0 / vector.manhattanLength();
29906
29907                         if ( scale !== Infinity ) {
29908
29909                                 vector.multiplyScalar( scale );
29910
29911                         } else {
29912
29913                                 vector.set( 1, 0, 0, 0 ); // do something reasonable
29914
29915                         }
29916
29917                         skinWeight.setXYZW( i, vector.x, vector.y, vector.z, vector.w );
29918
29919                 }
29920
29921         },
29922
29923         updateMatrixWorld: function ( force ) {
29924
29925                 Mesh.prototype.updateMatrixWorld.call( this, force );
29926
29927                 if ( this.bindMode === 'attached' ) {
29928
29929                         this.bindMatrixInverse.copy( this.matrixWorld ).invert();
29930
29931                 } else if ( this.bindMode === 'detached' ) {
29932
29933                         this.bindMatrixInverse.copy( this.bindMatrix ).invert();
29934
29935                 } else {
29936
29937                         console.warn( 'THREE.SkinnedMesh: Unrecognized bindMode: ' + this.bindMode );
29938
29939                 }
29940
29941         },
29942
29943         boneTransform: function ( index, target ) {
29944
29945                 const skeleton = this.skeleton;
29946                 const geometry = this.geometry;
29947
29948                 _skinIndex.fromBufferAttribute( geometry.attributes.skinIndex, index );
29949                 _skinWeight.fromBufferAttribute( geometry.attributes.skinWeight, index );
29950
29951                 _basePosition.fromBufferAttribute( geometry.attributes.position, index ).applyMatrix4( this.bindMatrix );
29952
29953                 target.set( 0, 0, 0 );
29954
29955                 for ( let i = 0; i < 4; i ++ ) {
29956
29957                         const weight = _skinWeight.getComponent( i );
29958
29959                         if ( weight !== 0 ) {
29960
29961                                 const boneIndex = _skinIndex.getComponent( i );
29962
29963                                 _matrix$1.multiplyMatrices( skeleton.bones[ boneIndex ].matrixWorld, skeleton.boneInverses[ boneIndex ] );
29964
29965                                 target.addScaledVector( _vector$7.copy( _basePosition ).applyMatrix4( _matrix$1 ), weight );
29966
29967                         }
29968
29969                 }
29970
29971                 return target.applyMatrix4( this.bindMatrixInverse );
29972
29973         }
29974
29975 } );
29976
29977 function Bone() {
29978
29979         Object3D.call( this );
29980
29981         this.type = 'Bone';
29982
29983 }
29984
29985 Bone.prototype = Object.assign( Object.create( Object3D.prototype ), {
29986
29987         constructor: Bone,
29988
29989         isBone: true
29990
29991 } );
29992
29993 const _offsetMatrix = new Matrix4();
29994 const _identityMatrix = new Matrix4();
29995
29996 function Skeleton( bones = [], boneInverses = [] ) {
29997
29998         this.uuid = MathUtils.generateUUID();
29999
30000         this.bones = bones.slice( 0 );
30001         this.boneInverses = boneInverses;
30002         this.boneMatrices = null;
30003
30004         this.boneTexture = null;
30005         this.boneTextureSize = 0;
30006
30007         this.frame = - 1;
30008
30009         this.init();
30010
30011 }
30012
30013 Object.assign( Skeleton.prototype, {
30014
30015         init: function () {
30016
30017                 const bones = this.bones;
30018                 const boneInverses = this.boneInverses;
30019
30020                 this.boneMatrices = new Float32Array( bones.length * 16 );
30021
30022                 // calculate inverse bone matrices if necessary
30023
30024                 if ( boneInverses.length === 0 ) {
30025
30026                         this.calculateInverses();
30027
30028                 } else {
30029
30030                         // handle special case
30031
30032                         if ( bones.length !== boneInverses.length ) {
30033
30034                                 console.warn( 'THREE.Skeleton: Number of inverse bone matrices does not match amount of bones.' );
30035
30036                                 this.boneInverses = [];
30037
30038                                 for ( let i = 0, il = this.bones.length; i < il; i ++ ) {
30039
30040                                         this.boneInverses.push( new Matrix4() );
30041
30042                                 }
30043
30044                         }
30045
30046                 }
30047
30048         },
30049
30050         calculateInverses: function () {
30051
30052                 this.boneInverses.length = 0;
30053
30054                 for ( let i = 0, il = this.bones.length; i < il; i ++ ) {
30055
30056                         const inverse = new Matrix4();
30057
30058                         if ( this.bones[ i ] ) {
30059
30060                                 inverse.copy( this.bones[ i ].matrixWorld ).invert();
30061
30062                         }
30063
30064                         this.boneInverses.push( inverse );
30065
30066                 }
30067
30068         },
30069
30070         pose: function () {
30071
30072                 // recover the bind-time world matrices
30073
30074                 for ( let i = 0, il = this.bones.length; i < il; i ++ ) {
30075
30076                         const bone = this.bones[ i ];
30077
30078                         if ( bone ) {
30079
30080                                 bone.matrixWorld.copy( this.boneInverses[ i ] ).invert();
30081
30082                         }
30083
30084                 }
30085
30086                 // compute the local matrices, positions, rotations and scales
30087
30088                 for ( let i = 0, il = this.bones.length; i < il; i ++ ) {
30089
30090                         const bone = this.bones[ i ];
30091
30092                         if ( bone ) {
30093
30094                                 if ( bone.parent && bone.parent.isBone ) {
30095
30096                                         bone.matrix.copy( bone.parent.matrixWorld ).invert();
30097                                         bone.matrix.multiply( bone.matrixWorld );
30098
30099                                 } else {
30100
30101                                         bone.matrix.copy( bone.matrixWorld );
30102
30103                                 }
30104
30105                                 bone.matrix.decompose( bone.position, bone.quaternion, bone.scale );
30106
30107                         }
30108
30109                 }
30110
30111         },
30112
30113         update: function () {
30114
30115                 const bones = this.bones;
30116                 const boneInverses = this.boneInverses;
30117                 const boneMatrices = this.boneMatrices;
30118                 const boneTexture = this.boneTexture;
30119
30120                 // flatten bone matrices to array
30121
30122                 for ( let i = 0, il = bones.length; i < il; i ++ ) {
30123
30124                         // compute the offset between the current and the original transform
30125
30126                         const matrix = bones[ i ] ? bones[ i ].matrixWorld : _identityMatrix;
30127
30128                         _offsetMatrix.multiplyMatrices( matrix, boneInverses[ i ] );
30129                         _offsetMatrix.toArray( boneMatrices, i * 16 );
30130
30131                 }
30132
30133                 if ( boneTexture !== null ) {
30134
30135                         boneTexture.needsUpdate = true;
30136
30137                 }
30138
30139         },
30140
30141         clone: function () {
30142
30143                 return new Skeleton( this.bones, this.boneInverses );
30144
30145         },
30146
30147         getBoneByName: function ( name ) {
30148
30149                 for ( let i = 0, il = this.bones.length; i < il; i ++ ) {
30150
30151                         const bone = this.bones[ i ];
30152
30153                         if ( bone.name === name ) {
30154
30155                                 return bone;
30156
30157                         }
30158
30159                 }
30160
30161                 return undefined;
30162
30163         },
30164
30165         dispose: function ( ) {
30166
30167                 if ( this.boneTexture !== null ) {
30168
30169                         this.boneTexture.dispose();
30170
30171                         this.boneTexture = null;
30172
30173                 }
30174
30175         },
30176
30177         fromJSON: function ( json, bones ) {
30178
30179                 this.uuid = json.uuid;
30180
30181                 for ( let i = 0, l = json.bones.length; i < l; i ++ ) {
30182
30183                         const uuid = json.bones[ i ];
30184                         let bone = bones[ uuid ];
30185
30186                         if ( bone === undefined ) {
30187
30188                                 console.warn( 'THREE.Skeleton: No bone found with UUID:', uuid );
30189                                 bone = new Bone();
30190
30191                         }
30192
30193                         this.bones.push( bone );
30194                         this.boneInverses.push( new Matrix4().fromArray( json.boneInverses[ i ] ) );
30195
30196                 }
30197
30198                 this.init();
30199
30200                 return this;
30201
30202         },
30203
30204         toJSON: function () {
30205
30206                 const data = {
30207                         metadata: {
30208                                 version: 4.5,
30209                                 type: 'Skeleton',
30210                                 generator: 'Skeleton.toJSON'
30211                         },
30212                         bones: [],
30213                         boneInverses: []
30214                 };
30215
30216                 data.uuid = this.uuid;
30217
30218                 const bones = this.bones;
30219                 const boneInverses = this.boneInverses;
30220
30221                 for ( let i = 0, l = bones.length; i < l; i ++ ) {
30222
30223                         const bone = bones[ i ];
30224                         data.bones.push( bone.uuid );
30225
30226                         const boneInverse = boneInverses[ i ];
30227                         data.boneInverses.push( boneInverse.toArray() );
30228
30229                 }
30230
30231                 return data;
30232
30233         }
30234
30235 } );
30236
30237 const _instanceLocalMatrix = new Matrix4();
30238 const _instanceWorldMatrix = new Matrix4();
30239
30240 const _instanceIntersects = [];
30241
30242 const _mesh = new Mesh();
30243
30244 function InstancedMesh( geometry, material, count ) {
30245
30246         Mesh.call( this, geometry, material );
30247
30248         this.instanceMatrix = new BufferAttribute( new Float32Array( count * 16 ), 16 );
30249         this.instanceColor = null;
30250
30251         this.count = count;
30252
30253         this.frustumCulled = false;
30254
30255 }
30256
30257 InstancedMesh.prototype = Object.assign( Object.create( Mesh.prototype ), {
30258
30259         constructor: InstancedMesh,
30260
30261         isInstancedMesh: true,
30262
30263         copy: function ( source ) {
30264
30265                 Mesh.prototype.copy.call( this, source );
30266
30267                 this.instanceMatrix.copy( source.instanceMatrix );
30268
30269                 if ( source.instanceColor !== null ) this.instanceColor = source.instanceColor.clone();
30270
30271                 this.count = source.count;
30272
30273                 return this;
30274
30275         },
30276
30277         getColorAt: function ( index, color ) {
30278
30279                 color.fromArray( this.instanceColor.array, index * 3 );
30280
30281         },
30282
30283         getMatrixAt: function ( index, matrix ) {
30284
30285                 matrix.fromArray( this.instanceMatrix.array, index * 16 );
30286
30287         },
30288
30289         raycast: function ( raycaster, intersects ) {
30290
30291                 const matrixWorld = this.matrixWorld;
30292                 const raycastTimes = this.count;
30293
30294                 _mesh.geometry = this.geometry;
30295                 _mesh.material = this.material;
30296
30297                 if ( _mesh.material === undefined ) return;
30298
30299                 for ( let instanceId = 0; instanceId < raycastTimes; instanceId ++ ) {
30300
30301                         // calculate the world matrix for each instance
30302
30303                         this.getMatrixAt( instanceId, _instanceLocalMatrix );
30304
30305                         _instanceWorldMatrix.multiplyMatrices( matrixWorld, _instanceLocalMatrix );
30306
30307                         // the mesh represents this single instance
30308
30309                         _mesh.matrixWorld = _instanceWorldMatrix;
30310
30311                         _mesh.raycast( raycaster, _instanceIntersects );
30312
30313                         // process the result of raycast
30314
30315                         for ( let i = 0, l = _instanceIntersects.length; i < l; i ++ ) {
30316
30317                                 const intersect = _instanceIntersects[ i ];
30318                                 intersect.instanceId = instanceId;
30319                                 intersect.object = this;
30320                                 intersects.push( intersect );
30321
30322                         }
30323
30324                         _instanceIntersects.length = 0;
30325
30326                 }
30327
30328         },
30329
30330         setColorAt: function ( index, color ) {
30331
30332                 if ( this.instanceColor === null ) {
30333
30334                         this.instanceColor = new BufferAttribute( new Float32Array( this.count * 3 ), 3 );
30335
30336                 }
30337
30338                 color.toArray( this.instanceColor.array, index * 3 );
30339
30340         },
30341
30342         setMatrixAt: function ( index, matrix ) {
30343
30344                 matrix.toArray( this.instanceMatrix.array, index * 16 );
30345
30346         },
30347
30348         updateMorphTargets: function () {
30349
30350         },
30351
30352         dispose: function () {
30353
30354                 this.dispatchEvent( { type: 'dispose' } );
30355
30356         }
30357
30358 } );
30359
30360 /**
30361  * parameters = {
30362  *  color: <hex>,
30363  *  opacity: <float>,
30364  *
30365  *  linewidth: <float>,
30366  *  linecap: "round",
30367  *  linejoin: "round"
30368  * }
30369  */
30370
30371 function LineBasicMaterial( parameters ) {
30372
30373         Material.call( this );
30374
30375         this.type = 'LineBasicMaterial';
30376
30377         this.color = new Color( 0xffffff );
30378
30379         this.linewidth = 1;
30380         this.linecap = 'round';
30381         this.linejoin = 'round';
30382
30383         this.morphTargets = false;
30384
30385         this.setValues( parameters );
30386
30387 }
30388
30389 LineBasicMaterial.prototype = Object.create( Material.prototype );
30390 LineBasicMaterial.prototype.constructor = LineBasicMaterial;
30391
30392 LineBasicMaterial.prototype.isLineBasicMaterial = true;
30393
30394 LineBasicMaterial.prototype.copy = function ( source ) {
30395
30396         Material.prototype.copy.call( this, source );
30397
30398         this.color.copy( source.color );
30399
30400         this.linewidth = source.linewidth;
30401         this.linecap = source.linecap;
30402         this.linejoin = source.linejoin;
30403
30404         this.morphTargets = source.morphTargets;
30405
30406         return this;
30407
30408 };
30409
30410 const _start = new Vector3();
30411 const _end = new Vector3();
30412 const _inverseMatrix$1 = new Matrix4();
30413 const _ray$1 = new Ray();
30414 const _sphere$2 = new Sphere();
30415
30416 function Line( geometry = new BufferGeometry(), material = new LineBasicMaterial() ) {
30417
30418         Object3D.call( this );
30419
30420         this.type = 'Line';
30421
30422         this.geometry = geometry;
30423         this.material = material;
30424
30425         this.updateMorphTargets();
30426
30427 }
30428
30429 Line.prototype = Object.assign( Object.create( Object3D.prototype ), {
30430
30431         constructor: Line,
30432
30433         isLine: true,
30434
30435         copy: function ( source ) {
30436
30437                 Object3D.prototype.copy.call( this, source );
30438
30439                 this.material = source.material;
30440                 this.geometry = source.geometry;
30441
30442                 return this;
30443
30444         },
30445
30446         computeLineDistances: function () {
30447
30448                 const geometry = this.geometry;
30449
30450                 if ( geometry.isBufferGeometry ) {
30451
30452                         // we assume non-indexed geometry
30453
30454                         if ( geometry.index === null ) {
30455
30456                                 const positionAttribute = geometry.attributes.position;
30457                                 const lineDistances = [ 0 ];
30458
30459                                 for ( let i = 1, l = positionAttribute.count; i < l; i ++ ) {
30460
30461                                         _start.fromBufferAttribute( positionAttribute, i - 1 );
30462                                         _end.fromBufferAttribute( positionAttribute, i );
30463
30464                                         lineDistances[ i ] = lineDistances[ i - 1 ];
30465                                         lineDistances[ i ] += _start.distanceTo( _end );
30466
30467                                 }
30468
30469                                 geometry.setAttribute( 'lineDistance', new Float32BufferAttribute( lineDistances, 1 ) );
30470
30471                         } else {
30472
30473                                 console.warn( 'THREE.Line.computeLineDistances(): Computation only possible with non-indexed BufferGeometry.' );
30474
30475                         }
30476
30477                 } else if ( geometry.isGeometry ) {
30478
30479                         console.error( 'THREE.Line.computeLineDistances() no longer supports THREE.Geometry. Use THREE.BufferGeometry instead.' );
30480
30481                 }
30482
30483                 return this;
30484
30485         },
30486
30487         raycast: function ( raycaster, intersects ) {
30488
30489                 const geometry = this.geometry;
30490                 const matrixWorld = this.matrixWorld;
30491                 const threshold = raycaster.params.Line.threshold;
30492
30493                 // Checking boundingSphere distance to ray
30494
30495                 if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere();
30496
30497                 _sphere$2.copy( geometry.boundingSphere );
30498                 _sphere$2.applyMatrix4( matrixWorld );
30499                 _sphere$2.radius += threshold;
30500
30501                 if ( raycaster.ray.intersectsSphere( _sphere$2 ) === false ) return;
30502
30503                 //
30504
30505                 _inverseMatrix$1.copy( matrixWorld ).invert();
30506                 _ray$1.copy( raycaster.ray ).applyMatrix4( _inverseMatrix$1 );
30507
30508                 const localThreshold = threshold / ( ( this.scale.x + this.scale.y + this.scale.z ) / 3 );
30509                 const localThresholdSq = localThreshold * localThreshold;
30510
30511                 const vStart = new Vector3();
30512                 const vEnd = new Vector3();
30513                 const interSegment = new Vector3();
30514                 const interRay = new Vector3();
30515                 const step = this.isLineSegments ? 2 : 1;
30516
30517                 if ( geometry.isBufferGeometry ) {
30518
30519                         const index = geometry.index;
30520                         const attributes = geometry.attributes;
30521                         const positionAttribute = attributes.position;
30522
30523                         if ( index !== null ) {
30524
30525                                 const indices = index.array;
30526
30527                                 for ( let i = 0, l = indices.length - 1; i < l; i += step ) {
30528
30529                                         const a = indices[ i ];
30530                                         const b = indices[ i + 1 ];
30531
30532                                         vStart.fromBufferAttribute( positionAttribute, a );
30533                                         vEnd.fromBufferAttribute( positionAttribute, b );
30534
30535                                         const distSq = _ray$1.distanceSqToSegment( vStart, vEnd, interRay, interSegment );
30536
30537                                         if ( distSq > localThresholdSq ) continue;
30538
30539                                         interRay.applyMatrix4( this.matrixWorld ); //Move back to world space for distance calculation
30540
30541                                         const distance = raycaster.ray.origin.distanceTo( interRay );
30542
30543                                         if ( distance < raycaster.near || distance > raycaster.far ) continue;
30544
30545                                         intersects.push( {
30546
30547                                                 distance: distance,
30548                                                 // What do we want? intersection point on the ray or on the segment??
30549                                                 // point: raycaster.ray.at( distance ),
30550                                                 point: interSegment.clone().applyMatrix4( this.matrixWorld ),
30551                                                 index: i,
30552                                                 face: null,
30553                                                 faceIndex: null,
30554                                                 object: this
30555
30556                                         } );
30557
30558                                 }
30559
30560                         } else {
30561
30562                                 for ( let i = 0, l = positionAttribute.count - 1; i < l; i += step ) {
30563
30564                                         vStart.fromBufferAttribute( positionAttribute, i );
30565                                         vEnd.fromBufferAttribute( positionAttribute, i + 1 );
30566
30567                                         const distSq = _ray$1.distanceSqToSegment( vStart, vEnd, interRay, interSegment );
30568
30569                                         if ( distSq > localThresholdSq ) continue;
30570
30571                                         interRay.applyMatrix4( this.matrixWorld ); //Move back to world space for distance calculation
30572
30573                                         const distance = raycaster.ray.origin.distanceTo( interRay );
30574
30575                                         if ( distance < raycaster.near || distance > raycaster.far ) continue;
30576
30577                                         intersects.push( {
30578
30579                                                 distance: distance,
30580                                                 // What do we want? intersection point on the ray or on the segment??
30581                                                 // point: raycaster.ray.at( distance ),
30582                                                 point: interSegment.clone().applyMatrix4( this.matrixWorld ),
30583                                                 index: i,
30584                                                 face: null,
30585                                                 faceIndex: null,
30586                                                 object: this
30587
30588                                         } );
30589
30590                                 }
30591
30592                         }
30593
30594                 } else if ( geometry.isGeometry ) {
30595
30596                         console.error( 'THREE.Line.raycast() no longer supports THREE.Geometry. Use THREE.BufferGeometry instead.' );
30597
30598                 }
30599
30600         },
30601
30602         updateMorphTargets: function () {
30603
30604                 const geometry = this.geometry;
30605
30606                 if ( geometry.isBufferGeometry ) {
30607
30608                         const morphAttributes = geometry.morphAttributes;
30609                         const keys = Object.keys( morphAttributes );
30610
30611                         if ( keys.length > 0 ) {
30612
30613                                 const morphAttribute = morphAttributes[ keys[ 0 ] ];
30614
30615                                 if ( morphAttribute !== undefined ) {
30616
30617                                         this.morphTargetInfluences = [];
30618                                         this.morphTargetDictionary = {};
30619
30620                                         for ( let m = 0, ml = morphAttribute.length; m < ml; m ++ ) {
30621
30622                                                 const name = morphAttribute[ m ].name || String( m );
30623
30624                                                 this.morphTargetInfluences.push( 0 );
30625                                                 this.morphTargetDictionary[ name ] = m;
30626
30627                                         }
30628
30629                                 }
30630
30631                         }
30632
30633                 } else {
30634
30635                         const morphTargets = geometry.morphTargets;
30636
30637                         if ( morphTargets !== undefined && morphTargets.length > 0 ) {
30638
30639                                 console.error( 'THREE.Line.updateMorphTargets() does not support THREE.Geometry. Use THREE.BufferGeometry instead.' );
30640
30641                         }
30642
30643                 }
30644
30645         }
30646
30647 } );
30648
30649 const _start$1 = new Vector3();
30650 const _end$1 = new Vector3();
30651
30652 function LineSegments( geometry, material ) {
30653
30654         Line.call( this, geometry, material );
30655
30656         this.type = 'LineSegments';
30657
30658 }
30659
30660 LineSegments.prototype = Object.assign( Object.create( Line.prototype ), {
30661
30662         constructor: LineSegments,
30663
30664         isLineSegments: true,
30665
30666         computeLineDistances: function () {
30667
30668                 const geometry = this.geometry;
30669
30670                 if ( geometry.isBufferGeometry ) {
30671
30672                         // we assume non-indexed geometry
30673
30674                         if ( geometry.index === null ) {
30675
30676                                 const positionAttribute = geometry.attributes.position;
30677                                 const lineDistances = [];
30678
30679                                 for ( let i = 0, l = positionAttribute.count; i < l; i += 2 ) {
30680
30681                                         _start$1.fromBufferAttribute( positionAttribute, i );
30682                                         _end$1.fromBufferAttribute( positionAttribute, i + 1 );
30683
30684                                         lineDistances[ i ] = ( i === 0 ) ? 0 : lineDistances[ i - 1 ];
30685                                         lineDistances[ i + 1 ] = lineDistances[ i ] + _start$1.distanceTo( _end$1 );
30686
30687                                 }
30688
30689                                 geometry.setAttribute( 'lineDistance', new Float32BufferAttribute( lineDistances, 1 ) );
30690
30691                         } else {
30692
30693                                 console.warn( 'THREE.LineSegments.computeLineDistances(): Computation only possible with non-indexed BufferGeometry.' );
30694
30695                         }
30696
30697                 } else if ( geometry.isGeometry ) {
30698
30699                         console.error( 'THREE.LineSegments.computeLineDistances() no longer supports THREE.Geometry. Use THREE.BufferGeometry instead.' );
30700
30701                 }
30702
30703                 return this;
30704
30705         }
30706
30707 } );
30708
30709 function LineLoop( geometry, material ) {
30710
30711         Line.call( this, geometry, material );
30712
30713         this.type = 'LineLoop';
30714
30715 }
30716
30717 LineLoop.prototype = Object.assign( Object.create( Line.prototype ), {
30718
30719         constructor: LineLoop,
30720
30721         isLineLoop: true,
30722
30723 } );
30724
30725 /**
30726  * parameters = {
30727  *  color: <hex>,
30728  *  opacity: <float>,
30729  *  map: new THREE.Texture( <Image> ),
30730  *  alphaMap: new THREE.Texture( <Image> ),
30731  *
30732  *  size: <float>,
30733  *  sizeAttenuation: <bool>
30734  *
30735  *  morphTargets: <bool>
30736  * }
30737  */
30738
30739 function PointsMaterial( parameters ) {
30740
30741         Material.call( this );
30742
30743         this.type = 'PointsMaterial';
30744
30745         this.color = new Color( 0xffffff );
30746
30747         this.map = null;
30748
30749         this.alphaMap = null;
30750
30751         this.size = 1;
30752         this.sizeAttenuation = true;
30753
30754         this.morphTargets = false;
30755
30756         this.setValues( parameters );
30757
30758 }
30759
30760 PointsMaterial.prototype = Object.create( Material.prototype );
30761 PointsMaterial.prototype.constructor = PointsMaterial;
30762
30763 PointsMaterial.prototype.isPointsMaterial = true;
30764
30765 PointsMaterial.prototype.copy = function ( source ) {
30766
30767         Material.prototype.copy.call( this, source );
30768
30769         this.color.copy( source.color );
30770
30771         this.map = source.map;
30772
30773         this.alphaMap = source.alphaMap;
30774
30775         this.size = source.size;
30776         this.sizeAttenuation = source.sizeAttenuation;
30777
30778         this.morphTargets = source.morphTargets;
30779
30780         return this;
30781
30782 };
30783
30784 const _inverseMatrix$2 = new Matrix4();
30785 const _ray$2 = new Ray();
30786 const _sphere$3 = new Sphere();
30787 const _position$1 = new Vector3();
30788
30789 function Points( geometry = new BufferGeometry(), material = new PointsMaterial() ) {
30790
30791         Object3D.call( this );
30792
30793         this.type = 'Points';
30794
30795         this.geometry = geometry;
30796         this.material = material;
30797
30798         this.updateMorphTargets();
30799
30800 }
30801
30802 Points.prototype = Object.assign( Object.create( Object3D.prototype ), {
30803
30804         constructor: Points,
30805
30806         isPoints: true,
30807
30808         copy: function ( source ) {
30809
30810                 Object3D.prototype.copy.call( this, source );
30811
30812                 this.material = source.material;
30813                 this.geometry = source.geometry;
30814
30815                 return this;
30816
30817         },
30818
30819         raycast: function ( raycaster, intersects ) {
30820
30821                 const geometry = this.geometry;
30822                 const matrixWorld = this.matrixWorld;
30823                 const threshold = raycaster.params.Points.threshold;
30824
30825                 // Checking boundingSphere distance to ray
30826
30827                 if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere();
30828
30829                 _sphere$3.copy( geometry.boundingSphere );
30830                 _sphere$3.applyMatrix4( matrixWorld );
30831                 _sphere$3.radius += threshold;
30832
30833                 if ( raycaster.ray.intersectsSphere( _sphere$3 ) === false ) return;
30834
30835                 //
30836
30837                 _inverseMatrix$2.copy( matrixWorld ).invert();
30838                 _ray$2.copy( raycaster.ray ).applyMatrix4( _inverseMatrix$2 );
30839
30840                 const localThreshold = threshold / ( ( this.scale.x + this.scale.y + this.scale.z ) / 3 );
30841                 const localThresholdSq = localThreshold * localThreshold;
30842
30843                 if ( geometry.isBufferGeometry ) {
30844
30845                         const index = geometry.index;
30846                         const attributes = geometry.attributes;
30847                         const positionAttribute = attributes.position;
30848
30849                         if ( index !== null ) {
30850
30851                                 const indices = index.array;
30852
30853                                 for ( let i = 0, il = indices.length; i < il; i ++ ) {
30854
30855                                         const a = indices[ i ];
30856
30857                                         _position$1.fromBufferAttribute( positionAttribute, a );
30858
30859                                         testPoint( _position$1, a, localThresholdSq, matrixWorld, raycaster, intersects, this );
30860
30861                                 }
30862
30863                         } else {
30864
30865                                 for ( let i = 0, l = positionAttribute.count; i < l; i ++ ) {
30866
30867                                         _position$1.fromBufferAttribute( positionAttribute, i );
30868
30869                                         testPoint( _position$1, i, localThresholdSq, matrixWorld, raycaster, intersects, this );
30870
30871                                 }
30872
30873                         }
30874
30875                 } else {
30876
30877                         console.error( 'THREE.Points.raycast() no longer supports THREE.Geometry. Use THREE.BufferGeometry instead.' );
30878
30879                 }
30880
30881         },
30882
30883         updateMorphTargets: function () {
30884
30885                 const geometry = this.geometry;
30886
30887                 if ( geometry.isBufferGeometry ) {
30888
30889                         const morphAttributes = geometry.morphAttributes;
30890                         const keys = Object.keys( morphAttributes );
30891
30892                         if ( keys.length > 0 ) {
30893
30894                                 const morphAttribute = morphAttributes[ keys[ 0 ] ];
30895
30896                                 if ( morphAttribute !== undefined ) {
30897
30898                                         this.morphTargetInfluences = [];
30899                                         this.morphTargetDictionary = {};
30900
30901                                         for ( let m = 0, ml = morphAttribute.length; m < ml; m ++ ) {
30902
30903                                                 const name = morphAttribute[ m ].name || String( m );
30904
30905                                                 this.morphTargetInfluences.push( 0 );
30906                                                 this.morphTargetDictionary[ name ] = m;
30907
30908                                         }
30909
30910                                 }
30911
30912                         }
30913
30914                 } else {
30915
30916                         const morphTargets = geometry.morphTargets;
30917
30918                         if ( morphTargets !== undefined && morphTargets.length > 0 ) {
30919
30920                                 console.error( 'THREE.Points.updateMorphTargets() does not support THREE.Geometry. Use THREE.BufferGeometry instead.' );
30921
30922                         }
30923
30924                 }
30925
30926         }
30927
30928 } );
30929
30930 function testPoint( point, index, localThresholdSq, matrixWorld, raycaster, intersects, object ) {
30931
30932         const rayPointDistanceSq = _ray$2.distanceSqToPoint( point );
30933
30934         if ( rayPointDistanceSq < localThresholdSq ) {
30935
30936                 const intersectPoint = new Vector3();
30937
30938                 _ray$2.closestPointToPoint( point, intersectPoint );
30939                 intersectPoint.applyMatrix4( matrixWorld );
30940
30941                 const distance = raycaster.ray.origin.distanceTo( intersectPoint );
30942
30943                 if ( distance < raycaster.near || distance > raycaster.far ) return;
30944
30945                 intersects.push( {
30946
30947                         distance: distance,
30948                         distanceToRay: Math.sqrt( rayPointDistanceSq ),
30949                         point: intersectPoint,
30950                         index: index,
30951                         face: null,
30952                         object: object
30953
30954                 } );
30955
30956         }
30957
30958 }
30959
30960 function VideoTexture( video, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ) {
30961
30962         Texture.call( this, video, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy );
30963
30964         this.format = format !== undefined ? format : RGBFormat;
30965
30966         this.minFilter = minFilter !== undefined ? minFilter : LinearFilter;
30967         this.magFilter = magFilter !== undefined ? magFilter : LinearFilter;
30968
30969         this.generateMipmaps = false;
30970
30971         const scope = this;
30972
30973         function updateVideo() {
30974
30975                 scope.needsUpdate = true;
30976                 video.requestVideoFrameCallback( updateVideo );
30977
30978         }
30979
30980         if ( 'requestVideoFrameCallback' in video ) {
30981
30982                 video.requestVideoFrameCallback( updateVideo );
30983
30984         }
30985
30986 }
30987
30988 VideoTexture.prototype = Object.assign( Object.create( Texture.prototype ), {
30989
30990         constructor: VideoTexture,
30991
30992         clone: function () {
30993
30994                 return new this.constructor( this.image ).copy( this );
30995
30996         },
30997
30998         isVideoTexture: true,
30999
31000         update: function () {
31001
31002                 const video = this.image;
31003                 const hasVideoFrameCallback = 'requestVideoFrameCallback' in video;
31004
31005                 if ( hasVideoFrameCallback === false && video.readyState >= video.HAVE_CURRENT_DATA ) {
31006
31007                         this.needsUpdate = true;
31008
31009                 }
31010
31011         }
31012
31013 } );
31014
31015 function CompressedTexture( mipmaps, width, height, format, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy, encoding ) {
31016
31017         Texture.call( this, null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding );
31018
31019         this.image = { width: width, height: height };
31020         this.mipmaps = mipmaps;
31021
31022         // no flipping for cube textures
31023         // (also flipping doesn't work for compressed textures )
31024
31025         this.flipY = false;
31026
31027         // can't generate mipmaps for compressed textures
31028         // mips must be embedded in DDS files
31029
31030         this.generateMipmaps = false;
31031
31032 }
31033
31034 CompressedTexture.prototype = Object.create( Texture.prototype );
31035 CompressedTexture.prototype.constructor = CompressedTexture;
31036
31037 CompressedTexture.prototype.isCompressedTexture = true;
31038
31039 function CanvasTexture( canvas, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ) {
31040
31041         Texture.call( this, canvas, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy );
31042
31043         this.needsUpdate = true;
31044
31045 }
31046
31047 CanvasTexture.prototype = Object.create( Texture.prototype );
31048 CanvasTexture.prototype.constructor = CanvasTexture;
31049 CanvasTexture.prototype.isCanvasTexture = true;
31050
31051 function DepthTexture( width, height, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy, format ) {
31052
31053         format = format !== undefined ? format : DepthFormat;
31054
31055         if ( format !== DepthFormat && format !== DepthStencilFormat ) {
31056
31057                 throw new Error( 'DepthTexture format must be either THREE.DepthFormat or THREE.DepthStencilFormat' );
31058
31059         }
31060
31061         if ( type === undefined && format === DepthFormat ) type = UnsignedShortType;
31062         if ( type === undefined && format === DepthStencilFormat ) type = UnsignedInt248Type;
31063
31064         Texture.call( this, null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy );
31065
31066         this.image = { width: width, height: height };
31067
31068         this.magFilter = magFilter !== undefined ? magFilter : NearestFilter;
31069         this.minFilter = minFilter !== undefined ? minFilter : NearestFilter;
31070
31071         this.flipY = false;
31072         this.generateMipmaps = false;
31073
31074 }
31075
31076 DepthTexture.prototype = Object.create( Texture.prototype );
31077 DepthTexture.prototype.constructor = DepthTexture;
31078 DepthTexture.prototype.isDepthTexture = true;
31079
31080 class CircleGeometry extends BufferGeometry {
31081
31082         constructor( radius = 1, segments = 8, thetaStart = 0, thetaLength = Math.PI * 2 ) {
31083
31084                 super();
31085
31086                 this.type = 'CircleGeometry';
31087
31088                 this.parameters = {
31089                         radius: radius,
31090                         segments: segments,
31091                         thetaStart: thetaStart,
31092                         thetaLength: thetaLength
31093                 };
31094
31095                 segments = Math.max( 3, segments );
31096
31097                 // buffers
31098
31099                 const indices = [];
31100                 const vertices = [];
31101                 const normals = [];
31102                 const uvs = [];
31103
31104                 // helper variables
31105
31106                 const vertex = new Vector3();
31107                 const uv = new Vector2();
31108
31109                 // center point
31110
31111                 vertices.push( 0, 0, 0 );
31112                 normals.push( 0, 0, 1 );
31113                 uvs.push( 0.5, 0.5 );
31114
31115                 for ( let s = 0, i = 3; s <= segments; s ++, i += 3 ) {
31116
31117                         const segment = thetaStart + s / segments * thetaLength;
31118
31119                         // vertex
31120
31121                         vertex.x = radius * Math.cos( segment );
31122                         vertex.y = radius * Math.sin( segment );
31123
31124                         vertices.push( vertex.x, vertex.y, vertex.z );
31125
31126                         // normal
31127
31128                         normals.push( 0, 0, 1 );
31129
31130                         // uvs
31131
31132                         uv.x = ( vertices[ i ] / radius + 1 ) / 2;
31133                         uv.y = ( vertices[ i + 1 ] / radius + 1 ) / 2;
31134
31135                         uvs.push( uv.x, uv.y );
31136
31137                 }
31138
31139                 // indices
31140
31141                 for ( let i = 1; i <= segments; i ++ ) {
31142
31143                         indices.push( i, i + 1, 0 );
31144
31145                 }
31146
31147                 // build geometry
31148
31149                 this.setIndex( indices );
31150                 this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
31151                 this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
31152                 this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
31153
31154         }
31155
31156 }
31157
31158 new Vector3();
31159 new Vector3();
31160 new Vector3();
31161 new Triangle();
31162
31163 /**
31164  * Port from https://github.com/mapbox/earcut (v2.2.2)
31165  */
31166
31167 const Earcut = {
31168
31169         triangulate: function ( data, holeIndices, dim ) {
31170
31171                 dim = dim || 2;
31172
31173                 const hasHoles = holeIndices && holeIndices.length;
31174                 const outerLen = hasHoles ? holeIndices[ 0 ] * dim : data.length;
31175                 let outerNode = linkedList$1( data, 0, outerLen, dim, true );
31176                 const triangles = [];
31177
31178                 if ( ! outerNode || outerNode.next === outerNode.prev ) return triangles;
31179
31180                 let minX, minY, maxX, maxY, x, y, invSize;
31181
31182                 if ( hasHoles ) outerNode = eliminateHoles$1( data, holeIndices, outerNode, dim );
31183
31184                 // if the shape is not too simple, we'll use z-order curve hash later; calculate polygon bbox
31185                 if ( data.length > 80 * dim ) {
31186
31187                         minX = maxX = data[ 0 ];
31188                         minY = maxY = data[ 1 ];
31189
31190                         for ( let i = dim; i < outerLen; i += dim ) {
31191
31192                                 x = data[ i ];
31193                                 y = data[ i + 1 ];
31194                                 if ( x < minX ) minX = x;
31195                                 if ( y < minY ) minY = y;
31196                                 if ( x > maxX ) maxX = x;
31197                                 if ( y > maxY ) maxY = y;
31198
31199                         }
31200
31201                         // minX, minY and invSize are later used to transform coords into integers for z-order calculation
31202                         invSize = Math.max( maxX - minX, maxY - minY );
31203                         invSize = invSize !== 0 ? 1 / invSize : 0;
31204
31205                 }
31206
31207                 earcutLinked$1( outerNode, triangles, dim, minX, minY, invSize );
31208
31209                 return triangles;
31210
31211         }
31212
31213 };
31214
31215 // create a circular doubly linked list from polygon points in the specified winding order
31216 function linkedList$1( data, start, end, dim, clockwise ) {
31217
31218         let i, last;
31219
31220         if ( clockwise === ( signedArea$2( data, start, end, dim ) > 0 ) ) {
31221
31222                 for ( i = start; i < end; i += dim ) last = insertNode$2( i, data[ i ], data[ i + 1 ], last );
31223
31224         } else {
31225
31226                 for ( i = end - dim; i >= start; i -= dim ) last = insertNode$2( i, data[ i ], data[ i + 1 ], last );
31227
31228         }
31229
31230         if ( last && equals$2( last, last.next ) ) {
31231
31232                 removeNode$2( last );
31233                 last = last.next;
31234
31235         }
31236
31237         return last;
31238
31239 }
31240
31241 // eliminate colinear or duplicate points
31242 function filterPoints$1( start, end ) {
31243
31244         if ( ! start ) return start;
31245         if ( ! end ) end = start;
31246
31247         let p = start,
31248                 again;
31249         do {
31250
31251                 again = false;
31252
31253                 if ( ! p.steiner && ( equals$2( p, p.next ) || area$1( p.prev, p, p.next ) === 0 ) ) {
31254
31255                         removeNode$2( p );
31256                         p = end = p.prev;
31257                         if ( p === p.next ) break;
31258                         again = true;
31259
31260                 } else {
31261
31262                         p = p.next;
31263
31264                 }
31265
31266         } while ( again || p !== end );
31267
31268         return end;
31269
31270 }
31271
31272 // main ear slicing loop which triangulates a polygon (given as a linked list)
31273 function earcutLinked$1( ear, triangles, dim, minX, minY, invSize, pass ) {
31274
31275         if ( ! ear ) return;
31276
31277         // interlink polygon nodes in z-order
31278         if ( ! pass && invSize ) indexCurve$1( ear, minX, minY, invSize );
31279
31280         let stop = ear,
31281                 prev, next;
31282
31283         // iterate through ears, slicing them one by one
31284         while ( ear.prev !== ear.next ) {
31285
31286                 prev = ear.prev;
31287                 next = ear.next;
31288
31289                 if ( invSize ? isEarHashed$1( ear, minX, minY, invSize ) : isEar$1( ear ) ) {
31290
31291                         // cut off the triangle
31292                         triangles.push( prev.i / dim );
31293                         triangles.push( ear.i / dim );
31294                         triangles.push( next.i / dim );
31295
31296                         removeNode$2( ear );
31297
31298                         // skipping the next vertex leads to less sliver triangles
31299                         ear = next.next;
31300                         stop = next.next;
31301
31302                         continue;
31303
31304                 }
31305
31306                 ear = next;
31307
31308                 // if we looped through the whole remaining polygon and can't find any more ears
31309                 if ( ear === stop ) {
31310
31311                         // try filtering points and slicing again
31312                         if ( ! pass ) {
31313
31314                                 earcutLinked$1( filterPoints$1( ear ), triangles, dim, minX, minY, invSize, 1 );
31315
31316                                 // if this didn't work, try curing all small self-intersections locally
31317
31318                         } else if ( pass === 1 ) {
31319
31320                                 ear = cureLocalIntersections$1( filterPoints$1( ear ), triangles, dim );
31321                                 earcutLinked$1( ear, triangles, dim, minX, minY, invSize, 2 );
31322
31323                                 // as a last resort, try splitting the remaining polygon into two
31324
31325                         } else if ( pass === 2 ) {
31326
31327                                 splitEarcut$1( ear, triangles, dim, minX, minY, invSize );
31328
31329                         }
31330
31331                         break;
31332
31333                 }
31334
31335         }
31336
31337 }
31338
31339 // check whether a polygon node forms a valid ear with adjacent nodes
31340 function isEar$1( ear ) {
31341
31342         const a = ear.prev,
31343                 b = ear,
31344                 c = ear.next;
31345
31346         if ( area$1( a, b, c ) >= 0 ) return false; // reflex, can't be an ear
31347
31348         // now make sure we don't have other points inside the potential ear
31349         let p = ear.next.next;
31350
31351         while ( p !== ear.prev ) {
31352
31353                 if ( pointInTriangle$1( a.x, a.y, b.x, b.y, c.x, c.y, p.x, p.y ) &&
31354                         area$1( p.prev, p, p.next ) >= 0 ) return false;
31355                 p = p.next;
31356
31357         }
31358
31359         return true;
31360
31361 }
31362
31363 function isEarHashed$1( ear, minX, minY, invSize ) {
31364
31365         const a = ear.prev,
31366                 b = ear,
31367                 c = ear.next;
31368
31369         if ( area$1( a, b, c ) >= 0 ) return false; // reflex, can't be an ear
31370
31371         // triangle bbox; min & max are calculated like this for speed
31372         const minTX = a.x < b.x ? ( a.x < c.x ? a.x : c.x ) : ( b.x < c.x ? b.x : c.x ),
31373                 minTY = a.y < b.y ? ( a.y < c.y ? a.y : c.y ) : ( b.y < c.y ? b.y : c.y ),
31374                 maxTX = a.x > b.x ? ( a.x > c.x ? a.x : c.x ) : ( b.x > c.x ? b.x : c.x ),
31375                 maxTY = a.y > b.y ? ( a.y > c.y ? a.y : c.y ) : ( b.y > c.y ? b.y : c.y );
31376
31377         // z-order range for the current triangle bbox;
31378         const minZ = zOrder$1( minTX, minTY, minX, minY, invSize ),
31379                 maxZ = zOrder$1( maxTX, maxTY, minX, minY, invSize );
31380
31381         let p = ear.prevZ,
31382                 n = ear.nextZ;
31383
31384         // look for points inside the triangle in both directions
31385         while ( p && p.z >= minZ && n && n.z <= maxZ ) {
31386
31387                 if ( p !== ear.prev && p !== ear.next &&
31388                         pointInTriangle$1( a.x, a.y, b.x, b.y, c.x, c.y, p.x, p.y ) &&
31389                         area$1( p.prev, p, p.next ) >= 0 ) return false;
31390                 p = p.prevZ;
31391
31392                 if ( n !== ear.prev && n !== ear.next &&
31393                         pointInTriangle$1( a.x, a.y, b.x, b.y, c.x, c.y, n.x, n.y ) &&
31394                         area$1( n.prev, n, n.next ) >= 0 ) return false;
31395                 n = n.nextZ;
31396
31397         }
31398
31399         // look for remaining points in decreasing z-order
31400         while ( p && p.z >= minZ ) {
31401
31402                 if ( p !== ear.prev && p !== ear.next &&
31403                         pointInTriangle$1( a.x, a.y, b.x, b.y, c.x, c.y, p.x, p.y ) &&
31404                         area$1( p.prev, p, p.next ) >= 0 ) return false;
31405                 p = p.prevZ;
31406
31407         }
31408
31409         // look for remaining points in increasing z-order
31410         while ( n && n.z <= maxZ ) {
31411
31412                 if ( n !== ear.prev && n !== ear.next &&
31413                         pointInTriangle$1( a.x, a.y, b.x, b.y, c.x, c.y, n.x, n.y ) &&
31414                         area$1( n.prev, n, n.next ) >= 0 ) return false;
31415                 n = n.nextZ;
31416
31417         }
31418
31419         return true;
31420
31421 }
31422
31423 // go through all polygon nodes and cure small local self-intersections
31424 function cureLocalIntersections$1( start, triangles, dim ) {
31425
31426         let p = start;
31427         do {
31428
31429                 const a = p.prev,
31430                         b = p.next.next;
31431
31432                 if ( ! equals$2( a, b ) && intersects$2( a, p, p.next, b ) && locallyInside$1( a, b ) && locallyInside$1( b, a ) ) {
31433
31434                         triangles.push( a.i / dim );
31435                         triangles.push( p.i / dim );
31436                         triangles.push( b.i / dim );
31437
31438                         // remove two nodes involved
31439                         removeNode$2( p );
31440                         removeNode$2( p.next );
31441
31442                         p = start = b;
31443
31444                 }
31445
31446                 p = p.next;
31447
31448         } while ( p !== start );
31449
31450         return filterPoints$1( p );
31451
31452 }
31453
31454 // try splitting polygon into two and triangulate them independently
31455 function splitEarcut$1( start, triangles, dim, minX, minY, invSize ) {
31456
31457         // look for a valid diagonal that divides the polygon into two
31458         let a = start;
31459         do {
31460
31461                 let b = a.next.next;
31462                 while ( b !== a.prev ) {
31463
31464                         if ( a.i !== b.i && isValidDiagonal$1( a, b ) ) {
31465
31466                                 // split the polygon in two by the diagonal
31467                                 let c = splitPolygon$1( a, b );
31468
31469                                 // filter colinear points around the cuts
31470                                 a = filterPoints$1( a, a.next );
31471                                 c = filterPoints$1( c, c.next );
31472
31473                                 // run earcut on each half
31474                                 earcutLinked$1( a, triangles, dim, minX, minY, invSize );
31475                                 earcutLinked$1( c, triangles, dim, minX, minY, invSize );
31476                                 return;
31477
31478                         }
31479
31480                         b = b.next;
31481
31482                 }
31483
31484                 a = a.next;
31485
31486         } while ( a !== start );
31487
31488 }
31489
31490 // link every hole into the outer loop, producing a single-ring polygon without holes
31491 function eliminateHoles$1( data, holeIndices, outerNode, dim ) {
31492
31493         const queue = [];
31494         let i, len, start, end, list;
31495
31496         for ( i = 0, len = holeIndices.length; i < len; i ++ ) {
31497
31498                 start = holeIndices[ i ] * dim;
31499                 end = i < len - 1 ? holeIndices[ i + 1 ] * dim : data.length;
31500                 list = linkedList$1( data, start, end, dim, false );
31501                 if ( list === list.next ) list.steiner = true;
31502                 queue.push( getLeftmost$1( list ) );
31503
31504         }
31505
31506         queue.sort( compareX$1 );
31507
31508         // process holes from left to right
31509         for ( i = 0; i < queue.length; i ++ ) {
31510
31511                 eliminateHole$1( queue[ i ], outerNode );
31512                 outerNode = filterPoints$1( outerNode, outerNode.next );
31513
31514         }
31515
31516         return outerNode;
31517
31518 }
31519
31520 function compareX$1( a, b ) {
31521
31522         return a.x - b.x;
31523
31524 }
31525
31526 // find a bridge between vertices that connects hole with an outer ring and and link it
31527 function eliminateHole$1( hole, outerNode ) {
31528
31529         outerNode = findHoleBridge$1( hole, outerNode );
31530         if ( outerNode ) {
31531
31532                 const b = splitPolygon$1( outerNode, hole );
31533
31534                 // filter collinear points around the cuts
31535                 filterPoints$1( outerNode, outerNode.next );
31536                 filterPoints$1( b, b.next );
31537
31538         }
31539
31540 }
31541
31542 // David Eberly's algorithm for finding a bridge between hole and outer polygon
31543 function findHoleBridge$1( hole, outerNode ) {
31544
31545         let p = outerNode;
31546         const hx = hole.x;
31547         const hy = hole.y;
31548         let qx = - Infinity, m;
31549
31550         // find a segment intersected by a ray from the hole's leftmost point to the left;
31551         // segment's endpoint with lesser x will be potential connection point
31552         do {
31553
31554                 if ( hy <= p.y && hy >= p.next.y && p.next.y !== p.y ) {
31555
31556                         const x = p.x + ( hy - p.y ) * ( p.next.x - p.x ) / ( p.next.y - p.y );
31557                         if ( x <= hx && x > qx ) {
31558
31559                                 qx = x;
31560                                 if ( x === hx ) {
31561
31562                                         if ( hy === p.y ) return p;
31563                                         if ( hy === p.next.y ) return p.next;
31564
31565                                 }
31566
31567                                 m = p.x < p.next.x ? p : p.next;
31568
31569                         }
31570
31571                 }
31572
31573                 p = p.next;
31574
31575         } while ( p !== outerNode );
31576
31577         if ( ! m ) return null;
31578
31579         if ( hx === qx ) return m; // hole touches outer segment; pick leftmost endpoint
31580
31581         // look for points inside the triangle of hole point, segment intersection and endpoint;
31582         // if there are no points found, we have a valid connection;
31583         // otherwise choose the point of the minimum angle with the ray as connection point
31584
31585         const stop = m,
31586                 mx = m.x,
31587                 my = m.y;
31588         let tanMin = Infinity, tan;
31589
31590         p = m;
31591
31592         do {
31593
31594                 if ( hx >= p.x && p.x >= mx && hx !== p.x &&
31595                                 pointInTriangle$1( hy < my ? hx : qx, hy, mx, my, hy < my ? qx : hx, hy, p.x, p.y ) ) {
31596
31597                         tan = Math.abs( hy - p.y ) / ( hx - p.x ); // tangential
31598
31599                         if ( locallyInside$1( p, hole ) && ( tan < tanMin || ( tan === tanMin && ( p.x > m.x || ( p.x === m.x && sectorContainsSector$1( m, p ) ) ) ) ) ) {
31600
31601                                 m = p;
31602                                 tanMin = tan;
31603
31604                         }
31605
31606                 }
31607
31608                 p = p.next;
31609
31610         } while ( p !== stop );
31611
31612         return m;
31613
31614 }
31615
31616 // whether sector in vertex m contains sector in vertex p in the same coordinates
31617 function sectorContainsSector$1( m, p ) {
31618
31619         return area$1( m.prev, m, p.prev ) < 0 && area$1( p.next, m, m.next ) < 0;
31620
31621 }
31622
31623 // interlink polygon nodes in z-order
31624 function indexCurve$1( start, minX, minY, invSize ) {
31625
31626         let p = start;
31627         do {
31628
31629                 if ( p.z === null ) p.z = zOrder$1( p.x, p.y, minX, minY, invSize );
31630                 p.prevZ = p.prev;
31631                 p.nextZ = p.next;
31632                 p = p.next;
31633
31634         } while ( p !== start );
31635
31636         p.prevZ.nextZ = null;
31637         p.prevZ = null;
31638
31639         sortLinked$1( p );
31640
31641 }
31642
31643 // Simon Tatham's linked list merge sort algorithm
31644 // http://www.chiark.greenend.org.uk/~sgtatham/algorithms/listsort.html
31645 function sortLinked$1( list ) {
31646
31647         let i, p, q, e, tail, numMerges, pSize, qSize,
31648                 inSize = 1;
31649
31650         do {
31651
31652                 p = list;
31653                 list = null;
31654                 tail = null;
31655                 numMerges = 0;
31656
31657                 while ( p ) {
31658
31659                         numMerges ++;
31660                         q = p;
31661                         pSize = 0;
31662                         for ( i = 0; i < inSize; i ++ ) {
31663
31664                                 pSize ++;
31665                                 q = q.nextZ;
31666                                 if ( ! q ) break;
31667
31668                         }
31669
31670                         qSize = inSize;
31671
31672                         while ( pSize > 0 || ( qSize > 0 && q ) ) {
31673
31674                                 if ( pSize !== 0 && ( qSize === 0 || ! q || p.z <= q.z ) ) {
31675
31676                                         e = p;
31677                                         p = p.nextZ;
31678                                         pSize --;
31679
31680                                 } else {
31681
31682                                         e = q;
31683                                         q = q.nextZ;
31684                                         qSize --;
31685
31686                                 }
31687
31688                                 if ( tail ) tail.nextZ = e;
31689                                 else list = e;
31690
31691                                 e.prevZ = tail;
31692                                 tail = e;
31693
31694                         }
31695
31696                         p = q;
31697
31698                 }
31699
31700                 tail.nextZ = null;
31701                 inSize *= 2;
31702
31703         } while ( numMerges > 1 );
31704
31705         return list;
31706
31707 }
31708
31709 // z-order of a point given coords and inverse of the longer side of data bbox
31710 function zOrder$1( x, y, minX, minY, invSize ) {
31711
31712         // coords are transformed into non-negative 15-bit integer range
31713         x = 32767 * ( x - minX ) * invSize;
31714         y = 32767 * ( y - minY ) * invSize;
31715
31716         x = ( x | ( x << 8 ) ) & 0x00FF00FF;
31717         x = ( x | ( x << 4 ) ) & 0x0F0F0F0F;
31718         x = ( x | ( x << 2 ) ) & 0x33333333;
31719         x = ( x | ( x << 1 ) ) & 0x55555555;
31720
31721         y = ( y | ( y << 8 ) ) & 0x00FF00FF;
31722         y = ( y | ( y << 4 ) ) & 0x0F0F0F0F;
31723         y = ( y | ( y << 2 ) ) & 0x33333333;
31724         y = ( y | ( y << 1 ) ) & 0x55555555;
31725
31726         return x | ( y << 1 );
31727
31728 }
31729
31730 // find the leftmost node of a polygon ring
31731 function getLeftmost$1( start ) {
31732
31733         let p = start,
31734                 leftmost = start;
31735         do {
31736
31737                 if ( p.x < leftmost.x || ( p.x === leftmost.x && p.y < leftmost.y ) ) leftmost = p;
31738                 p = p.next;
31739
31740         } while ( p !== start );
31741
31742         return leftmost;
31743
31744 }
31745
31746 // check if a point lies within a convex triangle
31747 function pointInTriangle$1( ax, ay, bx, by, cx, cy, px, py ) {
31748
31749         return ( cx - px ) * ( ay - py ) - ( ax - px ) * ( cy - py ) >= 0 &&
31750                         ( ax - px ) * ( by - py ) - ( bx - px ) * ( ay - py ) >= 0 &&
31751                         ( bx - px ) * ( cy - py ) - ( cx - px ) * ( by - py ) >= 0;
31752
31753 }
31754
31755 // check if a diagonal between two polygon nodes is valid (lies in polygon interior)
31756 function isValidDiagonal$1( a, b ) {
31757
31758         return a.next.i !== b.i && a.prev.i !== b.i && ! intersectsPolygon$1( a, b ) && // dones't intersect other edges
31759                 ( locallyInside$1( a, b ) && locallyInside$1( b, a ) && middleInside$1( a, b ) && // locally visible
31760                 ( area$1( a.prev, a, b.prev ) || area$1( a, b.prev, b ) ) || // does not create opposite-facing sectors
31761                 equals$2( a, b ) && area$1( a.prev, a, a.next ) > 0 && area$1( b.prev, b, b.next ) > 0 ); // special zero-length case
31762
31763 }
31764
31765 // signed area of a triangle
31766 function area$1( p, q, r ) {
31767
31768         return ( q.y - p.y ) * ( r.x - q.x ) - ( q.x - p.x ) * ( r.y - q.y );
31769
31770 }
31771
31772 // check if two points are equal
31773 function equals$2( p1, p2 ) {
31774
31775         return p1.x === p2.x && p1.y === p2.y;
31776
31777 }
31778
31779 // check if two segments intersect
31780 function intersects$2( p1, q1, p2, q2 ) {
31781
31782         const o1 = sign$2( area$1( p1, q1, p2 ) );
31783         const o2 = sign$2( area$1( p1, q1, q2 ) );
31784         const o3 = sign$2( area$1( p2, q2, p1 ) );
31785         const o4 = sign$2( area$1( p2, q2, q1 ) );
31786
31787         if ( o1 !== o2 && o3 !== o4 ) return true; // general case
31788
31789         if ( o1 === 0 && onSegment$1( p1, p2, q1 ) ) return true; // p1, q1 and p2 are collinear and p2 lies on p1q1
31790         if ( o2 === 0 && onSegment$1( p1, q2, q1 ) ) return true; // p1, q1 and q2 are collinear and q2 lies on p1q1
31791         if ( o3 === 0 && onSegment$1( p2, p1, q2 ) ) return true; // p2, q2 and p1 are collinear and p1 lies on p2q2
31792         if ( o4 === 0 && onSegment$1( p2, q1, q2 ) ) return true; // p2, q2 and q1 are collinear and q1 lies on p2q2
31793
31794         return false;
31795
31796 }
31797
31798 // for collinear points p, q, r, check if point q lies on segment pr
31799 function onSegment$1( p, q, r ) {
31800
31801         return q.x <= Math.max( p.x, r.x ) && q.x >= Math.min( p.x, r.x ) && q.y <= Math.max( p.y, r.y ) && q.y >= Math.min( p.y, r.y );
31802
31803 }
31804
31805 function sign$2( num ) {
31806
31807         return num > 0 ? 1 : num < 0 ? - 1 : 0;
31808
31809 }
31810
31811 // check if a polygon diagonal intersects any polygon segments
31812 function intersectsPolygon$1( a, b ) {
31813
31814         let p = a;
31815         do {
31816
31817                 if ( p.i !== a.i && p.next.i !== a.i && p.i !== b.i && p.next.i !== b.i &&
31818                                 intersects$2( p, p.next, a, b ) ) return true;
31819                 p = p.next;
31820
31821         } while ( p !== a );
31822
31823         return false;
31824
31825 }
31826
31827 // check if a polygon diagonal is locally inside the polygon
31828 function locallyInside$1( a, b ) {
31829
31830         return area$1( a.prev, a, a.next ) < 0 ?
31831                 area$1( a, b, a.next ) >= 0 && area$1( a, a.prev, b ) >= 0 :
31832                 area$1( a, b, a.prev ) < 0 || area$1( a, a.next, b ) < 0;
31833
31834 }
31835
31836 // check if the middle point of a polygon diagonal is inside the polygon
31837 function middleInside$1( a, b ) {
31838
31839         let p = a,
31840                 inside = false;
31841         const px = ( a.x + b.x ) / 2,
31842                 py = ( a.y + b.y ) / 2;
31843         do {
31844
31845                 if ( ( ( p.y > py ) !== ( p.next.y > py ) ) && p.next.y !== p.y &&
31846                                 ( px < ( p.next.x - p.x ) * ( py - p.y ) / ( p.next.y - p.y ) + p.x ) )
31847                         inside = ! inside;
31848                 p = p.next;
31849
31850         } while ( p !== a );
31851
31852         return inside;
31853
31854 }
31855
31856 // link two polygon vertices with a bridge; if the vertices belong to the same ring, it splits polygon into two;
31857 // if one belongs to the outer ring and another to a hole, it merges it into a single ring
31858 function splitPolygon$1( a, b ) {
31859
31860         const a2 = new Node$1( a.i, a.x, a.y ),
31861                 b2 = new Node$1( b.i, b.x, b.y ),
31862                 an = a.next,
31863                 bp = b.prev;
31864
31865         a.next = b;
31866         b.prev = a;
31867
31868         a2.next = an;
31869         an.prev = a2;
31870
31871         b2.next = a2;
31872         a2.prev = b2;
31873
31874         bp.next = b2;
31875         b2.prev = bp;
31876
31877         return b2;
31878
31879 }
31880
31881 // create a node and optionally link it with previous one (in a circular doubly linked list)
31882 function insertNode$2( i, x, y, last ) {
31883
31884         const p = new Node$1( i, x, y );
31885
31886         if ( ! last ) {
31887
31888                 p.prev = p;
31889                 p.next = p;
31890
31891         } else {
31892
31893                 p.next = last.next;
31894                 p.prev = last;
31895                 last.next.prev = p;
31896                 last.next = p;
31897
31898         }
31899
31900         return p;
31901
31902 }
31903
31904 function removeNode$2( p ) {
31905
31906         p.next.prev = p.prev;
31907         p.prev.next = p.next;
31908
31909         if ( p.prevZ ) p.prevZ.nextZ = p.nextZ;
31910         if ( p.nextZ ) p.nextZ.prevZ = p.prevZ;
31911
31912 }
31913
31914 function Node$1( i, x, y ) {
31915
31916         // vertex index in coordinates array
31917         this.i = i;
31918
31919         // vertex coordinates
31920         this.x = x;
31921         this.y = y;
31922
31923         // previous and next vertex nodes in a polygon ring
31924         this.prev = null;
31925         this.next = null;
31926
31927         // z-order curve value
31928         this.z = null;
31929
31930         // previous and next nodes in z-order
31931         this.prevZ = null;
31932         this.nextZ = null;
31933
31934         // indicates whether this is a steiner point
31935         this.steiner = false;
31936
31937 }
31938
31939 function signedArea$2( data, start, end, dim ) {
31940
31941         let sum = 0;
31942         for ( let i = start, j = end - dim; i < end; i += dim ) {
31943
31944                 sum += ( data[ j ] - data[ i ] ) * ( data[ i + 1 ] + data[ j + 1 ] );
31945                 j = i;
31946
31947         }
31948
31949         return sum;
31950
31951 }
31952
31953 const ShapeUtils = {
31954
31955         // calculate area of the contour polygon
31956
31957         area: function ( contour ) {
31958
31959                 const n = contour.length;
31960                 let a = 0.0;
31961
31962                 for ( let p = n - 1, q = 0; q < n; p = q ++ ) {
31963
31964                         a += contour[ p ].x * contour[ q ].y - contour[ q ].x * contour[ p ].y;
31965
31966                 }
31967
31968                 return a * 0.5;
31969
31970         },
31971
31972         isClockWise: function ( pts ) {
31973
31974                 return ShapeUtils.area( pts ) < 0;
31975
31976         },
31977
31978         triangulateShape: function ( contour, holes ) {
31979
31980                 const vertices = []; // flat array of vertices like [ x0,y0, x1,y1, x2,y2, ... ]
31981                 const holeIndices = []; // array of hole indices
31982                 const faces = []; // final array of vertex indices like [ [ a,b,d ], [ b,c,d ] ]
31983
31984                 removeDupEndPts( contour );
31985                 addContour( vertices, contour );
31986
31987                 //
31988
31989                 let holeIndex = contour.length;
31990
31991                 holes.forEach( removeDupEndPts );
31992
31993                 for ( let i = 0; i < holes.length; i ++ ) {
31994
31995                         holeIndices.push( holeIndex );
31996                         holeIndex += holes[ i ].length;
31997                         addContour( vertices, holes[ i ] );
31998
31999                 }
32000
32001                 //
32002
32003                 const triangles = Earcut.triangulate( vertices, holeIndices );
32004
32005                 //
32006
32007                 for ( let i = 0; i < triangles.length; i += 3 ) {
32008
32009                         faces.push( triangles.slice( i, i + 3 ) );
32010
32011                 }
32012
32013                 return faces;
32014
32015         }
32016
32017 };
32018
32019 function removeDupEndPts( points ) {
32020
32021         const l = points.length;
32022
32023         if ( l > 2 && points[ l - 1 ].equals( points[ 0 ] ) ) {
32024
32025                 points.pop();
32026
32027         }
32028
32029 }
32030
32031 function addContour( vertices, contour ) {
32032
32033         for ( let i = 0; i < contour.length; i ++ ) {
32034
32035                 vertices.push( contour[ i ].x );
32036                 vertices.push( contour[ i ].y );
32037
32038         }
32039
32040 }
32041
32042 /**
32043  * Creates extruded geometry from a path shape.
32044  *
32045  * parameters = {
32046  *
32047  *  curveSegments: <int>, // number of points on the curves
32048  *  steps: <int>, // number of points for z-side extrusions / used for subdividing segments of extrude spline too
32049  *  depth: <float>, // Depth to extrude the shape
32050  *
32051  *  bevelEnabled: <bool>, // turn on bevel
32052  *  bevelThickness: <float>, // how deep into the original shape bevel goes
32053  *  bevelSize: <float>, // how far from shape outline (including bevelOffset) is bevel
32054  *  bevelOffset: <float>, // how far from shape outline does bevel start
32055  *  bevelSegments: <int>, // number of bevel layers
32056  *
32057  *  extrudePath: <THREE.Curve> // curve to extrude shape along
32058  *
32059  *  UVGenerator: <Object> // object that provides UV generator functions
32060  *
32061  * }
32062  */
32063
32064 class ExtrudeGeometry extends BufferGeometry {
32065
32066         constructor( shapes, options ) {
32067
32068                 super();
32069
32070                 this.type = 'ExtrudeGeometry';
32071
32072                 this.parameters = {
32073                         shapes: shapes,
32074                         options: options
32075                 };
32076
32077                 shapes = Array.isArray( shapes ) ? shapes : [ shapes ];
32078
32079                 const scope = this;
32080
32081                 const verticesArray = [];
32082                 const uvArray = [];
32083
32084                 for ( let i = 0, l = shapes.length; i < l; i ++ ) {
32085
32086                         const shape = shapes[ i ];
32087                         addShape( shape );
32088
32089                 }
32090
32091                 // build geometry
32092
32093                 this.setAttribute( 'position', new Float32BufferAttribute( verticesArray, 3 ) );
32094                 this.setAttribute( 'uv', new Float32BufferAttribute( uvArray, 2 ) );
32095
32096                 this.computeVertexNormals();
32097
32098                 // functions
32099
32100                 function addShape( shape ) {
32101
32102                         const placeholder = [];
32103
32104                         // options
32105
32106                         const curveSegments = options.curveSegments !== undefined ? options.curveSegments : 12;
32107                         const steps = options.steps !== undefined ? options.steps : 1;
32108                         let depth = options.depth !== undefined ? options.depth : 100;
32109
32110                         let bevelEnabled = options.bevelEnabled !== undefined ? options.bevelEnabled : true;
32111                         let bevelThickness = options.bevelThickness !== undefined ? options.bevelThickness : 6;
32112                         let bevelSize = options.bevelSize !== undefined ? options.bevelSize : bevelThickness - 2;
32113                         let bevelOffset = options.bevelOffset !== undefined ? options.bevelOffset : 0;
32114                         let bevelSegments = options.bevelSegments !== undefined ? options.bevelSegments : 3;
32115
32116                         const extrudePath = options.extrudePath;
32117
32118                         const uvgen = options.UVGenerator !== undefined ? options.UVGenerator : WorldUVGenerator;
32119
32120                         // deprecated options
32121
32122                         if ( options.amount !== undefined ) {
32123
32124                                 console.warn( 'THREE.ExtrudeBufferGeometry: amount has been renamed to depth.' );
32125                                 depth = options.amount;
32126
32127                         }
32128
32129                         //
32130
32131                         let extrudePts, extrudeByPath = false;
32132                         let splineTube, binormal, normal, position2;
32133
32134                         if ( extrudePath ) {
32135
32136                                 extrudePts = extrudePath.getSpacedPoints( steps );
32137
32138                                 extrudeByPath = true;
32139                                 bevelEnabled = false; // bevels not supported for path extrusion
32140
32141                                 // SETUP TNB variables
32142
32143                                 // TODO1 - have a .isClosed in spline?
32144
32145                                 splineTube = extrudePath.computeFrenetFrames( steps, false );
32146
32147                                 // console.log(splineTube, 'splineTube', splineTube.normals.length, 'steps', steps, 'extrudePts', extrudePts.length);
32148
32149                                 binormal = new Vector3();
32150                                 normal = new Vector3();
32151                                 position2 = new Vector3();
32152
32153                         }
32154
32155                         // Safeguards if bevels are not enabled
32156
32157                         if ( ! bevelEnabled ) {
32158
32159                                 bevelSegments = 0;
32160                                 bevelThickness = 0;
32161                                 bevelSize = 0;
32162                                 bevelOffset = 0;
32163
32164                         }
32165
32166                         // Variables initialization
32167
32168                         const shapePoints = shape.extractPoints( curveSegments );
32169
32170                         let vertices = shapePoints.shape;
32171                         const holes = shapePoints.holes;
32172
32173                         const reverse = ! ShapeUtils.isClockWise( vertices );
32174
32175                         if ( reverse ) {
32176
32177                                 vertices = vertices.reverse();
32178
32179                                 // Maybe we should also check if holes are in the opposite direction, just to be safe ...
32180
32181                                 for ( let h = 0, hl = holes.length; h < hl; h ++ ) {
32182
32183                                         const ahole = holes[ h ];
32184
32185                                         if ( ShapeUtils.isClockWise( ahole ) ) {
32186
32187                                                 holes[ h ] = ahole.reverse();
32188
32189                                         }
32190
32191                                 }
32192
32193                         }
32194
32195
32196                         const faces = ShapeUtils.triangulateShape( vertices, holes );
32197
32198                         /* Vertices */
32199
32200                         const contour = vertices; // vertices has all points but contour has only points of circumference
32201
32202                         for ( let h = 0, hl = holes.length; h < hl; h ++ ) {
32203
32204                                 const ahole = holes[ h ];
32205
32206                                 vertices = vertices.concat( ahole );
32207
32208                         }
32209
32210
32211                         function scalePt2( pt, vec, size ) {
32212
32213                                 if ( ! vec ) console.error( 'THREE.ExtrudeGeometry: vec does not exist' );
32214
32215                                 return vec.clone().multiplyScalar( size ).add( pt );
32216
32217                         }
32218
32219                         const vlen = vertices.length, flen = faces.length;
32220
32221
32222                         // Find directions for point movement
32223
32224
32225                         function getBevelVec( inPt, inPrev, inNext ) {
32226
32227                                 // computes for inPt the corresponding point inPt' on a new contour
32228                                 //   shifted by 1 unit (length of normalized vector) to the left
32229                                 // if we walk along contour clockwise, this new contour is outside the old one
32230                                 //
32231                                 // inPt' is the intersection of the two lines parallel to the two
32232                                 //  adjacent edges of inPt at a distance of 1 unit on the left side.
32233
32234                                 let v_trans_x, v_trans_y, shrink_by; // resulting translation vector for inPt
32235
32236                                 // good reading for geometry algorithms (here: line-line intersection)
32237                                 // http://geomalgorithms.com/a05-_intersect-1.html
32238
32239                                 const v_prev_x = inPt.x - inPrev.x,
32240                                         v_prev_y = inPt.y - inPrev.y;
32241                                 const v_next_x = inNext.x - inPt.x,
32242                                         v_next_y = inNext.y - inPt.y;
32243
32244                                 const v_prev_lensq = ( v_prev_x * v_prev_x + v_prev_y * v_prev_y );
32245
32246                                 // check for collinear edges
32247                                 const collinear0 = ( v_prev_x * v_next_y - v_prev_y * v_next_x );
32248
32249                                 if ( Math.abs( collinear0 ) > Number.EPSILON ) {
32250
32251                                         // not collinear
32252
32253                                         // length of vectors for normalizing
32254
32255                                         const v_prev_len = Math.sqrt( v_prev_lensq );
32256                                         const v_next_len = Math.sqrt( v_next_x * v_next_x + v_next_y * v_next_y );
32257
32258                                         // shift adjacent points by unit vectors to the left
32259
32260                                         const ptPrevShift_x = ( inPrev.x - v_prev_y / v_prev_len );
32261                                         const ptPrevShift_y = ( inPrev.y + v_prev_x / v_prev_len );
32262
32263                                         const ptNextShift_x = ( inNext.x - v_next_y / v_next_len );
32264                                         const ptNextShift_y = ( inNext.y + v_next_x / v_next_len );
32265
32266                                         // scaling factor for v_prev to intersection point
32267
32268                                         const sf = ( ( ptNextShift_x - ptPrevShift_x ) * v_next_y -
32269                                                         ( ptNextShift_y - ptPrevShift_y ) * v_next_x ) /
32270                                                 ( v_prev_x * v_next_y - v_prev_y * v_next_x );
32271
32272                                         // vector from inPt to intersection point
32273
32274                                         v_trans_x = ( ptPrevShift_x + v_prev_x * sf - inPt.x );
32275                                         v_trans_y = ( ptPrevShift_y + v_prev_y * sf - inPt.y );
32276
32277                                         // Don't normalize!, otherwise sharp corners become ugly
32278                                         //  but prevent crazy spikes
32279                                         const v_trans_lensq = ( v_trans_x * v_trans_x + v_trans_y * v_trans_y );
32280                                         if ( v_trans_lensq <= 2 ) {
32281
32282                                                 return new Vector2( v_trans_x, v_trans_y );
32283
32284                                         } else {
32285
32286                                                 shrink_by = Math.sqrt( v_trans_lensq / 2 );
32287
32288                                         }
32289
32290                                 } else {
32291
32292                                         // handle special case of collinear edges
32293
32294                                         let direction_eq = false; // assumes: opposite
32295
32296                                         if ( v_prev_x > Number.EPSILON ) {
32297
32298                                                 if ( v_next_x > Number.EPSILON ) {
32299
32300                                                         direction_eq = true;
32301
32302                                                 }
32303
32304                                         } else {
32305
32306                                                 if ( v_prev_x < - Number.EPSILON ) {
32307
32308                                                         if ( v_next_x < - Number.EPSILON ) {
32309
32310                                                                 direction_eq = true;
32311
32312                                                         }
32313
32314                                                 } else {
32315
32316                                                         if ( Math.sign( v_prev_y ) === Math.sign( v_next_y ) ) {
32317
32318                                                                 direction_eq = true;
32319
32320                                                         }
32321
32322                                                 }
32323
32324                                         }
32325
32326                                         if ( direction_eq ) {
32327
32328                                                 // console.log("Warning: lines are a straight sequence");
32329                                                 v_trans_x = - v_prev_y;
32330                                                 v_trans_y = v_prev_x;
32331                                                 shrink_by = Math.sqrt( v_prev_lensq );
32332
32333                                         } else {
32334
32335                                                 // console.log("Warning: lines are a straight spike");
32336                                                 v_trans_x = v_prev_x;
32337                                                 v_trans_y = v_prev_y;
32338                                                 shrink_by = Math.sqrt( v_prev_lensq / 2 );
32339
32340                                         }
32341
32342                                 }
32343
32344                                 return new Vector2( v_trans_x / shrink_by, v_trans_y / shrink_by );
32345
32346                         }
32347
32348
32349                         const contourMovements = [];
32350
32351                         for ( let i = 0, il = contour.length, j = il - 1, k = i + 1; i < il; i ++, j ++, k ++ ) {
32352
32353                                 if ( j === il ) j = 0;
32354                                 if ( k === il ) k = 0;
32355
32356                                 //  (j)---(i)---(k)
32357                                 // console.log('i,j,k', i, j , k)
32358
32359                                 contourMovements[ i ] = getBevelVec( contour[ i ], contour[ j ], contour[ k ] );
32360
32361                         }
32362
32363                         const holesMovements = [];
32364                         let oneHoleMovements, verticesMovements = contourMovements.concat();
32365
32366                         for ( let h = 0, hl = holes.length; h < hl; h ++ ) {
32367
32368                                 const ahole = holes[ h ];
32369
32370                                 oneHoleMovements = [];
32371
32372                                 for ( let i = 0, il = ahole.length, j = il - 1, k = i + 1; i < il; i ++, j ++, k ++ ) {
32373
32374                                         if ( j === il ) j = 0;
32375                                         if ( k === il ) k = 0;
32376
32377                                         //  (j)---(i)---(k)
32378                                         oneHoleMovements[ i ] = getBevelVec( ahole[ i ], ahole[ j ], ahole[ k ] );
32379
32380                                 }
32381
32382                                 holesMovements.push( oneHoleMovements );
32383                                 verticesMovements = verticesMovements.concat( oneHoleMovements );
32384
32385                         }
32386
32387
32388                         // Loop bevelSegments, 1 for the front, 1 for the back
32389
32390                         for ( let b = 0; b < bevelSegments; b ++ ) {
32391
32392                                 //for ( b = bevelSegments; b > 0; b -- ) {
32393
32394                                 const t = b / bevelSegments;
32395                                 const z = bevelThickness * Math.cos( t * Math.PI / 2 );
32396                                 const bs = bevelSize * Math.sin( t * Math.PI / 2 ) + bevelOffset;
32397
32398                                 // contract shape
32399
32400                                 for ( let i = 0, il = contour.length; i < il; i ++ ) {
32401
32402                                         const vert = scalePt2( contour[ i ], contourMovements[ i ], bs );
32403
32404                                         v( vert.x, vert.y, - z );
32405
32406                                 }
32407
32408                                 // expand holes
32409
32410                                 for ( let h = 0, hl = holes.length; h < hl; h ++ ) {
32411
32412                                         const ahole = holes[ h ];
32413                                         oneHoleMovements = holesMovements[ h ];
32414
32415                                         for ( let i = 0, il = ahole.length; i < il; i ++ ) {
32416
32417                                                 const vert = scalePt2( ahole[ i ], oneHoleMovements[ i ], bs );
32418
32419                                                 v( vert.x, vert.y, - z );
32420
32421                                         }
32422
32423                                 }
32424
32425                         }
32426
32427                         const bs = bevelSize + bevelOffset;
32428
32429                         // Back facing vertices
32430
32431                         for ( let i = 0; i < vlen; i ++ ) {
32432
32433                                 const vert = bevelEnabled ? scalePt2( vertices[ i ], verticesMovements[ i ], bs ) : vertices[ i ];
32434
32435                                 if ( ! extrudeByPath ) {
32436
32437                                         v( vert.x, vert.y, 0 );
32438
32439                                 } else {
32440
32441                                         // v( vert.x, vert.y + extrudePts[ 0 ].y, extrudePts[ 0 ].x );
32442
32443                                         normal.copy( splineTube.normals[ 0 ] ).multiplyScalar( vert.x );
32444                                         binormal.copy( splineTube.binormals[ 0 ] ).multiplyScalar( vert.y );
32445
32446                                         position2.copy( extrudePts[ 0 ] ).add( normal ).add( binormal );
32447
32448                                         v( position2.x, position2.y, position2.z );
32449
32450                                 }
32451
32452                         }
32453
32454                         // Add stepped vertices...
32455                         // Including front facing vertices
32456
32457                         for ( let s = 1; s <= steps; s ++ ) {
32458
32459                                 for ( let i = 0; i < vlen; i ++ ) {
32460
32461                                         const vert = bevelEnabled ? scalePt2( vertices[ i ], verticesMovements[ i ], bs ) : vertices[ i ];
32462
32463                                         if ( ! extrudeByPath ) {
32464
32465                                                 v( vert.x, vert.y, depth / steps * s );
32466
32467                                         } else {
32468
32469                                                 // v( vert.x, vert.y + extrudePts[ s - 1 ].y, extrudePts[ s - 1 ].x );
32470
32471                                                 normal.copy( splineTube.normals[ s ] ).multiplyScalar( vert.x );
32472                                                 binormal.copy( splineTube.binormals[ s ] ).multiplyScalar( vert.y );
32473
32474                                                 position2.copy( extrudePts[ s ] ).add( normal ).add( binormal );
32475
32476                                                 v( position2.x, position2.y, position2.z );
32477
32478                                         }
32479
32480                                 }
32481
32482                         }
32483
32484
32485                         // Add bevel segments planes
32486
32487                         //for ( b = 1; b <= bevelSegments; b ++ ) {
32488                         for ( let b = bevelSegments - 1; b >= 0; b -- ) {
32489
32490                                 const t = b / bevelSegments;
32491                                 const z = bevelThickness * Math.cos( t * Math.PI / 2 );
32492                                 const bs = bevelSize * Math.sin( t * Math.PI / 2 ) + bevelOffset;
32493
32494                                 // contract shape
32495
32496                                 for ( let i = 0, il = contour.length; i < il; i ++ ) {
32497
32498                                         const vert = scalePt2( contour[ i ], contourMovements[ i ], bs );
32499                                         v( vert.x, vert.y, depth + z );
32500
32501                                 }
32502
32503                                 // expand holes
32504
32505                                 for ( let h = 0, hl = holes.length; h < hl; h ++ ) {
32506
32507                                         const ahole = holes[ h ];
32508                                         oneHoleMovements = holesMovements[ h ];
32509
32510                                         for ( let i = 0, il = ahole.length; i < il; i ++ ) {
32511
32512                                                 const vert = scalePt2( ahole[ i ], oneHoleMovements[ i ], bs );
32513
32514                                                 if ( ! extrudeByPath ) {
32515
32516                                                         v( vert.x, vert.y, depth + z );
32517
32518                                                 } else {
32519
32520                                                         v( vert.x, vert.y + extrudePts[ steps - 1 ].y, extrudePts[ steps - 1 ].x + z );
32521
32522                                                 }
32523
32524                                         }
32525
32526                                 }
32527
32528                         }
32529
32530                         /* Faces */
32531
32532                         // Top and bottom faces
32533
32534                         buildLidFaces();
32535
32536                         // Sides faces
32537
32538                         buildSideFaces();
32539
32540
32541                         /////  Internal functions
32542
32543                         function buildLidFaces() {
32544
32545                                 const start = verticesArray.length / 3;
32546
32547                                 if ( bevelEnabled ) {
32548
32549                                         let layer = 0; // steps + 1
32550                                         let offset = vlen * layer;
32551
32552                                         // Bottom faces
32553
32554                                         for ( let i = 0; i < flen; i ++ ) {
32555
32556                                                 const face = faces[ i ];
32557                                                 f3( face[ 2 ] + offset, face[ 1 ] + offset, face[ 0 ] + offset );
32558
32559                                         }
32560
32561                                         layer = steps + bevelSegments * 2;
32562                                         offset = vlen * layer;
32563
32564                                         // Top faces
32565
32566                                         for ( let i = 0; i < flen; i ++ ) {
32567
32568                                                 const face = faces[ i ];
32569                                                 f3( face[ 0 ] + offset, face[ 1 ] + offset, face[ 2 ] + offset );
32570
32571                                         }
32572
32573                                 } else {
32574
32575                                         // Bottom faces
32576
32577                                         for ( let i = 0; i < flen; i ++ ) {
32578
32579                                                 const face = faces[ i ];
32580                                                 f3( face[ 2 ], face[ 1 ], face[ 0 ] );
32581
32582                                         }
32583
32584                                         // Top faces
32585
32586                                         for ( let i = 0; i < flen; i ++ ) {
32587
32588                                                 const face = faces[ i ];
32589                                                 f3( face[ 0 ] + vlen * steps, face[ 1 ] + vlen * steps, face[ 2 ] + vlen * steps );
32590
32591                                         }
32592
32593                                 }
32594
32595                                 scope.addGroup( start, verticesArray.length / 3 - start, 0 );
32596
32597                         }
32598
32599                         // Create faces for the z-sides of the shape
32600
32601                         function buildSideFaces() {
32602
32603                                 const start = verticesArray.length / 3;
32604                                 let layeroffset = 0;
32605                                 sidewalls( contour, layeroffset );
32606                                 layeroffset += contour.length;
32607
32608                                 for ( let h = 0, hl = holes.length; h < hl; h ++ ) {
32609
32610                                         const ahole = holes[ h ];
32611                                         sidewalls( ahole, layeroffset );
32612
32613                                         //, true
32614                                         layeroffset += ahole.length;
32615
32616                                 }
32617
32618
32619                                 scope.addGroup( start, verticesArray.length / 3 - start, 1 );
32620
32621
32622                         }
32623
32624                         function sidewalls( contour, layeroffset ) {
32625
32626                                 let i = contour.length;
32627
32628                                 while ( -- i >= 0 ) {
32629
32630                                         const j = i;
32631                                         let k = i - 1;
32632                                         if ( k < 0 ) k = contour.length - 1;
32633
32634                                         //console.log('b', i,j, i-1, k,vertices.length);
32635
32636                                         for ( let s = 0, sl = ( steps + bevelSegments * 2 ); s < sl; s ++ ) {
32637
32638                                                 const slen1 = vlen * s;
32639                                                 const slen2 = vlen * ( s + 1 );
32640
32641                                                 const a = layeroffset + j + slen1,
32642                                                         b = layeroffset + k + slen1,
32643                                                         c = layeroffset + k + slen2,
32644                                                         d = layeroffset + j + slen2;
32645
32646                                                 f4( a, b, c, d );
32647
32648                                         }
32649
32650                                 }
32651
32652                         }
32653
32654                         function v( x, y, z ) {
32655
32656                                 placeholder.push( x );
32657                                 placeholder.push( y );
32658                                 placeholder.push( z );
32659
32660                         }
32661
32662
32663                         function f3( a, b, c ) {
32664
32665                                 addVertex( a );
32666                                 addVertex( b );
32667                                 addVertex( c );
32668
32669                                 const nextIndex = verticesArray.length / 3;
32670                                 const uvs = uvgen.generateTopUV( scope, verticesArray, nextIndex - 3, nextIndex - 2, nextIndex - 1 );
32671
32672                                 addUV( uvs[ 0 ] );
32673                                 addUV( uvs[ 1 ] );
32674                                 addUV( uvs[ 2 ] );
32675
32676                         }
32677
32678                         function f4( a, b, c, d ) {
32679
32680                                 addVertex( a );
32681                                 addVertex( b );
32682                                 addVertex( d );
32683
32684                                 addVertex( b );
32685                                 addVertex( c );
32686                                 addVertex( d );
32687
32688
32689                                 const nextIndex = verticesArray.length / 3;
32690                                 const uvs = uvgen.generateSideWallUV( scope, verticesArray, nextIndex - 6, nextIndex - 3, nextIndex - 2, nextIndex - 1 );
32691
32692                                 addUV( uvs[ 0 ] );
32693                                 addUV( uvs[ 1 ] );
32694                                 addUV( uvs[ 3 ] );
32695
32696                                 addUV( uvs[ 1 ] );
32697                                 addUV( uvs[ 2 ] );
32698                                 addUV( uvs[ 3 ] );
32699
32700                         }
32701
32702                         function addVertex( index ) {
32703
32704                                 verticesArray.push( placeholder[ index * 3 + 0 ] );
32705                                 verticesArray.push( placeholder[ index * 3 + 1 ] );
32706                                 verticesArray.push( placeholder[ index * 3 + 2 ] );
32707
32708                         }
32709
32710
32711                         function addUV( vector2 ) {
32712
32713                                 uvArray.push( vector2.x );
32714                                 uvArray.push( vector2.y );
32715
32716                         }
32717
32718                 }
32719
32720         }
32721
32722         toJSON() {
32723
32724                 const data = BufferGeometry.prototype.toJSON.call( this );
32725
32726                 const shapes = this.parameters.shapes;
32727                 const options = this.parameters.options;
32728
32729                 return toJSON( shapes, options, data );
32730
32731         }
32732
32733 }
32734
32735 const WorldUVGenerator = {
32736
32737         generateTopUV: function ( geometry, vertices, indexA, indexB, indexC ) {
32738
32739                 const a_x = vertices[ indexA * 3 ];
32740                 const a_y = vertices[ indexA * 3 + 1 ];
32741                 const b_x = vertices[ indexB * 3 ];
32742                 const b_y = vertices[ indexB * 3 + 1 ];
32743                 const c_x = vertices[ indexC * 3 ];
32744                 const c_y = vertices[ indexC * 3 + 1 ];
32745
32746                 return [
32747                         new Vector2( a_x, a_y ),
32748                         new Vector2( b_x, b_y ),
32749                         new Vector2( c_x, c_y )
32750                 ];
32751
32752         },
32753
32754         generateSideWallUV: function ( geometry, vertices, indexA, indexB, indexC, indexD ) {
32755
32756                 const a_x = vertices[ indexA * 3 ];
32757                 const a_y = vertices[ indexA * 3 + 1 ];
32758                 const a_z = vertices[ indexA * 3 + 2 ];
32759                 const b_x = vertices[ indexB * 3 ];
32760                 const b_y = vertices[ indexB * 3 + 1 ];
32761                 const b_z = vertices[ indexB * 3 + 2 ];
32762                 const c_x = vertices[ indexC * 3 ];
32763                 const c_y = vertices[ indexC * 3 + 1 ];
32764                 const c_z = vertices[ indexC * 3 + 2 ];
32765                 const d_x = vertices[ indexD * 3 ];
32766                 const d_y = vertices[ indexD * 3 + 1 ];
32767                 const d_z = vertices[ indexD * 3 + 2 ];
32768
32769                 if ( Math.abs( a_y - b_y ) < 0.01 ) {
32770
32771                         return [
32772                                 new Vector2( a_x, 1 - a_z ),
32773                                 new Vector2( b_x, 1 - b_z ),
32774                                 new Vector2( c_x, 1 - c_z ),
32775                                 new Vector2( d_x, 1 - d_z )
32776                         ];
32777
32778                 } else {
32779
32780                         return [
32781                                 new Vector2( a_y, 1 - a_z ),
32782                                 new Vector2( b_y, 1 - b_z ),
32783                                 new Vector2( c_y, 1 - c_z ),
32784                                 new Vector2( d_y, 1 - d_z )
32785                         ];
32786
32787                 }
32788
32789         }
32790
32791 };
32792
32793 function toJSON( shapes, options, data ) {
32794
32795         data.shapes = [];
32796
32797         if ( Array.isArray( shapes ) ) {
32798
32799                 for ( let i = 0, l = shapes.length; i < l; i ++ ) {
32800
32801                         const shape = shapes[ i ];
32802
32803                         data.shapes.push( shape.uuid );
32804
32805                 }
32806
32807         } else {
32808
32809                 data.shapes.push( shapes.uuid );
32810
32811         }
32812
32813         if ( options.extrudePath !== undefined ) data.options.extrudePath = options.extrudePath.toJSON();
32814
32815         return data;
32816
32817 }
32818
32819 /**
32820  * Parametric Surfaces Geometry
32821  * based on the brilliant article by @prideout https://prideout.net/blog/old/blog/index.html@p=44.html
32822  */
32823
32824 function ParametricGeometry( func, slices, stacks ) {
32825
32826         BufferGeometry.call( this );
32827
32828         this.type = 'ParametricGeometry';
32829
32830         this.parameters = {
32831                 func: func,
32832                 slices: slices,
32833                 stacks: stacks
32834         };
32835
32836         // buffers
32837
32838         const indices = [];
32839         const vertices = [];
32840         const normals = [];
32841         const uvs = [];
32842
32843         const EPS = 0.00001;
32844
32845         const normal = new Vector3();
32846
32847         const p0 = new Vector3(), p1 = new Vector3();
32848         const pu = new Vector3(), pv = new Vector3();
32849
32850         if ( func.length < 3 ) {
32851
32852                 console.error( 'THREE.ParametricGeometry: Function must now modify a Vector3 as third parameter.' );
32853
32854         }
32855
32856         // generate vertices, normals and uvs
32857
32858         const sliceCount = slices + 1;
32859
32860         for ( let i = 0; i <= stacks; i ++ ) {
32861
32862                 const v = i / stacks;
32863
32864                 for ( let j = 0; j <= slices; j ++ ) {
32865
32866                         const u = j / slices;
32867
32868                         // vertex
32869
32870                         func( u, v, p0 );
32871                         vertices.push( p0.x, p0.y, p0.z );
32872
32873                         // normal
32874
32875                         // approximate tangent vectors via finite differences
32876
32877                         if ( u - EPS >= 0 ) {
32878
32879                                 func( u - EPS, v, p1 );
32880                                 pu.subVectors( p0, p1 );
32881
32882                         } else {
32883
32884                                 func( u + EPS, v, p1 );
32885                                 pu.subVectors( p1, p0 );
32886
32887                         }
32888
32889                         if ( v - EPS >= 0 ) {
32890
32891                                 func( u, v - EPS, p1 );
32892                                 pv.subVectors( p0, p1 );
32893
32894                         } else {
32895
32896                                 func( u, v + EPS, p1 );
32897                                 pv.subVectors( p1, p0 );
32898
32899                         }
32900
32901                         // cross product of tangent vectors returns surface normal
32902
32903                         normal.crossVectors( pu, pv ).normalize();
32904                         normals.push( normal.x, normal.y, normal.z );
32905
32906                         // uv
32907
32908                         uvs.push( u, v );
32909
32910                 }
32911
32912         }
32913
32914         // generate indices
32915
32916         for ( let i = 0; i < stacks; i ++ ) {
32917
32918                 for ( let j = 0; j < slices; j ++ ) {
32919
32920                         const a = i * sliceCount + j;
32921                         const b = i * sliceCount + j + 1;
32922                         const c = ( i + 1 ) * sliceCount + j + 1;
32923                         const d = ( i + 1 ) * sliceCount + j;
32924
32925                         // faces one and two
32926
32927                         indices.push( a, b, d );
32928                         indices.push( b, c, d );
32929
32930                 }
32931
32932         }
32933
32934         // build geometry
32935
32936         this.setIndex( indices );
32937         this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
32938         this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
32939         this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
32940
32941 }
32942
32943 ParametricGeometry.prototype = Object.create( BufferGeometry.prototype );
32944 ParametricGeometry.prototype.constructor = ParametricGeometry;
32945
32946 class ShapeGeometry extends BufferGeometry {
32947
32948         constructor( shapes, curveSegments = 12 ) {
32949
32950                 super();
32951                 this.type = 'ShapeGeometry';
32952
32953                 this.parameters = {
32954                         shapes: shapes,
32955                         curveSegments: curveSegments
32956                 };
32957
32958                 // buffers
32959
32960                 const indices = [];
32961                 const vertices = [];
32962                 const normals = [];
32963                 const uvs = [];
32964
32965                 // helper variables
32966
32967                 let groupStart = 0;
32968                 let groupCount = 0;
32969
32970                 // allow single and array values for "shapes" parameter
32971
32972                 if ( Array.isArray( shapes ) === false ) {
32973
32974                         addShape( shapes );
32975
32976                 } else {
32977
32978                         for ( let i = 0; i < shapes.length; i ++ ) {
32979
32980                                 addShape( shapes[ i ] );
32981
32982                                 this.addGroup( groupStart, groupCount, i ); // enables MultiMaterial support
32983
32984                                 groupStart += groupCount;
32985                                 groupCount = 0;
32986
32987                         }
32988
32989                 }
32990
32991                 // build geometry
32992
32993                 this.setIndex( indices );
32994                 this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
32995                 this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
32996                 this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
32997
32998
32999                 // helper functions
33000
33001                 function addShape( shape ) {
33002
33003                         const indexOffset = vertices.length / 3;
33004                         const points = shape.extractPoints( curveSegments );
33005
33006                         let shapeVertices = points.shape;
33007                         const shapeHoles = points.holes;
33008
33009                         // check direction of vertices
33010
33011                         if ( ShapeUtils.isClockWise( shapeVertices ) === false ) {
33012
33013                                 shapeVertices = shapeVertices.reverse();
33014
33015                         }
33016
33017                         for ( let i = 0, l = shapeHoles.length; i < l; i ++ ) {
33018
33019                                 const shapeHole = shapeHoles[ i ];
33020
33021                                 if ( ShapeUtils.isClockWise( shapeHole ) === true ) {
33022
33023                                         shapeHoles[ i ] = shapeHole.reverse();
33024
33025                                 }
33026
33027                         }
33028
33029                         const faces = ShapeUtils.triangulateShape( shapeVertices, shapeHoles );
33030
33031                         // join vertices of inner and outer paths to a single array
33032
33033                         for ( let i = 0, l = shapeHoles.length; i < l; i ++ ) {
33034
33035                                 const shapeHole = shapeHoles[ i ];
33036                                 shapeVertices = shapeVertices.concat( shapeHole );
33037
33038                         }
33039
33040                         // vertices, normals, uvs
33041
33042                         for ( let i = 0, l = shapeVertices.length; i < l; i ++ ) {
33043
33044                                 const vertex = shapeVertices[ i ];
33045
33046                                 vertices.push( vertex.x, vertex.y, 0 );
33047                                 normals.push( 0, 0, 1 );
33048                                 uvs.push( vertex.x, vertex.y ); // world uvs
33049
33050                         }
33051
33052                         // incides
33053
33054                         for ( let i = 0, l = faces.length; i < l; i ++ ) {
33055
33056                                 const face = faces[ i ];
33057
33058                                 const a = face[ 0 ] + indexOffset;
33059                                 const b = face[ 1 ] + indexOffset;
33060                                 const c = face[ 2 ] + indexOffset;
33061
33062                                 indices.push( a, b, c );
33063                                 groupCount += 3;
33064
33065                         }
33066
33067                 }
33068
33069         }
33070
33071         toJSON() {
33072
33073                 const data = BufferGeometry.prototype.toJSON.call( this );
33074
33075                 const shapes = this.parameters.shapes;
33076
33077                 return toJSON$1( shapes, data );
33078
33079         }
33080
33081 }
33082
33083 function toJSON$1( shapes, data ) {
33084
33085         data.shapes = [];
33086
33087         if ( Array.isArray( shapes ) ) {
33088
33089                 for ( let i = 0, l = shapes.length; i < l; i ++ ) {
33090
33091                         const shape = shapes[ i ];
33092
33093                         data.shapes.push( shape.uuid );
33094
33095                 }
33096
33097         } else {
33098
33099                 data.shapes.push( shapes.uuid );
33100
33101         }
33102
33103         return data;
33104
33105 }
33106
33107 class SphereGeometry extends BufferGeometry {
33108
33109         constructor( radius = 1, widthSegments = 8, heightSegments = 6, phiStart = 0, phiLength = Math.PI * 2, thetaStart = 0, thetaLength = Math.PI ) {
33110
33111                 super();
33112                 this.type = 'SphereGeometry';
33113
33114                 this.parameters = {
33115                         radius: radius,
33116                         widthSegments: widthSegments,
33117                         heightSegments: heightSegments,
33118                         phiStart: phiStart,
33119                         phiLength: phiLength,
33120                         thetaStart: thetaStart,
33121                         thetaLength: thetaLength
33122                 };
33123
33124                 widthSegments = Math.max( 3, Math.floor( widthSegments ) );
33125                 heightSegments = Math.max( 2, Math.floor( heightSegments ) );
33126
33127                 const thetaEnd = Math.min( thetaStart + thetaLength, Math.PI );
33128
33129                 let index = 0;
33130                 const grid = [];
33131
33132                 const vertex = new Vector3();
33133                 const normal = new Vector3();
33134
33135                 // buffers
33136
33137                 const indices = [];
33138                 const vertices = [];
33139                 const normals = [];
33140                 const uvs = [];
33141
33142                 // generate vertices, normals and uvs
33143
33144                 for ( let iy = 0; iy <= heightSegments; iy ++ ) {
33145
33146                         const verticesRow = [];
33147
33148                         const v = iy / heightSegments;
33149
33150                         // special case for the poles
33151
33152                         let uOffset = 0;
33153
33154                         if ( iy == 0 && thetaStart == 0 ) {
33155
33156                                 uOffset = 0.5 / widthSegments;
33157
33158                         } else if ( iy == heightSegments && thetaEnd == Math.PI ) {
33159
33160                                 uOffset = - 0.5 / widthSegments;
33161
33162                         }
33163
33164                         for ( let ix = 0; ix <= widthSegments; ix ++ ) {
33165
33166                                 const u = ix / widthSegments;
33167
33168                                 // vertex
33169
33170                                 vertex.x = - radius * Math.cos( phiStart + u * phiLength ) * Math.sin( thetaStart + v * thetaLength );
33171                                 vertex.y = radius * Math.cos( thetaStart + v * thetaLength );
33172                                 vertex.z = radius * Math.sin( phiStart + u * phiLength ) * Math.sin( thetaStart + v * thetaLength );
33173
33174                                 vertices.push( vertex.x, vertex.y, vertex.z );
33175
33176                                 // normal
33177
33178                                 normal.copy( vertex ).normalize();
33179                                 normals.push( normal.x, normal.y, normal.z );
33180
33181                                 // uv
33182
33183                                 uvs.push( u + uOffset, 1 - v );
33184
33185                                 verticesRow.push( index ++ );
33186
33187                         }
33188
33189                         grid.push( verticesRow );
33190
33191                 }
33192
33193                 // indices
33194
33195                 for ( let iy = 0; iy < heightSegments; iy ++ ) {
33196
33197                         for ( let ix = 0; ix < widthSegments; ix ++ ) {
33198
33199                                 const a = grid[ iy ][ ix + 1 ];
33200                                 const b = grid[ iy ][ ix ];
33201                                 const c = grid[ iy + 1 ][ ix ];
33202                                 const d = grid[ iy + 1 ][ ix + 1 ];
33203
33204                                 if ( iy !== 0 || thetaStart > 0 ) indices.push( a, b, d );
33205                                 if ( iy !== heightSegments - 1 || thetaEnd < Math.PI ) indices.push( b, c, d );
33206
33207                         }
33208
33209                 }
33210
33211                 // build geometry
33212
33213                 this.setIndex( indices );
33214                 this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
33215                 this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
33216                 this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
33217
33218         }
33219
33220 }
33221
33222 /**
33223  * parameters = {
33224  *  color: <THREE.Color>
33225  * }
33226  */
33227
33228 function ShadowMaterial( parameters ) {
33229
33230         Material.call( this );
33231
33232         this.type = 'ShadowMaterial';
33233
33234         this.color = new Color( 0x000000 );
33235         this.transparent = true;
33236
33237         this.setValues( parameters );
33238
33239 }
33240
33241 ShadowMaterial.prototype = Object.create( Material.prototype );
33242 ShadowMaterial.prototype.constructor = ShadowMaterial;
33243
33244 ShadowMaterial.prototype.isShadowMaterial = true;
33245
33246 ShadowMaterial.prototype.copy = function ( source ) {
33247
33248         Material.prototype.copy.call( this, source );
33249
33250         this.color.copy( source.color );
33251
33252         return this;
33253
33254 };
33255
33256 function RawShaderMaterial( parameters ) {
33257
33258         ShaderMaterial.call( this, parameters );
33259
33260         this.type = 'RawShaderMaterial';
33261
33262 }
33263
33264 RawShaderMaterial.prototype = Object.create( ShaderMaterial.prototype );
33265 RawShaderMaterial.prototype.constructor = RawShaderMaterial;
33266
33267 RawShaderMaterial.prototype.isRawShaderMaterial = true;
33268
33269 /**
33270  * parameters = {
33271  *  color: <hex>,
33272  *  roughness: <float>,
33273  *  metalness: <float>,
33274  *  opacity: <float>,
33275  *
33276  *  map: new THREE.Texture( <Image> ),
33277  *
33278  *  lightMap: new THREE.Texture( <Image> ),
33279  *  lightMapIntensity: <float>
33280  *
33281  *  aoMap: new THREE.Texture( <Image> ),
33282  *  aoMapIntensity: <float>
33283  *
33284  *  emissive: <hex>,
33285  *  emissiveIntensity: <float>
33286  *  emissiveMap: new THREE.Texture( <Image> ),
33287  *
33288  *  bumpMap: new THREE.Texture( <Image> ),
33289  *  bumpScale: <float>,
33290  *
33291  *  normalMap: new THREE.Texture( <Image> ),
33292  *  normalMapType: THREE.TangentSpaceNormalMap,
33293  *  normalScale: <Vector2>,
33294  *
33295  *  displacementMap: new THREE.Texture( <Image> ),
33296  *  displacementScale: <float>,
33297  *  displacementBias: <float>,
33298  *
33299  *  roughnessMap: new THREE.Texture( <Image> ),
33300  *
33301  *  metalnessMap: new THREE.Texture( <Image> ),
33302  *
33303  *  alphaMap: new THREE.Texture( <Image> ),
33304  *
33305  *  envMap: new THREE.CubeTexture( [posx, negx, posy, negy, posz, negz] ),
33306  *  envMapIntensity: <float>
33307  *
33308  *  refractionRatio: <float>,
33309  *
33310  *  wireframe: <boolean>,
33311  *  wireframeLinewidth: <float>,
33312  *
33313  *  skinning: <bool>,
33314  *  morphTargets: <bool>,
33315  *  morphNormals: <bool>
33316  * }
33317  */
33318
33319 function MeshStandardMaterial( parameters ) {
33320
33321         Material.call( this );
33322
33323         this.defines = { 'STANDARD': '' };
33324
33325         this.type = 'MeshStandardMaterial';
33326
33327         this.color = new Color( 0xffffff ); // diffuse
33328         this.roughness = 1.0;
33329         this.metalness = 0.0;
33330
33331         this.map = null;
33332
33333         this.lightMap = null;
33334         this.lightMapIntensity = 1.0;
33335
33336         this.aoMap = null;
33337         this.aoMapIntensity = 1.0;
33338
33339         this.emissive = new Color( 0x000000 );
33340         this.emissiveIntensity = 1.0;
33341         this.emissiveMap = null;
33342
33343         this.bumpMap = null;
33344         this.bumpScale = 1;
33345
33346         this.normalMap = null;
33347         this.normalMapType = TangentSpaceNormalMap;
33348         this.normalScale = new Vector2( 1, 1 );
33349
33350         this.displacementMap = null;
33351         this.displacementScale = 1;
33352         this.displacementBias = 0;
33353
33354         this.roughnessMap = null;
33355
33356         this.metalnessMap = null;
33357
33358         this.alphaMap = null;
33359
33360         this.envMap = null;
33361         this.envMapIntensity = 1.0;
33362
33363         this.refractionRatio = 0.98;
33364
33365         this.wireframe = false;
33366         this.wireframeLinewidth = 1;
33367         this.wireframeLinecap = 'round';
33368         this.wireframeLinejoin = 'round';
33369
33370         this.skinning = false;
33371         this.morphTargets = false;
33372         this.morphNormals = false;
33373
33374         this.vertexTangents = false;
33375
33376         this.setValues( parameters );
33377
33378 }
33379
33380 MeshStandardMaterial.prototype = Object.create( Material.prototype );
33381 MeshStandardMaterial.prototype.constructor = MeshStandardMaterial;
33382
33383 MeshStandardMaterial.prototype.isMeshStandardMaterial = true;
33384
33385 MeshStandardMaterial.prototype.copy = function ( source ) {
33386
33387         Material.prototype.copy.call( this, source );
33388
33389         this.defines = { 'STANDARD': '' };
33390
33391         this.color.copy( source.color );
33392         this.roughness = source.roughness;
33393         this.metalness = source.metalness;
33394
33395         this.map = source.map;
33396
33397         this.lightMap = source.lightMap;
33398         this.lightMapIntensity = source.lightMapIntensity;
33399
33400         this.aoMap = source.aoMap;
33401         this.aoMapIntensity = source.aoMapIntensity;
33402
33403         this.emissive.copy( source.emissive );
33404         this.emissiveMap = source.emissiveMap;
33405         this.emissiveIntensity = source.emissiveIntensity;
33406
33407         this.bumpMap = source.bumpMap;
33408         this.bumpScale = source.bumpScale;
33409
33410         this.normalMap = source.normalMap;
33411         this.normalMapType = source.normalMapType;
33412         this.normalScale.copy( source.normalScale );
33413
33414         this.displacementMap = source.displacementMap;
33415         this.displacementScale = source.displacementScale;
33416         this.displacementBias = source.displacementBias;
33417
33418         this.roughnessMap = source.roughnessMap;
33419
33420         this.metalnessMap = source.metalnessMap;
33421
33422         this.alphaMap = source.alphaMap;
33423
33424         this.envMap = source.envMap;
33425         this.envMapIntensity = source.envMapIntensity;
33426
33427         this.refractionRatio = source.refractionRatio;
33428
33429         this.wireframe = source.wireframe;
33430         this.wireframeLinewidth = source.wireframeLinewidth;
33431         this.wireframeLinecap = source.wireframeLinecap;
33432         this.wireframeLinejoin = source.wireframeLinejoin;
33433
33434         this.skinning = source.skinning;
33435         this.morphTargets = source.morphTargets;
33436         this.morphNormals = source.morphNormals;
33437
33438         this.vertexTangents = source.vertexTangents;
33439
33440         return this;
33441
33442 };
33443
33444 /**
33445  * parameters = {
33446  *  clearcoat: <float>,
33447  *  clearcoatMap: new THREE.Texture( <Image> ),
33448  *  clearcoatRoughness: <float>,
33449  *  clearcoatRoughnessMap: new THREE.Texture( <Image> ),
33450  *  clearcoatNormalScale: <Vector2>,
33451  *  clearcoatNormalMap: new THREE.Texture( <Image> ),
33452  *
33453  *  reflectivity: <float>,
33454  *  ior: <float>,
33455  *
33456  *  sheen: <Color>,
33457  *
33458  *  transmission: <float>,
33459  *  transmissionMap: new THREE.Texture( <Image> )
33460  * }
33461  */
33462
33463 function MeshPhysicalMaterial( parameters ) {
33464
33465         MeshStandardMaterial.call( this );
33466
33467         this.defines = {
33468
33469                 'STANDARD': '',
33470                 'PHYSICAL': ''
33471
33472         };
33473
33474         this.type = 'MeshPhysicalMaterial';
33475
33476         this.clearcoat = 0.0;
33477         this.clearcoatMap = null;
33478         this.clearcoatRoughness = 0.0;
33479         this.clearcoatRoughnessMap = null;
33480         this.clearcoatNormalScale = new Vector2( 1, 1 );
33481         this.clearcoatNormalMap = null;
33482
33483         this.reflectivity = 0.5; // maps to F0 = 0.04
33484
33485         Object.defineProperty( this, 'ior', {
33486                 get: function () {
33487
33488                         return ( 1 + 0.4 * this.reflectivity ) / ( 1 - 0.4 * this.reflectivity );
33489
33490                 },
33491                 set: function ( ior ) {
33492
33493                         this.reflectivity = MathUtils.clamp( 2.5 * ( ior - 1 ) / ( ior + 1 ), 0, 1 );
33494
33495                 }
33496         } );
33497
33498         this.sheen = null; // null will disable sheen bsdf
33499
33500         this.transmission = 0.0;
33501         this.transmissionMap = null;
33502
33503         this.setValues( parameters );
33504
33505 }
33506
33507 MeshPhysicalMaterial.prototype = Object.create( MeshStandardMaterial.prototype );
33508 MeshPhysicalMaterial.prototype.constructor = MeshPhysicalMaterial;
33509
33510 MeshPhysicalMaterial.prototype.isMeshPhysicalMaterial = true;
33511
33512 MeshPhysicalMaterial.prototype.copy = function ( source ) {
33513
33514         MeshStandardMaterial.prototype.copy.call( this, source );
33515
33516         this.defines = {
33517
33518                 'STANDARD': '',
33519                 'PHYSICAL': ''
33520
33521         };
33522
33523         this.clearcoat = source.clearcoat;
33524         this.clearcoatMap = source.clearcoatMap;
33525         this.clearcoatRoughness = source.clearcoatRoughness;
33526         this.clearcoatRoughnessMap = source.clearcoatRoughnessMap;
33527         this.clearcoatNormalMap = source.clearcoatNormalMap;
33528         this.clearcoatNormalScale.copy( source.clearcoatNormalScale );
33529
33530         this.reflectivity = source.reflectivity;
33531
33532         if ( source.sheen ) {
33533
33534                 this.sheen = ( this.sheen || new Color() ).copy( source.sheen );
33535
33536         } else {
33537
33538                 this.sheen = null;
33539
33540         }
33541
33542         this.transmission = source.transmission;
33543         this.transmissionMap = source.transmissionMap;
33544
33545         return this;
33546
33547 };
33548
33549 /**
33550  * parameters = {
33551  *  color: <hex>,
33552  *  specular: <hex>,
33553  *  shininess: <float>,
33554  *  opacity: <float>,
33555  *
33556  *  map: new THREE.Texture( <Image> ),
33557  *
33558  *  lightMap: new THREE.Texture( <Image> ),
33559  *  lightMapIntensity: <float>
33560  *
33561  *  aoMap: new THREE.Texture( <Image> ),
33562  *  aoMapIntensity: <float>
33563  *
33564  *  emissive: <hex>,
33565  *  emissiveIntensity: <float>
33566  *  emissiveMap: new THREE.Texture( <Image> ),
33567  *
33568  *  bumpMap: new THREE.Texture( <Image> ),
33569  *  bumpScale: <float>,
33570  *
33571  *  normalMap: new THREE.Texture( <Image> ),
33572  *  normalMapType: THREE.TangentSpaceNormalMap,
33573  *  normalScale: <Vector2>,
33574  *
33575  *  displacementMap: new THREE.Texture( <Image> ),
33576  *  displacementScale: <float>,
33577  *  displacementBias: <float>,
33578  *
33579  *  specularMap: new THREE.Texture( <Image> ),
33580  *
33581  *  alphaMap: new THREE.Texture( <Image> ),
33582  *
33583  *  envMap: new THREE.CubeTexture( [posx, negx, posy, negy, posz, negz] ),
33584  *  combine: THREE.MultiplyOperation,
33585  *  reflectivity: <float>,
33586  *  refractionRatio: <float>,
33587  *
33588  *  wireframe: <boolean>,
33589  *  wireframeLinewidth: <float>,
33590  *
33591  *  skinning: <bool>,
33592  *  morphTargets: <bool>,
33593  *  morphNormals: <bool>
33594  * }
33595  */
33596
33597 function MeshPhongMaterial( parameters ) {
33598
33599         Material.call( this );
33600
33601         this.type = 'MeshPhongMaterial';
33602
33603         this.color = new Color( 0xffffff ); // diffuse
33604         this.specular = new Color( 0x111111 );
33605         this.shininess = 30;
33606
33607         this.map = null;
33608
33609         this.lightMap = null;
33610         this.lightMapIntensity = 1.0;
33611
33612         this.aoMap = null;
33613         this.aoMapIntensity = 1.0;
33614
33615         this.emissive = new Color( 0x000000 );
33616         this.emissiveIntensity = 1.0;
33617         this.emissiveMap = null;
33618
33619         this.bumpMap = null;
33620         this.bumpScale = 1;
33621
33622         this.normalMap = null;
33623         this.normalMapType = TangentSpaceNormalMap;
33624         this.normalScale = new Vector2( 1, 1 );
33625
33626         this.displacementMap = null;
33627         this.displacementScale = 1;
33628         this.displacementBias = 0;
33629
33630         this.specularMap = null;
33631
33632         this.alphaMap = null;
33633
33634         this.envMap = null;
33635         this.combine = MultiplyOperation;
33636         this.reflectivity = 1;
33637         this.refractionRatio = 0.98;
33638
33639         this.wireframe = false;
33640         this.wireframeLinewidth = 1;
33641         this.wireframeLinecap = 'round';
33642         this.wireframeLinejoin = 'round';
33643
33644         this.skinning = false;
33645         this.morphTargets = false;
33646         this.morphNormals = false;
33647
33648         this.setValues( parameters );
33649
33650 }
33651
33652 MeshPhongMaterial.prototype = Object.create( Material.prototype );
33653 MeshPhongMaterial.prototype.constructor = MeshPhongMaterial;
33654
33655 MeshPhongMaterial.prototype.isMeshPhongMaterial = true;
33656
33657 MeshPhongMaterial.prototype.copy = function ( source ) {
33658
33659         Material.prototype.copy.call( this, source );
33660
33661         this.color.copy( source.color );
33662         this.specular.copy( source.specular );
33663         this.shininess = source.shininess;
33664
33665         this.map = source.map;
33666
33667         this.lightMap = source.lightMap;
33668         this.lightMapIntensity = source.lightMapIntensity;
33669
33670         this.aoMap = source.aoMap;
33671         this.aoMapIntensity = source.aoMapIntensity;
33672
33673         this.emissive.copy( source.emissive );
33674         this.emissiveMap = source.emissiveMap;
33675         this.emissiveIntensity = source.emissiveIntensity;
33676
33677         this.bumpMap = source.bumpMap;
33678         this.bumpScale = source.bumpScale;
33679
33680         this.normalMap = source.normalMap;
33681         this.normalMapType = source.normalMapType;
33682         this.normalScale.copy( source.normalScale );
33683
33684         this.displacementMap = source.displacementMap;
33685         this.displacementScale = source.displacementScale;
33686         this.displacementBias = source.displacementBias;
33687
33688         this.specularMap = source.specularMap;
33689
33690         this.alphaMap = source.alphaMap;
33691
33692         this.envMap = source.envMap;
33693         this.combine = source.combine;
33694         this.reflectivity = source.reflectivity;
33695         this.refractionRatio = source.refractionRatio;
33696
33697         this.wireframe = source.wireframe;
33698         this.wireframeLinewidth = source.wireframeLinewidth;
33699         this.wireframeLinecap = source.wireframeLinecap;
33700         this.wireframeLinejoin = source.wireframeLinejoin;
33701
33702         this.skinning = source.skinning;
33703         this.morphTargets = source.morphTargets;
33704         this.morphNormals = source.morphNormals;
33705
33706         return this;
33707
33708 };
33709
33710 /**
33711  * parameters = {
33712  *  color: <hex>,
33713  *
33714  *  map: new THREE.Texture( <Image> ),
33715  *  gradientMap: new THREE.Texture( <Image> ),
33716  *
33717  *  lightMap: new THREE.Texture( <Image> ),
33718  *  lightMapIntensity: <float>
33719  *
33720  *  aoMap: new THREE.Texture( <Image> ),
33721  *  aoMapIntensity: <float>
33722  *
33723  *  emissive: <hex>,
33724  *  emissiveIntensity: <float>
33725  *  emissiveMap: new THREE.Texture( <Image> ),
33726  *
33727  *  bumpMap: new THREE.Texture( <Image> ),
33728  *  bumpScale: <float>,
33729  *
33730  *  normalMap: new THREE.Texture( <Image> ),
33731  *  normalMapType: THREE.TangentSpaceNormalMap,
33732  *  normalScale: <Vector2>,
33733  *
33734  *  displacementMap: new THREE.Texture( <Image> ),
33735  *  displacementScale: <float>,
33736  *  displacementBias: <float>,
33737  *
33738  *  alphaMap: new THREE.Texture( <Image> ),
33739  *
33740  *  wireframe: <boolean>,
33741  *  wireframeLinewidth: <float>,
33742  *
33743  *  skinning: <bool>,
33744  *  morphTargets: <bool>,
33745  *  morphNormals: <bool>
33746  * }
33747  */
33748
33749 function MeshToonMaterial( parameters ) {
33750
33751         Material.call( this );
33752
33753         this.defines = { 'TOON': '' };
33754
33755         this.type = 'MeshToonMaterial';
33756
33757         this.color = new Color( 0xffffff );
33758
33759         this.map = null;
33760         this.gradientMap = null;
33761
33762         this.lightMap = null;
33763         this.lightMapIntensity = 1.0;
33764
33765         this.aoMap = null;
33766         this.aoMapIntensity = 1.0;
33767
33768         this.emissive = new Color( 0x000000 );
33769         this.emissiveIntensity = 1.0;
33770         this.emissiveMap = null;
33771
33772         this.bumpMap = null;
33773         this.bumpScale = 1;
33774
33775         this.normalMap = null;
33776         this.normalMapType = TangentSpaceNormalMap;
33777         this.normalScale = new Vector2( 1, 1 );
33778
33779         this.displacementMap = null;
33780         this.displacementScale = 1;
33781         this.displacementBias = 0;
33782
33783         this.alphaMap = null;
33784
33785         this.wireframe = false;
33786         this.wireframeLinewidth = 1;
33787         this.wireframeLinecap = 'round';
33788         this.wireframeLinejoin = 'round';
33789
33790         this.skinning = false;
33791         this.morphTargets = false;
33792         this.morphNormals = false;
33793
33794         this.setValues( parameters );
33795
33796 }
33797
33798 MeshToonMaterial.prototype = Object.create( Material.prototype );
33799 MeshToonMaterial.prototype.constructor = MeshToonMaterial;
33800
33801 MeshToonMaterial.prototype.isMeshToonMaterial = true;
33802
33803 MeshToonMaterial.prototype.copy = function ( source ) {
33804
33805         Material.prototype.copy.call( this, source );
33806
33807         this.color.copy( source.color );
33808
33809         this.map = source.map;
33810         this.gradientMap = source.gradientMap;
33811
33812         this.lightMap = source.lightMap;
33813         this.lightMapIntensity = source.lightMapIntensity;
33814
33815         this.aoMap = source.aoMap;
33816         this.aoMapIntensity = source.aoMapIntensity;
33817
33818         this.emissive.copy( source.emissive );
33819         this.emissiveMap = source.emissiveMap;
33820         this.emissiveIntensity = source.emissiveIntensity;
33821
33822         this.bumpMap = source.bumpMap;
33823         this.bumpScale = source.bumpScale;
33824
33825         this.normalMap = source.normalMap;
33826         this.normalMapType = source.normalMapType;
33827         this.normalScale.copy( source.normalScale );
33828
33829         this.displacementMap = source.displacementMap;
33830         this.displacementScale = source.displacementScale;
33831         this.displacementBias = source.displacementBias;
33832
33833         this.alphaMap = source.alphaMap;
33834
33835         this.wireframe = source.wireframe;
33836         this.wireframeLinewidth = source.wireframeLinewidth;
33837         this.wireframeLinecap = source.wireframeLinecap;
33838         this.wireframeLinejoin = source.wireframeLinejoin;
33839
33840         this.skinning = source.skinning;
33841         this.morphTargets = source.morphTargets;
33842         this.morphNormals = source.morphNormals;
33843
33844         return this;
33845
33846 };
33847
33848 /**
33849  * parameters = {
33850  *  opacity: <float>,
33851  *
33852  *  bumpMap: new THREE.Texture( <Image> ),
33853  *  bumpScale: <float>,
33854  *
33855  *  normalMap: new THREE.Texture( <Image> ),
33856  *  normalMapType: THREE.TangentSpaceNormalMap,
33857  *  normalScale: <Vector2>,
33858  *
33859  *  displacementMap: new THREE.Texture( <Image> ),
33860  *  displacementScale: <float>,
33861  *  displacementBias: <float>,
33862  *
33863  *  wireframe: <boolean>,
33864  *  wireframeLinewidth: <float>
33865  *
33866  *  skinning: <bool>,
33867  *  morphTargets: <bool>,
33868  *  morphNormals: <bool>
33869  * }
33870  */
33871
33872 function MeshNormalMaterial( parameters ) {
33873
33874         Material.call( this );
33875
33876         this.type = 'MeshNormalMaterial';
33877
33878         this.bumpMap = null;
33879         this.bumpScale = 1;
33880
33881         this.normalMap = null;
33882         this.normalMapType = TangentSpaceNormalMap;
33883         this.normalScale = new Vector2( 1, 1 );
33884
33885         this.displacementMap = null;
33886         this.displacementScale = 1;
33887         this.displacementBias = 0;
33888
33889         this.wireframe = false;
33890         this.wireframeLinewidth = 1;
33891
33892         this.fog = false;
33893
33894         this.skinning = false;
33895         this.morphTargets = false;
33896         this.morphNormals = false;
33897
33898         this.setValues( parameters );
33899
33900 }
33901
33902 MeshNormalMaterial.prototype = Object.create( Material.prototype );
33903 MeshNormalMaterial.prototype.constructor = MeshNormalMaterial;
33904
33905 MeshNormalMaterial.prototype.isMeshNormalMaterial = true;
33906
33907 MeshNormalMaterial.prototype.copy = function ( source ) {
33908
33909         Material.prototype.copy.call( this, source );
33910
33911         this.bumpMap = source.bumpMap;
33912         this.bumpScale = source.bumpScale;
33913
33914         this.normalMap = source.normalMap;
33915         this.normalMapType = source.normalMapType;
33916         this.normalScale.copy( source.normalScale );
33917
33918         this.displacementMap = source.displacementMap;
33919         this.displacementScale = source.displacementScale;
33920         this.displacementBias = source.displacementBias;
33921
33922         this.wireframe = source.wireframe;
33923         this.wireframeLinewidth = source.wireframeLinewidth;
33924
33925         this.skinning = source.skinning;
33926         this.morphTargets = source.morphTargets;
33927         this.morphNormals = source.morphNormals;
33928
33929         return this;
33930
33931 };
33932
33933 /**
33934  * parameters = {
33935  *  color: <hex>,
33936  *  opacity: <float>,
33937  *
33938  *  map: new THREE.Texture( <Image> ),
33939  *
33940  *  lightMap: new THREE.Texture( <Image> ),
33941  *  lightMapIntensity: <float>
33942  *
33943  *  aoMap: new THREE.Texture( <Image> ),
33944  *  aoMapIntensity: <float>
33945  *
33946  *  emissive: <hex>,
33947  *  emissiveIntensity: <float>
33948  *  emissiveMap: new THREE.Texture( <Image> ),
33949  *
33950  *  specularMap: new THREE.Texture( <Image> ),
33951  *
33952  *  alphaMap: new THREE.Texture( <Image> ),
33953  *
33954  *  envMap: new THREE.CubeTexture( [posx, negx, posy, negy, posz, negz] ),
33955  *  combine: THREE.Multiply,
33956  *  reflectivity: <float>,
33957  *  refractionRatio: <float>,
33958  *
33959  *  wireframe: <boolean>,
33960  *  wireframeLinewidth: <float>,
33961  *
33962  *  skinning: <bool>,
33963  *  morphTargets: <bool>,
33964  *  morphNormals: <bool>
33965  * }
33966  */
33967
33968 function MeshLambertMaterial( parameters ) {
33969
33970         Material.call( this );
33971
33972         this.type = 'MeshLambertMaterial';
33973
33974         this.color = new Color( 0xffffff ); // diffuse
33975
33976         this.map = null;
33977
33978         this.lightMap = null;
33979         this.lightMapIntensity = 1.0;
33980
33981         this.aoMap = null;
33982         this.aoMapIntensity = 1.0;
33983
33984         this.emissive = new Color( 0x000000 );
33985         this.emissiveIntensity = 1.0;
33986         this.emissiveMap = null;
33987
33988         this.specularMap = null;
33989
33990         this.alphaMap = null;
33991
33992         this.envMap = null;
33993         this.combine = MultiplyOperation;
33994         this.reflectivity = 1;
33995         this.refractionRatio = 0.98;
33996
33997         this.wireframe = false;
33998         this.wireframeLinewidth = 1;
33999         this.wireframeLinecap = 'round';
34000         this.wireframeLinejoin = 'round';
34001
34002         this.skinning = false;
34003         this.morphTargets = false;
34004         this.morphNormals = false;
34005
34006         this.setValues( parameters );
34007
34008 }
34009
34010 MeshLambertMaterial.prototype = Object.create( Material.prototype );
34011 MeshLambertMaterial.prototype.constructor = MeshLambertMaterial;
34012
34013 MeshLambertMaterial.prototype.isMeshLambertMaterial = true;
34014
34015 MeshLambertMaterial.prototype.copy = function ( source ) {
34016
34017         Material.prototype.copy.call( this, source );
34018
34019         this.color.copy( source.color );
34020
34021         this.map = source.map;
34022
34023         this.lightMap = source.lightMap;
34024         this.lightMapIntensity = source.lightMapIntensity;
34025
34026         this.aoMap = source.aoMap;
34027         this.aoMapIntensity = source.aoMapIntensity;
34028
34029         this.emissive.copy( source.emissive );
34030         this.emissiveMap = source.emissiveMap;
34031         this.emissiveIntensity = source.emissiveIntensity;
34032
34033         this.specularMap = source.specularMap;
34034
34035         this.alphaMap = source.alphaMap;
34036
34037         this.envMap = source.envMap;
34038         this.combine = source.combine;
34039         this.reflectivity = source.reflectivity;
34040         this.refractionRatio = source.refractionRatio;
34041
34042         this.wireframe = source.wireframe;
34043         this.wireframeLinewidth = source.wireframeLinewidth;
34044         this.wireframeLinecap = source.wireframeLinecap;
34045         this.wireframeLinejoin = source.wireframeLinejoin;
34046
34047         this.skinning = source.skinning;
34048         this.morphTargets = source.morphTargets;
34049         this.morphNormals = source.morphNormals;
34050
34051         return this;
34052
34053 };
34054
34055 /**
34056  * parameters = {
34057  *  color: <hex>,
34058  *  opacity: <float>,
34059  *
34060  *  matcap: new THREE.Texture( <Image> ),
34061  *
34062  *  map: new THREE.Texture( <Image> ),
34063  *
34064  *  bumpMap: new THREE.Texture( <Image> ),
34065  *  bumpScale: <float>,
34066  *
34067  *  normalMap: new THREE.Texture( <Image> ),
34068  *  normalMapType: THREE.TangentSpaceNormalMap,
34069  *  normalScale: <Vector2>,
34070  *
34071  *  displacementMap: new THREE.Texture( <Image> ),
34072  *  displacementScale: <float>,
34073  *  displacementBias: <float>,
34074  *
34075  *  alphaMap: new THREE.Texture( <Image> ),
34076  *
34077  *  skinning: <bool>,
34078  *  morphTargets: <bool>,
34079  *  morphNormals: <bool>
34080  * }
34081  */
34082
34083 function MeshMatcapMaterial( parameters ) {
34084
34085         Material.call( this );
34086
34087         this.defines = { 'MATCAP': '' };
34088
34089         this.type = 'MeshMatcapMaterial';
34090
34091         this.color = new Color( 0xffffff ); // diffuse
34092
34093         this.matcap = null;
34094
34095         this.map = null;
34096
34097         this.bumpMap = null;
34098         this.bumpScale = 1;
34099
34100         this.normalMap = null;
34101         this.normalMapType = TangentSpaceNormalMap;
34102         this.normalScale = new Vector2( 1, 1 );
34103
34104         this.displacementMap = null;
34105         this.displacementScale = 1;
34106         this.displacementBias = 0;
34107
34108         this.alphaMap = null;
34109
34110         this.skinning = false;
34111         this.morphTargets = false;
34112         this.morphNormals = false;
34113
34114         this.setValues( parameters );
34115
34116 }
34117
34118 MeshMatcapMaterial.prototype = Object.create( Material.prototype );
34119 MeshMatcapMaterial.prototype.constructor = MeshMatcapMaterial;
34120
34121 MeshMatcapMaterial.prototype.isMeshMatcapMaterial = true;
34122
34123 MeshMatcapMaterial.prototype.copy = function ( source ) {
34124
34125         Material.prototype.copy.call( this, source );
34126
34127         this.defines = { 'MATCAP': '' };
34128
34129         this.color.copy( source.color );
34130
34131         this.matcap = source.matcap;
34132
34133         this.map = source.map;
34134
34135         this.bumpMap = source.bumpMap;
34136         this.bumpScale = source.bumpScale;
34137
34138         this.normalMap = source.normalMap;
34139         this.normalMapType = source.normalMapType;
34140         this.normalScale.copy( source.normalScale );
34141
34142         this.displacementMap = source.displacementMap;
34143         this.displacementScale = source.displacementScale;
34144         this.displacementBias = source.displacementBias;
34145
34146         this.alphaMap = source.alphaMap;
34147
34148         this.skinning = source.skinning;
34149         this.morphTargets = source.morphTargets;
34150         this.morphNormals = source.morphNormals;
34151
34152         return this;
34153
34154 };
34155
34156 /**
34157  * parameters = {
34158  *  color: <hex>,
34159  *  opacity: <float>,
34160  *
34161  *  linewidth: <float>,
34162  *
34163  *  scale: <float>,
34164  *  dashSize: <float>,
34165  *  gapSize: <float>
34166  * }
34167  */
34168
34169 function LineDashedMaterial( parameters ) {
34170
34171         LineBasicMaterial.call( this );
34172
34173         this.type = 'LineDashedMaterial';
34174
34175         this.scale = 1;
34176         this.dashSize = 3;
34177         this.gapSize = 1;
34178
34179         this.setValues( parameters );
34180
34181 }
34182
34183 LineDashedMaterial.prototype = Object.create( LineBasicMaterial.prototype );
34184 LineDashedMaterial.prototype.constructor = LineDashedMaterial;
34185
34186 LineDashedMaterial.prototype.isLineDashedMaterial = true;
34187
34188 LineDashedMaterial.prototype.copy = function ( source ) {
34189
34190         LineBasicMaterial.prototype.copy.call( this, source );
34191
34192         this.scale = source.scale;
34193         this.dashSize = source.dashSize;
34194         this.gapSize = source.gapSize;
34195
34196         return this;
34197
34198 };
34199
34200 var Materials = /*#__PURE__*/Object.freeze({
34201         __proto__: null,
34202         ShadowMaterial: ShadowMaterial,
34203         SpriteMaterial: SpriteMaterial,
34204         RawShaderMaterial: RawShaderMaterial,
34205         ShaderMaterial: ShaderMaterial,
34206         PointsMaterial: PointsMaterial,
34207         MeshPhysicalMaterial: MeshPhysicalMaterial,
34208         MeshStandardMaterial: MeshStandardMaterial,
34209         MeshPhongMaterial: MeshPhongMaterial,
34210         MeshToonMaterial: MeshToonMaterial,
34211         MeshNormalMaterial: MeshNormalMaterial,
34212         MeshLambertMaterial: MeshLambertMaterial,
34213         MeshDepthMaterial: MeshDepthMaterial,
34214         MeshDistanceMaterial: MeshDistanceMaterial,
34215         MeshBasicMaterial: MeshBasicMaterial,
34216         MeshMatcapMaterial: MeshMatcapMaterial,
34217         LineDashedMaterial: LineDashedMaterial,
34218         LineBasicMaterial: LineBasicMaterial,
34219         Material: Material
34220 });
34221
34222 const AnimationUtils = {
34223
34224         // same as Array.prototype.slice, but also works on typed arrays
34225         arraySlice: function ( array, from, to ) {
34226
34227                 if ( AnimationUtils.isTypedArray( array ) ) {
34228
34229                         // in ios9 array.subarray(from, undefined) will return empty array
34230                         // but array.subarray(from) or array.subarray(from, len) is correct
34231                         return new array.constructor( array.subarray( from, to !== undefined ? to : array.length ) );
34232
34233                 }
34234
34235                 return array.slice( from, to );
34236
34237         },
34238
34239         // converts an array to a specific type
34240         convertArray: function ( array, type, forceClone ) {
34241
34242                 if ( ! array || // let 'undefined' and 'null' pass
34243                         ! forceClone && array.constructor === type ) return array;
34244
34245                 if ( typeof type.BYTES_PER_ELEMENT === 'number' ) {
34246
34247                         return new type( array ); // create typed array
34248
34249                 }
34250
34251                 return Array.prototype.slice.call( array ); // create Array
34252
34253         },
34254
34255         isTypedArray: function ( object ) {
34256
34257                 return ArrayBuffer.isView( object ) &&
34258                         ! ( object instanceof DataView );
34259
34260         },
34261
34262         // returns an array by which times and values can be sorted
34263         getKeyframeOrder: function ( times ) {
34264
34265                 function compareTime( i, j ) {
34266
34267                         return times[ i ] - times[ j ];
34268
34269                 }
34270
34271                 const n = times.length;
34272                 const result = new Array( n );
34273                 for ( let i = 0; i !== n; ++ i ) result[ i ] = i;
34274
34275                 result.sort( compareTime );
34276
34277                 return result;
34278
34279         },
34280
34281         // uses the array previously returned by 'getKeyframeOrder' to sort data
34282         sortedArray: function ( values, stride, order ) {
34283
34284                 const nValues = values.length;
34285                 const result = new values.constructor( nValues );
34286
34287                 for ( let i = 0, dstOffset = 0; dstOffset !== nValues; ++ i ) {
34288
34289                         const srcOffset = order[ i ] * stride;
34290
34291                         for ( let j = 0; j !== stride; ++ j ) {
34292
34293                                 result[ dstOffset ++ ] = values[ srcOffset + j ];
34294
34295                         }
34296
34297                 }
34298
34299                 return result;
34300
34301         },
34302
34303         // function for parsing AOS keyframe formats
34304         flattenJSON: function ( jsonKeys, times, values, valuePropertyName ) {
34305
34306                 let i = 1, key = jsonKeys[ 0 ];
34307
34308                 while ( key !== undefined && key[ valuePropertyName ] === undefined ) {
34309
34310                         key = jsonKeys[ i ++ ];
34311
34312                 }
34313
34314                 if ( key === undefined ) return; // no data
34315
34316                 let value = key[ valuePropertyName ];
34317                 if ( value === undefined ) return; // no data
34318
34319                 if ( Array.isArray( value ) ) {
34320
34321                         do {
34322
34323                                 value = key[ valuePropertyName ];
34324
34325                                 if ( value !== undefined ) {
34326
34327                                         times.push( key.time );
34328                                         values.push.apply( values, value ); // push all elements
34329
34330                                 }
34331
34332                                 key = jsonKeys[ i ++ ];
34333
34334                         } while ( key !== undefined );
34335
34336                 } else if ( value.toArray !== undefined ) {
34337
34338                         // ...assume THREE.Math-ish
34339
34340                         do {
34341
34342                                 value = key[ valuePropertyName ];
34343
34344                                 if ( value !== undefined ) {
34345
34346                                         times.push( key.time );
34347                                         value.toArray( values, values.length );
34348
34349                                 }
34350
34351                                 key = jsonKeys[ i ++ ];
34352
34353                         } while ( key !== undefined );
34354
34355                 } else {
34356
34357                         // otherwise push as-is
34358
34359                         do {
34360
34361                                 value = key[ valuePropertyName ];
34362
34363                                 if ( value !== undefined ) {
34364
34365                                         times.push( key.time );
34366                                         values.push( value );
34367
34368                                 }
34369
34370                                 key = jsonKeys[ i ++ ];
34371
34372                         } while ( key !== undefined );
34373
34374                 }
34375
34376         },
34377
34378         subclip: function ( sourceClip, name, startFrame, endFrame, fps = 30 ) {
34379
34380                 const clip = sourceClip.clone();
34381
34382                 clip.name = name;
34383
34384                 const tracks = [];
34385
34386                 for ( let i = 0; i < clip.tracks.length; ++ i ) {
34387
34388                         const track = clip.tracks[ i ];
34389                         const valueSize = track.getValueSize();
34390
34391                         const times = [];
34392                         const values = [];
34393
34394                         for ( let j = 0; j < track.times.length; ++ j ) {
34395
34396                                 const frame = track.times[ j ] * fps;
34397
34398                                 if ( frame < startFrame || frame >= endFrame ) continue;
34399
34400                                 times.push( track.times[ j ] );
34401
34402                                 for ( let k = 0; k < valueSize; ++ k ) {
34403
34404                                         values.push( track.values[ j * valueSize + k ] );
34405
34406                                 }
34407
34408                         }
34409
34410                         if ( times.length === 0 ) continue;
34411
34412                         track.times = AnimationUtils.convertArray( times, track.times.constructor );
34413                         track.values = AnimationUtils.convertArray( values, track.values.constructor );
34414
34415                         tracks.push( track );
34416
34417                 }
34418
34419                 clip.tracks = tracks;
34420
34421                 // find minimum .times value across all tracks in the trimmed clip
34422
34423                 let minStartTime = Infinity;
34424
34425                 for ( let i = 0; i < clip.tracks.length; ++ i ) {
34426
34427                         if ( minStartTime > clip.tracks[ i ].times[ 0 ] ) {
34428
34429                                 minStartTime = clip.tracks[ i ].times[ 0 ];
34430
34431                         }
34432
34433                 }
34434
34435                 // shift all tracks such that clip begins at t=0
34436
34437                 for ( let i = 0; i < clip.tracks.length; ++ i ) {
34438
34439                         clip.tracks[ i ].shift( - 1 * minStartTime );
34440
34441                 }
34442
34443                 clip.resetDuration();
34444
34445                 return clip;
34446
34447         },
34448
34449         makeClipAdditive: function ( targetClip, referenceFrame = 0, referenceClip = targetClip, fps = 30 ) {
34450
34451                 if ( fps <= 0 ) fps = 30;
34452
34453                 const numTracks = referenceClip.tracks.length;
34454                 const referenceTime = referenceFrame / fps;
34455
34456                 // Make each track's values relative to the values at the reference frame
34457                 for ( let i = 0; i < numTracks; ++ i ) {
34458
34459                         const referenceTrack = referenceClip.tracks[ i ];
34460                         const referenceTrackType = referenceTrack.ValueTypeName;
34461
34462                         // Skip this track if it's non-numeric
34463                         if ( referenceTrackType === 'bool' || referenceTrackType === 'string' ) continue;
34464
34465                         // Find the track in the target clip whose name and type matches the reference track
34466                         const targetTrack = targetClip.tracks.find( function ( track ) {
34467
34468                                 return track.name === referenceTrack.name
34469                                         && track.ValueTypeName === referenceTrackType;
34470
34471                         } );
34472
34473                         if ( targetTrack === undefined ) continue;
34474
34475                         let referenceOffset = 0;
34476                         const referenceValueSize = referenceTrack.getValueSize();
34477
34478                         if ( referenceTrack.createInterpolant.isInterpolantFactoryMethodGLTFCubicSpline ) {
34479
34480                                 referenceOffset = referenceValueSize / 3;
34481
34482                         }
34483
34484                         let targetOffset = 0;
34485                         const targetValueSize = targetTrack.getValueSize();
34486
34487                         if ( targetTrack.createInterpolant.isInterpolantFactoryMethodGLTFCubicSpline ) {
34488
34489                                 targetOffset = targetValueSize / 3;
34490
34491                         }
34492
34493                         const lastIndex = referenceTrack.times.length - 1;
34494                         let referenceValue;
34495
34496                         // Find the value to subtract out of the track
34497                         if ( referenceTime <= referenceTrack.times[ 0 ] ) {
34498
34499                                 // Reference frame is earlier than the first keyframe, so just use the first keyframe
34500                                 const startIndex = referenceOffset;
34501                                 const endIndex = referenceValueSize - referenceOffset;
34502                                 referenceValue = AnimationUtils.arraySlice( referenceTrack.values, startIndex, endIndex );
34503
34504                         } else if ( referenceTime >= referenceTrack.times[ lastIndex ] ) {
34505
34506                                 // Reference frame is after the last keyframe, so just use the last keyframe
34507                                 const startIndex = lastIndex * referenceValueSize + referenceOffset;
34508                                 const endIndex = startIndex + referenceValueSize - referenceOffset;
34509                                 referenceValue = AnimationUtils.arraySlice( referenceTrack.values, startIndex, endIndex );
34510
34511                         } else {
34512
34513                                 // Interpolate to the reference value
34514                                 const interpolant = referenceTrack.createInterpolant();
34515                                 const startIndex = referenceOffset;
34516                                 const endIndex = referenceValueSize - referenceOffset;
34517                                 interpolant.evaluate( referenceTime );
34518                                 referenceValue = AnimationUtils.arraySlice( interpolant.resultBuffer, startIndex, endIndex );
34519
34520                         }
34521
34522                         // Conjugate the quaternion
34523                         if ( referenceTrackType === 'quaternion' ) {
34524
34525                                 const referenceQuat = new Quaternion().fromArray( referenceValue ).normalize().conjugate();
34526                                 referenceQuat.toArray( referenceValue );
34527
34528                         }
34529
34530                         // Subtract the reference value from all of the track values
34531
34532                         const numTimes = targetTrack.times.length;
34533                         for ( let j = 0; j < numTimes; ++ j ) {
34534
34535                                 const valueStart = j * targetValueSize + targetOffset;
34536
34537                                 if ( referenceTrackType === 'quaternion' ) {
34538
34539                                         // Multiply the conjugate for quaternion track types
34540                                         Quaternion.multiplyQuaternionsFlat(
34541                                                 targetTrack.values,
34542                                                 valueStart,
34543                                                 referenceValue,
34544                                                 0,
34545                                                 targetTrack.values,
34546                                                 valueStart
34547                                         );
34548
34549                                 } else {
34550
34551                                         const valueEnd = targetValueSize - targetOffset * 2;
34552
34553                                         // Subtract each value for all other numeric track types
34554                                         for ( let k = 0; k < valueEnd; ++ k ) {
34555
34556                                                 targetTrack.values[ valueStart + k ] -= referenceValue[ k ];
34557
34558                                         }
34559
34560                                 }
34561
34562                         }
34563
34564                 }
34565
34566                 targetClip.blendMode = AdditiveAnimationBlendMode;
34567
34568                 return targetClip;
34569
34570         }
34571
34572 };
34573
34574 /**
34575  * Abstract base class of interpolants over parametric samples.
34576  *
34577  * The parameter domain is one dimensional, typically the time or a path
34578  * along a curve defined by the data.
34579  *
34580  * The sample values can have any dimensionality and derived classes may
34581  * apply special interpretations to the data.
34582  *
34583  * This class provides the interval seek in a Template Method, deferring
34584  * the actual interpolation to derived classes.
34585  *
34586  * Time complexity is O(1) for linear access crossing at most two points
34587  * and O(log N) for random access, where N is the number of positions.
34588  *
34589  * References:
34590  *
34591  *              http://www.oodesign.com/template-method-pattern.html
34592  *
34593  */
34594
34595 function Interpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) {
34596
34597         this.parameterPositions = parameterPositions;
34598         this._cachedIndex = 0;
34599
34600         this.resultBuffer = resultBuffer !== undefined ?
34601                 resultBuffer : new sampleValues.constructor( sampleSize );
34602         this.sampleValues = sampleValues;
34603         this.valueSize = sampleSize;
34604
34605 }
34606
34607 Object.assign( Interpolant.prototype, {
34608
34609         evaluate: function ( t ) {
34610
34611                 const pp = this.parameterPositions;
34612                 let i1 = this._cachedIndex,
34613                         t1 = pp[ i1 ],
34614                         t0 = pp[ i1 - 1 ];
34615
34616                 validate_interval: {
34617
34618                         seek: {
34619
34620                                 let right;
34621
34622                                 linear_scan: {
34623
34624                                         //- See http://jsperf.com/comparison-to-undefined/3
34625                                         //- slower code:
34626                                         //-
34627                                         //-                             if ( t >= t1 || t1 === undefined ) {
34628                                         forward_scan: if ( ! ( t < t1 ) ) {
34629
34630                                                 for ( let giveUpAt = i1 + 2; ; ) {
34631
34632                                                         if ( t1 === undefined ) {
34633
34634                                                                 if ( t < t0 ) break forward_scan;
34635
34636                                                                 // after end
34637
34638                                                                 i1 = pp.length;
34639                                                                 this._cachedIndex = i1;
34640                                                                 return this.afterEnd_( i1 - 1, t, t0 );
34641
34642                                                         }
34643
34644                                                         if ( i1 === giveUpAt ) break; // this loop
34645
34646                                                         t0 = t1;
34647                                                         t1 = pp[ ++ i1 ];
34648
34649                                                         if ( t < t1 ) {
34650
34651                                                                 // we have arrived at the sought interval
34652                                                                 break seek;
34653
34654                                                         }
34655
34656                                                 }
34657
34658                                                 // prepare binary search on the right side of the index
34659                                                 right = pp.length;
34660                                                 break linear_scan;
34661
34662                                         }
34663
34664                                         //- slower code:
34665                                         //-                                     if ( t < t0 || t0 === undefined ) {
34666                                         if ( ! ( t >= t0 ) ) {
34667
34668                                                 // looping?
34669
34670                                                 const t1global = pp[ 1 ];
34671
34672                                                 if ( t < t1global ) {
34673
34674                                                         i1 = 2; // + 1, using the scan for the details
34675                                                         t0 = t1global;
34676
34677                                                 }
34678
34679                                                 // linear reverse scan
34680
34681                                                 for ( let giveUpAt = i1 - 2; ; ) {
34682
34683                                                         if ( t0 === undefined ) {
34684
34685                                                                 // before start
34686
34687                                                                 this._cachedIndex = 0;
34688                                                                 return this.beforeStart_( 0, t, t1 );
34689
34690                                                         }
34691
34692                                                         if ( i1 === giveUpAt ) break; // this loop
34693
34694                                                         t1 = t0;
34695                                                         t0 = pp[ -- i1 - 1 ];
34696
34697                                                         if ( t >= t0 ) {
34698
34699                                                                 // we have arrived at the sought interval
34700                                                                 break seek;
34701
34702                                                         }
34703
34704                                                 }
34705
34706                                                 // prepare binary search on the left side of the index
34707                                                 right = i1;
34708                                                 i1 = 0;
34709                                                 break linear_scan;
34710
34711                                         }
34712
34713                                         // the interval is valid
34714
34715                                         break validate_interval;
34716
34717                                 } // linear scan
34718
34719                                 // binary search
34720
34721                                 while ( i1 < right ) {
34722
34723                                         const mid = ( i1 + right ) >>> 1;
34724
34725                                         if ( t < pp[ mid ] ) {
34726
34727                                                 right = mid;
34728
34729                                         } else {
34730
34731                                                 i1 = mid + 1;
34732
34733                                         }
34734
34735                                 }
34736
34737                                 t1 = pp[ i1 ];
34738                                 t0 = pp[ i1 - 1 ];
34739
34740                                 // check boundary cases, again
34741
34742                                 if ( t0 === undefined ) {
34743
34744                                         this._cachedIndex = 0;
34745                                         return this.beforeStart_( 0, t, t1 );
34746
34747                                 }
34748
34749                                 if ( t1 === undefined ) {
34750
34751                                         i1 = pp.length;
34752                                         this._cachedIndex = i1;
34753                                         return this.afterEnd_( i1 - 1, t0, t );
34754
34755                                 }
34756
34757                         } // seek
34758
34759                         this._cachedIndex = i1;
34760
34761                         this.intervalChanged_( i1, t0, t1 );
34762
34763                 } // validate_interval
34764
34765                 return this.interpolate_( i1, t0, t, t1 );
34766
34767         },
34768
34769         settings: null, // optional, subclass-specific settings structure
34770         // Note: The indirection allows central control of many interpolants.
34771
34772         // --- Protected interface
34773
34774         DefaultSettings_: {},
34775
34776         getSettings_: function () {
34777
34778                 return this.settings || this.DefaultSettings_;
34779
34780         },
34781
34782         copySampleValue_: function ( index ) {
34783
34784                 // copies a sample value to the result buffer
34785
34786                 const result = this.resultBuffer,
34787                         values = this.sampleValues,
34788                         stride = this.valueSize,
34789                         offset = index * stride;
34790
34791                 for ( let i = 0; i !== stride; ++ i ) {
34792
34793                         result[ i ] = values[ offset + i ];
34794
34795                 }
34796
34797                 return result;
34798
34799         },
34800
34801         // Template methods for derived classes:
34802
34803         interpolate_: function ( /* i1, t0, t, t1 */ ) {
34804
34805                 throw new Error( 'call to abstract method' );
34806                 // implementations shall return this.resultBuffer
34807
34808         },
34809
34810         intervalChanged_: function ( /* i1, t0, t1 */ ) {
34811
34812                 // empty
34813
34814         }
34815
34816 } );
34817
34818 // DECLARE ALIAS AFTER assign prototype
34819 Object.assign( Interpolant.prototype, {
34820
34821         //( 0, t, t0 ), returns this.resultBuffer
34822         beforeStart_: Interpolant.prototype.copySampleValue_,
34823
34824         //( N-1, tN-1, t ), returns this.resultBuffer
34825         afterEnd_: Interpolant.prototype.copySampleValue_,
34826
34827 } );
34828
34829 /**
34830  * Fast and simple cubic spline interpolant.
34831  *
34832  * It was derived from a Hermitian construction setting the first derivative
34833  * at each sample position to the linear slope between neighboring positions
34834  * over their parameter interval.
34835  */
34836
34837 function CubicInterpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) {
34838
34839         Interpolant.call( this, parameterPositions, sampleValues, sampleSize, resultBuffer );
34840
34841         this._weightPrev = - 0;
34842         this._offsetPrev = - 0;
34843         this._weightNext = - 0;
34844         this._offsetNext = - 0;
34845
34846 }
34847
34848 CubicInterpolant.prototype = Object.assign( Object.create( Interpolant.prototype ), {
34849
34850         constructor: CubicInterpolant,
34851
34852         DefaultSettings_: {
34853
34854                 endingStart: ZeroCurvatureEnding,
34855                 endingEnd: ZeroCurvatureEnding
34856
34857         },
34858
34859         intervalChanged_: function ( i1, t0, t1 ) {
34860
34861                 const pp = this.parameterPositions;
34862                 let iPrev = i1 - 2,
34863                         iNext = i1 + 1,
34864
34865                         tPrev = pp[ iPrev ],
34866                         tNext = pp[ iNext ];
34867
34868                 if ( tPrev === undefined ) {
34869
34870                         switch ( this.getSettings_().endingStart ) {
34871
34872                                 case ZeroSlopeEnding:
34873
34874                                         // f'(t0) = 0
34875                                         iPrev = i1;
34876                                         tPrev = 2 * t0 - t1;
34877
34878                                         break;
34879
34880                                 case WrapAroundEnding:
34881
34882                                         // use the other end of the curve
34883                                         iPrev = pp.length - 2;
34884                                         tPrev = t0 + pp[ iPrev ] - pp[ iPrev + 1 ];
34885
34886                                         break;
34887
34888                                 default: // ZeroCurvatureEnding
34889
34890                                         // f''(t0) = 0 a.k.a. Natural Spline
34891                                         iPrev = i1;
34892                                         tPrev = t1;
34893
34894                         }
34895
34896                 }
34897
34898                 if ( tNext === undefined ) {
34899
34900                         switch ( this.getSettings_().endingEnd ) {
34901
34902                                 case ZeroSlopeEnding:
34903
34904                                         // f'(tN) = 0
34905                                         iNext = i1;
34906                                         tNext = 2 * t1 - t0;
34907
34908                                         break;
34909
34910                                 case WrapAroundEnding:
34911
34912                                         // use the other end of the curve
34913                                         iNext = 1;
34914                                         tNext = t1 + pp[ 1 ] - pp[ 0 ];
34915
34916                                         break;
34917
34918                                 default: // ZeroCurvatureEnding
34919
34920                                         // f''(tN) = 0, a.k.a. Natural Spline
34921                                         iNext = i1 - 1;
34922                                         tNext = t0;
34923
34924                         }
34925
34926                 }
34927
34928                 const halfDt = ( t1 - t0 ) * 0.5,
34929                         stride = this.valueSize;
34930
34931                 this._weightPrev = halfDt / ( t0 - tPrev );
34932                 this._weightNext = halfDt / ( tNext - t1 );
34933                 this._offsetPrev = iPrev * stride;
34934                 this._offsetNext = iNext * stride;
34935
34936         },
34937
34938         interpolate_: function ( i1, t0, t, t1 ) {
34939
34940                 const result = this.resultBuffer,
34941                         values = this.sampleValues,
34942                         stride = this.valueSize,
34943
34944                         o1 = i1 * stride,               o0 = o1 - stride,
34945                         oP = this._offsetPrev,  oN = this._offsetNext,
34946                         wP = this._weightPrev,  wN = this._weightNext,
34947
34948                         p = ( t - t0 ) / ( t1 - t0 ),
34949                         pp = p * p,
34950                         ppp = pp * p;
34951
34952                 // evaluate polynomials
34953
34954                 const sP = - wP * ppp + 2 * wP * pp - wP * p;
34955                 const s0 = ( 1 + wP ) * ppp + ( - 1.5 - 2 * wP ) * pp + ( - 0.5 + wP ) * p + 1;
34956                 const s1 = ( - 1 - wN ) * ppp + ( 1.5 + wN ) * pp + 0.5 * p;
34957                 const sN = wN * ppp - wN * pp;
34958
34959                 // combine data linearly
34960
34961                 for ( let i = 0; i !== stride; ++ i ) {
34962
34963                         result[ i ] =
34964                                         sP * values[ oP + i ] +
34965                                         s0 * values[ o0 + i ] +
34966                                         s1 * values[ o1 + i ] +
34967                                         sN * values[ oN + i ];
34968
34969                 }
34970
34971                 return result;
34972
34973         }
34974
34975 } );
34976
34977 function LinearInterpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) {
34978
34979         Interpolant.call( this, parameterPositions, sampleValues, sampleSize, resultBuffer );
34980
34981 }
34982
34983 LinearInterpolant.prototype = Object.assign( Object.create( Interpolant.prototype ), {
34984
34985         constructor: LinearInterpolant,
34986
34987         interpolate_: function ( i1, t0, t, t1 ) {
34988
34989                 const result = this.resultBuffer,
34990                         values = this.sampleValues,
34991                         stride = this.valueSize,
34992
34993                         offset1 = i1 * stride,
34994                         offset0 = offset1 - stride,
34995
34996                         weight1 = ( t - t0 ) / ( t1 - t0 ),
34997                         weight0 = 1 - weight1;
34998
34999                 for ( let i = 0; i !== stride; ++ i ) {
35000
35001                         result[ i ] =
35002                                         values[ offset0 + i ] * weight0 +
35003                                         values[ offset1 + i ] * weight1;
35004
35005                 }
35006
35007                 return result;
35008
35009         }
35010
35011 } );
35012
35013 /**
35014  *
35015  * Interpolant that evaluates to the sample value at the position preceeding
35016  * the parameter.
35017  */
35018
35019 function DiscreteInterpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) {
35020
35021         Interpolant.call( this, parameterPositions, sampleValues, sampleSize, resultBuffer );
35022
35023 }
35024
35025 DiscreteInterpolant.prototype = Object.assign( Object.create( Interpolant.prototype ), {
35026
35027         constructor: DiscreteInterpolant,
35028
35029         interpolate_: function ( i1 /*, t0, t, t1 */ ) {
35030
35031                 return this.copySampleValue_( i1 - 1 );
35032
35033         }
35034
35035 } );
35036
35037 function KeyframeTrack( name, times, values, interpolation ) {
35038
35039         if ( name === undefined ) throw new Error( 'THREE.KeyframeTrack: track name is undefined' );
35040         if ( times === undefined || times.length === 0 ) throw new Error( 'THREE.KeyframeTrack: no keyframes in track named ' + name );
35041
35042         this.name = name;
35043
35044         this.times = AnimationUtils.convertArray( times, this.TimeBufferType );
35045         this.values = AnimationUtils.convertArray( values, this.ValueBufferType );
35046
35047         this.setInterpolation( interpolation || this.DefaultInterpolation );
35048
35049 }
35050
35051 // Static methods
35052
35053 Object.assign( KeyframeTrack, {
35054
35055         // Serialization (in static context, because of constructor invocation
35056         // and automatic invocation of .toJSON):
35057
35058         toJSON: function ( track ) {
35059
35060                 const trackType = track.constructor;
35061
35062                 let json;
35063
35064                 // derived classes can define a static toJSON method
35065                 if ( trackType.toJSON !== undefined ) {
35066
35067                         json = trackType.toJSON( track );
35068
35069                 } else {
35070
35071                         // by default, we assume the data can be serialized as-is
35072                         json = {
35073
35074                                 'name': track.name,
35075                                 'times': AnimationUtils.convertArray( track.times, Array ),
35076                                 'values': AnimationUtils.convertArray( track.values, Array )
35077
35078                         };
35079
35080                         const interpolation = track.getInterpolation();
35081
35082                         if ( interpolation !== track.DefaultInterpolation ) {
35083
35084                                 json.interpolation = interpolation;
35085
35086                         }
35087
35088                 }
35089
35090                 json.type = track.ValueTypeName; // mandatory
35091
35092                 return json;
35093
35094         }
35095
35096 } );
35097
35098 Object.assign( KeyframeTrack.prototype, {
35099
35100         constructor: KeyframeTrack,
35101
35102         TimeBufferType: Float32Array,
35103
35104         ValueBufferType: Float32Array,
35105
35106         DefaultInterpolation: InterpolateLinear,
35107
35108         InterpolantFactoryMethodDiscrete: function ( result ) {
35109
35110                 return new DiscreteInterpolant( this.times, this.values, this.getValueSize(), result );
35111
35112         },
35113
35114         InterpolantFactoryMethodLinear: function ( result ) {
35115
35116                 return new LinearInterpolant( this.times, this.values, this.getValueSize(), result );
35117
35118         },
35119
35120         InterpolantFactoryMethodSmooth: function ( result ) {
35121
35122                 return new CubicInterpolant( this.times, this.values, this.getValueSize(), result );
35123
35124         },
35125
35126         setInterpolation: function ( interpolation ) {
35127
35128                 let factoryMethod;
35129
35130                 switch ( interpolation ) {
35131
35132                         case InterpolateDiscrete:
35133
35134                                 factoryMethod = this.InterpolantFactoryMethodDiscrete;
35135
35136                                 break;
35137
35138                         case InterpolateLinear:
35139
35140                                 factoryMethod = this.InterpolantFactoryMethodLinear;
35141
35142                                 break;
35143
35144                         case InterpolateSmooth:
35145
35146                                 factoryMethod = this.InterpolantFactoryMethodSmooth;
35147
35148                                 break;
35149
35150                 }
35151
35152                 if ( factoryMethod === undefined ) {
35153
35154                         const message = 'unsupported interpolation for ' +
35155                                 this.ValueTypeName + ' keyframe track named ' + this.name;
35156
35157                         if ( this.createInterpolant === undefined ) {
35158
35159                                 // fall back to default, unless the default itself is messed up
35160                                 if ( interpolation !== this.DefaultInterpolation ) {
35161
35162                                         this.setInterpolation( this.DefaultInterpolation );
35163
35164                                 } else {
35165
35166                                         throw new Error( message ); // fatal, in this case
35167
35168                                 }
35169
35170                         }
35171
35172                         console.warn( 'THREE.KeyframeTrack:', message );
35173                         return this;
35174
35175                 }
35176
35177                 this.createInterpolant = factoryMethod;
35178
35179                 return this;
35180
35181         },
35182
35183         getInterpolation: function () {
35184
35185                 switch ( this.createInterpolant ) {
35186
35187                         case this.InterpolantFactoryMethodDiscrete:
35188
35189                                 return InterpolateDiscrete;
35190
35191                         case this.InterpolantFactoryMethodLinear:
35192
35193                                 return InterpolateLinear;
35194
35195                         case this.InterpolantFactoryMethodSmooth:
35196
35197                                 return InterpolateSmooth;
35198
35199                 }
35200
35201         },
35202
35203         getValueSize: function () {
35204
35205                 return this.values.length / this.times.length;
35206
35207         },
35208
35209         // move all keyframes either forwards or backwards in time
35210         shift: function ( timeOffset ) {
35211
35212                 if ( timeOffset !== 0.0 ) {
35213
35214                         const times = this.times;
35215
35216                         for ( let i = 0, n = times.length; i !== n; ++ i ) {
35217
35218                                 times[ i ] += timeOffset;
35219
35220                         }
35221
35222                 }
35223
35224                 return this;
35225
35226         },
35227
35228         // scale all keyframe times by a factor (useful for frame <-> seconds conversions)
35229         scale: function ( timeScale ) {
35230
35231                 if ( timeScale !== 1.0 ) {
35232
35233                         const times = this.times;
35234
35235                         for ( let i = 0, n = times.length; i !== n; ++ i ) {
35236
35237                                 times[ i ] *= timeScale;
35238
35239                         }
35240
35241                 }
35242
35243                 return this;
35244
35245         },
35246
35247         // removes keyframes before and after animation without changing any values within the range [startTime, endTime].
35248         // IMPORTANT: We do not shift around keys to the start of the track time, because for interpolated keys this will change their values
35249         trim: function ( startTime, endTime ) {
35250
35251                 const times = this.times,
35252                         nKeys = times.length;
35253
35254                 let from = 0,
35255                         to = nKeys - 1;
35256
35257                 while ( from !== nKeys && times[ from ] < startTime ) {
35258
35259                         ++ from;
35260
35261                 }
35262
35263                 while ( to !== - 1 && times[ to ] > endTime ) {
35264
35265                         -- to;
35266
35267                 }
35268
35269                 ++ to; // inclusive -> exclusive bound
35270
35271                 if ( from !== 0 || to !== nKeys ) {
35272
35273                         // empty tracks are forbidden, so keep at least one keyframe
35274                         if ( from >= to ) {
35275
35276                                 to = Math.max( to, 1 );
35277                                 from = to - 1;
35278
35279                         }
35280
35281                         const stride = this.getValueSize();
35282                         this.times = AnimationUtils.arraySlice( times, from, to );
35283                         this.values = AnimationUtils.arraySlice( this.values, from * stride, to * stride );
35284
35285                 }
35286
35287                 return this;
35288
35289         },
35290
35291         // ensure we do not get a GarbageInGarbageOut situation, make sure tracks are at least minimally viable
35292         validate: function () {
35293
35294                 let valid = true;
35295
35296                 const valueSize = this.getValueSize();
35297                 if ( valueSize - Math.floor( valueSize ) !== 0 ) {
35298
35299                         console.error( 'THREE.KeyframeTrack: Invalid value size in track.', this );
35300                         valid = false;
35301
35302                 }
35303
35304                 const times = this.times,
35305                         values = this.values,
35306
35307                         nKeys = times.length;
35308
35309                 if ( nKeys === 0 ) {
35310
35311                         console.error( 'THREE.KeyframeTrack: Track is empty.', this );
35312                         valid = false;
35313
35314                 }
35315
35316                 let prevTime = null;
35317
35318                 for ( let i = 0; i !== nKeys; i ++ ) {
35319
35320                         const currTime = times[ i ];
35321
35322                         if ( typeof currTime === 'number' && isNaN( currTime ) ) {
35323
35324                                 console.error( 'THREE.KeyframeTrack: Time is not a valid number.', this, i, currTime );
35325                                 valid = false;
35326                                 break;
35327
35328                         }
35329
35330                         if ( prevTime !== null && prevTime > currTime ) {
35331
35332                                 console.error( 'THREE.KeyframeTrack: Out of order keys.', this, i, currTime, prevTime );
35333                                 valid = false;
35334                                 break;
35335
35336                         }
35337
35338                         prevTime = currTime;
35339
35340                 }
35341
35342                 if ( values !== undefined ) {
35343
35344                         if ( AnimationUtils.isTypedArray( values ) ) {
35345
35346                                 for ( let i = 0, n = values.length; i !== n; ++ i ) {
35347
35348                                         const value = values[ i ];
35349
35350                                         if ( isNaN( value ) ) {
35351
35352                                                 console.error( 'THREE.KeyframeTrack: Value is not a valid number.', this, i, value );
35353                                                 valid = false;
35354                                                 break;
35355
35356                                         }
35357
35358                                 }
35359
35360                         }
35361
35362                 }
35363
35364                 return valid;
35365
35366         },
35367
35368         // removes equivalent sequential keys as common in morph target sequences
35369         // (0,0,0,0,1,1,1,0,0,0,0,0,0,0) --> (0,0,1,1,0,0)
35370         optimize: function () {
35371
35372                 // times or values may be shared with other tracks, so overwriting is unsafe
35373                 const times = AnimationUtils.arraySlice( this.times ),
35374                         values = AnimationUtils.arraySlice( this.values ),
35375                         stride = this.getValueSize(),
35376
35377                         smoothInterpolation = this.getInterpolation() === InterpolateSmooth,
35378
35379                         lastIndex = times.length - 1;
35380
35381                 let writeIndex = 1;
35382
35383                 for ( let i = 1; i < lastIndex; ++ i ) {
35384
35385                         let keep = false;
35386
35387                         const time = times[ i ];
35388                         const timeNext = times[ i + 1 ];
35389
35390                         // remove adjacent keyframes scheduled at the same time
35391
35392                         if ( time !== timeNext && ( i !== 1 || time !== times[ 0 ] ) ) {
35393
35394                                 if ( ! smoothInterpolation ) {
35395
35396                                         // remove unnecessary keyframes same as their neighbors
35397
35398                                         const offset = i * stride,
35399                                                 offsetP = offset - stride,
35400                                                 offsetN = offset + stride;
35401
35402                                         for ( let j = 0; j !== stride; ++ j ) {
35403
35404                                                 const value = values[ offset + j ];
35405
35406                                                 if ( value !== values[ offsetP + j ] ||
35407                                                         value !== values[ offsetN + j ] ) {
35408
35409                                                         keep = true;
35410                                                         break;
35411
35412                                                 }
35413
35414                                         }
35415
35416                                 } else {
35417
35418                                         keep = true;
35419
35420                                 }
35421
35422                         }
35423
35424                         // in-place compaction
35425
35426                         if ( keep ) {
35427
35428                                 if ( i !== writeIndex ) {
35429
35430                                         times[ writeIndex ] = times[ i ];
35431
35432                                         const readOffset = i * stride,
35433                                                 writeOffset = writeIndex * stride;
35434
35435                                         for ( let j = 0; j !== stride; ++ j ) {
35436
35437                                                 values[ writeOffset + j ] = values[ readOffset + j ];
35438
35439                                         }
35440
35441                                 }
35442
35443                                 ++ writeIndex;
35444
35445                         }
35446
35447                 }
35448
35449                 // flush last keyframe (compaction looks ahead)
35450
35451                 if ( lastIndex > 0 ) {
35452
35453                         times[ writeIndex ] = times[ lastIndex ];
35454
35455                         for ( let readOffset = lastIndex * stride, writeOffset = writeIndex * stride, j = 0; j !== stride; ++ j ) {
35456
35457                                 values[ writeOffset + j ] = values[ readOffset + j ];
35458
35459                         }
35460
35461                         ++ writeIndex;
35462
35463                 }
35464
35465                 if ( writeIndex !== times.length ) {
35466
35467                         this.times = AnimationUtils.arraySlice( times, 0, writeIndex );
35468                         this.values = AnimationUtils.arraySlice( values, 0, writeIndex * stride );
35469
35470                 } else {
35471
35472                         this.times = times;
35473                         this.values = values;
35474
35475                 }
35476
35477                 return this;
35478
35479         },
35480
35481         clone: function () {
35482
35483                 const times = AnimationUtils.arraySlice( this.times, 0 );
35484                 const values = AnimationUtils.arraySlice( this.values, 0 );
35485
35486                 const TypedKeyframeTrack = this.constructor;
35487                 const track = new TypedKeyframeTrack( this.name, times, values );
35488
35489                 // Interpolant argument to constructor is not saved, so copy the factory method directly.
35490                 track.createInterpolant = this.createInterpolant;
35491
35492                 return track;
35493
35494         }
35495
35496 } );
35497
35498 /**
35499  * A Track of Boolean keyframe values.
35500  */
35501
35502 function BooleanKeyframeTrack( name, times, values ) {
35503
35504         KeyframeTrack.call( this, name, times, values );
35505
35506 }
35507
35508 BooleanKeyframeTrack.prototype = Object.assign( Object.create( KeyframeTrack.prototype ), {
35509
35510         constructor: BooleanKeyframeTrack,
35511
35512         ValueTypeName: 'bool',
35513         ValueBufferType: Array,
35514
35515         DefaultInterpolation: InterpolateDiscrete,
35516
35517         InterpolantFactoryMethodLinear: undefined,
35518         InterpolantFactoryMethodSmooth: undefined
35519
35520         // Note: Actually this track could have a optimized / compressed
35521         // representation of a single value and a custom interpolant that
35522         // computes "firstValue ^ isOdd( index )".
35523
35524 } );
35525
35526 /**
35527  * A Track of keyframe values that represent color.
35528  */
35529
35530 function ColorKeyframeTrack( name, times, values, interpolation ) {
35531
35532         KeyframeTrack.call( this, name, times, values, interpolation );
35533
35534 }
35535
35536 ColorKeyframeTrack.prototype = Object.assign( Object.create( KeyframeTrack.prototype ), {
35537
35538         constructor: ColorKeyframeTrack,
35539
35540         ValueTypeName: 'color'
35541
35542         // ValueBufferType is inherited
35543
35544         // DefaultInterpolation is inherited
35545
35546         // Note: Very basic implementation and nothing special yet.
35547         // However, this is the place for color space parameterization.
35548
35549 } );
35550
35551 /**
35552  * A Track of numeric keyframe values.
35553  */
35554
35555 function NumberKeyframeTrack( name, times, values, interpolation ) {
35556
35557         KeyframeTrack.call( this, name, times, values, interpolation );
35558
35559 }
35560
35561 NumberKeyframeTrack.prototype = Object.assign( Object.create( KeyframeTrack.prototype ), {
35562
35563         constructor: NumberKeyframeTrack,
35564
35565         ValueTypeName: 'number'
35566
35567         // ValueBufferType is inherited
35568
35569         // DefaultInterpolation is inherited
35570
35571 } );
35572
35573 /**
35574  * Spherical linear unit quaternion interpolant.
35575  */
35576
35577 function QuaternionLinearInterpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) {
35578
35579         Interpolant.call( this, parameterPositions, sampleValues, sampleSize, resultBuffer );
35580
35581 }
35582
35583 QuaternionLinearInterpolant.prototype = Object.assign( Object.create( Interpolant.prototype ), {
35584
35585         constructor: QuaternionLinearInterpolant,
35586
35587         interpolate_: function ( i1, t0, t, t1 ) {
35588
35589                 const result = this.resultBuffer,
35590                         values = this.sampleValues,
35591                         stride = this.valueSize,
35592
35593                         alpha = ( t - t0 ) / ( t1 - t0 );
35594
35595                 let offset = i1 * stride;
35596
35597                 for ( let end = offset + stride; offset !== end; offset += 4 ) {
35598
35599                         Quaternion.slerpFlat( result, 0, values, offset - stride, values, offset, alpha );
35600
35601                 }
35602
35603                 return result;
35604
35605         }
35606
35607 } );
35608
35609 /**
35610  * A Track of quaternion keyframe values.
35611  */
35612
35613 function QuaternionKeyframeTrack( name, times, values, interpolation ) {
35614
35615         KeyframeTrack.call( this, name, times, values, interpolation );
35616
35617 }
35618
35619 QuaternionKeyframeTrack.prototype = Object.assign( Object.create( KeyframeTrack.prototype ), {
35620
35621         constructor: QuaternionKeyframeTrack,
35622
35623         ValueTypeName: 'quaternion',
35624
35625         // ValueBufferType is inherited
35626
35627         DefaultInterpolation: InterpolateLinear,
35628
35629         InterpolantFactoryMethodLinear: function ( result ) {
35630
35631                 return new QuaternionLinearInterpolant( this.times, this.values, this.getValueSize(), result );
35632
35633         },
35634
35635         InterpolantFactoryMethodSmooth: undefined // not yet implemented
35636
35637 } );
35638
35639 /**
35640  * A Track that interpolates Strings
35641  */
35642
35643 function StringKeyframeTrack( name, times, values, interpolation ) {
35644
35645         KeyframeTrack.call( this, name, times, values, interpolation );
35646
35647 }
35648
35649 StringKeyframeTrack.prototype = Object.assign( Object.create( KeyframeTrack.prototype ), {
35650
35651         constructor: StringKeyframeTrack,
35652
35653         ValueTypeName: 'string',
35654         ValueBufferType: Array,
35655
35656         DefaultInterpolation: InterpolateDiscrete,
35657
35658         InterpolantFactoryMethodLinear: undefined,
35659
35660         InterpolantFactoryMethodSmooth: undefined
35661
35662 } );
35663
35664 /**
35665  * A Track of vectored keyframe values.
35666  */
35667
35668 function VectorKeyframeTrack( name, times, values, interpolation ) {
35669
35670         KeyframeTrack.call( this, name, times, values, interpolation );
35671
35672 }
35673
35674 VectorKeyframeTrack.prototype = Object.assign( Object.create( KeyframeTrack.prototype ), {
35675
35676         constructor: VectorKeyframeTrack,
35677
35678         ValueTypeName: 'vector'
35679
35680         // ValueBufferType is inherited
35681
35682         // DefaultInterpolation is inherited
35683
35684 } );
35685
35686 function AnimationClip( name, duration = - 1, tracks, blendMode = NormalAnimationBlendMode ) {
35687
35688         this.name = name;
35689         this.tracks = tracks;
35690         this.duration = duration;
35691         this.blendMode = blendMode;
35692
35693         this.uuid = MathUtils.generateUUID();
35694
35695         // this means it should figure out its duration by scanning the tracks
35696         if ( this.duration < 0 ) {
35697
35698                 this.resetDuration();
35699
35700         }
35701
35702 }
35703
35704 function getTrackTypeForValueTypeName( typeName ) {
35705
35706         switch ( typeName.toLowerCase() ) {
35707
35708                 case 'scalar':
35709                 case 'double':
35710                 case 'float':
35711                 case 'number':
35712                 case 'integer':
35713
35714                         return NumberKeyframeTrack;
35715
35716                 case 'vector':
35717                 case 'vector2':
35718                 case 'vector3':
35719                 case 'vector4':
35720
35721                         return VectorKeyframeTrack;
35722
35723                 case 'color':
35724
35725                         return ColorKeyframeTrack;
35726
35727                 case 'quaternion':
35728
35729                         return QuaternionKeyframeTrack;
35730
35731                 case 'bool':
35732                 case 'boolean':
35733
35734                         return BooleanKeyframeTrack;
35735
35736                 case 'string':
35737
35738                         return StringKeyframeTrack;
35739
35740         }
35741
35742         throw new Error( 'THREE.KeyframeTrack: Unsupported typeName: ' + typeName );
35743
35744 }
35745
35746 function parseKeyframeTrack( json ) {
35747
35748         if ( json.type === undefined ) {
35749
35750                 throw new Error( 'THREE.KeyframeTrack: track type undefined, can not parse' );
35751
35752         }
35753
35754         const trackType = getTrackTypeForValueTypeName( json.type );
35755
35756         if ( json.times === undefined ) {
35757
35758                 const times = [], values = [];
35759
35760                 AnimationUtils.flattenJSON( json.keys, times, values, 'value' );
35761
35762                 json.times = times;
35763                 json.values = values;
35764
35765         }
35766
35767         // derived classes can define a static parse method
35768         if ( trackType.parse !== undefined ) {
35769
35770                 return trackType.parse( json );
35771
35772         } else {
35773
35774                 // by default, we assume a constructor compatible with the base
35775                 return new trackType( json.name, json.times, json.values, json.interpolation );
35776
35777         }
35778
35779 }
35780
35781 Object.assign( AnimationClip, {
35782
35783         parse: function ( json ) {
35784
35785                 const tracks = [],
35786                         jsonTracks = json.tracks,
35787                         frameTime = 1.0 / ( json.fps || 1.0 );
35788
35789                 for ( let i = 0, n = jsonTracks.length; i !== n; ++ i ) {
35790
35791                         tracks.push( parseKeyframeTrack( jsonTracks[ i ] ).scale( frameTime ) );
35792
35793                 }
35794
35795                 const clip = new AnimationClip( json.name, json.duration, tracks, json.blendMode );
35796                 clip.uuid = json.uuid;
35797
35798                 return clip;
35799
35800         },
35801
35802         toJSON: function ( clip ) {
35803
35804                 const tracks = [],
35805                         clipTracks = clip.tracks;
35806
35807                 const json = {
35808
35809                         'name': clip.name,
35810                         'duration': clip.duration,
35811                         'tracks': tracks,
35812                         'uuid': clip.uuid,
35813                         'blendMode': clip.blendMode
35814
35815                 };
35816
35817                 for ( let i = 0, n = clipTracks.length; i !== n; ++ i ) {
35818
35819                         tracks.push( KeyframeTrack.toJSON( clipTracks[ i ] ) );
35820
35821                 }
35822
35823                 return json;
35824
35825         },
35826
35827         CreateFromMorphTargetSequence: function ( name, morphTargetSequence, fps, noLoop ) {
35828
35829                 const numMorphTargets = morphTargetSequence.length;
35830                 const tracks = [];
35831
35832                 for ( let i = 0; i < numMorphTargets; i ++ ) {
35833
35834                         let times = [];
35835                         let values = [];
35836
35837                         times.push(
35838                                 ( i + numMorphTargets - 1 ) % numMorphTargets,
35839                                 i,
35840                                 ( i + 1 ) % numMorphTargets );
35841
35842                         values.push( 0, 1, 0 );
35843
35844                         const order = AnimationUtils.getKeyframeOrder( times );
35845                         times = AnimationUtils.sortedArray( times, 1, order );
35846                         values = AnimationUtils.sortedArray( values, 1, order );
35847
35848                         // if there is a key at the first frame, duplicate it as the
35849                         // last frame as well for perfect loop.
35850                         if ( ! noLoop && times[ 0 ] === 0 ) {
35851
35852                                 times.push( numMorphTargets );
35853                                 values.push( values[ 0 ] );
35854
35855                         }
35856
35857                         tracks.push(
35858                                 new NumberKeyframeTrack(
35859                                         '.morphTargetInfluences[' + morphTargetSequence[ i ].name + ']',
35860                                         times, values
35861                                 ).scale( 1.0 / fps ) );
35862
35863                 }
35864
35865                 return new AnimationClip( name, - 1, tracks );
35866
35867         },
35868
35869         findByName: function ( objectOrClipArray, name ) {
35870
35871                 let clipArray = objectOrClipArray;
35872
35873                 if ( ! Array.isArray( objectOrClipArray ) ) {
35874
35875                         const o = objectOrClipArray;
35876                         clipArray = o.geometry && o.geometry.animations || o.animations;
35877
35878                 }
35879
35880                 for ( let i = 0; i < clipArray.length; i ++ ) {
35881
35882                         if ( clipArray[ i ].name === name ) {
35883
35884                                 return clipArray[ i ];
35885
35886                         }
35887
35888                 }
35889
35890                 return null;
35891
35892         },
35893
35894         CreateClipsFromMorphTargetSequences: function ( morphTargets, fps, noLoop ) {
35895
35896                 const animationToMorphTargets = {};
35897
35898                 // tested with https://regex101.com/ on trick sequences
35899                 // such flamingo_flyA_003, flamingo_run1_003, crdeath0059
35900                 const pattern = /^([\w-]*?)([\d]+)$/;
35901
35902                 // sort morph target names into animation groups based
35903                 // patterns like Walk_001, Walk_002, Run_001, Run_002
35904                 for ( let i = 0, il = morphTargets.length; i < il; i ++ ) {
35905
35906                         const morphTarget = morphTargets[ i ];
35907                         const parts = morphTarget.name.match( pattern );
35908
35909                         if ( parts && parts.length > 1 ) {
35910
35911                                 const name = parts[ 1 ];
35912
35913                                 let animationMorphTargets = animationToMorphTargets[ name ];
35914
35915                                 if ( ! animationMorphTargets ) {
35916
35917                                         animationToMorphTargets[ name ] = animationMorphTargets = [];
35918
35919                                 }
35920
35921                                 animationMorphTargets.push( morphTarget );
35922
35923                         }
35924
35925                 }
35926
35927                 const clips = [];
35928
35929                 for ( const name in animationToMorphTargets ) {
35930
35931                         clips.push( AnimationClip.CreateFromMorphTargetSequence( name, animationToMorphTargets[ name ], fps, noLoop ) );
35932
35933                 }
35934
35935                 return clips;
35936
35937         },
35938
35939         // parse the animation.hierarchy format
35940         parseAnimation: function ( animation, bones ) {
35941
35942                 if ( ! animation ) {
35943
35944                         console.error( 'THREE.AnimationClip: No animation in JSONLoader data.' );
35945                         return null;
35946
35947                 }
35948
35949                 const addNonemptyTrack = function ( trackType, trackName, animationKeys, propertyName, destTracks ) {
35950
35951                         // only return track if there are actually keys.
35952                         if ( animationKeys.length !== 0 ) {
35953
35954                                 const times = [];
35955                                 const values = [];
35956
35957                                 AnimationUtils.flattenJSON( animationKeys, times, values, propertyName );
35958
35959                                 // empty keys are filtered out, so check again
35960                                 if ( times.length !== 0 ) {
35961
35962                                         destTracks.push( new trackType( trackName, times, values ) );
35963
35964                                 }
35965
35966                         }
35967
35968                 };
35969
35970                 const tracks = [];
35971
35972                 const clipName = animation.name || 'default';
35973                 const fps = animation.fps || 30;
35974                 const blendMode = animation.blendMode;
35975
35976                 // automatic length determination in AnimationClip.
35977                 let duration = animation.length || - 1;
35978
35979                 const hierarchyTracks = animation.hierarchy || [];
35980
35981                 for ( let h = 0; h < hierarchyTracks.length; h ++ ) {
35982
35983                         const animationKeys = hierarchyTracks[ h ].keys;
35984
35985                         // skip empty tracks
35986                         if ( ! animationKeys || animationKeys.length === 0 ) continue;
35987
35988                         // process morph targets
35989                         if ( animationKeys[ 0 ].morphTargets ) {
35990
35991                                 // figure out all morph targets used in this track
35992                                 const morphTargetNames = {};
35993
35994                                 let k;
35995
35996                                 for ( k = 0; k < animationKeys.length; k ++ ) {
35997
35998                                         if ( animationKeys[ k ].morphTargets ) {
35999
36000                                                 for ( let m = 0; m < animationKeys[ k ].morphTargets.length; m ++ ) {
36001
36002                                                         morphTargetNames[ animationKeys[ k ].morphTargets[ m ] ] = - 1;
36003
36004                                                 }
36005
36006                                         }
36007
36008                                 }
36009
36010                                 // create a track for each morph target with all zero
36011                                 // morphTargetInfluences except for the keys in which
36012                                 // the morphTarget is named.
36013                                 for ( const morphTargetName in morphTargetNames ) {
36014
36015                                         const times = [];
36016                                         const values = [];
36017
36018                                         for ( let m = 0; m !== animationKeys[ k ].morphTargets.length; ++ m ) {
36019
36020                                                 const animationKey = animationKeys[ k ];
36021
36022                                                 times.push( animationKey.time );
36023                                                 values.push( ( animationKey.morphTarget === morphTargetName ) ? 1 : 0 );
36024
36025                                         }
36026
36027                                         tracks.push( new NumberKeyframeTrack( '.morphTargetInfluence[' + morphTargetName + ']', times, values ) );
36028
36029                                 }
36030
36031                                 duration = morphTargetNames.length * ( fps || 1.0 );
36032
36033                         } else {
36034
36035                                 // ...assume skeletal animation
36036
36037                                 const boneName = '.bones[' + bones[ h ].name + ']';
36038
36039                                 addNonemptyTrack(
36040                                         VectorKeyframeTrack, boneName + '.position',
36041                                         animationKeys, 'pos', tracks );
36042
36043                                 addNonemptyTrack(
36044                                         QuaternionKeyframeTrack, boneName + '.quaternion',
36045                                         animationKeys, 'rot', tracks );
36046
36047                                 addNonemptyTrack(
36048                                         VectorKeyframeTrack, boneName + '.scale',
36049                                         animationKeys, 'scl', tracks );
36050
36051                         }
36052
36053                 }
36054
36055                 if ( tracks.length === 0 ) {
36056
36057                         return null;
36058
36059                 }
36060
36061                 const clip = new AnimationClip( clipName, duration, tracks, blendMode );
36062
36063                 return clip;
36064
36065         }
36066
36067 } );
36068
36069 Object.assign( AnimationClip.prototype, {
36070
36071         resetDuration: function () {
36072
36073                 const tracks = this.tracks;
36074                 let duration = 0;
36075
36076                 for ( let i = 0, n = tracks.length; i !== n; ++ i ) {
36077
36078                         const track = this.tracks[ i ];
36079
36080                         duration = Math.max( duration, track.times[ track.times.length - 1 ] );
36081
36082                 }
36083
36084                 this.duration = duration;
36085
36086                 return this;
36087
36088         },
36089
36090         trim: function () {
36091
36092                 for ( let i = 0; i < this.tracks.length; i ++ ) {
36093
36094                         this.tracks[ i ].trim( 0, this.duration );
36095
36096                 }
36097
36098                 return this;
36099
36100         },
36101
36102         validate: function () {
36103
36104                 let valid = true;
36105
36106                 for ( let i = 0; i < this.tracks.length; i ++ ) {
36107
36108                         valid = valid && this.tracks[ i ].validate();
36109
36110                 }
36111
36112                 return valid;
36113
36114         },
36115
36116         optimize: function () {
36117
36118                 for ( let i = 0; i < this.tracks.length; i ++ ) {
36119
36120                         this.tracks[ i ].optimize();
36121
36122                 }
36123
36124                 return this;
36125
36126         },
36127
36128         clone: function () {
36129
36130                 const tracks = [];
36131
36132                 for ( let i = 0; i < this.tracks.length; i ++ ) {
36133
36134                         tracks.push( this.tracks[ i ].clone() );
36135
36136                 }
36137
36138                 return new AnimationClip( this.name, this.duration, tracks, this.blendMode );
36139
36140         },
36141
36142         toJSON: function () {
36143
36144                 return AnimationClip.toJSON( this );
36145
36146         }
36147
36148 } );
36149
36150 const Cache = {
36151
36152         enabled: false,
36153
36154         files: {},
36155
36156         add: function ( key, file ) {
36157
36158                 if ( this.enabled === false ) return;
36159
36160                 // console.log( 'THREE.Cache', 'Adding key:', key );
36161
36162                 this.files[ key ] = file;
36163
36164         },
36165
36166         get: function ( key ) {
36167
36168                 if ( this.enabled === false ) return;
36169
36170                 // console.log( 'THREE.Cache', 'Checking key:', key );
36171
36172                 return this.files[ key ];
36173
36174         },
36175
36176         remove: function ( key ) {
36177
36178                 delete this.files[ key ];
36179
36180         },
36181
36182         clear: function () {
36183
36184                 this.files = {};
36185
36186         }
36187
36188 };
36189
36190 function LoadingManager( onLoad, onProgress, onError ) {
36191
36192         const scope = this;
36193
36194         let isLoading = false;
36195         let itemsLoaded = 0;
36196         let itemsTotal = 0;
36197         let urlModifier = undefined;
36198         const handlers = [];
36199
36200         // Refer to #5689 for the reason why we don't set .onStart
36201         // in the constructor
36202
36203         this.onStart = undefined;
36204         this.onLoad = onLoad;
36205         this.onProgress = onProgress;
36206         this.onError = onError;
36207
36208         this.itemStart = function ( url ) {
36209
36210                 itemsTotal ++;
36211
36212                 if ( isLoading === false ) {
36213
36214                         if ( scope.onStart !== undefined ) {
36215
36216                                 scope.onStart( url, itemsLoaded, itemsTotal );
36217
36218                         }
36219
36220                 }
36221
36222                 isLoading = true;
36223
36224         };
36225
36226         this.itemEnd = function ( url ) {
36227
36228                 itemsLoaded ++;
36229
36230                 if ( scope.onProgress !== undefined ) {
36231
36232                         scope.onProgress( url, itemsLoaded, itemsTotal );
36233
36234                 }
36235
36236                 if ( itemsLoaded === itemsTotal ) {
36237
36238                         isLoading = false;
36239
36240                         if ( scope.onLoad !== undefined ) {
36241
36242                                 scope.onLoad();
36243
36244                         }
36245
36246                 }
36247
36248         };
36249
36250         this.itemError = function ( url ) {
36251
36252                 if ( scope.onError !== undefined ) {
36253
36254                         scope.onError( url );
36255
36256                 }
36257
36258         };
36259
36260         this.resolveURL = function ( url ) {
36261
36262                 if ( urlModifier ) {
36263
36264                         return urlModifier( url );
36265
36266                 }
36267
36268                 return url;
36269
36270         };
36271
36272         this.setURLModifier = function ( transform ) {
36273
36274                 urlModifier = transform;
36275
36276                 return this;
36277
36278         };
36279
36280         this.addHandler = function ( regex, loader ) {
36281
36282                 handlers.push( regex, loader );
36283
36284                 return this;
36285
36286         };
36287
36288         this.removeHandler = function ( regex ) {
36289
36290                 const index = handlers.indexOf( regex );
36291
36292                 if ( index !== - 1 ) {
36293
36294                         handlers.splice( index, 2 );
36295
36296                 }
36297
36298                 return this;
36299
36300         };
36301
36302         this.getHandler = function ( file ) {
36303
36304                 for ( let i = 0, l = handlers.length; i < l; i += 2 ) {
36305
36306                         const regex = handlers[ i ];
36307                         const loader = handlers[ i + 1 ];
36308
36309                         if ( regex.global ) regex.lastIndex = 0; // see #17920
36310
36311                         if ( regex.test( file ) ) {
36312
36313                                 return loader;
36314
36315                         }
36316
36317                 }
36318
36319                 return null;
36320
36321         };
36322
36323 }
36324
36325 const DefaultLoadingManager = new LoadingManager();
36326
36327 function Loader( manager ) {
36328
36329         this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager;
36330
36331         this.crossOrigin = 'anonymous';
36332         this.withCredentials = false;
36333         this.path = '';
36334         this.resourcePath = '';
36335         this.requestHeader = {};
36336
36337 }
36338
36339 Object.assign( Loader.prototype, {
36340
36341         load: function ( /* url, onLoad, onProgress, onError */ ) {},
36342
36343         loadAsync: function ( url, onProgress ) {
36344
36345                 const scope = this;
36346
36347                 return new Promise( function ( resolve, reject ) {
36348
36349                         scope.load( url, resolve, onProgress, reject );
36350
36351                 } );
36352
36353         },
36354
36355         parse: function ( /* data */ ) {},
36356
36357         setCrossOrigin: function ( crossOrigin ) {
36358
36359                 this.crossOrigin = crossOrigin;
36360                 return this;
36361
36362         },
36363
36364         setWithCredentials: function ( value ) {
36365
36366                 this.withCredentials = value;
36367                 return this;
36368
36369         },
36370
36371         setPath: function ( path ) {
36372
36373                 this.path = path;
36374                 return this;
36375
36376         },
36377
36378         setResourcePath: function ( resourcePath ) {
36379
36380                 this.resourcePath = resourcePath;
36381                 return this;
36382
36383         },
36384
36385         setRequestHeader: function ( requestHeader ) {
36386
36387                 this.requestHeader = requestHeader;
36388                 return this;
36389
36390         }
36391
36392 } );
36393
36394 const loading = {};
36395
36396 function FileLoader( manager ) {
36397
36398         Loader.call( this, manager );
36399
36400 }
36401
36402 FileLoader.prototype = Object.assign( Object.create( Loader.prototype ), {
36403
36404         constructor: FileLoader,
36405
36406         load: function ( url, onLoad, onProgress, onError ) {
36407
36408                 if ( url === undefined ) url = '';
36409
36410                 if ( this.path !== undefined ) url = this.path + url;
36411
36412                 url = this.manager.resolveURL( url );
36413
36414                 const scope = this;
36415
36416                 const cached = Cache.get( url );
36417
36418                 if ( cached !== undefined ) {
36419
36420                         scope.manager.itemStart( url );
36421
36422                         setTimeout( function () {
36423
36424                                 if ( onLoad ) onLoad( cached );
36425
36426                                 scope.manager.itemEnd( url );
36427
36428                         }, 0 );
36429
36430                         return cached;
36431
36432                 }
36433
36434                 // Check if request is duplicate
36435
36436                 if ( loading[ url ] !== undefined ) {
36437
36438                         loading[ url ].push( {
36439
36440                                 onLoad: onLoad,
36441                                 onProgress: onProgress,
36442                                 onError: onError
36443
36444                         } );
36445
36446                         return;
36447
36448                 }
36449
36450                 // Check for data: URI
36451                 const dataUriRegex = /^data:(.*?)(;base64)?,(.*)$/;
36452                 const dataUriRegexResult = url.match( dataUriRegex );
36453                 let request;
36454
36455                 // Safari can not handle Data URIs through XMLHttpRequest so process manually
36456                 if ( dataUriRegexResult ) {
36457
36458                         const mimeType = dataUriRegexResult[ 1 ];
36459                         const isBase64 = !! dataUriRegexResult[ 2 ];
36460
36461                         let data = dataUriRegexResult[ 3 ];
36462                         data = decodeURIComponent( data );
36463
36464                         if ( isBase64 ) data = atob( data );
36465
36466                         try {
36467
36468                                 let response;
36469                                 const responseType = ( this.responseType || '' ).toLowerCase();
36470
36471                                 switch ( responseType ) {
36472
36473                                         case 'arraybuffer':
36474                                         case 'blob':
36475
36476                                                 const view = new Uint8Array( data.length );
36477
36478                                                 for ( let i = 0; i < data.length; i ++ ) {
36479
36480                                                         view[ i ] = data.charCodeAt( i );
36481
36482                                                 }
36483
36484                                                 if ( responseType === 'blob' ) {
36485
36486                                                         response = new Blob( [ view.buffer ], { type: mimeType } );
36487
36488                                                 } else {
36489
36490                                                         response = view.buffer;
36491
36492                                                 }
36493
36494                                                 break;
36495
36496                                         case 'document':
36497
36498                                                 const parser = new DOMParser();
36499                                                 response = parser.parseFromString( data, mimeType );
36500
36501                                                 break;
36502
36503                                         case 'json':
36504
36505                                                 response = JSON.parse( data );
36506
36507                                                 break;
36508
36509                                         default: // 'text' or other
36510
36511                                                 response = data;
36512
36513                                                 break;
36514
36515                                 }
36516
36517                                 // Wait for next browser tick like standard XMLHttpRequest event dispatching does
36518                                 setTimeout( function () {
36519
36520                                         if ( onLoad ) onLoad( response );
36521
36522                                         scope.manager.itemEnd( url );
36523
36524                                 }, 0 );
36525
36526                         } catch ( error ) {
36527
36528                                 // Wait for next browser tick like standard XMLHttpRequest event dispatching does
36529                                 setTimeout( function () {
36530
36531                                         if ( onError ) onError( error );
36532
36533                                         scope.manager.itemError( url );
36534                                         scope.manager.itemEnd( url );
36535
36536                                 }, 0 );
36537
36538                         }
36539
36540                 } else {
36541
36542                         // Initialise array for duplicate requests
36543
36544                         loading[ url ] = [];
36545
36546                         loading[ url ].push( {
36547
36548                                 onLoad: onLoad,
36549                                 onProgress: onProgress,
36550                                 onError: onError
36551
36552                         } );
36553
36554                         request = new XMLHttpRequest();
36555
36556                         request.open( 'GET', url, true );
36557
36558                         request.addEventListener( 'load', function ( event ) {
36559
36560                                 const response = this.response;
36561
36562                                 const callbacks = loading[ url ];
36563
36564                                 delete loading[ url ];
36565
36566                                 if ( this.status === 200 || this.status === 0 ) {
36567
36568                                         // Some browsers return HTTP Status 0 when using non-http protocol
36569                                         // e.g. 'file://' or 'data://'. Handle as success.
36570
36571                                         if ( this.status === 0 ) console.warn( 'THREE.FileLoader: HTTP Status 0 received.' );
36572
36573                                         // Add to cache only on HTTP success, so that we do not cache
36574                                         // error response bodies as proper responses to requests.
36575                                         Cache.add( url, response );
36576
36577                                         for ( let i = 0, il = callbacks.length; i < il; i ++ ) {
36578
36579                                                 const callback = callbacks[ i ];
36580                                                 if ( callback.onLoad ) callback.onLoad( response );
36581
36582                                         }
36583
36584                                         scope.manager.itemEnd( url );
36585
36586                                 } else {
36587
36588                                         for ( let i = 0, il = callbacks.length; i < il; i ++ ) {
36589
36590                                                 const callback = callbacks[ i ];
36591                                                 if ( callback.onError ) callback.onError( event );
36592
36593                                         }
36594
36595                                         scope.manager.itemError( url );
36596                                         scope.manager.itemEnd( url );
36597
36598                                 }
36599
36600                         }, false );
36601
36602                         request.addEventListener( 'progress', function ( event ) {
36603
36604                                 const callbacks = loading[ url ];
36605
36606                                 for ( let i = 0, il = callbacks.length; i < il; i ++ ) {
36607
36608                                         const callback = callbacks[ i ];
36609                                         if ( callback.onProgress ) callback.onProgress( event );
36610
36611                                 }
36612
36613                         }, false );
36614
36615                         request.addEventListener( 'error', function ( event ) {
36616
36617                                 const callbacks = loading[ url ];
36618
36619                                 delete loading[ url ];
36620
36621                                 for ( let i = 0, il = callbacks.length; i < il; i ++ ) {
36622
36623                                         const callback = callbacks[ i ];
36624                                         if ( callback.onError ) callback.onError( event );
36625
36626                                 }
36627
36628                                 scope.manager.itemError( url );
36629                                 scope.manager.itemEnd( url );
36630
36631                         }, false );
36632
36633                         request.addEventListener( 'abort', function ( event ) {
36634
36635                                 const callbacks = loading[ url ];
36636
36637                                 delete loading[ url ];
36638
36639                                 for ( let i = 0, il = callbacks.length; i < il; i ++ ) {
36640
36641                                         const callback = callbacks[ i ];
36642                                         if ( callback.onError ) callback.onError( event );
36643
36644                                 }
36645
36646                                 scope.manager.itemError( url );
36647                                 scope.manager.itemEnd( url );
36648
36649                         }, false );
36650
36651                         if ( this.responseType !== undefined ) request.responseType = this.responseType;
36652                         if ( this.withCredentials !== undefined ) request.withCredentials = this.withCredentials;
36653
36654                         if ( request.overrideMimeType ) request.overrideMimeType( this.mimeType !== undefined ? this.mimeType : 'text/plain' );
36655
36656                         for ( const header in this.requestHeader ) {
36657
36658                                 request.setRequestHeader( header, this.requestHeader[ header ] );
36659
36660                         }
36661
36662                         request.send( null );
36663
36664                 }
36665
36666                 scope.manager.itemStart( url );
36667
36668                 return request;
36669
36670         },
36671
36672         setResponseType: function ( value ) {
36673
36674                 this.responseType = value;
36675                 return this;
36676
36677         },
36678
36679         setMimeType: function ( value ) {
36680
36681                 this.mimeType = value;
36682                 return this;
36683
36684         }
36685
36686 } );
36687
36688 function AnimationLoader( manager ) {
36689
36690         Loader.call( this, manager );
36691
36692 }
36693
36694 AnimationLoader.prototype = Object.assign( Object.create( Loader.prototype ), {
36695
36696         constructor: AnimationLoader,
36697
36698         load: function ( url, onLoad, onProgress, onError ) {
36699
36700                 const scope = this;
36701
36702                 const loader = new FileLoader( scope.manager );
36703                 loader.setPath( scope.path );
36704                 loader.setRequestHeader( scope.requestHeader );
36705                 loader.setWithCredentials( scope.withCredentials );
36706                 loader.load( url, function ( text ) {
36707
36708                         try {
36709
36710                                 onLoad( scope.parse( JSON.parse( text ) ) );
36711
36712                         } catch ( e ) {
36713
36714                                 if ( onError ) {
36715
36716                                         onError( e );
36717
36718                                 } else {
36719
36720                                         console.error( e );
36721
36722                                 }
36723
36724                                 scope.manager.itemError( url );
36725
36726                         }
36727
36728                 }, onProgress, onError );
36729
36730         },
36731
36732         parse: function ( json ) {
36733
36734                 const animations = [];
36735
36736                 for ( let i = 0; i < json.length; i ++ ) {
36737
36738                         const clip = AnimationClip.parse( json[ i ] );
36739
36740                         animations.push( clip );
36741
36742                 }
36743
36744                 return animations;
36745
36746         }
36747
36748 } );
36749
36750 /**
36751  * Abstract Base class to block based textures loader (dds, pvr, ...)
36752  *
36753  * Sub classes have to implement the parse() method which will be used in load().
36754  */
36755
36756 function CompressedTextureLoader( manager ) {
36757
36758         Loader.call( this, manager );
36759
36760 }
36761
36762 CompressedTextureLoader.prototype = Object.assign( Object.create( Loader.prototype ), {
36763
36764         constructor: CompressedTextureLoader,
36765
36766         load: function ( url, onLoad, onProgress, onError ) {
36767
36768                 const scope = this;
36769
36770                 const images = [];
36771
36772                 const texture = new CompressedTexture();
36773
36774                 const loader = new FileLoader( this.manager );
36775                 loader.setPath( this.path );
36776                 loader.setResponseType( 'arraybuffer' );
36777                 loader.setRequestHeader( this.requestHeader );
36778                 loader.setWithCredentials( scope.withCredentials );
36779
36780                 let loaded = 0;
36781
36782                 function loadTexture( i ) {
36783
36784                         loader.load( url[ i ], function ( buffer ) {
36785
36786                                 const texDatas = scope.parse( buffer, true );
36787
36788                                 images[ i ] = {
36789                                         width: texDatas.width,
36790                                         height: texDatas.height,
36791                                         format: texDatas.format,
36792                                         mipmaps: texDatas.mipmaps
36793                                 };
36794
36795                                 loaded += 1;
36796
36797                                 if ( loaded === 6 ) {
36798
36799                                         if ( texDatas.mipmapCount === 1 ) texture.minFilter = LinearFilter;
36800
36801                                         texture.image = images;
36802                                         texture.format = texDatas.format;
36803                                         texture.needsUpdate = true;
36804
36805                                         if ( onLoad ) onLoad( texture );
36806
36807                                 }
36808
36809                         }, onProgress, onError );
36810
36811                 }
36812
36813                 if ( Array.isArray( url ) ) {
36814
36815                         for ( let i = 0, il = url.length; i < il; ++ i ) {
36816
36817                                 loadTexture( i );
36818
36819                         }
36820
36821                 } else {
36822
36823                         // compressed cubemap texture stored in a single DDS file
36824
36825                         loader.load( url, function ( buffer ) {
36826
36827                                 const texDatas = scope.parse( buffer, true );
36828
36829                                 if ( texDatas.isCubemap ) {
36830
36831                                         const faces = texDatas.mipmaps.length / texDatas.mipmapCount;
36832
36833                                         for ( let f = 0; f < faces; f ++ ) {
36834
36835                                                 images[ f ] = { mipmaps: [] };
36836
36837                                                 for ( let i = 0; i < texDatas.mipmapCount; i ++ ) {
36838
36839                                                         images[ f ].mipmaps.push( texDatas.mipmaps[ f * texDatas.mipmapCount + i ] );
36840                                                         images[ f ].format = texDatas.format;
36841                                                         images[ f ].width = texDatas.width;
36842                                                         images[ f ].height = texDatas.height;
36843
36844                                                 }
36845
36846                                         }
36847
36848                                         texture.image = images;
36849
36850                                 } else {
36851
36852                                         texture.image.width = texDatas.width;
36853                                         texture.image.height = texDatas.height;
36854                                         texture.mipmaps = texDatas.mipmaps;
36855
36856                                 }
36857
36858                                 if ( texDatas.mipmapCount === 1 ) {
36859
36860                                         texture.minFilter = LinearFilter;
36861
36862                                 }
36863
36864                                 texture.format = texDatas.format;
36865                                 texture.needsUpdate = true;
36866
36867                                 if ( onLoad ) onLoad( texture );
36868
36869                         }, onProgress, onError );
36870
36871                 }
36872
36873                 return texture;
36874
36875         }
36876
36877 } );
36878
36879 function ImageLoader( manager ) {
36880
36881         Loader.call( this, manager );
36882
36883 }
36884
36885 ImageLoader.prototype = Object.assign( Object.create( Loader.prototype ), {
36886
36887         constructor: ImageLoader,
36888
36889         load: function ( url, onLoad, onProgress, onError ) {
36890
36891                 if ( this.path !== undefined ) url = this.path + url;
36892
36893                 url = this.manager.resolveURL( url );
36894
36895                 const scope = this;
36896
36897                 const cached = Cache.get( url );
36898
36899                 if ( cached !== undefined ) {
36900
36901                         scope.manager.itemStart( url );
36902
36903                         setTimeout( function () {
36904
36905                                 if ( onLoad ) onLoad( cached );
36906
36907                                 scope.manager.itemEnd( url );
36908
36909                         }, 0 );
36910
36911                         return cached;
36912
36913                 }
36914
36915                 const image = document.createElementNS( 'http://www.w3.org/1999/xhtml', 'img' );
36916
36917                 function onImageLoad() {
36918
36919                         image.removeEventListener( 'load', onImageLoad, false );
36920                         image.removeEventListener( 'error', onImageError, false );
36921
36922                         Cache.add( url, this );
36923
36924                         if ( onLoad ) onLoad( this );
36925
36926                         scope.manager.itemEnd( url );
36927
36928                 }
36929
36930                 function onImageError( event ) {
36931
36932                         image.removeEventListener( 'load', onImageLoad, false );
36933                         image.removeEventListener( 'error', onImageError, false );
36934
36935                         if ( onError ) onError( event );
36936
36937                         scope.manager.itemError( url );
36938                         scope.manager.itemEnd( url );
36939
36940                 }
36941
36942                 image.addEventListener( 'load', onImageLoad, false );
36943                 image.addEventListener( 'error', onImageError, false );
36944
36945                 if ( url.substr( 0, 5 ) !== 'data:' ) {
36946
36947                         if ( this.crossOrigin !== undefined ) image.crossOrigin = this.crossOrigin;
36948
36949                 }
36950
36951                 scope.manager.itemStart( url );
36952
36953                 image.src = url;
36954
36955                 return image;
36956
36957         }
36958
36959 } );
36960
36961 function CubeTextureLoader( manager ) {
36962
36963         Loader.call( this, manager );
36964
36965 }
36966
36967 CubeTextureLoader.prototype = Object.assign( Object.create( Loader.prototype ), {
36968
36969         constructor: CubeTextureLoader,
36970
36971         load: function ( urls, onLoad, onProgress, onError ) {
36972
36973                 const texture = new CubeTexture();
36974
36975                 const loader = new ImageLoader( this.manager );
36976                 loader.setCrossOrigin( this.crossOrigin );
36977                 loader.setPath( this.path );
36978
36979                 let loaded = 0;
36980
36981                 function loadTexture( i ) {
36982
36983                         loader.load( urls[ i ], function ( image ) {
36984
36985                                 texture.images[ i ] = image;
36986
36987                                 loaded ++;
36988
36989                                 if ( loaded === 6 ) {
36990
36991                                         texture.needsUpdate = true;
36992
36993                                         if ( onLoad ) onLoad( texture );
36994
36995                                 }
36996
36997                         }, undefined, onError );
36998
36999                 }
37000
37001                 for ( let i = 0; i < urls.length; ++ i ) {
37002
37003                         loadTexture( i );
37004
37005                 }
37006
37007                 return texture;
37008
37009         }
37010
37011 } );
37012
37013 /**
37014  * Abstract Base class to load generic binary textures formats (rgbe, hdr, ...)
37015  *
37016  * Sub classes have to implement the parse() method which will be used in load().
37017  */
37018
37019 function DataTextureLoader( manager ) {
37020
37021         Loader.call( this, manager );
37022
37023 }
37024
37025 DataTextureLoader.prototype = Object.assign( Object.create( Loader.prototype ), {
37026
37027         constructor: DataTextureLoader,
37028
37029         load: function ( url, onLoad, onProgress, onError ) {
37030
37031                 const scope = this;
37032
37033                 const texture = new DataTexture();
37034
37035                 const loader = new FileLoader( this.manager );
37036                 loader.setResponseType( 'arraybuffer' );
37037                 loader.setRequestHeader( this.requestHeader );
37038                 loader.setPath( this.path );
37039                 loader.setWithCredentials( scope.withCredentials );
37040                 loader.load( url, function ( buffer ) {
37041
37042                         const texData = scope.parse( buffer );
37043
37044                         if ( ! texData ) return;
37045
37046                         if ( texData.image !== undefined ) {
37047
37048                                 texture.image = texData.image;
37049
37050                         } else if ( texData.data !== undefined ) {
37051
37052                                 texture.image.width = texData.width;
37053                                 texture.image.height = texData.height;
37054                                 texture.image.data = texData.data;
37055
37056                         }
37057
37058                         texture.wrapS = texData.wrapS !== undefined ? texData.wrapS : ClampToEdgeWrapping;
37059                         texture.wrapT = texData.wrapT !== undefined ? texData.wrapT : ClampToEdgeWrapping;
37060
37061                         texture.magFilter = texData.magFilter !== undefined ? texData.magFilter : LinearFilter;
37062                         texture.minFilter = texData.minFilter !== undefined ? texData.minFilter : LinearFilter;
37063
37064                         texture.anisotropy = texData.anisotropy !== undefined ? texData.anisotropy : 1;
37065
37066                         if ( texData.encoding !== undefined ) {
37067
37068                                 texture.encoding = texData.encoding;
37069
37070                         }
37071
37072                         if ( texData.flipY !== undefined ) {
37073
37074                                 texture.flipY = texData.flipY;
37075
37076                         }
37077
37078                         if ( texData.format !== undefined ) {
37079
37080                                 texture.format = texData.format;
37081
37082                         }
37083
37084                         if ( texData.type !== undefined ) {
37085
37086                                 texture.type = texData.type;
37087
37088                         }
37089
37090                         if ( texData.mipmaps !== undefined ) {
37091
37092                                 texture.mipmaps = texData.mipmaps;
37093                                 texture.minFilter = LinearMipmapLinearFilter; // presumably...
37094
37095                         }
37096
37097                         if ( texData.mipmapCount === 1 ) {
37098
37099                                 texture.minFilter = LinearFilter;
37100
37101                         }
37102
37103                         texture.needsUpdate = true;
37104
37105                         if ( onLoad ) onLoad( texture, texData );
37106
37107                 }, onProgress, onError );
37108
37109
37110                 return texture;
37111
37112         }
37113
37114 } );
37115
37116 function TextureLoader( manager ) {
37117
37118         Loader.call( this, manager );
37119
37120 }
37121
37122 TextureLoader.prototype = Object.assign( Object.create( Loader.prototype ), {
37123
37124         constructor: TextureLoader,
37125
37126         load: function ( url, onLoad, onProgress, onError ) {
37127
37128                 const texture = new Texture();
37129
37130                 const loader = new ImageLoader( this.manager );
37131                 loader.setCrossOrigin( this.crossOrigin );
37132                 loader.setPath( this.path );
37133
37134                 loader.load( url, function ( image ) {
37135
37136                         texture.image = image;
37137
37138                         // JPEGs can't have an alpha channel, so memory can be saved by storing them as RGB.
37139                         const isJPEG = url.search( /\.jpe?g($|\?)/i ) > 0 || url.search( /^data\:image\/jpeg/ ) === 0;
37140
37141                         texture.format = isJPEG ? RGBFormat : RGBAFormat;
37142                         texture.needsUpdate = true;
37143
37144                         if ( onLoad !== undefined ) {
37145
37146                                 onLoad( texture );
37147
37148                         }
37149
37150                 }, onProgress, onError );
37151
37152                 return texture;
37153
37154         }
37155
37156 } );
37157
37158 /**
37159  * Extensible curve object.
37160  *
37161  * Some common of curve methods:
37162  * .getPoint( t, optionalTarget ), .getTangent( t, optionalTarget )
37163  * .getPointAt( u, optionalTarget ), .getTangentAt( u, optionalTarget )
37164  * .getPoints(), .getSpacedPoints()
37165  * .getLength()
37166  * .updateArcLengths()
37167  *
37168  * This following curves inherit from THREE.Curve:
37169  *
37170  * -- 2D curves --
37171  * THREE.ArcCurve
37172  * THREE.CubicBezierCurve
37173  * THREE.EllipseCurve
37174  * THREE.LineCurve
37175  * THREE.QuadraticBezierCurve
37176  * THREE.SplineCurve
37177  *
37178  * -- 3D curves --
37179  * THREE.CatmullRomCurve3
37180  * THREE.CubicBezierCurve3
37181  * THREE.LineCurve3
37182  * THREE.QuadraticBezierCurve3
37183  *
37184  * A series of curves can be represented as a THREE.CurvePath.
37185  *
37186  **/
37187
37188 function Curve() {
37189
37190         this.type = 'Curve';
37191
37192         this.arcLengthDivisions = 200;
37193
37194 }
37195
37196 Object.assign( Curve.prototype, {
37197
37198         // Virtual base class method to overwrite and implement in subclasses
37199         //      - t [0 .. 1]
37200
37201         getPoint: function ( /* t, optionalTarget */ ) {
37202
37203                 console.warn( 'THREE.Curve: .getPoint() not implemented.' );
37204                 return null;
37205
37206         },
37207
37208         // Get point at relative position in curve according to arc length
37209         // - u [0 .. 1]
37210
37211         getPointAt: function ( u, optionalTarget ) {
37212
37213                 const t = this.getUtoTmapping( u );
37214                 return this.getPoint( t, optionalTarget );
37215
37216         },
37217
37218         // Get sequence of points using getPoint( t )
37219
37220         getPoints: function ( divisions = 5 ) {
37221
37222                 const points = [];
37223
37224                 for ( let d = 0; d <= divisions; d ++ ) {
37225
37226                         points.push( this.getPoint( d / divisions ) );
37227
37228                 }
37229
37230                 return points;
37231
37232         },
37233
37234         // Get sequence of points using getPointAt( u )
37235
37236         getSpacedPoints: function ( divisions = 5 ) {
37237
37238                 const points = [];
37239
37240                 for ( let d = 0; d <= divisions; d ++ ) {
37241
37242                         points.push( this.getPointAt( d / divisions ) );
37243
37244                 }
37245
37246                 return points;
37247
37248         },
37249
37250         // Get total curve arc length
37251
37252         getLength: function () {
37253
37254                 const lengths = this.getLengths();
37255                 return lengths[ lengths.length - 1 ];
37256
37257         },
37258
37259         // Get list of cumulative segment lengths
37260
37261         getLengths: function ( divisions ) {
37262
37263                 if ( divisions === undefined ) divisions = this.arcLengthDivisions;
37264
37265                 if ( this.cacheArcLengths &&
37266                         ( this.cacheArcLengths.length === divisions + 1 ) &&
37267                         ! this.needsUpdate ) {
37268
37269                         return this.cacheArcLengths;
37270
37271                 }
37272
37273                 this.needsUpdate = false;
37274
37275                 const cache = [];
37276                 let current, last = this.getPoint( 0 );
37277                 let sum = 0;
37278
37279                 cache.push( 0 );
37280
37281                 for ( let p = 1; p <= divisions; p ++ ) {
37282
37283                         current = this.getPoint( p / divisions );
37284                         sum += current.distanceTo( last );
37285                         cache.push( sum );
37286                         last = current;
37287
37288                 }
37289
37290                 this.cacheArcLengths = cache;
37291
37292                 return cache; // { sums: cache, sum: sum }; Sum is in the last element.
37293
37294         },
37295
37296         updateArcLengths: function () {
37297
37298                 this.needsUpdate = true;
37299                 this.getLengths();
37300
37301         },
37302
37303         // Given u ( 0 .. 1 ), get a t to find p. This gives you points which are equidistant
37304
37305         getUtoTmapping: function ( u, distance ) {
37306
37307                 const arcLengths = this.getLengths();
37308
37309                 let i = 0;
37310                 const il = arcLengths.length;
37311
37312                 let targetArcLength; // The targeted u distance value to get
37313
37314                 if ( distance ) {
37315
37316                         targetArcLength = distance;
37317
37318                 } else {
37319
37320                         targetArcLength = u * arcLengths[ il - 1 ];
37321
37322                 }
37323
37324                 // binary search for the index with largest value smaller than target u distance
37325
37326                 let low = 0, high = il - 1, comparison;
37327
37328                 while ( low <= high ) {
37329
37330                         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
37331
37332                         comparison = arcLengths[ i ] - targetArcLength;
37333
37334                         if ( comparison < 0 ) {
37335
37336                                 low = i + 1;
37337
37338                         } else if ( comparison > 0 ) {
37339
37340                                 high = i - 1;
37341
37342                         } else {
37343
37344                                 high = i;
37345                                 break;
37346
37347                                 // DONE
37348
37349                         }
37350
37351                 }
37352
37353                 i = high;
37354
37355                 if ( arcLengths[ i ] === targetArcLength ) {
37356
37357                         return i / ( il - 1 );
37358
37359                 }
37360
37361                 // we could get finer grain at lengths, or use simple interpolation between two points
37362
37363                 const lengthBefore = arcLengths[ i ];
37364                 const lengthAfter = arcLengths[ i + 1 ];
37365
37366                 const segmentLength = lengthAfter - lengthBefore;
37367
37368                 // determine where we are between the 'before' and 'after' points
37369
37370                 const segmentFraction = ( targetArcLength - lengthBefore ) / segmentLength;
37371
37372                 // add that fractional amount to t
37373
37374                 const t = ( i + segmentFraction ) / ( il - 1 );
37375
37376                 return t;
37377
37378         },
37379
37380         // Returns a unit vector tangent at t
37381         // In case any sub curve does not implement its tangent derivation,
37382         // 2 points a small delta apart will be used to find its gradient
37383         // which seems to give a reasonable approximation
37384
37385         getTangent: function ( t, optionalTarget ) {
37386
37387                 const delta = 0.0001;
37388                 let t1 = t - delta;
37389                 let t2 = t + delta;
37390
37391                 // Capping in case of danger
37392
37393                 if ( t1 < 0 ) t1 = 0;
37394                 if ( t2 > 1 ) t2 = 1;
37395
37396                 const pt1 = this.getPoint( t1 );
37397                 const pt2 = this.getPoint( t2 );
37398
37399                 const tangent = optionalTarget || ( ( pt1.isVector2 ) ? new Vector2() : new Vector3() );
37400
37401                 tangent.copy( pt2 ).sub( pt1 ).normalize();
37402
37403                 return tangent;
37404
37405         },
37406
37407         getTangentAt: function ( u, optionalTarget ) {
37408
37409                 const t = this.getUtoTmapping( u );
37410                 return this.getTangent( t, optionalTarget );
37411
37412         },
37413
37414         computeFrenetFrames: function ( segments, closed ) {
37415
37416                 // see http://www.cs.indiana.edu/pub/techreports/TR425.pdf
37417
37418                 const normal = new Vector3();
37419
37420                 const tangents = [];
37421                 const normals = [];
37422                 const binormals = [];
37423
37424                 const vec = new Vector3();
37425                 const mat = new Matrix4();
37426
37427                 // compute the tangent vectors for each segment on the curve
37428
37429                 for ( let i = 0; i <= segments; i ++ ) {
37430
37431                         const u = i / segments;
37432
37433                         tangents[ i ] = this.getTangentAt( u, new Vector3() );
37434                         tangents[ i ].normalize();
37435
37436                 }
37437
37438                 // select an initial normal vector perpendicular to the first tangent vector,
37439                 // and in the direction of the minimum tangent xyz component
37440
37441                 normals[ 0 ] = new Vector3();
37442                 binormals[ 0 ] = new Vector3();
37443                 let min = Number.MAX_VALUE;
37444                 const tx = Math.abs( tangents[ 0 ].x );
37445                 const ty = Math.abs( tangents[ 0 ].y );
37446                 const tz = Math.abs( tangents[ 0 ].z );
37447
37448                 if ( tx <= min ) {
37449
37450                         min = tx;
37451                         normal.set( 1, 0, 0 );
37452
37453                 }
37454
37455                 if ( ty <= min ) {
37456
37457                         min = ty;
37458                         normal.set( 0, 1, 0 );
37459
37460                 }
37461
37462                 if ( tz <= min ) {
37463
37464                         normal.set( 0, 0, 1 );
37465
37466                 }
37467
37468                 vec.crossVectors( tangents[ 0 ], normal ).normalize();
37469
37470                 normals[ 0 ].crossVectors( tangents[ 0 ], vec );
37471                 binormals[ 0 ].crossVectors( tangents[ 0 ], normals[ 0 ] );
37472
37473
37474                 // compute the slowly-varying normal and binormal vectors for each segment on the curve
37475
37476                 for ( let i = 1; i <= segments; i ++ ) {
37477
37478                         normals[ i ] = normals[ i - 1 ].clone();
37479
37480                         binormals[ i ] = binormals[ i - 1 ].clone();
37481
37482                         vec.crossVectors( tangents[ i - 1 ], tangents[ i ] );
37483
37484                         if ( vec.length() > Number.EPSILON ) {
37485
37486                                 vec.normalize();
37487
37488                                 const theta = Math.acos( MathUtils.clamp( tangents[ i - 1 ].dot( tangents[ i ] ), - 1, 1 ) ); // clamp for floating pt errors
37489
37490                                 normals[ i ].applyMatrix4( mat.makeRotationAxis( vec, theta ) );
37491
37492                         }
37493
37494                         binormals[ i ].crossVectors( tangents[ i ], normals[ i ] );
37495
37496                 }
37497
37498                 // if the curve is closed, postprocess the vectors so the first and last normal vectors are the same
37499
37500                 if ( closed === true ) {
37501
37502                         let theta = Math.acos( MathUtils.clamp( normals[ 0 ].dot( normals[ segments ] ), - 1, 1 ) );
37503                         theta /= segments;
37504
37505                         if ( tangents[ 0 ].dot( vec.crossVectors( normals[ 0 ], normals[ segments ] ) ) > 0 ) {
37506
37507                                 theta = - theta;
37508
37509                         }
37510
37511                         for ( let i = 1; i <= segments; i ++ ) {
37512
37513                                 // twist a little...
37514                                 normals[ i ].applyMatrix4( mat.makeRotationAxis( tangents[ i ], theta * i ) );
37515                                 binormals[ i ].crossVectors( tangents[ i ], normals[ i ] );
37516
37517                         }
37518
37519                 }
37520
37521                 return {
37522                         tangents: tangents,
37523                         normals: normals,
37524                         binormals: binormals
37525                 };
37526
37527         },
37528
37529         clone: function () {
37530
37531                 return new this.constructor().copy( this );
37532
37533         },
37534
37535         copy: function ( source ) {
37536
37537                 this.arcLengthDivisions = source.arcLengthDivisions;
37538
37539                 return this;
37540
37541         },
37542
37543         toJSON: function () {
37544
37545                 const data = {
37546                         metadata: {
37547                                 version: 4.5,
37548                                 type: 'Curve',
37549                                 generator: 'Curve.toJSON'
37550                         }
37551                 };
37552
37553                 data.arcLengthDivisions = this.arcLengthDivisions;
37554                 data.type = this.type;
37555
37556                 return data;
37557
37558         },
37559
37560         fromJSON: function ( json ) {
37561
37562                 this.arcLengthDivisions = json.arcLengthDivisions;
37563
37564                 return this;
37565
37566         }
37567
37568 } );
37569
37570 function EllipseCurve( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ) {
37571
37572         Curve.call( this );
37573
37574         this.type = 'EllipseCurve';
37575
37576         this.aX = aX || 0;
37577         this.aY = aY || 0;
37578
37579         this.xRadius = xRadius || 1;
37580         this.yRadius = yRadius || 1;
37581
37582         this.aStartAngle = aStartAngle || 0;
37583         this.aEndAngle = aEndAngle || 2 * Math.PI;
37584
37585         this.aClockwise = aClockwise || false;
37586
37587         this.aRotation = aRotation || 0;
37588
37589 }
37590
37591 EllipseCurve.prototype = Object.create( Curve.prototype );
37592 EllipseCurve.prototype.constructor = EllipseCurve;
37593
37594 EllipseCurve.prototype.isEllipseCurve = true;
37595
37596 EllipseCurve.prototype.getPoint = function ( t, optionalTarget ) {
37597
37598         const point = optionalTarget || new Vector2();
37599
37600         const twoPi = Math.PI * 2;
37601         let deltaAngle = this.aEndAngle - this.aStartAngle;
37602         const samePoints = Math.abs( deltaAngle ) < Number.EPSILON;
37603
37604         // ensures that deltaAngle is 0 .. 2 PI
37605         while ( deltaAngle < 0 ) deltaAngle += twoPi;
37606         while ( deltaAngle > twoPi ) deltaAngle -= twoPi;
37607
37608         if ( deltaAngle < Number.EPSILON ) {
37609
37610                 if ( samePoints ) {
37611
37612                         deltaAngle = 0;
37613
37614                 } else {
37615
37616                         deltaAngle = twoPi;
37617
37618                 }
37619
37620         }
37621
37622         if ( this.aClockwise === true && ! samePoints ) {
37623
37624                 if ( deltaAngle === twoPi ) {
37625
37626                         deltaAngle = - twoPi;
37627
37628                 } else {
37629
37630                         deltaAngle = deltaAngle - twoPi;
37631
37632                 }
37633
37634         }
37635
37636         const angle = this.aStartAngle + t * deltaAngle;
37637         let x = this.aX + this.xRadius * Math.cos( angle );
37638         let y = this.aY + this.yRadius * Math.sin( angle );
37639
37640         if ( this.aRotation !== 0 ) {
37641
37642                 const cos = Math.cos( this.aRotation );
37643                 const sin = Math.sin( this.aRotation );
37644
37645                 const tx = x - this.aX;
37646                 const ty = y - this.aY;
37647
37648                 // Rotate the point about the center of the ellipse.
37649                 x = tx * cos - ty * sin + this.aX;
37650                 y = tx * sin + ty * cos + this.aY;
37651
37652         }
37653
37654         return point.set( x, y );
37655
37656 };
37657
37658 EllipseCurve.prototype.copy = function ( source ) {
37659
37660         Curve.prototype.copy.call( this, source );
37661
37662         this.aX = source.aX;
37663         this.aY = source.aY;
37664
37665         this.xRadius = source.xRadius;
37666         this.yRadius = source.yRadius;
37667
37668         this.aStartAngle = source.aStartAngle;
37669         this.aEndAngle = source.aEndAngle;
37670
37671         this.aClockwise = source.aClockwise;
37672
37673         this.aRotation = source.aRotation;
37674
37675         return this;
37676
37677 };
37678
37679
37680 EllipseCurve.prototype.toJSON = function () {
37681
37682         const data = Curve.prototype.toJSON.call( this );
37683
37684         data.aX = this.aX;
37685         data.aY = this.aY;
37686
37687         data.xRadius = this.xRadius;
37688         data.yRadius = this.yRadius;
37689
37690         data.aStartAngle = this.aStartAngle;
37691         data.aEndAngle = this.aEndAngle;
37692
37693         data.aClockwise = this.aClockwise;
37694
37695         data.aRotation = this.aRotation;
37696
37697         return data;
37698
37699 };
37700
37701 EllipseCurve.prototype.fromJSON = function ( json ) {
37702
37703         Curve.prototype.fromJSON.call( this, json );
37704
37705         this.aX = json.aX;
37706         this.aY = json.aY;
37707
37708         this.xRadius = json.xRadius;
37709         this.yRadius = json.yRadius;
37710
37711         this.aStartAngle = json.aStartAngle;
37712         this.aEndAngle = json.aEndAngle;
37713
37714         this.aClockwise = json.aClockwise;
37715
37716         this.aRotation = json.aRotation;
37717
37718         return this;
37719
37720 };
37721
37722 function ArcCurve( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) {
37723
37724         EllipseCurve.call( this, aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise );
37725
37726         this.type = 'ArcCurve';
37727
37728 }
37729
37730 ArcCurve.prototype = Object.create( EllipseCurve.prototype );
37731 ArcCurve.prototype.constructor = ArcCurve;
37732
37733 ArcCurve.prototype.isArcCurve = true;
37734
37735 /**
37736  * Centripetal CatmullRom Curve - which is useful for avoiding
37737  * cusps and self-intersections in non-uniform catmull rom curves.
37738  * http://www.cemyuksel.com/research/catmullrom_param/catmullrom.pdf
37739  *
37740  * curve.type accepts centripetal(default), chordal and catmullrom
37741  * curve.tension is used for catmullrom which defaults to 0.5
37742  */
37743
37744
37745 /*
37746 Based on an optimized c++ solution in
37747  - http://stackoverflow.com/questions/9489736/catmull-rom-curve-with-no-cusps-and-no-self-intersections/
37748  - http://ideone.com/NoEbVM
37749
37750 This CubicPoly class could be used for reusing some variables and calculations,
37751 but for three.js curve use, it could be possible inlined and flatten into a single function call
37752 which can be placed in CurveUtils.
37753 */
37754
37755 function CubicPoly() {
37756
37757         let c0 = 0, c1 = 0, c2 = 0, c3 = 0;
37758
37759         /*
37760          * Compute coefficients for a cubic polynomial
37761          *   p(s) = c0 + c1*s + c2*s^2 + c3*s^3
37762          * such that
37763          *   p(0) = x0, p(1) = x1
37764          *  and
37765          *   p'(0) = t0, p'(1) = t1.
37766          */
37767         function init( x0, x1, t0, t1 ) {
37768
37769                 c0 = x0;
37770                 c1 = t0;
37771                 c2 = - 3 * x0 + 3 * x1 - 2 * t0 - t1;
37772                 c3 = 2 * x0 - 2 * x1 + t0 + t1;
37773
37774         }
37775
37776         return {
37777
37778                 initCatmullRom: function ( x0, x1, x2, x3, tension ) {
37779
37780                         init( x1, x2, tension * ( x2 - x0 ), tension * ( x3 - x1 ) );
37781
37782                 },
37783
37784                 initNonuniformCatmullRom: function ( x0, x1, x2, x3, dt0, dt1, dt2 ) {
37785
37786                         // compute tangents when parameterized in [t1,t2]
37787                         let t1 = ( x1 - x0 ) / dt0 - ( x2 - x0 ) / ( dt0 + dt1 ) + ( x2 - x1 ) / dt1;
37788                         let t2 = ( x2 - x1 ) / dt1 - ( x3 - x1 ) / ( dt1 + dt2 ) + ( x3 - x2 ) / dt2;
37789
37790                         // rescale tangents for parametrization in [0,1]
37791                         t1 *= dt1;
37792                         t2 *= dt1;
37793
37794                         init( x1, x2, t1, t2 );
37795
37796                 },
37797
37798                 calc: function ( t ) {
37799
37800                         const t2 = t * t;
37801                         const t3 = t2 * t;
37802                         return c0 + c1 * t + c2 * t2 + c3 * t3;
37803
37804                 }
37805
37806         };
37807
37808 }
37809
37810 //
37811
37812 const tmp = new Vector3();
37813 const px = new CubicPoly(), py = new CubicPoly(), pz = new CubicPoly();
37814
37815 function CatmullRomCurve3( points = [], closed = false, curveType = 'centripetal', tension = 0.5 ) {
37816
37817         Curve.call( this );
37818
37819         this.type = 'CatmullRomCurve3';
37820
37821         this.points = points;
37822         this.closed = closed;
37823         this.curveType = curveType;
37824         this.tension = tension;
37825
37826 }
37827
37828 CatmullRomCurve3.prototype = Object.create( Curve.prototype );
37829 CatmullRomCurve3.prototype.constructor = CatmullRomCurve3;
37830
37831 CatmullRomCurve3.prototype.isCatmullRomCurve3 = true;
37832
37833 CatmullRomCurve3.prototype.getPoint = function ( t, optionalTarget = new Vector3() ) {
37834
37835         const point = optionalTarget;
37836
37837         const points = this.points;
37838         const l = points.length;
37839
37840         const p = ( l - ( this.closed ? 0 : 1 ) ) * t;
37841         let intPoint = Math.floor( p );
37842         let weight = p - intPoint;
37843
37844         if ( this.closed ) {
37845
37846                 intPoint += intPoint > 0 ? 0 : ( Math.floor( Math.abs( intPoint ) / l ) + 1 ) * l;
37847
37848         } else if ( weight === 0 && intPoint === l - 1 ) {
37849
37850                 intPoint = l - 2;
37851                 weight = 1;
37852
37853         }
37854
37855         let p0, p3; // 4 points (p1 & p2 defined below)
37856
37857         if ( this.closed || intPoint > 0 ) {
37858
37859                 p0 = points[ ( intPoint - 1 ) % l ];
37860
37861         } else {
37862
37863                 // extrapolate first point
37864                 tmp.subVectors( points[ 0 ], points[ 1 ] ).add( points[ 0 ] );
37865                 p0 = tmp;
37866
37867         }
37868
37869         const p1 = points[ intPoint % l ];
37870         const p2 = points[ ( intPoint + 1 ) % l ];
37871
37872         if ( this.closed || intPoint + 2 < l ) {
37873
37874                 p3 = points[ ( intPoint + 2 ) % l ];
37875
37876         } else {
37877
37878                 // extrapolate last point
37879                 tmp.subVectors( points[ l - 1 ], points[ l - 2 ] ).add( points[ l - 1 ] );
37880                 p3 = tmp;
37881
37882         }
37883
37884         if ( this.curveType === 'centripetal' || this.curveType === 'chordal' ) {
37885
37886                 // init Centripetal / Chordal Catmull-Rom
37887                 const pow = this.curveType === 'chordal' ? 0.5 : 0.25;
37888                 let dt0 = Math.pow( p0.distanceToSquared( p1 ), pow );
37889                 let dt1 = Math.pow( p1.distanceToSquared( p2 ), pow );
37890                 let dt2 = Math.pow( p2.distanceToSquared( p3 ), pow );
37891
37892                 // safety check for repeated points
37893                 if ( dt1 < 1e-4 ) dt1 = 1.0;
37894                 if ( dt0 < 1e-4 ) dt0 = dt1;
37895                 if ( dt2 < 1e-4 ) dt2 = dt1;
37896
37897                 px.initNonuniformCatmullRom( p0.x, p1.x, p2.x, p3.x, dt0, dt1, dt2 );
37898                 py.initNonuniformCatmullRom( p0.y, p1.y, p2.y, p3.y, dt0, dt1, dt2 );
37899                 pz.initNonuniformCatmullRom( p0.z, p1.z, p2.z, p3.z, dt0, dt1, dt2 );
37900
37901         } else if ( this.curveType === 'catmullrom' ) {
37902
37903                 px.initCatmullRom( p0.x, p1.x, p2.x, p3.x, this.tension );
37904                 py.initCatmullRom( p0.y, p1.y, p2.y, p3.y, this.tension );
37905                 pz.initCatmullRom( p0.z, p1.z, p2.z, p3.z, this.tension );
37906
37907         }
37908
37909         point.set(
37910                 px.calc( weight ),
37911                 py.calc( weight ),
37912                 pz.calc( weight )
37913         );
37914
37915         return point;
37916
37917 };
37918
37919 CatmullRomCurve3.prototype.copy = function ( source ) {
37920
37921         Curve.prototype.copy.call( this, source );
37922
37923         this.points = [];
37924
37925         for ( let i = 0, l = source.points.length; i < l; i ++ ) {
37926
37927                 const point = source.points[ i ];
37928
37929                 this.points.push( point.clone() );
37930
37931         }
37932
37933         this.closed = source.closed;
37934         this.curveType = source.curveType;
37935         this.tension = source.tension;
37936
37937         return this;
37938
37939 };
37940
37941 CatmullRomCurve3.prototype.toJSON = function () {
37942
37943         const data = Curve.prototype.toJSON.call( this );
37944
37945         data.points = [];
37946
37947         for ( let i = 0, l = this.points.length; i < l; i ++ ) {
37948
37949                 const point = this.points[ i ];
37950                 data.points.push( point.toArray() );
37951
37952         }
37953
37954         data.closed = this.closed;
37955         data.curveType = this.curveType;
37956         data.tension = this.tension;
37957
37958         return data;
37959
37960 };
37961
37962 CatmullRomCurve3.prototype.fromJSON = function ( json ) {
37963
37964         Curve.prototype.fromJSON.call( this, json );
37965
37966         this.points = [];
37967
37968         for ( let i = 0, l = json.points.length; i < l; i ++ ) {
37969
37970                 const point = json.points[ i ];
37971                 this.points.push( new Vector3().fromArray( point ) );
37972
37973         }
37974
37975         this.closed = json.closed;
37976         this.curveType = json.curveType;
37977         this.tension = json.tension;
37978
37979         return this;
37980
37981 };
37982
37983 /**
37984  * Bezier Curves formulas obtained from
37985  * http://en.wikipedia.org/wiki/Bézier_curve
37986  */
37987
37988 function CatmullRom( t, p0, p1, p2, p3 ) {
37989
37990         const v0 = ( p2 - p0 ) * 0.5;
37991         const v1 = ( p3 - p1 ) * 0.5;
37992         const t2 = t * t;
37993         const t3 = t * t2;
37994         return ( 2 * p1 - 2 * p2 + v0 + v1 ) * t3 + ( - 3 * p1 + 3 * p2 - 2 * v0 - v1 ) * t2 + v0 * t + p1;
37995
37996 }
37997
37998 //
37999
38000 function QuadraticBezierP0( t, p ) {
38001
38002         const k = 1 - t;
38003         return k * k * p;
38004
38005 }
38006
38007 function QuadraticBezierP1( t, p ) {
38008
38009         return 2 * ( 1 - t ) * t * p;
38010
38011 }
38012
38013 function QuadraticBezierP2( t, p ) {
38014
38015         return t * t * p;
38016
38017 }
38018
38019 function QuadraticBezier( t, p0, p1, p2 ) {
38020
38021         return QuadraticBezierP0( t, p0 ) + QuadraticBezierP1( t, p1 ) +
38022                 QuadraticBezierP2( t, p2 );
38023
38024 }
38025
38026 //
38027
38028 function CubicBezierP0( t, p ) {
38029
38030         const k = 1 - t;
38031         return k * k * k * p;
38032
38033 }
38034
38035 function CubicBezierP1( t, p ) {
38036
38037         const k = 1 - t;
38038         return 3 * k * k * t * p;
38039
38040 }
38041
38042 function CubicBezierP2( t, p ) {
38043
38044         return 3 * ( 1 - t ) * t * t * p;
38045
38046 }
38047
38048 function CubicBezierP3( t, p ) {
38049
38050         return t * t * t * p;
38051
38052 }
38053
38054 function CubicBezier( t, p0, p1, p2, p3 ) {
38055
38056         return CubicBezierP0( t, p0 ) + CubicBezierP1( t, p1 ) + CubicBezierP2( t, p2 ) +
38057                 CubicBezierP3( t, p3 );
38058
38059 }
38060
38061 function CubicBezierCurve( v0 = new Vector2(), v1 = new Vector2(), v2 = new Vector2(), v3 = new Vector2() ) {
38062
38063         Curve.call( this );
38064
38065         this.type = 'CubicBezierCurve';
38066
38067         this.v0 = v0;
38068         this.v1 = v1;
38069         this.v2 = v2;
38070         this.v3 = v3;
38071
38072 }
38073
38074 CubicBezierCurve.prototype = Object.create( Curve.prototype );
38075 CubicBezierCurve.prototype.constructor = CubicBezierCurve;
38076
38077 CubicBezierCurve.prototype.isCubicBezierCurve = true;
38078
38079 CubicBezierCurve.prototype.getPoint = function ( t, optionalTarget = new Vector2() ) {
38080
38081         const point = optionalTarget;
38082
38083         const v0 = this.v0, v1 = this.v1, v2 = this.v2, v3 = this.v3;
38084
38085         point.set(
38086                 CubicBezier( t, v0.x, v1.x, v2.x, v3.x ),
38087                 CubicBezier( t, v0.y, v1.y, v2.y, v3.y )
38088         );
38089
38090         return point;
38091
38092 };
38093
38094 CubicBezierCurve.prototype.copy = function ( source ) {
38095
38096         Curve.prototype.copy.call( this, source );
38097
38098         this.v0.copy( source.v0 );
38099         this.v1.copy( source.v1 );
38100         this.v2.copy( source.v2 );
38101         this.v3.copy( source.v3 );
38102
38103         return this;
38104
38105 };
38106
38107 CubicBezierCurve.prototype.toJSON = function () {
38108
38109         const data = Curve.prototype.toJSON.call( this );
38110
38111         data.v0 = this.v0.toArray();
38112         data.v1 = this.v1.toArray();
38113         data.v2 = this.v2.toArray();
38114         data.v3 = this.v3.toArray();
38115
38116         return data;
38117
38118 };
38119
38120 CubicBezierCurve.prototype.fromJSON = function ( json ) {
38121
38122         Curve.prototype.fromJSON.call( this, json );
38123
38124         this.v0.fromArray( json.v0 );
38125         this.v1.fromArray( json.v1 );
38126         this.v2.fromArray( json.v2 );
38127         this.v3.fromArray( json.v3 );
38128
38129         return this;
38130
38131 };
38132
38133 function CubicBezierCurve3( v0 = new Vector3(), v1 = new Vector3(), v2 = new Vector3(), v3 = new Vector3() ) {
38134
38135         Curve.call( this );
38136
38137         this.type = 'CubicBezierCurve3';
38138
38139         this.v0 = v0;
38140         this.v1 = v1;
38141         this.v2 = v2;
38142         this.v3 = v3;
38143
38144 }
38145
38146 CubicBezierCurve3.prototype = Object.create( Curve.prototype );
38147 CubicBezierCurve3.prototype.constructor = CubicBezierCurve3;
38148
38149 CubicBezierCurve3.prototype.isCubicBezierCurve3 = true;
38150
38151 CubicBezierCurve3.prototype.getPoint = function ( t, optionalTarget = new Vector3() ) {
38152
38153         const point = optionalTarget;
38154
38155         const v0 = this.v0, v1 = this.v1, v2 = this.v2, v3 = this.v3;
38156
38157         point.set(
38158                 CubicBezier( t, v0.x, v1.x, v2.x, v3.x ),
38159                 CubicBezier( t, v0.y, v1.y, v2.y, v3.y ),
38160                 CubicBezier( t, v0.z, v1.z, v2.z, v3.z )
38161         );
38162
38163         return point;
38164
38165 };
38166
38167 CubicBezierCurve3.prototype.copy = function ( source ) {
38168
38169         Curve.prototype.copy.call( this, source );
38170
38171         this.v0.copy( source.v0 );
38172         this.v1.copy( source.v1 );
38173         this.v2.copy( source.v2 );
38174         this.v3.copy( source.v3 );
38175
38176         return this;
38177
38178 };
38179
38180 CubicBezierCurve3.prototype.toJSON = function () {
38181
38182         const data = Curve.prototype.toJSON.call( this );
38183
38184         data.v0 = this.v0.toArray();
38185         data.v1 = this.v1.toArray();
38186         data.v2 = this.v2.toArray();
38187         data.v3 = this.v3.toArray();
38188
38189         return data;
38190
38191 };
38192
38193 CubicBezierCurve3.prototype.fromJSON = function ( json ) {
38194
38195         Curve.prototype.fromJSON.call( this, json );
38196
38197         this.v0.fromArray( json.v0 );
38198         this.v1.fromArray( json.v1 );
38199         this.v2.fromArray( json.v2 );
38200         this.v3.fromArray( json.v3 );
38201
38202         return this;
38203
38204 };
38205
38206 function LineCurve( v1 = new Vector2(), v2 = new Vector2() ) {
38207
38208         Curve.call( this );
38209
38210         this.type = 'LineCurve';
38211
38212         this.v1 = v1;
38213         this.v2 = v2;
38214
38215 }
38216
38217 LineCurve.prototype = Object.create( Curve.prototype );
38218 LineCurve.prototype.constructor = LineCurve;
38219
38220 LineCurve.prototype.isLineCurve = true;
38221
38222 LineCurve.prototype.getPoint = function ( t, optionalTarget = new Vector2() ) {
38223
38224         const point = optionalTarget;
38225
38226         if ( t === 1 ) {
38227
38228                 point.copy( this.v2 );
38229
38230         } else {
38231
38232                 point.copy( this.v2 ).sub( this.v1 );
38233                 point.multiplyScalar( t ).add( this.v1 );
38234
38235         }
38236
38237         return point;
38238
38239 };
38240
38241 // Line curve is linear, so we can overwrite default getPointAt
38242
38243 LineCurve.prototype.getPointAt = function ( u, optionalTarget ) {
38244
38245         return this.getPoint( u, optionalTarget );
38246
38247 };
38248
38249 LineCurve.prototype.getTangent = function ( t, optionalTarget ) {
38250
38251         const tangent = optionalTarget || new Vector2();
38252
38253         tangent.copy( this.v2 ).sub( this.v1 ).normalize();
38254
38255         return tangent;
38256
38257 };
38258
38259 LineCurve.prototype.copy = function ( source ) {
38260
38261         Curve.prototype.copy.call( this, source );
38262
38263         this.v1.copy( source.v1 );
38264         this.v2.copy( source.v2 );
38265
38266         return this;
38267
38268 };
38269
38270 LineCurve.prototype.toJSON = function () {
38271
38272         const data = Curve.prototype.toJSON.call( this );
38273
38274         data.v1 = this.v1.toArray();
38275         data.v2 = this.v2.toArray();
38276
38277         return data;
38278
38279 };
38280
38281 LineCurve.prototype.fromJSON = function ( json ) {
38282
38283         Curve.prototype.fromJSON.call( this, json );
38284
38285         this.v1.fromArray( json.v1 );
38286         this.v2.fromArray( json.v2 );
38287
38288         return this;
38289
38290 };
38291
38292 function LineCurve3( v1 = new Vector3(), v2 = new Vector3() ) {
38293
38294         Curve.call( this );
38295
38296         this.type = 'LineCurve3';
38297
38298         this.v1 = v1;
38299         this.v2 = v2;
38300
38301 }
38302
38303 LineCurve3.prototype = Object.create( Curve.prototype );
38304 LineCurve3.prototype.constructor = LineCurve3;
38305
38306 LineCurve3.prototype.isLineCurve3 = true;
38307
38308 LineCurve3.prototype.getPoint = function ( t, optionalTarget = new Vector3() ) {
38309
38310         const point = optionalTarget;
38311
38312         if ( t === 1 ) {
38313
38314                 point.copy( this.v2 );
38315
38316         } else {
38317
38318                 point.copy( this.v2 ).sub( this.v1 );
38319                 point.multiplyScalar( t ).add( this.v1 );
38320
38321         }
38322
38323         return point;
38324
38325 };
38326
38327 // Line curve is linear, so we can overwrite default getPointAt
38328
38329 LineCurve3.prototype.getPointAt = function ( u, optionalTarget ) {
38330
38331         return this.getPoint( u, optionalTarget );
38332
38333 };
38334
38335 LineCurve3.prototype.copy = function ( source ) {
38336
38337         Curve.prototype.copy.call( this, source );
38338
38339         this.v1.copy( source.v1 );
38340         this.v2.copy( source.v2 );
38341
38342         return this;
38343
38344 };
38345
38346 LineCurve3.prototype.toJSON = function () {
38347
38348         const data = Curve.prototype.toJSON.call( this );
38349
38350         data.v1 = this.v1.toArray();
38351         data.v2 = this.v2.toArray();
38352
38353         return data;
38354
38355 };
38356
38357 LineCurve3.prototype.fromJSON = function ( json ) {
38358
38359         Curve.prototype.fromJSON.call( this, json );
38360
38361         this.v1.fromArray( json.v1 );
38362         this.v2.fromArray( json.v2 );
38363
38364         return this;
38365
38366 };
38367
38368 function QuadraticBezierCurve( v0 = new Vector2(), v1 = new Vector2(), v2 = new Vector2() ) {
38369
38370         Curve.call( this );
38371
38372         this.type = 'QuadraticBezierCurve';
38373
38374         this.v0 = v0;
38375         this.v1 = v1;
38376         this.v2 = v2;
38377
38378 }
38379
38380 QuadraticBezierCurve.prototype = Object.create( Curve.prototype );
38381 QuadraticBezierCurve.prototype.constructor = QuadraticBezierCurve;
38382
38383 QuadraticBezierCurve.prototype.isQuadraticBezierCurve = true;
38384
38385 QuadraticBezierCurve.prototype.getPoint = function ( t, optionalTarget = new Vector2() ) {
38386
38387         const point = optionalTarget;
38388
38389         const v0 = this.v0, v1 = this.v1, v2 = this.v2;
38390
38391         point.set(
38392                 QuadraticBezier( t, v0.x, v1.x, v2.x ),
38393                 QuadraticBezier( t, v0.y, v1.y, v2.y )
38394         );
38395
38396         return point;
38397
38398 };
38399
38400 QuadraticBezierCurve.prototype.copy = function ( source ) {
38401
38402         Curve.prototype.copy.call( this, source );
38403
38404         this.v0.copy( source.v0 );
38405         this.v1.copy( source.v1 );
38406         this.v2.copy( source.v2 );
38407
38408         return this;
38409
38410 };
38411
38412 QuadraticBezierCurve.prototype.toJSON = function () {
38413
38414         const data = Curve.prototype.toJSON.call( this );
38415
38416         data.v0 = this.v0.toArray();
38417         data.v1 = this.v1.toArray();
38418         data.v2 = this.v2.toArray();
38419
38420         return data;
38421
38422 };
38423
38424 QuadraticBezierCurve.prototype.fromJSON = function ( json ) {
38425
38426         Curve.prototype.fromJSON.call( this, json );
38427
38428         this.v0.fromArray( json.v0 );
38429         this.v1.fromArray( json.v1 );
38430         this.v2.fromArray( json.v2 );
38431
38432         return this;
38433
38434 };
38435
38436 function QuadraticBezierCurve3( v0 = new Vector3(), v1 = new Vector3(), v2 = new Vector3() ) {
38437
38438         Curve.call( this );
38439
38440         this.type = 'QuadraticBezierCurve3';
38441
38442         this.v0 = v0;
38443         this.v1 = v1;
38444         this.v2 = v2;
38445
38446 }
38447
38448 QuadraticBezierCurve3.prototype = Object.create( Curve.prototype );
38449 QuadraticBezierCurve3.prototype.constructor = QuadraticBezierCurve3;
38450
38451 QuadraticBezierCurve3.prototype.isQuadraticBezierCurve3 = true;
38452
38453 QuadraticBezierCurve3.prototype.getPoint = function ( t, optionalTarget = new Vector3() ) {
38454
38455         const point = optionalTarget;
38456
38457         const v0 = this.v0, v1 = this.v1, v2 = this.v2;
38458
38459         point.set(
38460                 QuadraticBezier( t, v0.x, v1.x, v2.x ),
38461                 QuadraticBezier( t, v0.y, v1.y, v2.y ),
38462                 QuadraticBezier( t, v0.z, v1.z, v2.z )
38463         );
38464
38465         return point;
38466
38467 };
38468
38469 QuadraticBezierCurve3.prototype.copy = function ( source ) {
38470
38471         Curve.prototype.copy.call( this, source );
38472
38473         this.v0.copy( source.v0 );
38474         this.v1.copy( source.v1 );
38475         this.v2.copy( source.v2 );
38476
38477         return this;
38478
38479 };
38480
38481 QuadraticBezierCurve3.prototype.toJSON = function () {
38482
38483         const data = Curve.prototype.toJSON.call( this );
38484
38485         data.v0 = this.v0.toArray();
38486         data.v1 = this.v1.toArray();
38487         data.v2 = this.v2.toArray();
38488
38489         return data;
38490
38491 };
38492
38493 QuadraticBezierCurve3.prototype.fromJSON = function ( json ) {
38494
38495         Curve.prototype.fromJSON.call( this, json );
38496
38497         this.v0.fromArray( json.v0 );
38498         this.v1.fromArray( json.v1 );
38499         this.v2.fromArray( json.v2 );
38500
38501         return this;
38502
38503 };
38504
38505 function SplineCurve( points = [] ) {
38506
38507         Curve.call( this );
38508
38509         this.type = 'SplineCurve';
38510
38511         this.points = points;
38512
38513 }
38514
38515 SplineCurve.prototype = Object.create( Curve.prototype );
38516 SplineCurve.prototype.constructor = SplineCurve;
38517
38518 SplineCurve.prototype.isSplineCurve = true;
38519
38520 SplineCurve.prototype.getPoint = function ( t, optionalTarget = new Vector2() ) {
38521
38522         const point = optionalTarget;
38523
38524         const points = this.points;
38525         const p = ( points.length - 1 ) * t;
38526
38527         const intPoint = Math.floor( p );
38528         const weight = p - intPoint;
38529
38530         const p0 = points[ intPoint === 0 ? intPoint : intPoint - 1 ];
38531         const p1 = points[ intPoint ];
38532         const p2 = points[ intPoint > points.length - 2 ? points.length - 1 : intPoint + 1 ];
38533         const p3 = points[ intPoint > points.length - 3 ? points.length - 1 : intPoint + 2 ];
38534
38535         point.set(
38536                 CatmullRom( weight, p0.x, p1.x, p2.x, p3.x ),
38537                 CatmullRom( weight, p0.y, p1.y, p2.y, p3.y )
38538         );
38539
38540         return point;
38541
38542 };
38543
38544 SplineCurve.prototype.copy = function ( source ) {
38545
38546         Curve.prototype.copy.call( this, source );
38547
38548         this.points = [];
38549
38550         for ( let i = 0, l = source.points.length; i < l; i ++ ) {
38551
38552                 const point = source.points[ i ];
38553
38554                 this.points.push( point.clone() );
38555
38556         }
38557
38558         return this;
38559
38560 };
38561
38562 SplineCurve.prototype.toJSON = function () {
38563
38564         const data = Curve.prototype.toJSON.call( this );
38565
38566         data.points = [];
38567
38568         for ( let i = 0, l = this.points.length; i < l; i ++ ) {
38569
38570                 const point = this.points[ i ];
38571                 data.points.push( point.toArray() );
38572
38573         }
38574
38575         return data;
38576
38577 };
38578
38579 SplineCurve.prototype.fromJSON = function ( json ) {
38580
38581         Curve.prototype.fromJSON.call( this, json );
38582
38583         this.points = [];
38584
38585         for ( let i = 0, l = json.points.length; i < l; i ++ ) {
38586
38587                 const point = json.points[ i ];
38588                 this.points.push( new Vector2().fromArray( point ) );
38589
38590         }
38591
38592         return this;
38593
38594 };
38595
38596 var Curves = /*#__PURE__*/Object.freeze({
38597         __proto__: null,
38598         ArcCurve: ArcCurve,
38599         CatmullRomCurve3: CatmullRomCurve3,
38600         CubicBezierCurve: CubicBezierCurve,
38601         CubicBezierCurve3: CubicBezierCurve3,
38602         EllipseCurve: EllipseCurve,
38603         LineCurve: LineCurve,
38604         LineCurve3: LineCurve3,
38605         QuadraticBezierCurve: QuadraticBezierCurve,
38606         QuadraticBezierCurve3: QuadraticBezierCurve3,
38607         SplineCurve: SplineCurve
38608 });
38609
38610 /**************************************************************
38611  *      Curved Path - a curve path is simply a array of connected
38612  *  curves, but retains the api of a curve
38613  **************************************************************/
38614
38615 function CurvePath() {
38616
38617         Curve.call( this );
38618
38619         this.type = 'CurvePath';
38620
38621         this.curves = [];
38622         this.autoClose = false; // Automatically closes the path
38623
38624 }
38625
38626 CurvePath.prototype = Object.assign( Object.create( Curve.prototype ), {
38627
38628         constructor: CurvePath,
38629
38630         add: function ( curve ) {
38631
38632                 this.curves.push( curve );
38633
38634         },
38635
38636         closePath: function () {
38637
38638                 // Add a line curve if start and end of lines are not connected
38639                 const startPoint = this.curves[ 0 ].getPoint( 0 );
38640                 const endPoint = this.curves[ this.curves.length - 1 ].getPoint( 1 );
38641
38642                 if ( ! startPoint.equals( endPoint ) ) {
38643
38644                         this.curves.push( new LineCurve( endPoint, startPoint ) );
38645
38646                 }
38647
38648         },
38649
38650         // To get accurate point with reference to
38651         // entire path distance at time t,
38652         // following has to be done:
38653
38654         // 1. Length of each sub path have to be known
38655         // 2. Locate and identify type of curve
38656         // 3. Get t for the curve
38657         // 4. Return curve.getPointAt(t')
38658
38659         getPoint: function ( t ) {
38660
38661                 const d = t * this.getLength();
38662                 const curveLengths = this.getCurveLengths();
38663                 let i = 0;
38664
38665                 // To think about boundaries points.
38666
38667                 while ( i < curveLengths.length ) {
38668
38669                         if ( curveLengths[ i ] >= d ) {
38670
38671                                 const diff = curveLengths[ i ] - d;
38672                                 const curve = this.curves[ i ];
38673
38674                                 const segmentLength = curve.getLength();
38675                                 const u = segmentLength === 0 ? 0 : 1 - diff / segmentLength;
38676
38677                                 return curve.getPointAt( u );
38678
38679                         }
38680
38681                         i ++;
38682
38683                 }
38684
38685                 return null;
38686
38687                 // loop where sum != 0, sum > d , sum+1 <d
38688
38689         },
38690
38691         // We cannot use the default THREE.Curve getPoint() with getLength() because in
38692         // THREE.Curve, getLength() depends on getPoint() but in THREE.CurvePath
38693         // getPoint() depends on getLength
38694
38695         getLength: function () {
38696
38697                 const lens = this.getCurveLengths();
38698                 return lens[ lens.length - 1 ];
38699
38700         },
38701
38702         // cacheLengths must be recalculated.
38703         updateArcLengths: function () {
38704
38705                 this.needsUpdate = true;
38706                 this.cacheLengths = null;
38707                 this.getCurveLengths();
38708
38709         },
38710
38711         // Compute lengths and cache them
38712         // We cannot overwrite getLengths() because UtoT mapping uses it.
38713
38714         getCurveLengths: function () {
38715
38716                 // We use cache values if curves and cache array are same length
38717
38718                 if ( this.cacheLengths && this.cacheLengths.length === this.curves.length ) {
38719
38720                         return this.cacheLengths;
38721
38722                 }
38723
38724                 // Get length of sub-curve
38725                 // Push sums into cached array
38726
38727                 const lengths = [];
38728                 let sums = 0;
38729
38730                 for ( let i = 0, l = this.curves.length; i < l; i ++ ) {
38731
38732                         sums += this.curves[ i ].getLength();
38733                         lengths.push( sums );
38734
38735                 }
38736
38737                 this.cacheLengths = lengths;
38738
38739                 return lengths;
38740
38741         },
38742
38743         getSpacedPoints: function ( divisions = 40 ) {
38744
38745                 const points = [];
38746
38747                 for ( let i = 0; i <= divisions; i ++ ) {
38748
38749                         points.push( this.getPoint( i / divisions ) );
38750
38751                 }
38752
38753                 if ( this.autoClose ) {
38754
38755                         points.push( points[ 0 ] );
38756
38757                 }
38758
38759                 return points;
38760
38761         },
38762
38763         getPoints: function ( divisions = 12 ) {
38764
38765                 const points = [];
38766                 let last;
38767
38768                 for ( let i = 0, curves = this.curves; i < curves.length; i ++ ) {
38769
38770                         const curve = curves[ i ];
38771                         const resolution = ( curve && curve.isEllipseCurve ) ? divisions * 2
38772                                 : ( curve && ( curve.isLineCurve || curve.isLineCurve3 ) ) ? 1
38773                                         : ( curve && curve.isSplineCurve ) ? divisions * curve.points.length
38774                                                 : divisions;
38775
38776                         const pts = curve.getPoints( resolution );
38777
38778                         for ( let j = 0; j < pts.length; j ++ ) {
38779
38780                                 const point = pts[ j ];
38781
38782                                 if ( last && last.equals( point ) ) continue; // ensures no consecutive points are duplicates
38783
38784                                 points.push( point );
38785                                 last = point;
38786
38787                         }
38788
38789                 }
38790
38791                 if ( this.autoClose && points.length > 1 && ! points[ points.length - 1 ].equals( points[ 0 ] ) ) {
38792
38793                         points.push( points[ 0 ] );
38794
38795                 }
38796
38797                 return points;
38798
38799         },
38800
38801         copy: function ( source ) {
38802
38803                 Curve.prototype.copy.call( this, source );
38804
38805                 this.curves = [];
38806
38807                 for ( let i = 0, l = source.curves.length; i < l; i ++ ) {
38808
38809                         const curve = source.curves[ i ];
38810
38811                         this.curves.push( curve.clone() );
38812
38813                 }
38814
38815                 this.autoClose = source.autoClose;
38816
38817                 return this;
38818
38819         },
38820
38821         toJSON: function () {
38822
38823                 const data = Curve.prototype.toJSON.call( this );
38824
38825                 data.autoClose = this.autoClose;
38826                 data.curves = [];
38827
38828                 for ( let i = 0, l = this.curves.length; i < l; i ++ ) {
38829
38830                         const curve = this.curves[ i ];
38831                         data.curves.push( curve.toJSON() );
38832
38833                 }
38834
38835                 return data;
38836
38837         },
38838
38839         fromJSON: function ( json ) {
38840
38841                 Curve.prototype.fromJSON.call( this, json );
38842
38843                 this.autoClose = json.autoClose;
38844                 this.curves = [];
38845
38846                 for ( let i = 0, l = json.curves.length; i < l; i ++ ) {
38847
38848                         const curve = json.curves[ i ];
38849                         this.curves.push( new Curves[ curve.type ]().fromJSON( curve ) );
38850
38851                 }
38852
38853                 return this;
38854
38855         }
38856
38857 } );
38858
38859 function Path( points ) {
38860
38861         CurvePath.call( this );
38862
38863         this.type = 'Path';
38864
38865         this.currentPoint = new Vector2();
38866
38867         if ( points ) {
38868
38869                 this.setFromPoints( points );
38870
38871         }
38872
38873 }
38874
38875 Path.prototype = Object.assign( Object.create( CurvePath.prototype ), {
38876
38877         constructor: Path,
38878
38879         setFromPoints: function ( points ) {
38880
38881                 this.moveTo( points[ 0 ].x, points[ 0 ].y );
38882
38883                 for ( let i = 1, l = points.length; i < l; i ++ ) {
38884
38885                         this.lineTo( points[ i ].x, points[ i ].y );
38886
38887                 }
38888
38889                 return this;
38890
38891         },
38892
38893         moveTo: function ( x, y ) {
38894
38895                 this.currentPoint.set( x, y ); // TODO consider referencing vectors instead of copying?
38896
38897                 return this;
38898
38899         },
38900
38901         lineTo: function ( x, y ) {
38902
38903                 const curve = new LineCurve( this.currentPoint.clone(), new Vector2( x, y ) );
38904                 this.curves.push( curve );
38905
38906                 this.currentPoint.set( x, y );
38907
38908                 return this;
38909
38910         },
38911
38912         quadraticCurveTo: function ( aCPx, aCPy, aX, aY ) {
38913
38914                 const curve = new QuadraticBezierCurve(
38915                         this.currentPoint.clone(),
38916                         new Vector2( aCPx, aCPy ),
38917                         new Vector2( aX, aY )
38918                 );
38919
38920                 this.curves.push( curve );
38921
38922                 this.currentPoint.set( aX, aY );
38923
38924                 return this;
38925
38926         },
38927
38928         bezierCurveTo: function ( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY ) {
38929
38930                 const curve = new CubicBezierCurve(
38931                         this.currentPoint.clone(),
38932                         new Vector2( aCP1x, aCP1y ),
38933                         new Vector2( aCP2x, aCP2y ),
38934                         new Vector2( aX, aY )
38935                 );
38936
38937                 this.curves.push( curve );
38938
38939                 this.currentPoint.set( aX, aY );
38940
38941                 return this;
38942
38943         },
38944
38945         splineThru: function ( pts /*Array of Vector*/ ) {
38946
38947                 const npts = [ this.currentPoint.clone() ].concat( pts );
38948
38949                 const curve = new SplineCurve( npts );
38950                 this.curves.push( curve );
38951
38952                 this.currentPoint.copy( pts[ pts.length - 1 ] );
38953
38954                 return this;
38955
38956         },
38957
38958         arc: function ( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) {
38959
38960                 const x0 = this.currentPoint.x;
38961                 const y0 = this.currentPoint.y;
38962
38963                 this.absarc( aX + x0, aY + y0, aRadius,
38964                         aStartAngle, aEndAngle, aClockwise );
38965
38966                 return this;
38967
38968         },
38969
38970         absarc: function ( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) {
38971
38972                 this.absellipse( aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise );
38973
38974                 return this;
38975
38976         },
38977
38978         ellipse: function ( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ) {
38979
38980                 const x0 = this.currentPoint.x;
38981                 const y0 = this.currentPoint.y;
38982
38983                 this.absellipse( aX + x0, aY + y0, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation );
38984
38985                 return this;
38986
38987         },
38988
38989         absellipse: function ( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ) {
38990
38991                 const curve = new EllipseCurve( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation );
38992
38993                 if ( this.curves.length > 0 ) {
38994
38995                         // if a previous curve is present, attempt to join
38996                         const firstPoint = curve.getPoint( 0 );
38997
38998                         if ( ! firstPoint.equals( this.currentPoint ) ) {
38999
39000                                 this.lineTo( firstPoint.x, firstPoint.y );
39001
39002                         }
39003
39004                 }
39005
39006                 this.curves.push( curve );
39007
39008                 const lastPoint = curve.getPoint( 1 );
39009                 this.currentPoint.copy( lastPoint );
39010
39011                 return this;
39012
39013         },
39014
39015         copy: function ( source ) {
39016
39017                 CurvePath.prototype.copy.call( this, source );
39018
39019                 this.currentPoint.copy( source.currentPoint );
39020
39021                 return this;
39022
39023         },
39024
39025         toJSON: function () {
39026
39027                 const data = CurvePath.prototype.toJSON.call( this );
39028
39029                 data.currentPoint = this.currentPoint.toArray();
39030
39031                 return data;
39032
39033         },
39034
39035         fromJSON: function ( json ) {
39036
39037                 CurvePath.prototype.fromJSON.call( this, json );
39038
39039                 this.currentPoint.fromArray( json.currentPoint );
39040
39041                 return this;
39042
39043         }
39044
39045 } );
39046
39047 function Shape( points ) {
39048
39049         Path.call( this, points );
39050
39051         this.uuid = MathUtils.generateUUID();
39052
39053         this.type = 'Shape';
39054
39055         this.holes = [];
39056
39057 }
39058
39059 Shape.prototype = Object.assign( Object.create( Path.prototype ), {
39060
39061         constructor: Shape,
39062
39063         getPointsHoles: function ( divisions ) {
39064
39065                 const holesPts = [];
39066
39067                 for ( let i = 0, l = this.holes.length; i < l; i ++ ) {
39068
39069                         holesPts[ i ] = this.holes[ i ].getPoints( divisions );
39070
39071                 }
39072
39073                 return holesPts;
39074
39075         },
39076
39077         // get points of shape and holes (keypoints based on segments parameter)
39078
39079         extractPoints: function ( divisions ) {
39080
39081                 return {
39082
39083                         shape: this.getPoints( divisions ),
39084                         holes: this.getPointsHoles( divisions )
39085
39086                 };
39087
39088         },
39089
39090         copy: function ( source ) {
39091
39092                 Path.prototype.copy.call( this, source );
39093
39094                 this.holes = [];
39095
39096                 for ( let i = 0, l = source.holes.length; i < l; i ++ ) {
39097
39098                         const hole = source.holes[ i ];
39099
39100                         this.holes.push( hole.clone() );
39101
39102                 }
39103
39104                 return this;
39105
39106         },
39107
39108         toJSON: function () {
39109
39110                 const data = Path.prototype.toJSON.call( this );
39111
39112                 data.uuid = this.uuid;
39113                 data.holes = [];
39114
39115                 for ( let i = 0, l = this.holes.length; i < l; i ++ ) {
39116
39117                         const hole = this.holes[ i ];
39118                         data.holes.push( hole.toJSON() );
39119
39120                 }
39121
39122                 return data;
39123
39124         },
39125
39126         fromJSON: function ( json ) {
39127
39128                 Path.prototype.fromJSON.call( this, json );
39129
39130                 this.uuid = json.uuid;
39131                 this.holes = [];
39132
39133                 for ( let i = 0, l = json.holes.length; i < l; i ++ ) {
39134
39135                         const hole = json.holes[ i ];
39136                         this.holes.push( new Path().fromJSON( hole ) );
39137
39138                 }
39139
39140                 return this;
39141
39142         }
39143
39144 } );
39145
39146 function Light( color, intensity = 1 ) {
39147
39148         Object3D.call( this );
39149
39150         this.type = 'Light';
39151
39152         this.color = new Color( color );
39153         this.intensity = intensity;
39154
39155 }
39156
39157 Light.prototype = Object.assign( Object.create( Object3D.prototype ), {
39158
39159         constructor: Light,
39160
39161         isLight: true,
39162
39163         copy: function ( source ) {
39164
39165                 Object3D.prototype.copy.call( this, source );
39166
39167                 this.color.copy( source.color );
39168                 this.intensity = source.intensity;
39169
39170                 return this;
39171
39172         },
39173
39174         toJSON: function ( meta ) {
39175
39176                 const data = Object3D.prototype.toJSON.call( this, meta );
39177
39178                 data.object.color = this.color.getHex();
39179                 data.object.intensity = this.intensity;
39180
39181                 if ( this.groundColor !== undefined ) data.object.groundColor = this.groundColor.getHex();
39182
39183                 if ( this.distance !== undefined ) data.object.distance = this.distance;
39184                 if ( this.angle !== undefined ) data.object.angle = this.angle;
39185                 if ( this.decay !== undefined ) data.object.decay = this.decay;
39186                 if ( this.penumbra !== undefined ) data.object.penumbra = this.penumbra;
39187
39188                 if ( this.shadow !== undefined ) data.object.shadow = this.shadow.toJSON();
39189
39190                 return data;
39191
39192         }
39193
39194 } );
39195
39196 function HemisphereLight( skyColor, groundColor, intensity ) {
39197
39198         Light.call( this, skyColor, intensity );
39199
39200         this.type = 'HemisphereLight';
39201
39202         this.position.copy( Object3D.DefaultUp );
39203         this.updateMatrix();
39204
39205         this.groundColor = new Color( groundColor );
39206
39207 }
39208
39209 HemisphereLight.prototype = Object.assign( Object.create( Light.prototype ), {
39210
39211         constructor: HemisphereLight,
39212
39213         isHemisphereLight: true,
39214
39215         copy: function ( source ) {
39216
39217                 Light.prototype.copy.call( this, source );
39218
39219                 this.groundColor.copy( source.groundColor );
39220
39221                 return this;
39222
39223         }
39224
39225 } );
39226
39227 function LightShadow( camera ) {
39228
39229         this.camera = camera;
39230
39231         this.bias = 0;
39232         this.normalBias = 0;
39233         this.radius = 1;
39234
39235         this.mapSize = new Vector2( 512, 512 );
39236
39237         this.map = null;
39238         this.mapPass = null;
39239         this.matrix = new Matrix4();
39240
39241         this.autoUpdate = true;
39242         this.needsUpdate = false;
39243
39244         this._frustum = new Frustum();
39245         this._frameExtents = new Vector2( 1, 1 );
39246
39247         this._viewportCount = 1;
39248
39249         this._viewports = [
39250
39251                 new Vector4( 0, 0, 1, 1 )
39252
39253         ];
39254
39255 }
39256
39257 Object.assign( LightShadow.prototype, {
39258
39259         _projScreenMatrix: new Matrix4(),
39260
39261         _lightPositionWorld: new Vector3(),
39262
39263         _lookTarget: new Vector3(),
39264
39265         getViewportCount: function () {
39266
39267                 return this._viewportCount;
39268
39269         },
39270
39271         getFrustum: function () {
39272
39273                 return this._frustum;
39274
39275         },
39276
39277         updateMatrices: function ( light ) {
39278
39279                 const shadowCamera = this.camera,
39280                         shadowMatrix = this.matrix,
39281                         projScreenMatrix = this._projScreenMatrix,
39282                         lookTarget = this._lookTarget,
39283                         lightPositionWorld = this._lightPositionWorld;
39284
39285                 lightPositionWorld.setFromMatrixPosition( light.matrixWorld );
39286                 shadowCamera.position.copy( lightPositionWorld );
39287
39288                 lookTarget.setFromMatrixPosition( light.target.matrixWorld );
39289                 shadowCamera.lookAt( lookTarget );
39290                 shadowCamera.updateMatrixWorld();
39291
39292                 projScreenMatrix.multiplyMatrices( shadowCamera.projectionMatrix, shadowCamera.matrixWorldInverse );
39293                 this._frustum.setFromProjectionMatrix( projScreenMatrix );
39294
39295                 shadowMatrix.set(
39296                         0.5, 0.0, 0.0, 0.5,
39297                         0.0, 0.5, 0.0, 0.5,
39298                         0.0, 0.0, 0.5, 0.5,
39299                         0.0, 0.0, 0.0, 1.0
39300                 );
39301
39302                 shadowMatrix.multiply( shadowCamera.projectionMatrix );
39303                 shadowMatrix.multiply( shadowCamera.matrixWorldInverse );
39304
39305         },
39306
39307         getViewport: function ( viewportIndex ) {
39308
39309                 return this._viewports[ viewportIndex ];
39310
39311         },
39312
39313         getFrameExtents: function () {
39314
39315                 return this._frameExtents;
39316
39317         },
39318
39319         copy: function ( source ) {
39320
39321                 this.camera = source.camera.clone();
39322
39323                 this.bias = source.bias;
39324                 this.radius = source.radius;
39325
39326                 this.mapSize.copy( source.mapSize );
39327
39328                 return this;
39329
39330         },
39331
39332         clone: function () {
39333
39334                 return new this.constructor().copy( this );
39335
39336         },
39337
39338         toJSON: function () {
39339
39340                 const object = {};
39341
39342                 if ( this.bias !== 0 ) object.bias = this.bias;
39343                 if ( this.normalBias !== 0 ) object.normalBias = this.normalBias;
39344                 if ( this.radius !== 1 ) object.radius = this.radius;
39345                 if ( this.mapSize.x !== 512 || this.mapSize.y !== 512 ) object.mapSize = this.mapSize.toArray();
39346
39347                 object.camera = this.camera.toJSON( false ).object;
39348                 delete object.camera.matrix;
39349
39350                 return object;
39351
39352         }
39353
39354 } );
39355
39356 function SpotLightShadow() {
39357
39358         LightShadow.call( this, new PerspectiveCamera( 50, 1, 0.5, 500 ) );
39359
39360         this.focus = 1;
39361
39362 }
39363
39364 SpotLightShadow.prototype = Object.assign( Object.create( LightShadow.prototype ), {
39365
39366         constructor: SpotLightShadow,
39367
39368         isSpotLightShadow: true,
39369
39370         updateMatrices: function ( light ) {
39371
39372                 const camera = this.camera;
39373
39374                 const fov = MathUtils.RAD2DEG * 2 * light.angle * this.focus;
39375                 const aspect = this.mapSize.width / this.mapSize.height;
39376                 const far = light.distance || camera.far;
39377
39378                 if ( fov !== camera.fov || aspect !== camera.aspect || far !== camera.far ) {
39379
39380                         camera.fov = fov;
39381                         camera.aspect = aspect;
39382                         camera.far = far;
39383                         camera.updateProjectionMatrix();
39384
39385                 }
39386
39387                 LightShadow.prototype.updateMatrices.call( this, light );
39388
39389         }
39390
39391 } );
39392
39393 function SpotLight( color, intensity, distance, angle, penumbra, decay ) {
39394
39395         Light.call( this, color, intensity );
39396
39397         this.type = 'SpotLight';
39398
39399         this.position.copy( Object3D.DefaultUp );
39400         this.updateMatrix();
39401
39402         this.target = new Object3D();
39403
39404         Object.defineProperty( this, 'power', {
39405                 get: function () {
39406
39407                         // intensity = power per solid angle.
39408                         // ref: equation (17) from https://seblagarde.files.wordpress.com/2015/07/course_notes_moving_frostbite_to_pbr_v32.pdf
39409                         return this.intensity * Math.PI;
39410
39411                 },
39412                 set: function ( power ) {
39413
39414                         // intensity = power per solid angle.
39415                         // ref: equation (17) from https://seblagarde.files.wordpress.com/2015/07/course_notes_moving_frostbite_to_pbr_v32.pdf
39416                         this.intensity = power / Math.PI;
39417
39418                 }
39419         } );
39420
39421         this.distance = ( distance !== undefined ) ? distance : 0;
39422         this.angle = ( angle !== undefined ) ? angle : Math.PI / 3;
39423         this.penumbra = ( penumbra !== undefined ) ? penumbra : 0;
39424         this.decay = ( decay !== undefined ) ? decay : 1;       // for physically correct lights, should be 2.
39425
39426         this.shadow = new SpotLightShadow();
39427
39428 }
39429
39430 SpotLight.prototype = Object.assign( Object.create( Light.prototype ), {
39431
39432         constructor: SpotLight,
39433
39434         isSpotLight: true,
39435
39436         copy: function ( source ) {
39437
39438                 Light.prototype.copy.call( this, source );
39439
39440                 this.distance = source.distance;
39441                 this.angle = source.angle;
39442                 this.penumbra = source.penumbra;
39443                 this.decay = source.decay;
39444
39445                 this.target = source.target.clone();
39446
39447                 this.shadow = source.shadow.clone();
39448
39449                 return this;
39450
39451         }
39452
39453 } );
39454
39455 function PointLightShadow() {
39456
39457         LightShadow.call( this, new PerspectiveCamera( 90, 1, 0.5, 500 ) );
39458
39459         this._frameExtents = new Vector2( 4, 2 );
39460
39461         this._viewportCount = 6;
39462
39463         this._viewports = [
39464                 // These viewports map a cube-map onto a 2D texture with the
39465                 // following orientation:
39466                 //
39467                 //  xzXZ
39468                 //   y Y
39469                 //
39470                 // X - Positive x direction
39471                 // x - Negative x direction
39472                 // Y - Positive y direction
39473                 // y - Negative y direction
39474                 // Z - Positive z direction
39475                 // z - Negative z direction
39476
39477                 // positive X
39478                 new Vector4( 2, 1, 1, 1 ),
39479                 // negative X
39480                 new Vector4( 0, 1, 1, 1 ),
39481                 // positive Z
39482                 new Vector4( 3, 1, 1, 1 ),
39483                 // negative Z
39484                 new Vector4( 1, 1, 1, 1 ),
39485                 // positive Y
39486                 new Vector4( 3, 0, 1, 1 ),
39487                 // negative Y
39488                 new Vector4( 1, 0, 1, 1 )
39489         ];
39490
39491         this._cubeDirections = [
39492                 new Vector3( 1, 0, 0 ), new Vector3( - 1, 0, 0 ), new Vector3( 0, 0, 1 ),
39493                 new Vector3( 0, 0, - 1 ), new Vector3( 0, 1, 0 ), new Vector3( 0, - 1, 0 )
39494         ];
39495
39496         this._cubeUps = [
39497                 new Vector3( 0, 1, 0 ), new Vector3( 0, 1, 0 ), new Vector3( 0, 1, 0 ),
39498                 new Vector3( 0, 1, 0 ), new Vector3( 0, 0, 1 ), new Vector3( 0, 0, - 1 )
39499         ];
39500
39501 }
39502
39503 PointLightShadow.prototype = Object.assign( Object.create( LightShadow.prototype ), {
39504
39505         constructor: PointLightShadow,
39506
39507         isPointLightShadow: true,
39508
39509         updateMatrices: function ( light, viewportIndex = 0 ) {
39510
39511                 const camera = this.camera,
39512                         shadowMatrix = this.matrix,
39513                         lightPositionWorld = this._lightPositionWorld,
39514                         lookTarget = this._lookTarget,
39515                         projScreenMatrix = this._projScreenMatrix;
39516
39517                 lightPositionWorld.setFromMatrixPosition( light.matrixWorld );
39518                 camera.position.copy( lightPositionWorld );
39519
39520                 lookTarget.copy( camera.position );
39521                 lookTarget.add( this._cubeDirections[ viewportIndex ] );
39522                 camera.up.copy( this._cubeUps[ viewportIndex ] );
39523                 camera.lookAt( lookTarget );
39524                 camera.updateMatrixWorld();
39525
39526                 shadowMatrix.makeTranslation( - lightPositionWorld.x, - lightPositionWorld.y, - lightPositionWorld.z );
39527
39528                 projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse );
39529                 this._frustum.setFromProjectionMatrix( projScreenMatrix );
39530
39531         }
39532
39533 } );
39534
39535 function PointLight( color, intensity, distance, decay ) {
39536
39537         Light.call( this, color, intensity );
39538
39539         this.type = 'PointLight';
39540
39541         Object.defineProperty( this, 'power', {
39542                 get: function () {
39543
39544                         // intensity = power per solid angle.
39545                         // ref: equation (15) from https://seblagarde.files.wordpress.com/2015/07/course_notes_moving_frostbite_to_pbr_v32.pdf
39546                         return this.intensity * 4 * Math.PI;
39547
39548                 },
39549                 set: function ( power ) {
39550
39551                         // intensity = power per solid angle.
39552                         // ref: equation (15) from https://seblagarde.files.wordpress.com/2015/07/course_notes_moving_frostbite_to_pbr_v32.pdf
39553                         this.intensity = power / ( 4 * Math.PI );
39554
39555                 }
39556         } );
39557
39558         this.distance = ( distance !== undefined ) ? distance : 0;
39559         this.decay = ( decay !== undefined ) ? decay : 1;       // for physically correct lights, should be 2.
39560
39561         this.shadow = new PointLightShadow();
39562
39563 }
39564
39565 PointLight.prototype = Object.assign( Object.create( Light.prototype ), {
39566
39567         constructor: PointLight,
39568
39569         isPointLight: true,
39570
39571         copy: function ( source ) {
39572
39573                 Light.prototype.copy.call( this, source );
39574
39575                 this.distance = source.distance;
39576                 this.decay = source.decay;
39577
39578                 this.shadow = source.shadow.clone();
39579
39580                 return this;
39581
39582         }
39583
39584 } );
39585
39586 function OrthographicCamera( left = - 1, right = 1, top = 1, bottom = - 1, near = 0.1, far = 2000 ) {
39587
39588         Camera$1.call( this );
39589
39590         this.type = 'OrthographicCamera';
39591
39592         this.zoom = 1;
39593         this.view = null;
39594
39595         this.left = left;
39596         this.right = right;
39597         this.top = top;
39598         this.bottom = bottom;
39599
39600         this.near = near;
39601         this.far = far;
39602
39603         this.updateProjectionMatrix();
39604
39605 }
39606
39607 OrthographicCamera.prototype = Object.assign( Object.create( Camera$1.prototype ), {
39608
39609         constructor: OrthographicCamera,
39610
39611         isOrthographicCamera: true,
39612
39613         copy: function ( source, recursive ) {
39614
39615                 Camera$1.prototype.copy.call( this, source, recursive );
39616
39617                 this.left = source.left;
39618                 this.right = source.right;
39619                 this.top = source.top;
39620                 this.bottom = source.bottom;
39621                 this.near = source.near;
39622                 this.far = source.far;
39623
39624                 this.zoom = source.zoom;
39625                 this.view = source.view === null ? null : Object.assign( {}, source.view );
39626
39627                 return this;
39628
39629         },
39630
39631         setViewOffset: function ( fullWidth, fullHeight, x, y, width, height ) {
39632
39633                 if ( this.view === null ) {
39634
39635                         this.view = {
39636                                 enabled: true,
39637                                 fullWidth: 1,
39638                                 fullHeight: 1,
39639                                 offsetX: 0,
39640                                 offsetY: 0,
39641                                 width: 1,
39642                                 height: 1
39643                         };
39644
39645                 }
39646
39647                 this.view.enabled = true;
39648                 this.view.fullWidth = fullWidth;
39649                 this.view.fullHeight = fullHeight;
39650                 this.view.offsetX = x;
39651                 this.view.offsetY = y;
39652                 this.view.width = width;
39653                 this.view.height = height;
39654
39655                 this.updateProjectionMatrix();
39656
39657         },
39658
39659         clearViewOffset: function () {
39660
39661                 if ( this.view !== null ) {
39662
39663                         this.view.enabled = false;
39664
39665                 }
39666
39667                 this.updateProjectionMatrix();
39668
39669         },
39670
39671         updateProjectionMatrix: function () {
39672
39673                 const dx = ( this.right - this.left ) / ( 2 * this.zoom );
39674                 const dy = ( this.top - this.bottom ) / ( 2 * this.zoom );
39675                 const cx = ( this.right + this.left ) / 2;
39676                 const cy = ( this.top + this.bottom ) / 2;
39677
39678                 let left = cx - dx;
39679                 let right = cx + dx;
39680                 let top = cy + dy;
39681                 let bottom = cy - dy;
39682
39683                 if ( this.view !== null && this.view.enabled ) {
39684
39685                         const scaleW = ( this.right - this.left ) / this.view.fullWidth / this.zoom;
39686                         const scaleH = ( this.top - this.bottom ) / this.view.fullHeight / this.zoom;
39687
39688                         left += scaleW * this.view.offsetX;
39689                         right = left + scaleW * this.view.width;
39690                         top -= scaleH * this.view.offsetY;
39691                         bottom = top - scaleH * this.view.height;
39692
39693                 }
39694
39695                 this.projectionMatrix.makeOrthographic( left, right, top, bottom, this.near, this.far );
39696
39697                 this.projectionMatrixInverse.copy( this.projectionMatrix ).invert();
39698
39699         },
39700
39701         toJSON: function ( meta ) {
39702
39703                 const data = Object3D.prototype.toJSON.call( this, meta );
39704
39705                 data.object.zoom = this.zoom;
39706                 data.object.left = this.left;
39707                 data.object.right = this.right;
39708                 data.object.top = this.top;
39709                 data.object.bottom = this.bottom;
39710                 data.object.near = this.near;
39711                 data.object.far = this.far;
39712
39713                 if ( this.view !== null ) data.object.view = Object.assign( {}, this.view );
39714
39715                 return data;
39716
39717         }
39718
39719 } );
39720
39721 function DirectionalLightShadow() {
39722
39723         LightShadow.call( this, new OrthographicCamera( - 5, 5, 5, - 5, 0.5, 500 ) );
39724
39725 }
39726
39727 DirectionalLightShadow.prototype = Object.assign( Object.create( LightShadow.prototype ), {
39728
39729         constructor: DirectionalLightShadow,
39730
39731         isDirectionalLightShadow: true,
39732
39733         updateMatrices: function ( light ) {
39734
39735                 LightShadow.prototype.updateMatrices.call( this, light );
39736
39737         }
39738
39739 } );
39740
39741 function DirectionalLight( color, intensity ) {
39742
39743         Light.call( this, color, intensity );
39744
39745         this.type = 'DirectionalLight';
39746
39747         this.position.copy( Object3D.DefaultUp );
39748         this.updateMatrix();
39749
39750         this.target = new Object3D();
39751
39752         this.shadow = new DirectionalLightShadow();
39753
39754 }
39755
39756 DirectionalLight.prototype = Object.assign( Object.create( Light.prototype ), {
39757
39758         constructor: DirectionalLight,
39759
39760         isDirectionalLight: true,
39761
39762         copy: function ( source ) {
39763
39764                 Light.prototype.copy.call( this, source );
39765
39766                 this.target = source.target.clone();
39767
39768                 this.shadow = source.shadow.clone();
39769
39770                 return this;
39771
39772         }
39773
39774 } );
39775
39776 function AmbientLight( color, intensity ) {
39777
39778         Light.call( this, color, intensity );
39779
39780         this.type = 'AmbientLight';
39781
39782 }
39783
39784 AmbientLight.prototype = Object.assign( Object.create( Light.prototype ), {
39785
39786         constructor: AmbientLight,
39787
39788         isAmbientLight: true
39789
39790 } );
39791
39792 function RectAreaLight( color, intensity, width, height ) {
39793
39794         Light.call( this, color, intensity );
39795
39796         this.type = 'RectAreaLight';
39797
39798         this.width = ( width !== undefined ) ? width : 10;
39799         this.height = ( height !== undefined ) ? height : 10;
39800
39801 }
39802
39803 RectAreaLight.prototype = Object.assign( Object.create( Light.prototype ), {
39804
39805         constructor: RectAreaLight,
39806
39807         isRectAreaLight: true,
39808
39809         copy: function ( source ) {
39810
39811                 Light.prototype.copy.call( this, source );
39812
39813                 this.width = source.width;
39814                 this.height = source.height;
39815
39816                 return this;
39817
39818         },
39819
39820         toJSON: function ( meta ) {
39821
39822                 const data = Light.prototype.toJSON.call( this, meta );
39823
39824                 data.object.width = this.width;
39825                 data.object.height = this.height;
39826
39827                 return data;
39828
39829         }
39830
39831 } );
39832
39833 /**
39834  * Primary reference:
39835  *   https://graphics.stanford.edu/papers/envmap/envmap.pdf
39836  *
39837  * Secondary reference:
39838  *   https://www.ppsloan.org/publications/StupidSH36.pdf
39839  */
39840
39841 // 3-band SH defined by 9 coefficients
39842
39843 class SphericalHarmonics3 {
39844
39845         constructor() {
39846
39847                 Object.defineProperty( this, 'isSphericalHarmonics3', { value: true } );
39848
39849                 this.coefficients = [];
39850
39851                 for ( let i = 0; i < 9; i ++ ) {
39852
39853                         this.coefficients.push( new Vector3() );
39854
39855                 }
39856
39857         }
39858
39859         set( coefficients ) {
39860
39861                 for ( let i = 0; i < 9; i ++ ) {
39862
39863                         this.coefficients[ i ].copy( coefficients[ i ] );
39864
39865                 }
39866
39867                 return this;
39868
39869         }
39870
39871         zero() {
39872
39873                 for ( let i = 0; i < 9; i ++ ) {
39874
39875                         this.coefficients[ i ].set( 0, 0, 0 );
39876
39877                 }
39878
39879                 return this;
39880
39881         }
39882
39883         // get the radiance in the direction of the normal
39884         // target is a Vector3
39885         getAt( normal, target ) {
39886
39887                 // normal is assumed to be unit length
39888
39889                 const x = normal.x, y = normal.y, z = normal.z;
39890
39891                 const coeff = this.coefficients;
39892
39893                 // band 0
39894                 target.copy( coeff[ 0 ] ).multiplyScalar( 0.282095 );
39895
39896                 // band 1
39897                 target.addScaledVector( coeff[ 1 ], 0.488603 * y );
39898                 target.addScaledVector( coeff[ 2 ], 0.488603 * z );
39899                 target.addScaledVector( coeff[ 3 ], 0.488603 * x );
39900
39901                 // band 2
39902                 target.addScaledVector( coeff[ 4 ], 1.092548 * ( x * y ) );
39903                 target.addScaledVector( coeff[ 5 ], 1.092548 * ( y * z ) );
39904                 target.addScaledVector( coeff[ 6 ], 0.315392 * ( 3.0 * z * z - 1.0 ) );
39905                 target.addScaledVector( coeff[ 7 ], 1.092548 * ( x * z ) );
39906                 target.addScaledVector( coeff[ 8 ], 0.546274 * ( x * x - y * y ) );
39907
39908                 return target;
39909
39910         }
39911
39912         // get the irradiance (radiance convolved with cosine lobe) in the direction of the normal
39913         // target is a Vector3
39914         // https://graphics.stanford.edu/papers/envmap/envmap.pdf
39915         getIrradianceAt( normal, target ) {
39916
39917                 // normal is assumed to be unit length
39918
39919                 const x = normal.x, y = normal.y, z = normal.z;
39920
39921                 const coeff = this.coefficients;
39922
39923                 // band 0
39924                 target.copy( coeff[ 0 ] ).multiplyScalar( 0.886227 ); // π * 0.282095
39925
39926                 // band 1
39927                 target.addScaledVector( coeff[ 1 ], 2.0 * 0.511664 * y ); // ( 2 * π / 3 ) * 0.488603
39928                 target.addScaledVector( coeff[ 2 ], 2.0 * 0.511664 * z );
39929                 target.addScaledVector( coeff[ 3 ], 2.0 * 0.511664 * x );
39930
39931                 // band 2
39932                 target.addScaledVector( coeff[ 4 ], 2.0 * 0.429043 * x * y ); // ( π / 4 ) * 1.092548
39933                 target.addScaledVector( coeff[ 5 ], 2.0 * 0.429043 * y * z );
39934                 target.addScaledVector( coeff[ 6 ], 0.743125 * z * z - 0.247708 ); // ( π / 4 ) * 0.315392 * 3
39935                 target.addScaledVector( coeff[ 7 ], 2.0 * 0.429043 * x * z );
39936                 target.addScaledVector( coeff[ 8 ], 0.429043 * ( x * x - y * y ) ); // ( π / 4 ) * 0.546274
39937
39938                 return target;
39939
39940         }
39941
39942         add( sh ) {
39943
39944                 for ( let i = 0; i < 9; i ++ ) {
39945
39946                         this.coefficients[ i ].add( sh.coefficients[ i ] );
39947
39948                 }
39949
39950                 return this;
39951
39952         }
39953
39954         addScaledSH( sh, s ) {
39955
39956                 for ( let i = 0; i < 9; i ++ ) {
39957
39958                         this.coefficients[ i ].addScaledVector( sh.coefficients[ i ], s );
39959
39960                 }
39961
39962                 return this;
39963
39964         }
39965
39966         scale( s ) {
39967
39968                 for ( let i = 0; i < 9; i ++ ) {
39969
39970                         this.coefficients[ i ].multiplyScalar( s );
39971
39972                 }
39973
39974                 return this;
39975
39976         }
39977
39978         lerp( sh, alpha ) {
39979
39980                 for ( let i = 0; i < 9; i ++ ) {
39981
39982                         this.coefficients[ i ].lerp( sh.coefficients[ i ], alpha );
39983
39984                 }
39985
39986                 return this;
39987
39988         }
39989
39990         equals( sh ) {
39991
39992                 for ( let i = 0; i < 9; i ++ ) {
39993
39994                         if ( ! this.coefficients[ i ].equals( sh.coefficients[ i ] ) ) {
39995
39996                                 return false;
39997
39998                         }
39999
40000                 }
40001
40002                 return true;
40003
40004         }
40005
40006         copy( sh ) {
40007
40008                 return this.set( sh.coefficients );
40009
40010         }
40011
40012         clone() {
40013
40014                 return new this.constructor().copy( this );
40015
40016         }
40017
40018         fromArray( array, offset = 0 ) {
40019
40020                 const coefficients = this.coefficients;
40021
40022                 for ( let i = 0; i < 9; i ++ ) {
40023
40024                         coefficients[ i ].fromArray( array, offset + ( i * 3 ) );
40025
40026                 }
40027
40028                 return this;
40029
40030         }
40031
40032         toArray( array = [], offset = 0 ) {
40033
40034                 const coefficients = this.coefficients;
40035
40036                 for ( let i = 0; i < 9; i ++ ) {
40037
40038                         coefficients[ i ].toArray( array, offset + ( i * 3 ) );
40039
40040                 }
40041
40042                 return array;
40043
40044         }
40045
40046         // evaluate the basis functions
40047         // shBasis is an Array[ 9 ]
40048         static getBasisAt( normal, shBasis ) {
40049
40050                 // normal is assumed to be unit length
40051
40052                 const x = normal.x, y = normal.y, z = normal.z;
40053
40054                 // band 0
40055                 shBasis[ 0 ] = 0.282095;
40056
40057                 // band 1
40058                 shBasis[ 1 ] = 0.488603 * y;
40059                 shBasis[ 2 ] = 0.488603 * z;
40060                 shBasis[ 3 ] = 0.488603 * x;
40061
40062                 // band 2
40063                 shBasis[ 4 ] = 1.092548 * x * y;
40064                 shBasis[ 5 ] = 1.092548 * y * z;
40065                 shBasis[ 6 ] = 0.315392 * ( 3 * z * z - 1 );
40066                 shBasis[ 7 ] = 1.092548 * x * z;
40067                 shBasis[ 8 ] = 0.546274 * ( x * x - y * y );
40068
40069         }
40070
40071 }
40072
40073 function LightProbe( sh, intensity ) {
40074
40075         Light.call( this, undefined, intensity );
40076
40077         this.type = 'LightProbe';
40078
40079         this.sh = ( sh !== undefined ) ? sh : new SphericalHarmonics3();
40080
40081 }
40082
40083 LightProbe.prototype = Object.assign( Object.create( Light.prototype ), {
40084
40085         constructor: LightProbe,
40086
40087         isLightProbe: true,
40088
40089         copy: function ( source ) {
40090
40091                 Light.prototype.copy.call( this, source );
40092
40093                 this.sh.copy( source.sh );
40094
40095                 return this;
40096
40097         },
40098
40099         fromJSON: function ( json ) {
40100
40101                 this.intensity = json.intensity; // TODO: Move this bit to Light.fromJSON();
40102                 this.sh.fromArray( json.sh );
40103
40104                 return this;
40105
40106         },
40107
40108         toJSON: function ( meta ) {
40109
40110                 const data = Light.prototype.toJSON.call( this, meta );
40111
40112                 data.object.sh = this.sh.toArray();
40113
40114                 return data;
40115
40116         }
40117
40118 } );
40119
40120 function MaterialLoader( manager ) {
40121
40122         Loader.call( this, manager );
40123
40124         this.textures = {};
40125
40126 }
40127
40128 MaterialLoader.prototype = Object.assign( Object.create( Loader.prototype ), {
40129
40130         constructor: MaterialLoader,
40131
40132         load: function ( url, onLoad, onProgress, onError ) {
40133
40134                 const scope = this;
40135
40136                 const loader = new FileLoader( scope.manager );
40137                 loader.setPath( scope.path );
40138                 loader.setRequestHeader( scope.requestHeader );
40139                 loader.setWithCredentials( scope.withCredentials );
40140                 loader.load( url, function ( text ) {
40141
40142                         try {
40143
40144                                 onLoad( scope.parse( JSON.parse( text ) ) );
40145
40146                         } catch ( e ) {
40147
40148                                 if ( onError ) {
40149
40150                                         onError( e );
40151
40152                                 } else {
40153
40154                                         console.error( e );
40155
40156                                 }
40157
40158                                 scope.manager.itemError( url );
40159
40160                         }
40161
40162                 }, onProgress, onError );
40163
40164         },
40165
40166         parse: function ( json ) {
40167
40168                 const textures = this.textures;
40169
40170                 function getTexture( name ) {
40171
40172                         if ( textures[ name ] === undefined ) {
40173
40174                                 console.warn( 'THREE.MaterialLoader: Undefined texture', name );
40175
40176                         }
40177
40178                         return textures[ name ];
40179
40180                 }
40181
40182                 const material = new Materials[ json.type ]();
40183
40184                 if ( json.uuid !== undefined ) material.uuid = json.uuid;
40185                 if ( json.name !== undefined ) material.name = json.name;
40186                 if ( json.color !== undefined && material.color !== undefined ) material.color.setHex( json.color );
40187                 if ( json.roughness !== undefined ) material.roughness = json.roughness;
40188                 if ( json.metalness !== undefined ) material.metalness = json.metalness;
40189                 if ( json.sheen !== undefined ) material.sheen = new Color().setHex( json.sheen );
40190                 if ( json.emissive !== undefined && material.emissive !== undefined ) material.emissive.setHex( json.emissive );
40191                 if ( json.specular !== undefined && material.specular !== undefined ) material.specular.setHex( json.specular );
40192                 if ( json.shininess !== undefined ) material.shininess = json.shininess;
40193                 if ( json.clearcoat !== undefined ) material.clearcoat = json.clearcoat;
40194                 if ( json.clearcoatRoughness !== undefined ) material.clearcoatRoughness = json.clearcoatRoughness;
40195                 if ( json.fog !== undefined ) material.fog = json.fog;
40196                 if ( json.flatShading !== undefined ) material.flatShading = json.flatShading;
40197                 if ( json.blending !== undefined ) material.blending = json.blending;
40198                 if ( json.combine !== undefined ) material.combine = json.combine;
40199                 if ( json.side !== undefined ) material.side = json.side;
40200                 if ( json.opacity !== undefined ) material.opacity = json.opacity;
40201                 if ( json.transparent !== undefined ) material.transparent = json.transparent;
40202                 if ( json.alphaTest !== undefined ) material.alphaTest = json.alphaTest;
40203                 if ( json.depthTest !== undefined ) material.depthTest = json.depthTest;
40204                 if ( json.depthWrite !== undefined ) material.depthWrite = json.depthWrite;
40205                 if ( json.colorWrite !== undefined ) material.colorWrite = json.colorWrite;
40206
40207                 if ( json.stencilWrite !== undefined ) material.stencilWrite = json.stencilWrite;
40208                 if ( json.stencilWriteMask !== undefined ) material.stencilWriteMask = json.stencilWriteMask;
40209                 if ( json.stencilFunc !== undefined ) material.stencilFunc = json.stencilFunc;
40210                 if ( json.stencilRef !== undefined ) material.stencilRef = json.stencilRef;
40211                 if ( json.stencilFuncMask !== undefined ) material.stencilFuncMask = json.stencilFuncMask;
40212                 if ( json.stencilFail !== undefined ) material.stencilFail = json.stencilFail;
40213                 if ( json.stencilZFail !== undefined ) material.stencilZFail = json.stencilZFail;
40214                 if ( json.stencilZPass !== undefined ) material.stencilZPass = json.stencilZPass;
40215
40216                 if ( json.wireframe !== undefined ) material.wireframe = json.wireframe;
40217                 if ( json.wireframeLinewidth !== undefined ) material.wireframeLinewidth = json.wireframeLinewidth;
40218                 if ( json.wireframeLinecap !== undefined ) material.wireframeLinecap = json.wireframeLinecap;
40219                 if ( json.wireframeLinejoin !== undefined ) material.wireframeLinejoin = json.wireframeLinejoin;
40220
40221                 if ( json.rotation !== undefined ) material.rotation = json.rotation;
40222
40223                 if ( json.linewidth !== 1 ) material.linewidth = json.linewidth;
40224                 if ( json.dashSize !== undefined ) material.dashSize = json.dashSize;
40225                 if ( json.gapSize !== undefined ) material.gapSize = json.gapSize;
40226                 if ( json.scale !== undefined ) material.scale = json.scale;
40227
40228                 if ( json.polygonOffset !== undefined ) material.polygonOffset = json.polygonOffset;
40229                 if ( json.polygonOffsetFactor !== undefined ) material.polygonOffsetFactor = json.polygonOffsetFactor;
40230                 if ( json.polygonOffsetUnits !== undefined ) material.polygonOffsetUnits = json.polygonOffsetUnits;
40231
40232                 if ( json.skinning !== undefined ) material.skinning = json.skinning;
40233                 if ( json.morphTargets !== undefined ) material.morphTargets = json.morphTargets;
40234                 if ( json.morphNormals !== undefined ) material.morphNormals = json.morphNormals;
40235                 if ( json.dithering !== undefined ) material.dithering = json.dithering;
40236
40237                 if ( json.vertexTangents !== undefined ) material.vertexTangents = json.vertexTangents;
40238
40239                 if ( json.visible !== undefined ) material.visible = json.visible;
40240
40241                 if ( json.toneMapped !== undefined ) material.toneMapped = json.toneMapped;
40242
40243                 if ( json.userData !== undefined ) material.userData = json.userData;
40244
40245                 if ( json.vertexColors !== undefined ) {
40246
40247                         if ( typeof json.vertexColors === 'number' ) {
40248
40249                                 material.vertexColors = ( json.vertexColors > 0 ) ? true : false;
40250
40251                         } else {
40252
40253                                 material.vertexColors = json.vertexColors;
40254
40255                         }
40256
40257                 }
40258
40259                 // Shader Material
40260
40261                 if ( json.uniforms !== undefined ) {
40262
40263                         for ( const name in json.uniforms ) {
40264
40265                                 const uniform = json.uniforms[ name ];
40266
40267                                 material.uniforms[ name ] = {};
40268
40269                                 switch ( uniform.type ) {
40270
40271                                         case 't':
40272                                                 material.uniforms[ name ].value = getTexture( uniform.value );
40273                                                 break;
40274
40275                                         case 'c':
40276                                                 material.uniforms[ name ].value = new Color().setHex( uniform.value );
40277                                                 break;
40278
40279                                         case 'v2':
40280                                                 material.uniforms[ name ].value = new Vector2().fromArray( uniform.value );
40281                                                 break;
40282
40283                                         case 'v3':
40284                                                 material.uniforms[ name ].value = new Vector3().fromArray( uniform.value );
40285                                                 break;
40286
40287                                         case 'v4':
40288                                                 material.uniforms[ name ].value = new Vector4().fromArray( uniform.value );
40289                                                 break;
40290
40291                                         case 'm3':
40292                                                 material.uniforms[ name ].value = new Matrix3().fromArray( uniform.value );
40293                                                 break;
40294
40295                                         case 'm4':
40296                                                 material.uniforms[ name ].value = new Matrix4().fromArray( uniform.value );
40297                                                 break;
40298
40299                                         default:
40300                                                 material.uniforms[ name ].value = uniform.value;
40301
40302                                 }
40303
40304                         }
40305
40306                 }
40307
40308                 if ( json.defines !== undefined ) material.defines = json.defines;
40309                 if ( json.vertexShader !== undefined ) material.vertexShader = json.vertexShader;
40310                 if ( json.fragmentShader !== undefined ) material.fragmentShader = json.fragmentShader;
40311
40312                 if ( json.extensions !== undefined ) {
40313
40314                         for ( const key in json.extensions ) {
40315
40316                                 material.extensions[ key ] = json.extensions[ key ];
40317
40318                         }
40319
40320                 }
40321
40322                 // Deprecated
40323
40324                 if ( json.shading !== undefined ) material.flatShading = json.shading === 1; // THREE.FlatShading
40325
40326                 // for PointsMaterial
40327
40328                 if ( json.size !== undefined ) material.size = json.size;
40329                 if ( json.sizeAttenuation !== undefined ) material.sizeAttenuation = json.sizeAttenuation;
40330
40331                 // maps
40332
40333                 if ( json.map !== undefined ) material.map = getTexture( json.map );
40334                 if ( json.matcap !== undefined ) material.matcap = getTexture( json.matcap );
40335
40336                 if ( json.alphaMap !== undefined ) material.alphaMap = getTexture( json.alphaMap );
40337
40338                 if ( json.bumpMap !== undefined ) material.bumpMap = getTexture( json.bumpMap );
40339                 if ( json.bumpScale !== undefined ) material.bumpScale = json.bumpScale;
40340
40341                 if ( json.normalMap !== undefined ) material.normalMap = getTexture( json.normalMap );
40342                 if ( json.normalMapType !== undefined ) material.normalMapType = json.normalMapType;
40343                 if ( json.normalScale !== undefined ) {
40344
40345                         let normalScale = json.normalScale;
40346
40347                         if ( Array.isArray( normalScale ) === false ) {
40348
40349                                 // Blender exporter used to export a scalar. See #7459
40350
40351                                 normalScale = [ normalScale, normalScale ];
40352
40353                         }
40354
40355                         material.normalScale = new Vector2().fromArray( normalScale );
40356
40357                 }
40358
40359                 if ( json.displacementMap !== undefined ) material.displacementMap = getTexture( json.displacementMap );
40360                 if ( json.displacementScale !== undefined ) material.displacementScale = json.displacementScale;
40361                 if ( json.displacementBias !== undefined ) material.displacementBias = json.displacementBias;
40362
40363                 if ( json.roughnessMap !== undefined ) material.roughnessMap = getTexture( json.roughnessMap );
40364                 if ( json.metalnessMap !== undefined ) material.metalnessMap = getTexture( json.metalnessMap );
40365
40366                 if ( json.emissiveMap !== undefined ) material.emissiveMap = getTexture( json.emissiveMap );
40367                 if ( json.emissiveIntensity !== undefined ) material.emissiveIntensity = json.emissiveIntensity;
40368
40369                 if ( json.specularMap !== undefined ) material.specularMap = getTexture( json.specularMap );
40370
40371                 if ( json.envMap !== undefined ) material.envMap = getTexture( json.envMap );
40372                 if ( json.envMapIntensity !== undefined ) material.envMapIntensity = json.envMapIntensity;
40373
40374                 if ( json.reflectivity !== undefined ) material.reflectivity = json.reflectivity;
40375                 if ( json.refractionRatio !== undefined ) material.refractionRatio = json.refractionRatio;
40376
40377                 if ( json.lightMap !== undefined ) material.lightMap = getTexture( json.lightMap );
40378                 if ( json.lightMapIntensity !== undefined ) material.lightMapIntensity = json.lightMapIntensity;
40379
40380                 if ( json.aoMap !== undefined ) material.aoMap = getTexture( json.aoMap );
40381                 if ( json.aoMapIntensity !== undefined ) material.aoMapIntensity = json.aoMapIntensity;
40382
40383                 if ( json.gradientMap !== undefined ) material.gradientMap = getTexture( json.gradientMap );
40384
40385                 if ( json.clearcoatMap !== undefined ) material.clearcoatMap = getTexture( json.clearcoatMap );
40386                 if ( json.clearcoatRoughnessMap !== undefined ) material.clearcoatRoughnessMap = getTexture( json.clearcoatRoughnessMap );
40387                 if ( json.clearcoatNormalMap !== undefined ) material.clearcoatNormalMap = getTexture( json.clearcoatNormalMap );
40388                 if ( json.clearcoatNormalScale !== undefined ) material.clearcoatNormalScale = new Vector2().fromArray( json.clearcoatNormalScale );
40389
40390                 if ( json.transmission !== undefined ) material.transmission = json.transmission;
40391                 if ( json.transmissionMap !== undefined ) material.transmissionMap = getTexture( json.transmissionMap );
40392
40393                 return material;
40394
40395         },
40396
40397         setTextures: function ( value ) {
40398
40399                 this.textures = value;
40400                 return this;
40401
40402         }
40403
40404 } );
40405
40406 const LoaderUtils = {
40407
40408         decodeText: function ( array ) {
40409
40410                 if ( typeof TextDecoder !== 'undefined' ) {
40411
40412                         return new TextDecoder().decode( array );
40413
40414                 }
40415
40416                 // Avoid the String.fromCharCode.apply(null, array) shortcut, which
40417                 // throws a "maximum call stack size exceeded" error for large arrays.
40418
40419                 let s = '';
40420
40421                 for ( let i = 0, il = array.length; i < il; i ++ ) {
40422
40423                         // Implicitly assumes little-endian.
40424                         s += String.fromCharCode( array[ i ] );
40425
40426                 }
40427
40428                 try {
40429
40430                         // merges multi-byte utf-8 characters.
40431
40432                         return decodeURIComponent( escape( s ) );
40433
40434                 } catch ( e ) { // see #16358
40435
40436                         return s;
40437
40438                 }
40439
40440         },
40441
40442         extractUrlBase: function ( url ) {
40443
40444                 const index = url.lastIndexOf( '/' );
40445
40446                 if ( index === - 1 ) return './';
40447
40448                 return url.substr( 0, index + 1 );
40449
40450         }
40451
40452 };
40453
40454 function InstancedBufferGeometry() {
40455
40456         BufferGeometry.call( this );
40457
40458         this.type = 'InstancedBufferGeometry';
40459         this.instanceCount = Infinity;
40460
40461 }
40462
40463 InstancedBufferGeometry.prototype = Object.assign( Object.create( BufferGeometry.prototype ), {
40464
40465         constructor: InstancedBufferGeometry,
40466
40467         isInstancedBufferGeometry: true,
40468
40469         copy: function ( source ) {
40470
40471                 BufferGeometry.prototype.copy.call( this, source );
40472
40473                 this.instanceCount = source.instanceCount;
40474
40475                 return this;
40476
40477         },
40478
40479         clone: function () {
40480
40481                 return new this.constructor().copy( this );
40482
40483         },
40484
40485         toJSON: function () {
40486
40487                 const data = BufferGeometry.prototype.toJSON.call( this );
40488
40489                 data.instanceCount = this.instanceCount;
40490
40491                 data.isInstancedBufferGeometry = true;
40492
40493                 return data;
40494
40495         }
40496
40497 } );
40498
40499 function InstancedBufferAttribute( array, itemSize, normalized, meshPerAttribute ) {
40500
40501         if ( typeof ( normalized ) === 'number' ) {
40502
40503                 meshPerAttribute = normalized;
40504
40505                 normalized = false;
40506
40507                 console.error( 'THREE.InstancedBufferAttribute: The constructor now expects normalized as the third argument.' );
40508
40509         }
40510
40511         BufferAttribute.call( this, array, itemSize, normalized );
40512
40513         this.meshPerAttribute = meshPerAttribute || 1;
40514
40515 }
40516
40517 InstancedBufferAttribute.prototype = Object.assign( Object.create( BufferAttribute.prototype ), {
40518
40519         constructor: InstancedBufferAttribute,
40520
40521         isInstancedBufferAttribute: true,
40522
40523         copy: function ( source ) {
40524
40525                 BufferAttribute.prototype.copy.call( this, source );
40526
40527                 this.meshPerAttribute = source.meshPerAttribute;
40528
40529                 return this;
40530
40531         },
40532
40533         toJSON: function ()     {
40534
40535                 const data = BufferAttribute.prototype.toJSON.call( this );
40536
40537                 data.meshPerAttribute = this.meshPerAttribute;
40538
40539                 data.isInstancedBufferAttribute = true;
40540
40541                 return data;
40542
40543         }
40544
40545 } );
40546
40547 function BufferGeometryLoader( manager ) {
40548
40549         Loader.call( this, manager );
40550
40551 }
40552
40553 BufferGeometryLoader.prototype = Object.assign( Object.create( Loader.prototype ), {
40554
40555         constructor: BufferGeometryLoader,
40556
40557         load: function ( url, onLoad, onProgress, onError ) {
40558
40559                 const scope = this;
40560
40561                 const loader = new FileLoader( scope.manager );
40562                 loader.setPath( scope.path );
40563                 loader.setRequestHeader( scope.requestHeader );
40564                 loader.setWithCredentials( scope.withCredentials );
40565                 loader.load( url, function ( text ) {
40566
40567                         try {
40568
40569                                 onLoad( scope.parse( JSON.parse( text ) ) );
40570
40571                         } catch ( e ) {
40572
40573                                 if ( onError ) {
40574
40575                                         onError( e );
40576
40577                                 } else {
40578
40579                                         console.error( e );
40580
40581                                 }
40582
40583                                 scope.manager.itemError( url );
40584
40585                         }
40586
40587                 }, onProgress, onError );
40588
40589         },
40590
40591         parse: function ( json ) {
40592
40593                 const interleavedBufferMap = {};
40594                 const arrayBufferMap = {};
40595
40596                 function getInterleavedBuffer( json, uuid ) {
40597
40598                         if ( interleavedBufferMap[ uuid ] !== undefined ) return interleavedBufferMap[ uuid ];
40599
40600                         const interleavedBuffers = json.interleavedBuffers;
40601                         const interleavedBuffer = interleavedBuffers[ uuid ];
40602
40603                         const buffer = getArrayBuffer( json, interleavedBuffer.buffer );
40604
40605                         const array = getTypedArray( interleavedBuffer.type, buffer );
40606                         const ib = new InterleavedBuffer( array, interleavedBuffer.stride );
40607                         ib.uuid = interleavedBuffer.uuid;
40608
40609                         interleavedBufferMap[ uuid ] = ib;
40610
40611                         return ib;
40612
40613                 }
40614
40615                 function getArrayBuffer( json, uuid ) {
40616
40617                         if ( arrayBufferMap[ uuid ] !== undefined ) return arrayBufferMap[ uuid ];
40618
40619                         const arrayBuffers = json.arrayBuffers;
40620                         const arrayBuffer = arrayBuffers[ uuid ];
40621
40622                         const ab = new Uint32Array( arrayBuffer ).buffer;
40623
40624                         arrayBufferMap[ uuid ] = ab;
40625
40626                         return ab;
40627
40628                 }
40629
40630                 const geometry = json.isInstancedBufferGeometry ? new InstancedBufferGeometry() : new BufferGeometry();
40631
40632                 const index = json.data.index;
40633
40634                 if ( index !== undefined ) {
40635
40636                         const typedArray = getTypedArray( index.type, index.array );
40637                         geometry.setIndex( new BufferAttribute( typedArray, 1 ) );
40638
40639                 }
40640
40641                 const attributes = json.data.attributes;
40642
40643                 for ( const key in attributes ) {
40644
40645                         const attribute = attributes[ key ];
40646                         let bufferAttribute;
40647
40648                         if ( attribute.isInterleavedBufferAttribute ) {
40649
40650                                 const interleavedBuffer = getInterleavedBuffer( json.data, attribute.data );
40651                                 bufferAttribute = new InterleavedBufferAttribute( interleavedBuffer, attribute.itemSize, attribute.offset, attribute.normalized );
40652
40653                         } else {
40654
40655                                 const typedArray = getTypedArray( attribute.type, attribute.array );
40656                                 const bufferAttributeConstr = attribute.isInstancedBufferAttribute ? InstancedBufferAttribute : BufferAttribute;
40657                                 bufferAttribute = new bufferAttributeConstr( typedArray, attribute.itemSize, attribute.normalized );
40658
40659                         }
40660
40661                         if ( attribute.name !== undefined ) bufferAttribute.name = attribute.name;
40662                         geometry.setAttribute( key, bufferAttribute );
40663
40664                 }
40665
40666                 const morphAttributes = json.data.morphAttributes;
40667
40668                 if ( morphAttributes ) {
40669
40670                         for ( const key in morphAttributes ) {
40671
40672                                 const attributeArray = morphAttributes[ key ];
40673
40674                                 const array = [];
40675
40676                                 for ( let i = 0, il = attributeArray.length; i < il; i ++ ) {
40677
40678                                         const attribute = attributeArray[ i ];
40679                                         let bufferAttribute;
40680
40681                                         if ( attribute.isInterleavedBufferAttribute ) {
40682
40683                                                 const interleavedBuffer = getInterleavedBuffer( json.data, attribute.data );
40684                                                 bufferAttribute = new InterleavedBufferAttribute( interleavedBuffer, attribute.itemSize, attribute.offset, attribute.normalized );
40685
40686                                         } else {
40687
40688                                                 const typedArray = getTypedArray( attribute.type, attribute.array );
40689                                                 bufferAttribute = new BufferAttribute( typedArray, attribute.itemSize, attribute.normalized );
40690
40691                                         }
40692
40693                                         if ( attribute.name !== undefined ) bufferAttribute.name = attribute.name;
40694                                         array.push( bufferAttribute );
40695
40696                                 }
40697
40698                                 geometry.morphAttributes[ key ] = array;
40699
40700                         }
40701
40702                 }
40703
40704                 const morphTargetsRelative = json.data.morphTargetsRelative;
40705
40706                 if ( morphTargetsRelative ) {
40707
40708                         geometry.morphTargetsRelative = true;
40709
40710                 }
40711
40712                 const groups = json.data.groups || json.data.drawcalls || json.data.offsets;
40713
40714                 if ( groups !== undefined ) {
40715
40716                         for ( let i = 0, n = groups.length; i !== n; ++ i ) {
40717
40718                                 const group = groups[ i ];
40719
40720                                 geometry.addGroup( group.start, group.count, group.materialIndex );
40721
40722                         }
40723
40724                 }
40725
40726                 const boundingSphere = json.data.boundingSphere;
40727
40728                 if ( boundingSphere !== undefined ) {
40729
40730                         const center = new Vector3();
40731
40732                         if ( boundingSphere.center !== undefined ) {
40733
40734                                 center.fromArray( boundingSphere.center );
40735
40736                         }
40737
40738                         geometry.boundingSphere = new Sphere( center, boundingSphere.radius );
40739
40740                 }
40741
40742                 if ( json.name ) geometry.name = json.name;
40743                 if ( json.userData ) geometry.userData = json.userData;
40744
40745                 return geometry;
40746
40747         }
40748
40749 } );
40750
40751 function ImageBitmapLoader( manager ) {
40752
40753         if ( typeof createImageBitmap === 'undefined' ) {
40754
40755                 console.warn( 'THREE.ImageBitmapLoader: createImageBitmap() not supported.' );
40756
40757         }
40758
40759         if ( typeof fetch === 'undefined' ) {
40760
40761                 console.warn( 'THREE.ImageBitmapLoader: fetch() not supported.' );
40762
40763         }
40764
40765         Loader.call( this, manager );
40766
40767         this.options = { premultiplyAlpha: 'none' };
40768
40769 }
40770
40771 ImageBitmapLoader.prototype = Object.assign( Object.create( Loader.prototype ), {
40772
40773         constructor: ImageBitmapLoader,
40774
40775         isImageBitmapLoader: true,
40776
40777         setOptions: function setOptions( options ) {
40778
40779                 this.options = options;
40780
40781                 return this;
40782
40783         },
40784
40785         load: function ( url, onLoad, onProgress, onError ) {
40786
40787                 if ( url === undefined ) url = '';
40788
40789                 if ( this.path !== undefined ) url = this.path + url;
40790
40791                 url = this.manager.resolveURL( url );
40792
40793                 const scope = this;
40794
40795                 const cached = Cache.get( url );
40796
40797                 if ( cached !== undefined ) {
40798
40799                         scope.manager.itemStart( url );
40800
40801                         setTimeout( function () {
40802
40803                                 if ( onLoad ) onLoad( cached );
40804
40805                                 scope.manager.itemEnd( url );
40806
40807                         }, 0 );
40808
40809                         return cached;
40810
40811                 }
40812
40813                 const fetchOptions = {};
40814                 fetchOptions.credentials = ( this.crossOrigin === 'anonymous' ) ? 'same-origin' : 'include';
40815
40816                 fetch( url, fetchOptions ).then( function ( res ) {
40817
40818                         return res.blob();
40819
40820                 } ).then( function ( blob ) {
40821
40822                         return createImageBitmap( blob, scope.options );
40823
40824                 } ).then( function ( imageBitmap ) {
40825
40826                         Cache.add( url, imageBitmap );
40827
40828                         if ( onLoad ) onLoad( imageBitmap );
40829
40830                         scope.manager.itemEnd( url );
40831
40832                 } ).catch( function ( e ) {
40833
40834                         if ( onError ) onError( e );
40835
40836                         scope.manager.itemError( url );
40837                         scope.manager.itemEnd( url );
40838
40839                 } );
40840
40841                 scope.manager.itemStart( url );
40842
40843         }
40844
40845 } );
40846
40847 function ShapePath() {
40848
40849         this.type = 'ShapePath';
40850
40851         this.color = new Color();
40852
40853         this.subPaths = [];
40854         this.currentPath = null;
40855
40856 }
40857
40858 Object.assign( ShapePath.prototype, {
40859
40860         moveTo: function ( x, y ) {
40861
40862                 this.currentPath = new Path();
40863                 this.subPaths.push( this.currentPath );
40864                 this.currentPath.moveTo( x, y );
40865
40866                 return this;
40867
40868         },
40869
40870         lineTo: function ( x, y ) {
40871
40872                 this.currentPath.lineTo( x, y );
40873
40874                 return this;
40875
40876         },
40877
40878         quadraticCurveTo: function ( aCPx, aCPy, aX, aY ) {
40879
40880                 this.currentPath.quadraticCurveTo( aCPx, aCPy, aX, aY );
40881
40882                 return this;
40883
40884         },
40885
40886         bezierCurveTo: function ( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY ) {
40887
40888                 this.currentPath.bezierCurveTo( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY );
40889
40890                 return this;
40891
40892         },
40893
40894         splineThru: function ( pts ) {
40895
40896                 this.currentPath.splineThru( pts );
40897
40898                 return this;
40899
40900         },
40901
40902         toShapes: function ( isCCW, noHoles ) {
40903
40904                 function toShapesNoHoles( inSubpaths ) {
40905
40906                         const shapes = [];
40907
40908                         for ( let i = 0, l = inSubpaths.length; i < l; i ++ ) {
40909
40910                                 const tmpPath = inSubpaths[ i ];
40911
40912                                 const tmpShape = new Shape();
40913                                 tmpShape.curves = tmpPath.curves;
40914
40915                                 shapes.push( tmpShape );
40916
40917                         }
40918
40919                         return shapes;
40920
40921                 }
40922
40923                 function isPointInsidePolygon( inPt, inPolygon ) {
40924
40925                         const polyLen = inPolygon.length;
40926
40927                         // inPt on polygon contour => immediate success    or
40928                         // toggling of inside/outside at every single! intersection point of an edge
40929                         //  with the horizontal line through inPt, left of inPt
40930                         //  not counting lowerY endpoints of edges and whole edges on that line
40931                         let inside = false;
40932                         for ( let p = polyLen - 1, q = 0; q < polyLen; p = q ++ ) {
40933
40934                                 let edgeLowPt = inPolygon[ p ];
40935                                 let edgeHighPt = inPolygon[ q ];
40936
40937                                 let edgeDx = edgeHighPt.x - edgeLowPt.x;
40938                                 let edgeDy = edgeHighPt.y - edgeLowPt.y;
40939
40940                                 if ( Math.abs( edgeDy ) > Number.EPSILON ) {
40941
40942                                         // not parallel
40943                                         if ( edgeDy < 0 ) {
40944
40945                                                 edgeLowPt = inPolygon[ q ]; edgeDx = - edgeDx;
40946                                                 edgeHighPt = inPolygon[ p ]; edgeDy = - edgeDy;
40947
40948                                         }
40949
40950                                         if ( ( inPt.y < edgeLowPt.y ) || ( inPt.y > edgeHighPt.y ) )            continue;
40951
40952                                         if ( inPt.y === edgeLowPt.y ) {
40953
40954                                                 if ( inPt.x === edgeLowPt.x )           return  true;           // inPt is on contour ?
40955                                                 // continue;                            // no intersection or edgeLowPt => doesn't count !!!
40956
40957                                         } else {
40958
40959                                                 const perpEdge = edgeDy * ( inPt.x - edgeLowPt.x ) - edgeDx * ( inPt.y - edgeLowPt.y );
40960                                                 if ( perpEdge === 0 )                           return  true;           // inPt is on contour ?
40961                                                 if ( perpEdge < 0 )                             continue;
40962                                                 inside = ! inside;              // true intersection left of inPt
40963
40964                                         }
40965
40966                                 } else {
40967
40968                                         // parallel or collinear
40969                                         if ( inPt.y !== edgeLowPt.y )           continue;                       // parallel
40970                                         // edge lies on the same horizontal line as inPt
40971                                         if ( ( ( edgeHighPt.x <= inPt.x ) && ( inPt.x <= edgeLowPt.x ) ) ||
40972                                                  ( ( edgeLowPt.x <= inPt.x ) && ( inPt.x <= edgeHighPt.x ) ) )          return  true;   // inPt: Point on contour !
40973                                         // continue;
40974
40975                                 }
40976
40977                         }
40978
40979                         return  inside;
40980
40981                 }
40982
40983                 const isClockWise = ShapeUtils.isClockWise;
40984
40985                 const subPaths = this.subPaths;
40986                 if ( subPaths.length === 0 ) return [];
40987
40988                 if ( noHoles === true ) return  toShapesNoHoles( subPaths );
40989
40990
40991                 let solid, tmpPath, tmpShape;
40992                 const shapes = [];
40993
40994                 if ( subPaths.length === 1 ) {
40995
40996                         tmpPath = subPaths[ 0 ];
40997                         tmpShape = new Shape();
40998                         tmpShape.curves = tmpPath.curves;
40999                         shapes.push( tmpShape );
41000                         return shapes;
41001
41002                 }
41003
41004                 let holesFirst = ! isClockWise( subPaths[ 0 ].getPoints() );
41005                 holesFirst = isCCW ? ! holesFirst : holesFirst;
41006
41007                 // console.log("Holes first", holesFirst);
41008
41009                 const betterShapeHoles = [];
41010                 const newShapes = [];
41011                 let newShapeHoles = [];
41012                 let mainIdx = 0;
41013                 let tmpPoints;
41014
41015                 newShapes[ mainIdx ] = undefined;
41016                 newShapeHoles[ mainIdx ] = [];
41017
41018                 for ( let i = 0, l = subPaths.length; i < l; i ++ ) {
41019
41020                         tmpPath = subPaths[ i ];
41021                         tmpPoints = tmpPath.getPoints();
41022                         solid = isClockWise( tmpPoints );
41023                         solid = isCCW ? ! solid : solid;
41024
41025                         if ( solid ) {
41026
41027                                 if ( ( ! holesFirst ) && ( newShapes[ mainIdx ] ) )     mainIdx ++;
41028
41029                                 newShapes[ mainIdx ] = { s: new Shape(), p: tmpPoints };
41030                                 newShapes[ mainIdx ].s.curves = tmpPath.curves;
41031
41032                                 if ( holesFirst )       mainIdx ++;
41033                                 newShapeHoles[ mainIdx ] = [];
41034
41035                                 //console.log('cw', i);
41036
41037                         } else {
41038
41039                                 newShapeHoles[ mainIdx ].push( { h: tmpPath, p: tmpPoints[ 0 ] } );
41040
41041                                 //console.log('ccw', i);
41042
41043                         }
41044
41045                 }
41046
41047                 // only Holes? -> probably all Shapes with wrong orientation
41048                 if ( ! newShapes[ 0 ] ) return  toShapesNoHoles( subPaths );
41049
41050
41051                 if ( newShapes.length > 1 ) {
41052
41053                         let ambiguous = false;
41054                         const toChange = [];
41055
41056                         for ( let sIdx = 0, sLen = newShapes.length; sIdx < sLen; sIdx ++ ) {
41057
41058                                 betterShapeHoles[ sIdx ] = [];
41059
41060                         }
41061
41062                         for ( let sIdx = 0, sLen = newShapes.length; sIdx < sLen; sIdx ++ ) {
41063
41064                                 const sho = newShapeHoles[ sIdx ];
41065
41066                                 for ( let hIdx = 0; hIdx < sho.length; hIdx ++ ) {
41067
41068                                         const ho = sho[ hIdx ];
41069                                         let hole_unassigned = true;
41070
41071                                         for ( let s2Idx = 0; s2Idx < newShapes.length; s2Idx ++ ) {
41072
41073                                                 if ( isPointInsidePolygon( ho.p, newShapes[ s2Idx ].p ) ) {
41074
41075                                                         if ( sIdx !== s2Idx )   toChange.push( { froms: sIdx, tos: s2Idx, hole: hIdx } );
41076                                                         if ( hole_unassigned ) {
41077
41078                                                                 hole_unassigned = false;
41079                                                                 betterShapeHoles[ s2Idx ].push( ho );
41080
41081                                                         } else {
41082
41083                                                                 ambiguous = true;
41084
41085                                                         }
41086
41087                                                 }
41088
41089                                         }
41090
41091                                         if ( hole_unassigned ) {
41092
41093                                                 betterShapeHoles[ sIdx ].push( ho );
41094
41095                                         }
41096
41097                                 }
41098
41099                         }
41100                         // console.log("ambiguous: ", ambiguous);
41101
41102                         if ( toChange.length > 0 ) {
41103
41104                                 // console.log("to change: ", toChange);
41105                                 if ( ! ambiguous )      newShapeHoles = betterShapeHoles;
41106
41107                         }
41108
41109                 }
41110
41111                 let tmpHoles;
41112
41113                 for ( let i = 0, il = newShapes.length; i < il; i ++ ) {
41114
41115                         tmpShape = newShapes[ i ].s;
41116                         shapes.push( tmpShape );
41117                         tmpHoles = newShapeHoles[ i ];
41118
41119                         for ( let j = 0, jl = tmpHoles.length; j < jl; j ++ ) {
41120
41121                                 tmpShape.holes.push( tmpHoles[ j ].h );
41122
41123                         }
41124
41125                 }
41126
41127                 //console.log("shape", shapes);
41128
41129                 return shapes;
41130
41131         }
41132
41133 } );
41134
41135 class Font {
41136
41137         constructor( data ) {
41138
41139                 Object.defineProperty( this, 'isFont', { value: true } );
41140
41141                 this.type = 'Font';
41142
41143                 this.data = data;
41144
41145         }
41146
41147         generateShapes( text, size = 100 ) {
41148
41149                 const shapes = [];
41150                 const paths = createPaths( text, size, this.data );
41151
41152                 for ( let p = 0, pl = paths.length; p < pl; p ++ ) {
41153
41154                         Array.prototype.push.apply( shapes, paths[ p ].toShapes() );
41155
41156                 }
41157
41158                 return shapes;
41159
41160         }
41161
41162 }
41163
41164 function createPaths( text, size, data ) {
41165
41166         const chars = Array.from ? Array.from( text ) : String( text ).split( '' ); // workaround for IE11, see #13988
41167         const scale = size / data.resolution;
41168         const line_height = ( data.boundingBox.yMax - data.boundingBox.yMin + data.underlineThickness ) * scale;
41169
41170         const paths = [];
41171
41172         let offsetX = 0, offsetY = 0;
41173
41174         for ( let i = 0; i < chars.length; i ++ ) {
41175
41176                 const char = chars[ i ];
41177
41178                 if ( char === '\n' ) {
41179
41180                         offsetX = 0;
41181                         offsetY -= line_height;
41182
41183                 } else {
41184
41185                         const ret = createPath( char, scale, offsetX, offsetY, data );
41186                         offsetX += ret.offsetX;
41187                         paths.push( ret.path );
41188
41189                 }
41190
41191         }
41192
41193         return paths;
41194
41195 }
41196
41197 function createPath( char, scale, offsetX, offsetY, data ) {
41198
41199         const glyph = data.glyphs[ char ] || data.glyphs[ '?' ];
41200
41201         if ( ! glyph ) {
41202
41203                 console.error( 'THREE.Font: character "' + char + '" does not exists in font family ' + data.familyName + '.' );
41204
41205                 return;
41206
41207         }
41208
41209         const path = new ShapePath();
41210
41211         let x, y, cpx, cpy, cpx1, cpy1, cpx2, cpy2;
41212
41213         if ( glyph.o ) {
41214
41215                 const outline = glyph._cachedOutline || ( glyph._cachedOutline = glyph.o.split( ' ' ) );
41216
41217                 for ( let i = 0, l = outline.length; i < l; ) {
41218
41219                         const action = outline[ i ++ ];
41220
41221                         switch ( action ) {
41222
41223                                 case 'm': // moveTo
41224
41225                                         x = outline[ i ++ ] * scale + offsetX;
41226                                         y = outline[ i ++ ] * scale + offsetY;
41227
41228                                         path.moveTo( x, y );
41229
41230                                         break;
41231
41232                                 case 'l': // lineTo
41233
41234                                         x = outline[ i ++ ] * scale + offsetX;
41235                                         y = outline[ i ++ ] * scale + offsetY;
41236
41237                                         path.lineTo( x, y );
41238
41239                                         break;
41240
41241                                 case 'q': // quadraticCurveTo
41242
41243                                         cpx = outline[ i ++ ] * scale + offsetX;
41244                                         cpy = outline[ i ++ ] * scale + offsetY;
41245                                         cpx1 = outline[ i ++ ] * scale + offsetX;
41246                                         cpy1 = outline[ i ++ ] * scale + offsetY;
41247
41248                                         path.quadraticCurveTo( cpx1, cpy1, cpx, cpy );
41249
41250                                         break;
41251
41252                                 case 'b': // bezierCurveTo
41253
41254                                         cpx = outline[ i ++ ] * scale + offsetX;
41255                                         cpy = outline[ i ++ ] * scale + offsetY;
41256                                         cpx1 = outline[ i ++ ] * scale + offsetX;
41257                                         cpy1 = outline[ i ++ ] * scale + offsetY;
41258                                         cpx2 = outline[ i ++ ] * scale + offsetX;
41259                                         cpy2 = outline[ i ++ ] * scale + offsetY;
41260
41261                                         path.bezierCurveTo( cpx1, cpy1, cpx2, cpy2, cpx, cpy );
41262
41263                                         break;
41264
41265                         }
41266
41267                 }
41268
41269         }
41270
41271         return { offsetX: glyph.ha * scale, path: path };
41272
41273 }
41274
41275 function FontLoader( manager ) {
41276
41277         Loader.call( this, manager );
41278
41279 }
41280
41281 FontLoader.prototype = Object.assign( Object.create( Loader.prototype ), {
41282
41283         constructor: FontLoader,
41284
41285         load: function ( url, onLoad, onProgress, onError ) {
41286
41287                 const scope = this;
41288
41289                 const loader = new FileLoader( this.manager );
41290                 loader.setPath( this.path );
41291                 loader.setRequestHeader( this.requestHeader );
41292                 loader.setWithCredentials( scope.withCredentials );
41293                 loader.load( url, function ( text ) {
41294
41295                         let json;
41296
41297                         try {
41298
41299                                 json = JSON.parse( text );
41300
41301                         } catch ( e ) {
41302
41303                                 console.warn( 'THREE.FontLoader: typeface.js support is being deprecated. Use typeface.json instead.' );
41304                                 json = JSON.parse( text.substring( 65, text.length - 2 ) );
41305
41306                         }
41307
41308                         const font = scope.parse( json );
41309
41310                         if ( onLoad ) onLoad( font );
41311
41312                 }, onProgress, onError );
41313
41314         },
41315
41316         parse: function ( json ) {
41317
41318                 return new Font( json );
41319
41320         }
41321
41322 } );
41323
41324 let _context;
41325
41326 const AudioContext = {
41327
41328         getContext: function () {
41329
41330                 if ( _context === undefined ) {
41331
41332                         _context = new ( window.AudioContext || window.webkitAudioContext )();
41333
41334                 }
41335
41336                 return _context;
41337
41338         },
41339
41340         setContext: function ( value ) {
41341
41342                 _context = value;
41343
41344         }
41345
41346 };
41347
41348 function AudioLoader( manager ) {
41349
41350         Loader.call( this, manager );
41351
41352 }
41353
41354 AudioLoader.prototype = Object.assign( Object.create( Loader.prototype ), {
41355
41356         constructor: AudioLoader,
41357
41358         load: function ( url, onLoad, onProgress, onError ) {
41359
41360                 const scope = this;
41361
41362                 const loader = new FileLoader( scope.manager );
41363                 loader.setResponseType( 'arraybuffer' );
41364                 loader.setPath( scope.path );
41365                 loader.setRequestHeader( scope.requestHeader );
41366                 loader.setWithCredentials( scope.withCredentials );
41367                 loader.load( url, function ( buffer ) {
41368
41369                         try {
41370
41371                                 // Create a copy of the buffer. The `decodeAudioData` method
41372                                 // detaches the buffer when complete, preventing reuse.
41373                                 const bufferCopy = buffer.slice( 0 );
41374
41375                                 const context = AudioContext.getContext();
41376                                 context.decodeAudioData( bufferCopy, function ( audioBuffer ) {
41377
41378                                         onLoad( audioBuffer );
41379
41380                                 } );
41381
41382                         } catch ( e ) {
41383
41384                                 if ( onError ) {
41385
41386                                         onError( e );
41387
41388                                 } else {
41389
41390                                         console.error( e );
41391
41392                                 }
41393
41394                                 scope.manager.itemError( url );
41395
41396                         }
41397
41398                 }, onProgress, onError );
41399
41400         }
41401
41402 } );
41403
41404 function HemisphereLightProbe( skyColor, groundColor, intensity ) {
41405
41406         LightProbe.call( this, undefined, intensity );
41407
41408         const color1 = new Color().set( skyColor );
41409         const color2 = new Color().set( groundColor );
41410
41411         const sky = new Vector3( color1.r, color1.g, color1.b );
41412         const ground = new Vector3( color2.r, color2.g, color2.b );
41413
41414         // without extra factor of PI in the shader, should = 1 / Math.sqrt( Math.PI );
41415         const c0 = Math.sqrt( Math.PI );
41416         const c1 = c0 * Math.sqrt( 0.75 );
41417
41418         this.sh.coefficients[ 0 ].copy( sky ).add( ground ).multiplyScalar( c0 );
41419         this.sh.coefficients[ 1 ].copy( sky ).sub( ground ).multiplyScalar( c1 );
41420
41421 }
41422
41423 HemisphereLightProbe.prototype = Object.assign( Object.create( LightProbe.prototype ), {
41424
41425         constructor: HemisphereLightProbe,
41426
41427         isHemisphereLightProbe: true,
41428
41429         copy: function ( source ) { // modifying colors not currently supported
41430
41431                 LightProbe.prototype.copy.call( this, source );
41432
41433                 return this;
41434
41435         },
41436
41437         toJSON: function ( meta ) {
41438
41439                 const data = LightProbe.prototype.toJSON.call( this, meta );
41440
41441                 // data.sh = this.sh.toArray(); // todo
41442
41443                 return data;
41444
41445         }
41446
41447 } );
41448
41449 function AmbientLightProbe( color, intensity ) {
41450
41451         LightProbe.call( this, undefined, intensity );
41452
41453         const color1 = new Color().set( color );
41454
41455         // without extra factor of PI in the shader, would be 2 / Math.sqrt( Math.PI );
41456         this.sh.coefficients[ 0 ].set( color1.r, color1.g, color1.b ).multiplyScalar( 2 * Math.sqrt( Math.PI ) );
41457
41458 }
41459
41460 AmbientLightProbe.prototype = Object.assign( Object.create( LightProbe.prototype ), {
41461
41462         constructor: AmbientLightProbe,
41463
41464         isAmbientLightProbe: true,
41465
41466         copy: function ( source ) { // modifying color not currently supported
41467
41468                 LightProbe.prototype.copy.call( this, source );
41469
41470                 return this;
41471
41472         },
41473
41474         toJSON: function ( meta ) {
41475
41476                 const data = LightProbe.prototype.toJSON.call( this, meta );
41477
41478                 // data.sh = this.sh.toArray(); // todo
41479
41480                 return data;
41481
41482         }
41483
41484 } );
41485
41486 const _eyeRight = new Matrix4();
41487 const _eyeLeft = new Matrix4();
41488
41489 function StereoCamera() {
41490
41491         this.type = 'StereoCamera';
41492
41493         this.aspect = 1;
41494
41495         this.eyeSep = 0.064;
41496
41497         this.cameraL = new PerspectiveCamera();
41498         this.cameraL.layers.enable( 1 );
41499         this.cameraL.matrixAutoUpdate = false;
41500
41501         this.cameraR = new PerspectiveCamera();
41502         this.cameraR.layers.enable( 2 );
41503         this.cameraR.matrixAutoUpdate = false;
41504
41505         this._cache = {
41506                 focus: null,
41507                 fov: null,
41508                 aspect: null,
41509                 near: null,
41510                 far: null,
41511                 zoom: null,
41512                 eyeSep: null
41513         };
41514
41515 }
41516
41517 Object.assign( StereoCamera.prototype, {
41518
41519         update: function ( camera ) {
41520
41521                 const cache = this._cache;
41522
41523                 const needsUpdate = cache.focus !== camera.focus || cache.fov !== camera.fov ||
41524                         cache.aspect !== camera.aspect * this.aspect || cache.near !== camera.near ||
41525                         cache.far !== camera.far || cache.zoom !== camera.zoom || cache.eyeSep !== this.eyeSep;
41526
41527                 if ( needsUpdate ) {
41528
41529                         cache.focus = camera.focus;
41530                         cache.fov = camera.fov;
41531                         cache.aspect = camera.aspect * this.aspect;
41532                         cache.near = camera.near;
41533                         cache.far = camera.far;
41534                         cache.zoom = camera.zoom;
41535                         cache.eyeSep = this.eyeSep;
41536
41537                         // Off-axis stereoscopic effect based on
41538                         // http://paulbourke.net/stereographics/stereorender/
41539
41540                         const projectionMatrix = camera.projectionMatrix.clone();
41541                         const eyeSepHalf = cache.eyeSep / 2;
41542                         const eyeSepOnProjection = eyeSepHalf * cache.near / cache.focus;
41543                         const ymax = ( cache.near * Math.tan( MathUtils.DEG2RAD * cache.fov * 0.5 ) ) / cache.zoom;
41544                         let xmin, xmax;
41545
41546                         // translate xOffset
41547
41548                         _eyeLeft.elements[ 12 ] = - eyeSepHalf;
41549                         _eyeRight.elements[ 12 ] = eyeSepHalf;
41550
41551                         // for left eye
41552
41553                         xmin = - ymax * cache.aspect + eyeSepOnProjection;
41554                         xmax = ymax * cache.aspect + eyeSepOnProjection;
41555
41556                         projectionMatrix.elements[ 0 ] = 2 * cache.near / ( xmax - xmin );
41557                         projectionMatrix.elements[ 8 ] = ( xmax + xmin ) / ( xmax - xmin );
41558
41559                         this.cameraL.projectionMatrix.copy( projectionMatrix );
41560
41561                         // for right eye
41562
41563                         xmin = - ymax * cache.aspect - eyeSepOnProjection;
41564                         xmax = ymax * cache.aspect - eyeSepOnProjection;
41565
41566                         projectionMatrix.elements[ 0 ] = 2 * cache.near / ( xmax - xmin );
41567                         projectionMatrix.elements[ 8 ] = ( xmax + xmin ) / ( xmax - xmin );
41568
41569                         this.cameraR.projectionMatrix.copy( projectionMatrix );
41570
41571                 }
41572
41573                 this.cameraL.matrixWorld.copy( camera.matrixWorld ).multiply( _eyeLeft );
41574                 this.cameraR.matrixWorld.copy( camera.matrixWorld ).multiply( _eyeRight );
41575
41576         }
41577
41578 } );
41579
41580 class Audio extends Object3D {
41581
41582         constructor( listener ) {
41583
41584                 super();
41585
41586                 this.type = 'Audio';
41587
41588                 this.listener = listener;
41589                 this.context = listener.context;
41590
41591                 this.gain = this.context.createGain();
41592                 this.gain.connect( listener.getInput() );
41593
41594                 this.autoplay = false;
41595
41596                 this.buffer = null;
41597                 this.detune = 0;
41598                 this.loop = false;
41599                 this.loopStart = 0;
41600                 this.loopEnd = 0;
41601                 this.offset = 0;
41602                 this.duration = undefined;
41603                 this.playbackRate = 1;
41604                 this.isPlaying = false;
41605                 this.hasPlaybackControl = true;
41606                 this.source = null;
41607                 this.sourceType = 'empty';
41608
41609                 this._startedAt = 0;
41610                 this._progress = 0;
41611                 this._connected = false;
41612
41613                 this.filters = [];
41614
41615         }
41616
41617         getOutput() {
41618
41619                 return this.gain;
41620
41621         }
41622
41623         setNodeSource( audioNode ) {
41624
41625                 this.hasPlaybackControl = false;
41626                 this.sourceType = 'audioNode';
41627                 this.source = audioNode;
41628                 this.connect();
41629
41630                 return this;
41631
41632         }
41633
41634         setMediaElementSource( mediaElement ) {
41635
41636                 this.hasPlaybackControl = false;
41637                 this.sourceType = 'mediaNode';
41638                 this.source = this.context.createMediaElementSource( mediaElement );
41639                 this.connect();
41640
41641                 return this;
41642
41643         }
41644
41645         setMediaStreamSource( mediaStream ) {
41646
41647                 this.hasPlaybackControl = false;
41648                 this.sourceType = 'mediaStreamNode';
41649                 this.source = this.context.createMediaStreamSource( mediaStream );
41650                 this.connect();
41651
41652                 return this;
41653
41654         }
41655
41656         setBuffer( audioBuffer ) {
41657
41658                 this.buffer = audioBuffer;
41659                 this.sourceType = 'buffer';
41660
41661                 if ( this.autoplay ) this.play();
41662
41663                 return this;
41664
41665         }
41666
41667         play( delay = 0 ) {
41668
41669                 if ( this.isPlaying === true ) {
41670
41671                         console.warn( 'THREE.Audio: Audio is already playing.' );
41672                         return;
41673
41674                 }
41675
41676                 if ( this.hasPlaybackControl === false ) {
41677
41678                         console.warn( 'THREE.Audio: this Audio has no playback control.' );
41679                         return;
41680
41681                 }
41682
41683                 this._startedAt = this.context.currentTime + delay;
41684
41685                 const source = this.context.createBufferSource();
41686                 source.buffer = this.buffer;
41687                 source.loop = this.loop;
41688                 source.loopStart = this.loopStart;
41689                 source.loopEnd = this.loopEnd;
41690                 source.onended = this.onEnded.bind( this );
41691                 source.start( this._startedAt, this._progress + this.offset, this.duration );
41692
41693                 this.isPlaying = true;
41694
41695                 this.source = source;
41696
41697                 this.setDetune( this.detune );
41698                 this.setPlaybackRate( this.playbackRate );
41699
41700                 return this.connect();
41701
41702         }
41703
41704         pause() {
41705
41706                 if ( this.hasPlaybackControl === false ) {
41707
41708                         console.warn( 'THREE.Audio: this Audio has no playback control.' );
41709                         return;
41710
41711                 }
41712
41713                 if ( this.isPlaying === true ) {
41714
41715                         // update current progress
41716
41717                         this._progress += Math.max( this.context.currentTime - this._startedAt, 0 ) * this.playbackRate;
41718
41719                         if ( this.loop === true ) {
41720
41721                                 // ensure _progress does not exceed duration with looped audios
41722
41723                                 this._progress = this._progress % ( this.duration || this.buffer.duration );
41724
41725                         }
41726
41727                         this.source.stop();
41728                         this.source.onended = null;
41729
41730                         this.isPlaying = false;
41731
41732                 }
41733
41734                 return this;
41735
41736         }
41737
41738         stop() {
41739
41740                 if ( this.hasPlaybackControl === false ) {
41741
41742                         console.warn( 'THREE.Audio: this Audio has no playback control.' );
41743                         return;
41744
41745                 }
41746
41747                 this._progress = 0;
41748
41749                 this.source.stop();
41750                 this.source.onended = null;
41751                 this.isPlaying = false;
41752
41753                 return this;
41754
41755         }
41756
41757         connect() {
41758
41759                 if ( this.filters.length > 0 ) {
41760
41761                         this.source.connect( this.filters[ 0 ] );
41762
41763                         for ( let i = 1, l = this.filters.length; i < l; i ++ ) {
41764
41765                                 this.filters[ i - 1 ].connect( this.filters[ i ] );
41766
41767                         }
41768
41769                         this.filters[ this.filters.length - 1 ].connect( this.getOutput() );
41770
41771                 } else {
41772
41773                         this.source.connect( this.getOutput() );
41774
41775                 }
41776
41777                 this._connected = true;
41778
41779                 return this;
41780
41781         }
41782
41783         disconnect() {
41784
41785                 if ( this.filters.length > 0 ) {
41786
41787                         this.source.disconnect( this.filters[ 0 ] );
41788
41789                         for ( let i = 1, l = this.filters.length; i < l; i ++ ) {
41790
41791                                 this.filters[ i - 1 ].disconnect( this.filters[ i ] );
41792
41793                         }
41794
41795                         this.filters[ this.filters.length - 1 ].disconnect( this.getOutput() );
41796
41797                 } else {
41798
41799                         this.source.disconnect( this.getOutput() );
41800
41801                 }
41802
41803                 this._connected = false;
41804
41805                 return this;
41806
41807         }
41808
41809         getFilters() {
41810
41811                 return this.filters;
41812
41813         }
41814
41815         setFilters( value ) {
41816
41817                 if ( ! value ) value = [];
41818
41819                 if ( this._connected === true ) {
41820
41821                         this.disconnect();
41822                         this.filters = value.slice();
41823                         this.connect();
41824
41825                 } else {
41826
41827                         this.filters = value.slice();
41828
41829                 }
41830
41831                 return this;
41832
41833         }
41834
41835         setDetune( value ) {
41836
41837                 this.detune = value;
41838
41839                 if ( this.source.detune === undefined ) return; // only set detune when available
41840
41841                 if ( this.isPlaying === true ) {
41842
41843                         this.source.detune.setTargetAtTime( this.detune, this.context.currentTime, 0.01 );
41844
41845                 }
41846
41847                 return this;
41848
41849         }
41850
41851         getDetune() {
41852
41853                 return this.detune;
41854
41855         }
41856
41857         getFilter() {
41858
41859                 return this.getFilters()[ 0 ];
41860
41861         }
41862
41863         setFilter( filter ) {
41864
41865                 return this.setFilters( filter ? [ filter ] : [] );
41866
41867         }
41868
41869         setPlaybackRate( value ) {
41870
41871                 if ( this.hasPlaybackControl === false ) {
41872
41873                         console.warn( 'THREE.Audio: this Audio has no playback control.' );
41874                         return;
41875
41876                 }
41877
41878                 this.playbackRate = value;
41879
41880                 if ( this.isPlaying === true ) {
41881
41882                         this.source.playbackRate.setTargetAtTime( this.playbackRate, this.context.currentTime, 0.01 );
41883
41884                 }
41885
41886                 return this;
41887
41888         }
41889
41890         getPlaybackRate() {
41891
41892                 return this.playbackRate;
41893
41894         }
41895
41896         onEnded() {
41897
41898                 this.isPlaying = false;
41899
41900         }
41901
41902         getLoop() {
41903
41904                 if ( this.hasPlaybackControl === false ) {
41905
41906                         console.warn( 'THREE.Audio: this Audio has no playback control.' );
41907                         return false;
41908
41909                 }
41910
41911                 return this.loop;
41912
41913         }
41914
41915         setLoop( value ) {
41916
41917                 if ( this.hasPlaybackControl === false ) {
41918
41919                         console.warn( 'THREE.Audio: this Audio has no playback control.' );
41920                         return;
41921
41922                 }
41923
41924                 this.loop = value;
41925
41926                 if ( this.isPlaying === true ) {
41927
41928                         this.source.loop = this.loop;
41929
41930                 }
41931
41932                 return this;
41933
41934         }
41935
41936         setLoopStart( value ) {
41937
41938                 this.loopStart = value;
41939
41940                 return this;
41941
41942         }
41943
41944         setLoopEnd( value ) {
41945
41946                 this.loopEnd = value;
41947
41948                 return this;
41949
41950         }
41951
41952         getVolume() {
41953
41954                 return this.gain.gain.value;
41955
41956         }
41957
41958         setVolume( value ) {
41959
41960                 this.gain.gain.setTargetAtTime( value, this.context.currentTime, 0.01 );
41961
41962                 return this;
41963
41964         }
41965
41966 }
41967
41968 function PropertyMixer( binding, typeName, valueSize ) {
41969
41970         this.binding = binding;
41971         this.valueSize = valueSize;
41972
41973         let mixFunction,
41974                 mixFunctionAdditive,
41975                 setIdentity;
41976
41977         // buffer layout: [ incoming | accu0 | accu1 | orig | addAccu | (optional work) ]
41978         //
41979         // interpolators can use .buffer as their .result
41980         // the data then goes to 'incoming'
41981         //
41982         // 'accu0' and 'accu1' are used frame-interleaved for
41983         // the cumulative result and are compared to detect
41984         // changes
41985         //
41986         // 'orig' stores the original state of the property
41987         //
41988         // 'add' is used for additive cumulative results
41989         //
41990         // 'work' is optional and is only present for quaternion types. It is used
41991         // to store intermediate quaternion multiplication results
41992
41993         switch ( typeName ) {
41994
41995                 case 'quaternion':
41996                         mixFunction = this._slerp;
41997                         mixFunctionAdditive = this._slerpAdditive;
41998                         setIdentity = this._setAdditiveIdentityQuaternion;
41999
42000                         this.buffer = new Float64Array( valueSize * 6 );
42001                         this._workIndex = 5;
42002                         break;
42003
42004                 case 'string':
42005                 case 'bool':
42006                         mixFunction = this._select;
42007
42008                         // Use the regular mix function and for additive on these types,
42009                         // additive is not relevant for non-numeric types
42010                         mixFunctionAdditive = this._select;
42011
42012                         setIdentity = this._setAdditiveIdentityOther;
42013
42014                         this.buffer = new Array( valueSize * 5 );
42015                         break;
42016
42017                 default:
42018                         mixFunction = this._lerp;
42019                         mixFunctionAdditive = this._lerpAdditive;
42020                         setIdentity = this._setAdditiveIdentityNumeric;
42021
42022                         this.buffer = new Float64Array( valueSize * 5 );
42023
42024         }
42025
42026         this._mixBufferRegion = mixFunction;
42027         this._mixBufferRegionAdditive = mixFunctionAdditive;
42028         this._setIdentity = setIdentity;
42029         this._origIndex = 3;
42030         this._addIndex = 4;
42031
42032         this.cumulativeWeight = 0;
42033         this.cumulativeWeightAdditive = 0;
42034
42035         this.useCount = 0;
42036         this.referenceCount = 0;
42037
42038 }
42039
42040 Object.assign( PropertyMixer.prototype, {
42041
42042         // accumulate data in the 'incoming' region into 'accu<i>'
42043         accumulate: function ( accuIndex, weight ) {
42044
42045                 // note: happily accumulating nothing when weight = 0, the caller knows
42046                 // the weight and shouldn't have made the call in the first place
42047
42048                 const buffer = this.buffer,
42049                         stride = this.valueSize,
42050                         offset = accuIndex * stride + stride;
42051
42052                 let currentWeight = this.cumulativeWeight;
42053
42054                 if ( currentWeight === 0 ) {
42055
42056                         // accuN := incoming * weight
42057
42058                         for ( let i = 0; i !== stride; ++ i ) {
42059
42060                                 buffer[ offset + i ] = buffer[ i ];
42061
42062                         }
42063
42064                         currentWeight = weight;
42065
42066                 } else {
42067
42068                         // accuN := accuN + incoming * weight
42069
42070                         currentWeight += weight;
42071                         const mix = weight / currentWeight;
42072                         this._mixBufferRegion( buffer, offset, 0, mix, stride );
42073
42074                 }
42075
42076                 this.cumulativeWeight = currentWeight;
42077
42078         },
42079
42080         // accumulate data in the 'incoming' region into 'add'
42081         accumulateAdditive: function ( weight ) {
42082
42083                 const buffer = this.buffer,
42084                         stride = this.valueSize,
42085                         offset = stride * this._addIndex;
42086
42087                 if ( this.cumulativeWeightAdditive === 0 ) {
42088
42089                         // add = identity
42090
42091                         this._setIdentity();
42092
42093                 }
42094
42095                 // add := add + incoming * weight
42096
42097                 this._mixBufferRegionAdditive( buffer, offset, 0, weight, stride );
42098                 this.cumulativeWeightAdditive += weight;
42099
42100         },
42101
42102         // apply the state of 'accu<i>' to the binding when accus differ
42103         apply: function ( accuIndex ) {
42104
42105                 const stride = this.valueSize,
42106                         buffer = this.buffer,
42107                         offset = accuIndex * stride + stride,
42108
42109                         weight = this.cumulativeWeight,
42110                         weightAdditive = this.cumulativeWeightAdditive,
42111
42112                         binding = this.binding;
42113
42114                 this.cumulativeWeight = 0;
42115                 this.cumulativeWeightAdditive = 0;
42116
42117                 if ( weight < 1 ) {
42118
42119                         // accuN := accuN + original * ( 1 - cumulativeWeight )
42120
42121                         const originalValueOffset = stride * this._origIndex;
42122
42123                         this._mixBufferRegion(
42124                                 buffer, offset, originalValueOffset, 1 - weight, stride );
42125
42126                 }
42127
42128                 if ( weightAdditive > 0 ) {
42129
42130                         // accuN := accuN + additive accuN
42131
42132                         this._mixBufferRegionAdditive( buffer, offset, this._addIndex * stride, 1, stride );
42133
42134                 }
42135
42136                 for ( let i = stride, e = stride + stride; i !== e; ++ i ) {
42137
42138                         if ( buffer[ i ] !== buffer[ i + stride ] ) {
42139
42140                                 // value has changed -> update scene graph
42141
42142                                 binding.setValue( buffer, offset );
42143                                 break;
42144
42145                         }
42146
42147                 }
42148
42149         },
42150
42151         // remember the state of the bound property and copy it to both accus
42152         saveOriginalState: function () {
42153
42154                 const binding = this.binding;
42155
42156                 const buffer = this.buffer,
42157                         stride = this.valueSize,
42158
42159                         originalValueOffset = stride * this._origIndex;
42160
42161                 binding.getValue( buffer, originalValueOffset );
42162
42163                 // accu[0..1] := orig -- initially detect changes against the original
42164                 for ( let i = stride, e = originalValueOffset; i !== e; ++ i ) {
42165
42166                         buffer[ i ] = buffer[ originalValueOffset + ( i % stride ) ];
42167
42168                 }
42169
42170                 // Add to identity for additive
42171                 this._setIdentity();
42172
42173                 this.cumulativeWeight = 0;
42174                 this.cumulativeWeightAdditive = 0;
42175
42176         },
42177
42178         // apply the state previously taken via 'saveOriginalState' to the binding
42179         restoreOriginalState: function () {
42180
42181                 const originalValueOffset = this.valueSize * 3;
42182                 this.binding.setValue( this.buffer, originalValueOffset );
42183
42184         },
42185
42186         _setAdditiveIdentityNumeric: function () {
42187
42188                 const startIndex = this._addIndex * this.valueSize;
42189                 const endIndex = startIndex + this.valueSize;
42190
42191                 for ( let i = startIndex; i < endIndex; i ++ ) {
42192
42193                         this.buffer[ i ] = 0;
42194
42195                 }
42196
42197         },
42198
42199         _setAdditiveIdentityQuaternion: function () {
42200
42201                 this._setAdditiveIdentityNumeric();
42202                 this.buffer[ this._addIndex * this.valueSize + 3 ] = 1;
42203
42204         },
42205
42206         _setAdditiveIdentityOther: function () {
42207
42208                 const startIndex = this._origIndex * this.valueSize;
42209                 const targetIndex = this._addIndex * this.valueSize;
42210
42211                 for ( let i = 0; i < this.valueSize; i ++ ) {
42212
42213                         this.buffer[ targetIndex + i ] = this.buffer[ startIndex + i ];
42214
42215                 }
42216
42217         },
42218
42219
42220         // mix functions
42221
42222         _select: function ( buffer, dstOffset, srcOffset, t, stride ) {
42223
42224                 if ( t >= 0.5 ) {
42225
42226                         for ( let i = 0; i !== stride; ++ i ) {
42227
42228                                 buffer[ dstOffset + i ] = buffer[ srcOffset + i ];
42229
42230                         }
42231
42232                 }
42233
42234         },
42235
42236         _slerp: function ( buffer, dstOffset, srcOffset, t ) {
42237
42238                 Quaternion.slerpFlat( buffer, dstOffset, buffer, dstOffset, buffer, srcOffset, t );
42239
42240         },
42241
42242         _slerpAdditive: function ( buffer, dstOffset, srcOffset, t, stride ) {
42243
42244                 const workOffset = this._workIndex * stride;
42245
42246                 // Store result in intermediate buffer offset
42247                 Quaternion.multiplyQuaternionsFlat( buffer, workOffset, buffer, dstOffset, buffer, srcOffset );
42248
42249                 // Slerp to the intermediate result
42250                 Quaternion.slerpFlat( buffer, dstOffset, buffer, dstOffset, buffer, workOffset, t );
42251
42252         },
42253
42254         _lerp: function ( buffer, dstOffset, srcOffset, t, stride ) {
42255
42256                 const s = 1 - t;
42257
42258                 for ( let i = 0; i !== stride; ++ i ) {
42259
42260                         const j = dstOffset + i;
42261
42262                         buffer[ j ] = buffer[ j ] * s + buffer[ srcOffset + i ] * t;
42263
42264                 }
42265
42266         },
42267
42268         _lerpAdditive: function ( buffer, dstOffset, srcOffset, t, stride ) {
42269
42270                 for ( let i = 0; i !== stride; ++ i ) {
42271
42272                         const j = dstOffset + i;
42273
42274                         buffer[ j ] = buffer[ j ] + buffer[ srcOffset + i ] * t;
42275
42276                 }
42277
42278         }
42279
42280 } );
42281
42282 // Characters [].:/ are reserved for track binding syntax.
42283 const _RESERVED_CHARS_RE = '\\[\\]\\.:\\/';
42284 const _reservedRe = new RegExp( '[' + _RESERVED_CHARS_RE + ']', 'g' );
42285
42286 // Attempts to allow node names from any language. ES5's `\w` regexp matches
42287 // only latin characters, and the unicode \p{L} is not yet supported. So
42288 // instead, we exclude reserved characters and match everything else.
42289 const _wordChar = '[^' + _RESERVED_CHARS_RE + ']';
42290 const _wordCharOrDot = '[^' + _RESERVED_CHARS_RE.replace( '\\.', '' ) + ']';
42291
42292 // Parent directories, delimited by '/' or ':'. Currently unused, but must
42293 // be matched to parse the rest of the track name.
42294 const _directoryRe = /((?:WC+[\/:])*)/.source.replace( 'WC', _wordChar );
42295
42296 // Target node. May contain word characters (a-zA-Z0-9_) and '.' or '-'.
42297 const _nodeRe = /(WCOD+)?/.source.replace( 'WCOD', _wordCharOrDot );
42298
42299 // Object on target node, and accessor. May not contain reserved
42300 // characters. Accessor may contain any character except closing bracket.
42301 const _objectRe = /(?:\.(WC+)(?:\[(.+)\])?)?/.source.replace( 'WC', _wordChar );
42302
42303 // Property and accessor. May not contain reserved characters. Accessor may
42304 // contain any non-bracket characters.
42305 const _propertyRe = /\.(WC+)(?:\[(.+)\])?/.source.replace( 'WC', _wordChar );
42306
42307 const _trackRe = new RegExp( ''
42308         + '^'
42309         + _directoryRe
42310         + _nodeRe
42311         + _objectRe
42312         + _propertyRe
42313         + '$'
42314 );
42315
42316 const _supportedObjectNames = [ 'material', 'materials', 'bones' ];
42317
42318 function Composite( targetGroup, path, optionalParsedPath ) {
42319
42320         const parsedPath = optionalParsedPath || PropertyBinding.parseTrackName( path );
42321
42322         this._targetGroup = targetGroup;
42323         this._bindings = targetGroup.subscribe_( path, parsedPath );
42324
42325 }
42326
42327 Object.assign( Composite.prototype, {
42328
42329         getValue: function ( array, offset ) {
42330
42331                 this.bind(); // bind all binding
42332
42333                 const firstValidIndex = this._targetGroup.nCachedObjects_,
42334                         binding = this._bindings[ firstValidIndex ];
42335
42336                 // and only call .getValue on the first
42337                 if ( binding !== undefined ) binding.getValue( array, offset );
42338
42339         },
42340
42341         setValue: function ( array, offset ) {
42342
42343                 const bindings = this._bindings;
42344
42345                 for ( let i = this._targetGroup.nCachedObjects_, n = bindings.length; i !== n; ++ i ) {
42346
42347                         bindings[ i ].setValue( array, offset );
42348
42349                 }
42350
42351         },
42352
42353         bind: function () {
42354
42355                 const bindings = this._bindings;
42356
42357                 for ( let i = this._targetGroup.nCachedObjects_, n = bindings.length; i !== n; ++ i ) {
42358
42359                         bindings[ i ].bind();
42360
42361                 }
42362
42363         },
42364
42365         unbind: function () {
42366
42367                 const bindings = this._bindings;
42368
42369                 for ( let i = this._targetGroup.nCachedObjects_, n = bindings.length; i !== n; ++ i ) {
42370
42371                         bindings[ i ].unbind();
42372
42373                 }
42374
42375         }
42376
42377 } );
42378
42379
42380 function PropertyBinding( rootNode, path, parsedPath ) {
42381
42382         this.path = path;
42383         this.parsedPath = parsedPath || PropertyBinding.parseTrackName( path );
42384
42385         this.node = PropertyBinding.findNode( rootNode, this.parsedPath.nodeName ) || rootNode;
42386
42387         this.rootNode = rootNode;
42388
42389 }
42390
42391 Object.assign( PropertyBinding, {
42392
42393         Composite: Composite,
42394
42395         create: function ( root, path, parsedPath ) {
42396
42397                 if ( ! ( root && root.isAnimationObjectGroup ) ) {
42398
42399                         return new PropertyBinding( root, path, parsedPath );
42400
42401                 } else {
42402
42403                         return new PropertyBinding.Composite( root, path, parsedPath );
42404
42405                 }
42406
42407         },
42408
42409         /**
42410          * Replaces spaces with underscores and removes unsupported characters from
42411          * node names, to ensure compatibility with parseTrackName().
42412          *
42413          * @param {string} name Node name to be sanitized.
42414          * @return {string}
42415          */
42416         sanitizeNodeName: function ( name ) {
42417
42418                 return name.replace( /\s/g, '_' ).replace( _reservedRe, '' );
42419
42420         },
42421
42422         parseTrackName: function ( trackName ) {
42423
42424                 const matches = _trackRe.exec( trackName );
42425
42426                 if ( ! matches ) {
42427
42428                         throw new Error( 'PropertyBinding: Cannot parse trackName: ' + trackName );
42429
42430                 }
42431
42432                 const results = {
42433                         // directoryName: matches[ 1 ], // (tschw) currently unused
42434                         nodeName: matches[ 2 ],
42435                         objectName: matches[ 3 ],
42436                         objectIndex: matches[ 4 ],
42437                         propertyName: matches[ 5 ], // required
42438                         propertyIndex: matches[ 6 ]
42439                 };
42440
42441                 const lastDot = results.nodeName && results.nodeName.lastIndexOf( '.' );
42442
42443                 if ( lastDot !== undefined && lastDot !== - 1 ) {
42444
42445                         const objectName = results.nodeName.substring( lastDot + 1 );
42446
42447                         // Object names must be checked against an allowlist. Otherwise, there
42448                         // is no way to parse 'foo.bar.baz': 'baz' must be a property, but
42449                         // 'bar' could be the objectName, or part of a nodeName (which can
42450                         // include '.' characters).
42451                         if ( _supportedObjectNames.indexOf( objectName ) !== - 1 ) {
42452
42453                                 results.nodeName = results.nodeName.substring( 0, lastDot );
42454                                 results.objectName = objectName;
42455
42456                         }
42457
42458                 }
42459
42460                 if ( results.propertyName === null || results.propertyName.length === 0 ) {
42461
42462                         throw new Error( 'PropertyBinding: can not parse propertyName from trackName: ' + trackName );
42463
42464                 }
42465
42466                 return results;
42467
42468         },
42469
42470         findNode: function ( root, nodeName ) {
42471
42472                 if ( ! nodeName || nodeName === '' || nodeName === '.' || nodeName === - 1 || nodeName === root.name || nodeName === root.uuid ) {
42473
42474                         return root;
42475
42476                 }
42477
42478                 // search into skeleton bones.
42479                 if ( root.skeleton ) {
42480
42481                         const bone = root.skeleton.getBoneByName( nodeName );
42482
42483                         if ( bone !== undefined ) {
42484
42485                                 return bone;
42486
42487                         }
42488
42489                 }
42490
42491                 // search into node subtree.
42492                 if ( root.children ) {
42493
42494                         const searchNodeSubtree = function ( children ) {
42495
42496                                 for ( let i = 0; i < children.length; i ++ ) {
42497
42498                                         const childNode = children[ i ];
42499
42500                                         if ( childNode.name === nodeName || childNode.uuid === nodeName ) {
42501
42502                                                 return childNode;
42503
42504                                         }
42505
42506                                         const result = searchNodeSubtree( childNode.children );
42507
42508                                         if ( result ) return result;
42509
42510                                 }
42511
42512                                 return null;
42513
42514                         };
42515
42516                         const subTreeNode = searchNodeSubtree( root.children );
42517
42518                         if ( subTreeNode ) {
42519
42520                                 return subTreeNode;
42521
42522                         }
42523
42524                 }
42525
42526                 return null;
42527
42528         }
42529
42530 } );
42531
42532 Object.assign( PropertyBinding.prototype, { // prototype, continued
42533
42534         // these are used to "bind" a nonexistent property
42535         _getValue_unavailable: function () {},
42536         _setValue_unavailable: function () {},
42537
42538         BindingType: {
42539                 Direct: 0,
42540                 EntireArray: 1,
42541                 ArrayElement: 2,
42542                 HasFromToArray: 3
42543         },
42544
42545         Versioning: {
42546                 None: 0,
42547                 NeedsUpdate: 1,
42548                 MatrixWorldNeedsUpdate: 2
42549         },
42550
42551         GetterByBindingType: [
42552
42553                 function getValue_direct( buffer, offset ) {
42554
42555                         buffer[ offset ] = this.node[ this.propertyName ];
42556
42557                 },
42558
42559                 function getValue_array( buffer, offset ) {
42560
42561                         const source = this.resolvedProperty;
42562
42563                         for ( let i = 0, n = source.length; i !== n; ++ i ) {
42564
42565                                 buffer[ offset ++ ] = source[ i ];
42566
42567                         }
42568
42569                 },
42570
42571                 function getValue_arrayElement( buffer, offset ) {
42572
42573                         buffer[ offset ] = this.resolvedProperty[ this.propertyIndex ];
42574
42575                 },
42576
42577                 function getValue_toArray( buffer, offset ) {
42578
42579                         this.resolvedProperty.toArray( buffer, offset );
42580
42581                 }
42582
42583         ],
42584
42585         SetterByBindingTypeAndVersioning: [
42586
42587                 [
42588                         // Direct
42589
42590                         function setValue_direct( buffer, offset ) {
42591
42592                                 this.targetObject[ this.propertyName ] = buffer[ offset ];
42593
42594                         },
42595
42596                         function setValue_direct_setNeedsUpdate( buffer, offset ) {
42597
42598                                 this.targetObject[ this.propertyName ] = buffer[ offset ];
42599                                 this.targetObject.needsUpdate = true;
42600
42601                         },
42602
42603                         function setValue_direct_setMatrixWorldNeedsUpdate( buffer, offset ) {
42604
42605                                 this.targetObject[ this.propertyName ] = buffer[ offset ];
42606                                 this.targetObject.matrixWorldNeedsUpdate = true;
42607
42608                         }
42609
42610                 ], [
42611
42612                         // EntireArray
42613
42614                         function setValue_array( buffer, offset ) {
42615
42616                                 const dest = this.resolvedProperty;
42617
42618                                 for ( let i = 0, n = dest.length; i !== n; ++ i ) {
42619
42620                                         dest[ i ] = buffer[ offset ++ ];
42621
42622                                 }
42623
42624                         },
42625
42626                         function setValue_array_setNeedsUpdate( buffer, offset ) {
42627
42628                                 const dest = this.resolvedProperty;
42629
42630                                 for ( let i = 0, n = dest.length; i !== n; ++ i ) {
42631
42632                                         dest[ i ] = buffer[ offset ++ ];
42633
42634                                 }
42635
42636                                 this.targetObject.needsUpdate = true;
42637
42638                         },
42639
42640                         function setValue_array_setMatrixWorldNeedsUpdate( buffer, offset ) {
42641
42642                                 const dest = this.resolvedProperty;
42643
42644                                 for ( let i = 0, n = dest.length; i !== n; ++ i ) {
42645
42646                                         dest[ i ] = buffer[ offset ++ ];
42647
42648                                 }
42649
42650                                 this.targetObject.matrixWorldNeedsUpdate = true;
42651
42652                         }
42653
42654                 ], [
42655
42656                         // ArrayElement
42657
42658                         function setValue_arrayElement( buffer, offset ) {
42659
42660                                 this.resolvedProperty[ this.propertyIndex ] = buffer[ offset ];
42661
42662                         },
42663
42664                         function setValue_arrayElement_setNeedsUpdate( buffer, offset ) {
42665
42666                                 this.resolvedProperty[ this.propertyIndex ] = buffer[ offset ];
42667                                 this.targetObject.needsUpdate = true;
42668
42669                         },
42670
42671                         function setValue_arrayElement_setMatrixWorldNeedsUpdate( buffer, offset ) {
42672
42673                                 this.resolvedProperty[ this.propertyIndex ] = buffer[ offset ];
42674                                 this.targetObject.matrixWorldNeedsUpdate = true;
42675
42676                         }
42677
42678                 ], [
42679
42680                         // HasToFromArray
42681
42682                         function setValue_fromArray( buffer, offset ) {
42683
42684                                 this.resolvedProperty.fromArray( buffer, offset );
42685
42686                         },
42687
42688                         function setValue_fromArray_setNeedsUpdate( buffer, offset ) {
42689
42690                                 this.resolvedProperty.fromArray( buffer, offset );
42691                                 this.targetObject.needsUpdate = true;
42692
42693                         },
42694
42695                         function setValue_fromArray_setMatrixWorldNeedsUpdate( buffer, offset ) {
42696
42697                                 this.resolvedProperty.fromArray( buffer, offset );
42698                                 this.targetObject.matrixWorldNeedsUpdate = true;
42699
42700                         }
42701
42702                 ]
42703
42704         ],
42705
42706         getValue: function getValue_unbound( targetArray, offset ) {
42707
42708                 this.bind();
42709                 this.getValue( targetArray, offset );
42710
42711                 // Note: This class uses a State pattern on a per-method basis:
42712                 // 'bind' sets 'this.getValue' / 'setValue' and shadows the
42713                 // prototype version of these methods with one that represents
42714                 // the bound state. When the property is not found, the methods
42715                 // become no-ops.
42716
42717         },
42718
42719         setValue: function getValue_unbound( sourceArray, offset ) {
42720
42721                 this.bind();
42722                 this.setValue( sourceArray, offset );
42723
42724         },
42725
42726         // create getter / setter pair for a property in the scene graph
42727         bind: function () {
42728
42729                 let targetObject = this.node;
42730                 const parsedPath = this.parsedPath;
42731
42732                 const objectName = parsedPath.objectName;
42733                 const propertyName = parsedPath.propertyName;
42734                 let propertyIndex = parsedPath.propertyIndex;
42735
42736                 if ( ! targetObject ) {
42737
42738                         targetObject = PropertyBinding.findNode( this.rootNode, parsedPath.nodeName ) || this.rootNode;
42739
42740                         this.node = targetObject;
42741
42742                 }
42743
42744                 // set fail state so we can just 'return' on error
42745                 this.getValue = this._getValue_unavailable;
42746                 this.setValue = this._setValue_unavailable;
42747
42748                 // ensure there is a value node
42749                 if ( ! targetObject ) {
42750
42751                         console.error( 'THREE.PropertyBinding: Trying to update node for track: ' + this.path + ' but it wasn\'t found.' );
42752                         return;
42753
42754                 }
42755
42756                 if ( objectName ) {
42757
42758                         let objectIndex = parsedPath.objectIndex;
42759
42760                         // special cases were we need to reach deeper into the hierarchy to get the face materials....
42761                         switch ( objectName ) {
42762
42763                                 case 'materials':
42764
42765                                         if ( ! targetObject.material ) {
42766
42767                                                 console.error( 'THREE.PropertyBinding: Can not bind to material as node does not have a material.', this );
42768                                                 return;
42769
42770                                         }
42771
42772                                         if ( ! targetObject.material.materials ) {
42773
42774                                                 console.error( 'THREE.PropertyBinding: Can not bind to material.materials as node.material does not have a materials array.', this );
42775                                                 return;
42776
42777                                         }
42778
42779                                         targetObject = targetObject.material.materials;
42780
42781                                         break;
42782
42783                                 case 'bones':
42784
42785                                         if ( ! targetObject.skeleton ) {
42786
42787                                                 console.error( 'THREE.PropertyBinding: Can not bind to bones as node does not have a skeleton.', this );
42788                                                 return;
42789
42790                                         }
42791
42792                                         // potential future optimization: skip this if propertyIndex is already an integer
42793                                         // and convert the integer string to a true integer.
42794
42795                                         targetObject = targetObject.skeleton.bones;
42796
42797                                         // support resolving morphTarget names into indices.
42798                                         for ( let i = 0; i < targetObject.length; i ++ ) {
42799
42800                                                 if ( targetObject[ i ].name === objectIndex ) {
42801
42802                                                         objectIndex = i;
42803                                                         break;
42804
42805                                                 }
42806
42807                                         }
42808
42809                                         break;
42810
42811                                 default:
42812
42813                                         if ( targetObject[ objectName ] === undefined ) {
42814
42815                                                 console.error( 'THREE.PropertyBinding: Can not bind to objectName of node undefined.', this );
42816                                                 return;
42817
42818                                         }
42819
42820                                         targetObject = targetObject[ objectName ];
42821
42822                         }
42823
42824
42825                         if ( objectIndex !== undefined ) {
42826
42827                                 if ( targetObject[ objectIndex ] === undefined ) {
42828
42829                                         console.error( 'THREE.PropertyBinding: Trying to bind to objectIndex of objectName, but is undefined.', this, targetObject );
42830                                         return;
42831
42832                                 }
42833
42834                                 targetObject = targetObject[ objectIndex ];
42835
42836                         }
42837
42838                 }
42839
42840                 // resolve property
42841                 const nodeProperty = targetObject[ propertyName ];
42842
42843                 if ( nodeProperty === undefined ) {
42844
42845                         const nodeName = parsedPath.nodeName;
42846
42847                         console.error( 'THREE.PropertyBinding: Trying to update property for track: ' + nodeName +
42848                                 '.' + propertyName + ' but it wasn\'t found.', targetObject );
42849                         return;
42850
42851                 }
42852
42853                 // determine versioning scheme
42854                 let versioning = this.Versioning.None;
42855
42856                 this.targetObject = targetObject;
42857
42858                 if ( targetObject.needsUpdate !== undefined ) { // material
42859
42860                         versioning = this.Versioning.NeedsUpdate;
42861
42862                 } else if ( targetObject.matrixWorldNeedsUpdate !== undefined ) { // node transform
42863
42864                         versioning = this.Versioning.MatrixWorldNeedsUpdate;
42865
42866                 }
42867
42868                 // determine how the property gets bound
42869                 let bindingType = this.BindingType.Direct;
42870
42871                 if ( propertyIndex !== undefined ) {
42872
42873                         // access a sub element of the property array (only primitives are supported right now)
42874
42875                         if ( propertyName === 'morphTargetInfluences' ) {
42876
42877                                 // potential optimization, skip this if propertyIndex is already an integer, and convert the integer string to a true integer.
42878
42879                                 // support resolving morphTarget names into indices.
42880                                 if ( ! targetObject.geometry ) {
42881
42882                                         console.error( 'THREE.PropertyBinding: Can not bind to morphTargetInfluences because node does not have a geometry.', this );
42883                                         return;
42884
42885                                 }
42886
42887                                 if ( targetObject.geometry.isBufferGeometry ) {
42888
42889                                         if ( ! targetObject.geometry.morphAttributes ) {
42890
42891                                                 console.error( 'THREE.PropertyBinding: Can not bind to morphTargetInfluences because node does not have a geometry.morphAttributes.', this );
42892                                                 return;
42893
42894                                         }
42895
42896                                         if ( targetObject.morphTargetDictionary[ propertyIndex ] !== undefined ) {
42897
42898                                                 propertyIndex = targetObject.morphTargetDictionary[ propertyIndex ];
42899
42900                                         }
42901
42902
42903                                 } else {
42904
42905                                         console.error( 'THREE.PropertyBinding: Can not bind to morphTargetInfluences on THREE.Geometry. Use THREE.BufferGeometry instead.', this );
42906                                         return;
42907
42908                                 }
42909
42910                         }
42911
42912                         bindingType = this.BindingType.ArrayElement;
42913
42914                         this.resolvedProperty = nodeProperty;
42915                         this.propertyIndex = propertyIndex;
42916
42917                 } else if ( nodeProperty.fromArray !== undefined && nodeProperty.toArray !== undefined ) {
42918
42919                         // must use copy for Object3D.Euler/Quaternion
42920
42921                         bindingType = this.BindingType.HasFromToArray;
42922
42923                         this.resolvedProperty = nodeProperty;
42924
42925                 } else if ( Array.isArray( nodeProperty ) ) {
42926
42927                         bindingType = this.BindingType.EntireArray;
42928
42929                         this.resolvedProperty = nodeProperty;
42930
42931                 } else {
42932
42933                         this.propertyName = propertyName;
42934
42935                 }
42936
42937                 // select getter / setter
42938                 this.getValue = this.GetterByBindingType[ bindingType ];
42939                 this.setValue = this.SetterByBindingTypeAndVersioning[ bindingType ][ versioning ];
42940
42941         },
42942
42943         unbind: function () {
42944
42945                 this.node = null;
42946
42947                 // back to the prototype version of getValue / setValue
42948                 // note: avoiding to mutate the shape of 'this' via 'delete'
42949                 this.getValue = this._getValue_unbound;
42950                 this.setValue = this._setValue_unbound;
42951
42952         }
42953
42954 } );
42955
42956 // DECLARE ALIAS AFTER assign prototype
42957 Object.assign( PropertyBinding.prototype, {
42958
42959         // initial state of these methods that calls 'bind'
42960         _getValue_unbound: PropertyBinding.prototype.getValue,
42961         _setValue_unbound: PropertyBinding.prototype.setValue,
42962
42963 } );
42964
42965 /**
42966  *
42967  * A group of objects that receives a shared animation state.
42968  *
42969  * Usage:
42970  *
42971  *  - Add objects you would otherwise pass as 'root' to the
42972  *    constructor or the .clipAction method of AnimationMixer.
42973  *
42974  *  - Instead pass this object as 'root'.
42975  *
42976  *  - You can also add and remove objects later when the mixer
42977  *    is running.
42978  *
42979  * Note:
42980  *
42981  *    Objects of this class appear as one object to the mixer,
42982  *    so cache control of the individual objects must be done
42983  *    on the group.
42984  *
42985  * Limitation:
42986  *
42987  *  - The animated properties must be compatible among the
42988  *    all objects in the group.
42989  *
42990  *  - A single property can either be controlled through a
42991  *    target group or directly, but not both.
42992  */
42993
42994 function AnimationObjectGroup() {
42995
42996         this.uuid = MathUtils.generateUUID();
42997
42998         // cached objects followed by the active ones
42999         this._objects = Array.prototype.slice.call( arguments );
43000
43001         this.nCachedObjects_ = 0; // threshold
43002         // note: read by PropertyBinding.Composite
43003
43004         const indices = {};
43005         this._indicesByUUID = indices; // for bookkeeping
43006
43007         for ( let i = 0, n = arguments.length; i !== n; ++ i ) {
43008
43009                 indices[ arguments[ i ].uuid ] = i;
43010
43011         }
43012
43013         this._paths = []; // inside: string
43014         this._parsedPaths = []; // inside: { we don't care, here }
43015         this._bindings = []; // inside: Array< PropertyBinding >
43016         this._bindingsIndicesByPath = {}; // inside: indices in these arrays
43017
43018         const scope = this;
43019
43020         this.stats = {
43021
43022                 objects: {
43023                         get total() {
43024
43025                                 return scope._objects.length;
43026
43027                         },
43028                         get inUse() {
43029
43030                                 return this.total - scope.nCachedObjects_;
43031
43032                         }
43033                 },
43034                 get bindingsPerObject() {
43035
43036                         return scope._bindings.length;
43037
43038                 }
43039
43040         };
43041
43042 }
43043
43044 Object.assign( AnimationObjectGroup.prototype, {
43045
43046         isAnimationObjectGroup: true,
43047
43048         add: function () {
43049
43050                 const objects = this._objects,
43051                         indicesByUUID = this._indicesByUUID,
43052                         paths = this._paths,
43053                         parsedPaths = this._parsedPaths,
43054                         bindings = this._bindings,
43055                         nBindings = bindings.length;
43056
43057                 let knownObject = undefined,
43058                         nObjects = objects.length,
43059                         nCachedObjects = this.nCachedObjects_;
43060
43061                 for ( let i = 0, n = arguments.length; i !== n; ++ i ) {
43062
43063                         const object = arguments[ i ],
43064                                 uuid = object.uuid;
43065                         let index = indicesByUUID[ uuid ];
43066
43067                         if ( index === undefined ) {
43068
43069                                 // unknown object -> add it to the ACTIVE region
43070
43071                                 index = nObjects ++;
43072                                 indicesByUUID[ uuid ] = index;
43073                                 objects.push( object );
43074
43075                                 // accounting is done, now do the same for all bindings
43076
43077                                 for ( let j = 0, m = nBindings; j !== m; ++ j ) {
43078
43079                                         bindings[ j ].push( new PropertyBinding( object, paths[ j ], parsedPaths[ j ] ) );
43080
43081                                 }
43082
43083                         } else if ( index < nCachedObjects ) {
43084
43085                                 knownObject = objects[ index ];
43086
43087                                 // move existing object to the ACTIVE region
43088
43089                                 const firstActiveIndex = -- nCachedObjects,
43090                                         lastCachedObject = objects[ firstActiveIndex ];
43091
43092                                 indicesByUUID[ lastCachedObject.uuid ] = index;
43093                                 objects[ index ] = lastCachedObject;
43094
43095                                 indicesByUUID[ uuid ] = firstActiveIndex;
43096                                 objects[ firstActiveIndex ] = object;
43097
43098                                 // accounting is done, now do the same for all bindings
43099
43100                                 for ( let j = 0, m = nBindings; j !== m; ++ j ) {
43101
43102                                         const bindingsForPath = bindings[ j ],
43103                                                 lastCached = bindingsForPath[ firstActiveIndex ];
43104
43105                                         let binding = bindingsForPath[ index ];
43106
43107                                         bindingsForPath[ index ] = lastCached;
43108
43109                                         if ( binding === undefined ) {
43110
43111                                                 // since we do not bother to create new bindings
43112                                                 // for objects that are cached, the binding may
43113                                                 // or may not exist
43114
43115                                                 binding = new PropertyBinding( object, paths[ j ], parsedPaths[ j ] );
43116
43117                                         }
43118
43119                                         bindingsForPath[ firstActiveIndex ] = binding;
43120
43121                                 }
43122
43123                         } else if ( objects[ index ] !== knownObject ) {
43124
43125                                 console.error( 'THREE.AnimationObjectGroup: Different objects with the same UUID ' +
43126                                         'detected. Clean the caches or recreate your infrastructure when reloading scenes.' );
43127
43128                         } // else the object is already where we want it to be
43129
43130                 } // for arguments
43131
43132                 this.nCachedObjects_ = nCachedObjects;
43133
43134         },
43135
43136         remove: function () {
43137
43138                 const objects = this._objects,
43139                         indicesByUUID = this._indicesByUUID,
43140                         bindings = this._bindings,
43141                         nBindings = bindings.length;
43142
43143                 let nCachedObjects = this.nCachedObjects_;
43144
43145                 for ( let i = 0, n = arguments.length; i !== n; ++ i ) {
43146
43147                         const object = arguments[ i ],
43148                                 uuid = object.uuid,
43149                                 index = indicesByUUID[ uuid ];
43150
43151                         if ( index !== undefined && index >= nCachedObjects ) {
43152
43153                                 // move existing object into the CACHED region
43154
43155                                 const lastCachedIndex = nCachedObjects ++,
43156                                         firstActiveObject = objects[ lastCachedIndex ];
43157
43158                                 indicesByUUID[ firstActiveObject.uuid ] = index;
43159                                 objects[ index ] = firstActiveObject;
43160
43161                                 indicesByUUID[ uuid ] = lastCachedIndex;
43162                                 objects[ lastCachedIndex ] = object;
43163
43164                                 // accounting is done, now do the same for all bindings
43165
43166                                 for ( let j = 0, m = nBindings; j !== m; ++ j ) {
43167
43168                                         const bindingsForPath = bindings[ j ],
43169                                                 firstActive = bindingsForPath[ lastCachedIndex ],
43170                                                 binding = bindingsForPath[ index ];
43171
43172                                         bindingsForPath[ index ] = firstActive;
43173                                         bindingsForPath[ lastCachedIndex ] = binding;
43174
43175                                 }
43176
43177                         }
43178
43179                 } // for arguments
43180
43181                 this.nCachedObjects_ = nCachedObjects;
43182
43183         },
43184
43185         // remove & forget
43186         uncache: function () {
43187
43188                 const objects = this._objects,
43189                         indicesByUUID = this._indicesByUUID,
43190                         bindings = this._bindings,
43191                         nBindings = bindings.length;
43192
43193                 let nCachedObjects = this.nCachedObjects_,
43194                         nObjects = objects.length;
43195
43196                 for ( let i = 0, n = arguments.length; i !== n; ++ i ) {
43197
43198                         const object = arguments[ i ],
43199                                 uuid = object.uuid,
43200                                 index = indicesByUUID[ uuid ];
43201
43202                         if ( index !== undefined ) {
43203
43204                                 delete indicesByUUID[ uuid ];
43205
43206                                 if ( index < nCachedObjects ) {
43207
43208                                         // object is cached, shrink the CACHED region
43209
43210                                         const firstActiveIndex = -- nCachedObjects,
43211                                                 lastCachedObject = objects[ firstActiveIndex ],
43212                                                 lastIndex = -- nObjects,
43213                                                 lastObject = objects[ lastIndex ];
43214
43215                                         // last cached object takes this object's place
43216                                         indicesByUUID[ lastCachedObject.uuid ] = index;
43217                                         objects[ index ] = lastCachedObject;
43218
43219                                         // last object goes to the activated slot and pop
43220                                         indicesByUUID[ lastObject.uuid ] = firstActiveIndex;
43221                                         objects[ firstActiveIndex ] = lastObject;
43222                                         objects.pop();
43223
43224                                         // accounting is done, now do the same for all bindings
43225
43226                                         for ( let j = 0, m = nBindings; j !== m; ++ j ) {
43227
43228                                                 const bindingsForPath = bindings[ j ],
43229                                                         lastCached = bindingsForPath[ firstActiveIndex ],
43230                                                         last = bindingsForPath[ lastIndex ];
43231
43232                                                 bindingsForPath[ index ] = lastCached;
43233                                                 bindingsForPath[ firstActiveIndex ] = last;
43234                                                 bindingsForPath.pop();
43235
43236                                         }
43237
43238                                 } else {
43239
43240                                         // object is active, just swap with the last and pop
43241
43242                                         const lastIndex = -- nObjects,
43243                                                 lastObject = objects[ lastIndex ];
43244
43245                                         if ( lastIndex > 0 ) {
43246
43247                                                 indicesByUUID[ lastObject.uuid ] = index;
43248
43249                                         }
43250
43251                                         objects[ index ] = lastObject;
43252                                         objects.pop();
43253
43254                                         // accounting is done, now do the same for all bindings
43255
43256                                         for ( let j = 0, m = nBindings; j !== m; ++ j ) {
43257
43258                                                 const bindingsForPath = bindings[ j ];
43259
43260                                                 bindingsForPath[ index ] = bindingsForPath[ lastIndex ];
43261                                                 bindingsForPath.pop();
43262
43263                                         }
43264
43265                                 } // cached or active
43266
43267                         } // if object is known
43268
43269                 } // for arguments
43270
43271                 this.nCachedObjects_ = nCachedObjects;
43272
43273         },
43274
43275         // Internal interface used by befriended PropertyBinding.Composite:
43276
43277         subscribe_: function ( path, parsedPath ) {
43278
43279                 // returns an array of bindings for the given path that is changed
43280                 // according to the contained objects in the group
43281
43282                 const indicesByPath = this._bindingsIndicesByPath;
43283                 let index = indicesByPath[ path ];
43284                 const bindings = this._bindings;
43285
43286                 if ( index !== undefined ) return bindings[ index ];
43287
43288                 const paths = this._paths,
43289                         parsedPaths = this._parsedPaths,
43290                         objects = this._objects,
43291                         nObjects = objects.length,
43292                         nCachedObjects = this.nCachedObjects_,
43293                         bindingsForPath = new Array( nObjects );
43294
43295                 index = bindings.length;
43296
43297                 indicesByPath[ path ] = index;
43298
43299                 paths.push( path );
43300                 parsedPaths.push( parsedPath );
43301                 bindings.push( bindingsForPath );
43302
43303                 for ( let i = nCachedObjects, n = objects.length; i !== n; ++ i ) {
43304
43305                         const object = objects[ i ];
43306                         bindingsForPath[ i ] = new PropertyBinding( object, path, parsedPath );
43307
43308                 }
43309
43310                 return bindingsForPath;
43311
43312         },
43313
43314         unsubscribe_: function ( path ) {
43315
43316                 // tells the group to forget about a property path and no longer
43317                 // update the array previously obtained with 'subscribe_'
43318
43319                 const indicesByPath = this._bindingsIndicesByPath,
43320                         index = indicesByPath[ path ];
43321
43322                 if ( index !== undefined ) {
43323
43324                         const paths = this._paths,
43325                                 parsedPaths = this._parsedPaths,
43326                                 bindings = this._bindings,
43327                                 lastBindingsIndex = bindings.length - 1,
43328                                 lastBindings = bindings[ lastBindingsIndex ],
43329                                 lastBindingsPath = path[ lastBindingsIndex ];
43330
43331                         indicesByPath[ lastBindingsPath ] = index;
43332
43333                         bindings[ index ] = lastBindings;
43334                         bindings.pop();
43335
43336                         parsedPaths[ index ] = parsedPaths[ lastBindingsIndex ];
43337                         parsedPaths.pop();
43338
43339                         paths[ index ] = paths[ lastBindingsIndex ];
43340                         paths.pop();
43341
43342                 }
43343
43344         }
43345
43346 } );
43347
43348 class AnimationAction {
43349
43350         constructor( mixer, clip, localRoot = null, blendMode = clip.blendMode ) {
43351
43352                 this._mixer = mixer;
43353                 this._clip = clip;
43354                 this._localRoot = localRoot;
43355                 this.blendMode = blendMode;
43356
43357                 const tracks = clip.tracks,
43358                         nTracks = tracks.length,
43359                         interpolants = new Array( nTracks );
43360
43361                 const interpolantSettings = {
43362                         endingStart: ZeroCurvatureEnding,
43363                         endingEnd: ZeroCurvatureEnding
43364                 };
43365
43366                 for ( let i = 0; i !== nTracks; ++ i ) {
43367
43368                         const interpolant = tracks[ i ].createInterpolant( null );
43369                         interpolants[ i ] = interpolant;
43370                         interpolant.settings = interpolantSettings;
43371
43372                 }
43373
43374                 this._interpolantSettings = interpolantSettings;
43375
43376                 this._interpolants = interpolants; // bound by the mixer
43377
43378                 // inside: PropertyMixer (managed by the mixer)
43379                 this._propertyBindings = new Array( nTracks );
43380
43381                 this._cacheIndex = null; // for the memory manager
43382                 this._byClipCacheIndex = null; // for the memory manager
43383
43384                 this._timeScaleInterpolant = null;
43385                 this._weightInterpolant = null;
43386
43387                 this.loop = LoopRepeat;
43388                 this._loopCount = - 1;
43389
43390                 // global mixer time when the action is to be started
43391                 // it's set back to 'null' upon start of the action
43392                 this._startTime = null;
43393
43394                 // scaled local time of the action
43395                 // gets clamped or wrapped to 0..clip.duration according to loop
43396                 this.time = 0;
43397
43398                 this.timeScale = 1;
43399                 this._effectiveTimeScale = 1;
43400
43401                 this.weight = 1;
43402                 this._effectiveWeight = 1;
43403
43404                 this.repetitions = Infinity; // no. of repetitions when looping
43405
43406                 this.paused = false; // true -> zero effective time scale
43407                 this.enabled = true; // false -> zero effective weight
43408
43409                 this.clampWhenFinished = false;// keep feeding the last frame?
43410
43411                 this.zeroSlopeAtStart = true;// for smooth interpolation w/o separate
43412                 this.zeroSlopeAtEnd = true;// clips for start, loop and end
43413
43414         }
43415
43416         // State & Scheduling
43417
43418         play() {
43419
43420                 this._mixer._activateAction( this );
43421
43422                 return this;
43423
43424         }
43425
43426         stop() {
43427
43428                 this._mixer._deactivateAction( this );
43429
43430                 return this.reset();
43431
43432         }
43433
43434         reset() {
43435
43436                 this.paused = false;
43437                 this.enabled = true;
43438
43439                 this.time = 0; // restart clip
43440                 this._loopCount = - 1;// forget previous loops
43441                 this._startTime = null;// forget scheduling
43442
43443                 return this.stopFading().stopWarping();
43444
43445         }
43446
43447         isRunning() {
43448
43449                 return this.enabled && ! this.paused && this.timeScale !== 0 &&
43450                         this._startTime === null && this._mixer._isActiveAction( this );
43451
43452         }
43453
43454         // return true when play has been called
43455         isScheduled() {
43456
43457                 return this._mixer._isActiveAction( this );
43458
43459         }
43460
43461         startAt( time ) {
43462
43463                 this._startTime = time;
43464
43465                 return this;
43466
43467         }
43468
43469         setLoop( mode, repetitions ) {
43470
43471                 this.loop = mode;
43472                 this.repetitions = repetitions;
43473
43474                 return this;
43475
43476         }
43477
43478         // Weight
43479
43480         // set the weight stopping any scheduled fading
43481         // although .enabled = false yields an effective weight of zero, this
43482         // method does *not* change .enabled, because it would be confusing
43483         setEffectiveWeight( weight ) {
43484
43485                 this.weight = weight;
43486
43487                 // note: same logic as when updated at runtime
43488                 this._effectiveWeight = this.enabled ? weight : 0;
43489
43490                 return this.stopFading();
43491
43492         }
43493
43494         // return the weight considering fading and .enabled
43495         getEffectiveWeight() {
43496
43497                 return this._effectiveWeight;
43498
43499         }
43500
43501         fadeIn( duration ) {
43502
43503                 return this._scheduleFading( duration, 0, 1 );
43504
43505         }
43506
43507         fadeOut( duration ) {
43508
43509                 return this._scheduleFading( duration, 1, 0 );
43510
43511         }
43512
43513         crossFadeFrom( fadeOutAction, duration, warp ) {
43514
43515                 fadeOutAction.fadeOut( duration );
43516                 this.fadeIn( duration );
43517
43518                 if ( warp ) {
43519
43520                         const fadeInDuration = this._clip.duration,
43521                                 fadeOutDuration = fadeOutAction._clip.duration,
43522
43523                                 startEndRatio = fadeOutDuration / fadeInDuration,
43524                                 endStartRatio = fadeInDuration / fadeOutDuration;
43525
43526                         fadeOutAction.warp( 1.0, startEndRatio, duration );
43527                         this.warp( endStartRatio, 1.0, duration );
43528
43529                 }
43530
43531                 return this;
43532
43533         }
43534
43535         crossFadeTo( fadeInAction, duration, warp ) {
43536
43537                 return fadeInAction.crossFadeFrom( this, duration, warp );
43538
43539         }
43540
43541         stopFading() {
43542
43543                 const weightInterpolant = this._weightInterpolant;
43544
43545                 if ( weightInterpolant !== null ) {
43546
43547                         this._weightInterpolant = null;
43548                         this._mixer._takeBackControlInterpolant( weightInterpolant );
43549
43550                 }
43551
43552                 return this;
43553
43554         }
43555
43556         // Time Scale Control
43557
43558         // set the time scale stopping any scheduled warping
43559         // although .paused = true yields an effective time scale of zero, this
43560         // method does *not* change .paused, because it would be confusing
43561         setEffectiveTimeScale( timeScale ) {
43562
43563                 this.timeScale = timeScale;
43564                 this._effectiveTimeScale = this.paused ? 0 : timeScale;
43565
43566                 return this.stopWarping();
43567
43568         }
43569
43570         // return the time scale considering warping and .paused
43571         getEffectiveTimeScale() {
43572
43573                 return this._effectiveTimeScale;
43574
43575         }
43576
43577         setDuration( duration ) {
43578
43579                 this.timeScale = this._clip.duration / duration;
43580
43581                 return this.stopWarping();
43582
43583         }
43584
43585         syncWith( action ) {
43586
43587                 this.time = action.time;
43588                 this.timeScale = action.timeScale;
43589
43590                 return this.stopWarping();
43591
43592         }
43593
43594         halt( duration ) {
43595
43596                 return this.warp( this._effectiveTimeScale, 0, duration );
43597
43598         }
43599
43600         warp( startTimeScale, endTimeScale, duration ) {
43601
43602                 const mixer = this._mixer,
43603                         now = mixer.time,
43604                         timeScale = this.timeScale;
43605
43606                 let interpolant = this._timeScaleInterpolant;
43607
43608                 if ( interpolant === null ) {
43609
43610                         interpolant = mixer._lendControlInterpolant();
43611                         this._timeScaleInterpolant = interpolant;
43612
43613                 }
43614
43615                 const times = interpolant.parameterPositions,
43616                         values = interpolant.sampleValues;
43617
43618                 times[ 0 ] = now;
43619                 times[ 1 ] = now + duration;
43620
43621                 values[ 0 ] = startTimeScale / timeScale;
43622                 values[ 1 ] = endTimeScale / timeScale;
43623
43624                 return this;
43625
43626         }
43627
43628         stopWarping() {
43629
43630                 const timeScaleInterpolant = this._timeScaleInterpolant;
43631
43632                 if ( timeScaleInterpolant !== null ) {
43633
43634                         this._timeScaleInterpolant = null;
43635                         this._mixer._takeBackControlInterpolant( timeScaleInterpolant );
43636
43637                 }
43638
43639                 return this;
43640
43641         }
43642
43643         // Object Accessors
43644
43645         getMixer() {
43646
43647                 return this._mixer;
43648
43649         }
43650
43651         getClip() {
43652
43653                 return this._clip;
43654
43655         }
43656
43657         getRoot() {
43658
43659                 return this._localRoot || this._mixer._root;
43660
43661         }
43662
43663         // Interna
43664
43665         _update( time, deltaTime, timeDirection, accuIndex ) {
43666
43667                 // called by the mixer
43668
43669                 if ( ! this.enabled ) {
43670
43671                         // call ._updateWeight() to update ._effectiveWeight
43672
43673                         this._updateWeight( time );
43674                         return;
43675
43676                 }
43677
43678                 const startTime = this._startTime;
43679
43680                 if ( startTime !== null ) {
43681
43682                         // check for scheduled start of action
43683
43684                         const timeRunning = ( time - startTime ) * timeDirection;
43685                         if ( timeRunning < 0 || timeDirection === 0 ) {
43686
43687                                 return; // yet to come / don't decide when delta = 0
43688
43689                         }
43690
43691                         // start
43692
43693                         this._startTime = null; // unschedule
43694                         deltaTime = timeDirection * timeRunning;
43695
43696                 }
43697
43698                 // apply time scale and advance time
43699
43700                 deltaTime *= this._updateTimeScale( time );
43701                 const clipTime = this._updateTime( deltaTime );
43702
43703                 // note: _updateTime may disable the action resulting in
43704                 // an effective weight of 0
43705
43706                 const weight = this._updateWeight( time );
43707
43708                 if ( weight > 0 ) {
43709
43710                         const interpolants = this._interpolants;
43711                         const propertyMixers = this._propertyBindings;
43712
43713                         switch ( this.blendMode ) {
43714
43715                                 case AdditiveAnimationBlendMode:
43716
43717                                         for ( let j = 0, m = interpolants.length; j !== m; ++ j ) {
43718
43719                                                 interpolants[ j ].evaluate( clipTime );
43720                                                 propertyMixers[ j ].accumulateAdditive( weight );
43721
43722                                         }
43723
43724                                         break;
43725
43726                                 case NormalAnimationBlendMode:
43727                                 default:
43728
43729                                         for ( let j = 0, m = interpolants.length; j !== m; ++ j ) {
43730
43731                                                 interpolants[ j ].evaluate( clipTime );
43732                                                 propertyMixers[ j ].accumulate( accuIndex, weight );
43733
43734                                         }
43735
43736                         }
43737
43738                 }
43739
43740         }
43741
43742         _updateWeight( time ) {
43743
43744                 let weight = 0;
43745
43746                 if ( this.enabled ) {
43747
43748                         weight = this.weight;
43749                         const interpolant = this._weightInterpolant;
43750
43751                         if ( interpolant !== null ) {
43752
43753                                 const interpolantValue = interpolant.evaluate( time )[ 0 ];
43754
43755                                 weight *= interpolantValue;
43756
43757                                 if ( time > interpolant.parameterPositions[ 1 ] ) {
43758
43759                                         this.stopFading();
43760
43761                                         if ( interpolantValue === 0 ) {
43762
43763                                                 // faded out, disable
43764                                                 this.enabled = false;
43765
43766                                         }
43767
43768                                 }
43769
43770                         }
43771
43772                 }
43773
43774                 this._effectiveWeight = weight;
43775                 return weight;
43776
43777         }
43778
43779         _updateTimeScale( time ) {
43780
43781                 let timeScale = 0;
43782
43783                 if ( ! this.paused ) {
43784
43785                         timeScale = this.timeScale;
43786
43787                         const interpolant = this._timeScaleInterpolant;
43788
43789                         if ( interpolant !== null ) {
43790
43791                                 const interpolantValue = interpolant.evaluate( time )[ 0 ];
43792
43793                                 timeScale *= interpolantValue;
43794
43795                                 if ( time > interpolant.parameterPositions[ 1 ] ) {
43796
43797                                         this.stopWarping();
43798
43799                                         if ( timeScale === 0 ) {
43800
43801                                                 // motion has halted, pause
43802                                                 this.paused = true;
43803
43804                                         } else {
43805
43806                                                 // warp done - apply final time scale
43807                                                 this.timeScale = timeScale;
43808
43809                                         }
43810
43811                                 }
43812
43813                         }
43814
43815                 }
43816
43817                 this._effectiveTimeScale = timeScale;
43818                 return timeScale;
43819
43820         }
43821
43822         _updateTime( deltaTime ) {
43823
43824                 const duration = this._clip.duration;
43825                 const loop = this.loop;
43826
43827                 let time = this.time + deltaTime;
43828                 let loopCount = this._loopCount;
43829
43830                 const pingPong = ( loop === LoopPingPong );
43831
43832                 if ( deltaTime === 0 ) {
43833
43834                         if ( loopCount === - 1 ) return time;
43835
43836                         return ( pingPong && ( loopCount & 1 ) === 1 ) ? duration - time : time;
43837
43838                 }
43839
43840                 if ( loop === LoopOnce ) {
43841
43842                         if ( loopCount === - 1 ) {
43843
43844                                 // just started
43845
43846                                 this._loopCount = 0;
43847                                 this._setEndings( true, true, false );
43848
43849                         }
43850
43851                         handle_stop: {
43852
43853                                 if ( time >= duration ) {
43854
43855                                         time = duration;
43856
43857                                 } else if ( time < 0 ) {
43858
43859                                         time = 0;
43860
43861                                 } else {
43862
43863                                         this.time = time;
43864
43865                                         break handle_stop;
43866
43867                                 }
43868
43869                                 if ( this.clampWhenFinished ) this.paused = true;
43870                                 else this.enabled = false;
43871
43872                                 this.time = time;
43873
43874                                 this._mixer.dispatchEvent( {
43875                                         type: 'finished', action: this,
43876                                         direction: deltaTime < 0 ? - 1 : 1
43877                                 } );
43878
43879                         }
43880
43881                 } else { // repetitive Repeat or PingPong
43882
43883                         if ( loopCount === - 1 ) {
43884
43885                                 // just started
43886
43887                                 if ( deltaTime >= 0 ) {
43888
43889                                         loopCount = 0;
43890
43891                                         this._setEndings( true, this.repetitions === 0, pingPong );
43892
43893                                 } else {
43894
43895                                         // when looping in reverse direction, the initial
43896                                         // transition through zero counts as a repetition,
43897                                         // so leave loopCount at -1
43898
43899                                         this._setEndings( this.repetitions === 0, true, pingPong );
43900
43901                                 }
43902
43903                         }
43904
43905                         if ( time >= duration || time < 0 ) {
43906
43907                                 // wrap around
43908
43909                                 const loopDelta = Math.floor( time / duration ); // signed
43910                                 time -= duration * loopDelta;
43911
43912                                 loopCount += Math.abs( loopDelta );
43913
43914                                 const pending = this.repetitions - loopCount;
43915
43916                                 if ( pending <= 0 ) {
43917
43918                                         // have to stop (switch state, clamp time, fire event)
43919
43920                                         if ( this.clampWhenFinished ) this.paused = true;
43921                                         else this.enabled = false;
43922
43923                                         time = deltaTime > 0 ? duration : 0;
43924
43925                                         this.time = time;
43926
43927                                         this._mixer.dispatchEvent( {
43928                                                 type: 'finished', action: this,
43929                                                 direction: deltaTime > 0 ? 1 : - 1
43930                                         } );
43931
43932                                 } else {
43933
43934                                         // keep running
43935
43936                                         if ( pending === 1 ) {
43937
43938                                                 // entering the last round
43939
43940                                                 const atStart = deltaTime < 0;
43941                                                 this._setEndings( atStart, ! atStart, pingPong );
43942
43943                                         } else {
43944
43945                                                 this._setEndings( false, false, pingPong );
43946
43947                                         }
43948
43949                                         this._loopCount = loopCount;
43950
43951                                         this.time = time;
43952
43953                                         this._mixer.dispatchEvent( {
43954                                                 type: 'loop', action: this, loopDelta: loopDelta
43955                                         } );
43956
43957                                 }
43958
43959                         } else {
43960
43961                                 this.time = time;
43962
43963                         }
43964
43965                         if ( pingPong && ( loopCount & 1 ) === 1 ) {
43966
43967                                 // invert time for the "pong round"
43968
43969                                 return duration - time;
43970
43971                         }
43972
43973                 }
43974
43975                 return time;
43976
43977         }
43978
43979         _setEndings( atStart, atEnd, pingPong ) {
43980
43981                 const settings = this._interpolantSettings;
43982
43983                 if ( pingPong ) {
43984
43985                         settings.endingStart = ZeroSlopeEnding;
43986                         settings.endingEnd = ZeroSlopeEnding;
43987
43988                 } else {
43989
43990                         // assuming for LoopOnce atStart == atEnd == true
43991
43992                         if ( atStart ) {
43993
43994                                 settings.endingStart = this.zeroSlopeAtStart ? ZeroSlopeEnding : ZeroCurvatureEnding;
43995
43996                         } else {
43997
43998                                 settings.endingStart = WrapAroundEnding;
43999
44000                         }
44001
44002                         if ( atEnd ) {
44003
44004                                 settings.endingEnd = this.zeroSlopeAtEnd ? ZeroSlopeEnding : ZeroCurvatureEnding;
44005
44006                         } else {
44007
44008                                 settings.endingEnd       = WrapAroundEnding;
44009
44010                         }
44011
44012                 }
44013
44014         }
44015
44016         _scheduleFading( duration, weightNow, weightThen ) {
44017
44018                 const mixer = this._mixer, now = mixer.time;
44019                 let interpolant = this._weightInterpolant;
44020
44021                 if ( interpolant === null ) {
44022
44023                         interpolant = mixer._lendControlInterpolant();
44024                         this._weightInterpolant = interpolant;
44025
44026                 }
44027
44028                 const times = interpolant.parameterPositions,
44029                         values = interpolant.sampleValues;
44030
44031                 times[ 0 ] = now;
44032                 values[ 0 ] = weightNow;
44033                 times[ 1 ] = now + duration;
44034                 values[ 1 ] = weightThen;
44035
44036                 return this;
44037
44038         }
44039
44040 }
44041
44042 function AnimationMixer( root ) {
44043
44044         this._root = root;
44045         this._initMemoryManager();
44046         this._accuIndex = 0;
44047
44048         this.time = 0;
44049
44050         this.timeScale = 1.0;
44051
44052 }
44053
44054 AnimationMixer.prototype = Object.assign( Object.create( EventDispatcher.prototype ), {
44055
44056         constructor: AnimationMixer,
44057
44058         _bindAction: function ( action, prototypeAction ) {
44059
44060                 const root = action._localRoot || this._root,
44061                         tracks = action._clip.tracks,
44062                         nTracks = tracks.length,
44063                         bindings = action._propertyBindings,
44064                         interpolants = action._interpolants,
44065                         rootUuid = root.uuid,
44066                         bindingsByRoot = this._bindingsByRootAndName;
44067
44068                 let bindingsByName = bindingsByRoot[ rootUuid ];
44069
44070                 if ( bindingsByName === undefined ) {
44071
44072                         bindingsByName = {};
44073                         bindingsByRoot[ rootUuid ] = bindingsByName;
44074
44075                 }
44076
44077                 for ( let i = 0; i !== nTracks; ++ i ) {
44078
44079                         const track = tracks[ i ],
44080                                 trackName = track.name;
44081
44082                         let binding = bindingsByName[ trackName ];
44083
44084                         if ( binding !== undefined ) {
44085
44086                                 bindings[ i ] = binding;
44087
44088                         } else {
44089
44090                                 binding = bindings[ i ];
44091
44092                                 if ( binding !== undefined ) {
44093
44094                                         // existing binding, make sure the cache knows
44095
44096                                         if ( binding._cacheIndex === null ) {
44097
44098                                                 ++ binding.referenceCount;
44099                                                 this._addInactiveBinding( binding, rootUuid, trackName );
44100
44101                                         }
44102
44103                                         continue;
44104
44105                                 }
44106
44107                                 const path = prototypeAction && prototypeAction.
44108                                         _propertyBindings[ i ].binding.parsedPath;
44109
44110                                 binding = new PropertyMixer(
44111                                         PropertyBinding.create( root, trackName, path ),
44112                                         track.ValueTypeName, track.getValueSize() );
44113
44114                                 ++ binding.referenceCount;
44115                                 this._addInactiveBinding( binding, rootUuid, trackName );
44116
44117                                 bindings[ i ] = binding;
44118
44119                         }
44120
44121                         interpolants[ i ].resultBuffer = binding.buffer;
44122
44123                 }
44124
44125         },
44126
44127         _activateAction: function ( action ) {
44128
44129                 if ( ! this._isActiveAction( action ) ) {
44130
44131                         if ( action._cacheIndex === null ) {
44132
44133                                 // this action has been forgotten by the cache, but the user
44134                                 // appears to be still using it -> rebind
44135
44136                                 const rootUuid = ( action._localRoot || this._root ).uuid,
44137                                         clipUuid = action._clip.uuid,
44138                                         actionsForClip = this._actionsByClip[ clipUuid ];
44139
44140                                 this._bindAction( action,
44141                                         actionsForClip && actionsForClip.knownActions[ 0 ] );
44142
44143                                 this._addInactiveAction( action, clipUuid, rootUuid );
44144
44145                         }
44146
44147                         const bindings = action._propertyBindings;
44148
44149                         // increment reference counts / sort out state
44150                         for ( let i = 0, n = bindings.length; i !== n; ++ i ) {
44151
44152                                 const binding = bindings[ i ];
44153
44154                                 if ( binding.useCount ++ === 0 ) {
44155
44156                                         this._lendBinding( binding );
44157                                         binding.saveOriginalState();
44158
44159                                 }
44160
44161                         }
44162
44163                         this._lendAction( action );
44164
44165                 }
44166
44167         },
44168
44169         _deactivateAction: function ( action ) {
44170
44171                 if ( this._isActiveAction( action ) ) {
44172
44173                         const bindings = action._propertyBindings;
44174
44175                         // decrement reference counts / sort out state
44176                         for ( let i = 0, n = bindings.length; i !== n; ++ i ) {
44177
44178                                 const binding = bindings[ i ];
44179
44180                                 if ( -- binding.useCount === 0 ) {
44181
44182                                         binding.restoreOriginalState();
44183                                         this._takeBackBinding( binding );
44184
44185                                 }
44186
44187                         }
44188
44189                         this._takeBackAction( action );
44190
44191                 }
44192
44193         },
44194
44195         // Memory manager
44196
44197         _initMemoryManager: function () {
44198
44199                 this._actions = []; // 'nActiveActions' followed by inactive ones
44200                 this._nActiveActions = 0;
44201
44202                 this._actionsByClip = {};
44203                 // inside:
44204                 // {
44205                 //      knownActions: Array< AnimationAction > - used as prototypes
44206                 //      actionByRoot: AnimationAction - lookup
44207                 // }
44208
44209
44210                 this._bindings = []; // 'nActiveBindings' followed by inactive ones
44211                 this._nActiveBindings = 0;
44212
44213                 this._bindingsByRootAndName = {}; // inside: Map< name, PropertyMixer >
44214
44215
44216                 this._controlInterpolants = []; // same game as above
44217                 this._nActiveControlInterpolants = 0;
44218
44219                 const scope = this;
44220
44221                 this.stats = {
44222
44223                         actions: {
44224                                 get total() {
44225
44226                                         return scope._actions.length;
44227
44228                                 },
44229                                 get inUse() {
44230
44231                                         return scope._nActiveActions;
44232
44233                                 }
44234                         },
44235                         bindings: {
44236                                 get total() {
44237
44238                                         return scope._bindings.length;
44239
44240                                 },
44241                                 get inUse() {
44242
44243                                         return scope._nActiveBindings;
44244
44245                                 }
44246                         },
44247                         controlInterpolants: {
44248                                 get total() {
44249
44250                                         return scope._controlInterpolants.length;
44251
44252                                 },
44253                                 get inUse() {
44254
44255                                         return scope._nActiveControlInterpolants;
44256
44257                                 }
44258                         }
44259
44260                 };
44261
44262         },
44263
44264         // Memory management for AnimationAction objects
44265
44266         _isActiveAction: function ( action ) {
44267
44268                 const index = action._cacheIndex;
44269                 return index !== null && index < this._nActiveActions;
44270
44271         },
44272
44273         _addInactiveAction: function ( action, clipUuid, rootUuid ) {
44274
44275                 const actions = this._actions,
44276                         actionsByClip = this._actionsByClip;
44277
44278                 let actionsForClip = actionsByClip[ clipUuid ];
44279
44280                 if ( actionsForClip === undefined ) {
44281
44282                         actionsForClip = {
44283
44284                                 knownActions: [ action ],
44285                                 actionByRoot: {}
44286
44287                         };
44288
44289                         action._byClipCacheIndex = 0;
44290
44291                         actionsByClip[ clipUuid ] = actionsForClip;
44292
44293                 } else {
44294
44295                         const knownActions = actionsForClip.knownActions;
44296
44297                         action._byClipCacheIndex = knownActions.length;
44298                         knownActions.push( action );
44299
44300                 }
44301
44302                 action._cacheIndex = actions.length;
44303                 actions.push( action );
44304
44305                 actionsForClip.actionByRoot[ rootUuid ] = action;
44306
44307         },
44308
44309         _removeInactiveAction: function ( action ) {
44310
44311                 const actions = this._actions,
44312                         lastInactiveAction = actions[ actions.length - 1 ],
44313                         cacheIndex = action._cacheIndex;
44314
44315                 lastInactiveAction._cacheIndex = cacheIndex;
44316                 actions[ cacheIndex ] = lastInactiveAction;
44317                 actions.pop();
44318
44319                 action._cacheIndex = null;
44320
44321
44322                 const clipUuid = action._clip.uuid,
44323                         actionsByClip = this._actionsByClip,
44324                         actionsForClip = actionsByClip[ clipUuid ],
44325                         knownActionsForClip = actionsForClip.knownActions,
44326
44327                         lastKnownAction =
44328                                 knownActionsForClip[ knownActionsForClip.length - 1 ],
44329
44330                         byClipCacheIndex = action._byClipCacheIndex;
44331
44332                 lastKnownAction._byClipCacheIndex = byClipCacheIndex;
44333                 knownActionsForClip[ byClipCacheIndex ] = lastKnownAction;
44334                 knownActionsForClip.pop();
44335
44336                 action._byClipCacheIndex = null;
44337
44338
44339                 const actionByRoot = actionsForClip.actionByRoot,
44340                         rootUuid = ( action._localRoot || this._root ).uuid;
44341
44342                 delete actionByRoot[ rootUuid ];
44343
44344                 if ( knownActionsForClip.length === 0 ) {
44345
44346                         delete actionsByClip[ clipUuid ];
44347
44348                 }
44349
44350                 this._removeInactiveBindingsForAction( action );
44351
44352         },
44353
44354         _removeInactiveBindingsForAction: function ( action ) {
44355
44356                 const bindings = action._propertyBindings;
44357
44358                 for ( let i = 0, n = bindings.length; i !== n; ++ i ) {
44359
44360                         const binding = bindings[ i ];
44361
44362                         if ( -- binding.referenceCount === 0 ) {
44363
44364                                 this._removeInactiveBinding( binding );
44365
44366                         }
44367
44368                 }
44369
44370         },
44371
44372         _lendAction: function ( action ) {
44373
44374                 // [ active actions |  inactive actions  ]
44375                 // [  active actions >| inactive actions ]
44376                 //                 s        a
44377                 //                  <-swap->
44378                 //                 a        s
44379
44380                 const actions = this._actions,
44381                         prevIndex = action._cacheIndex,
44382
44383                         lastActiveIndex = this._nActiveActions ++,
44384
44385                         firstInactiveAction = actions[ lastActiveIndex ];
44386
44387                 action._cacheIndex = lastActiveIndex;
44388                 actions[ lastActiveIndex ] = action;
44389
44390                 firstInactiveAction._cacheIndex = prevIndex;
44391                 actions[ prevIndex ] = firstInactiveAction;
44392
44393         },
44394
44395         _takeBackAction: function ( action ) {
44396
44397                 // [  active actions  | inactive actions ]
44398                 // [ active actions |< inactive actions  ]
44399                 //        a        s
44400                 //         <-swap->
44401                 //        s        a
44402
44403                 const actions = this._actions,
44404                         prevIndex = action._cacheIndex,
44405
44406                         firstInactiveIndex = -- this._nActiveActions,
44407
44408                         lastActiveAction = actions[ firstInactiveIndex ];
44409
44410                 action._cacheIndex = firstInactiveIndex;
44411                 actions[ firstInactiveIndex ] = action;
44412
44413                 lastActiveAction._cacheIndex = prevIndex;
44414                 actions[ prevIndex ] = lastActiveAction;
44415
44416         },
44417
44418         // Memory management for PropertyMixer objects
44419
44420         _addInactiveBinding: function ( binding, rootUuid, trackName ) {
44421
44422                 const bindingsByRoot = this._bindingsByRootAndName,
44423                         bindings = this._bindings;
44424
44425                 let bindingByName = bindingsByRoot[ rootUuid ];
44426
44427                 if ( bindingByName === undefined ) {
44428
44429                         bindingByName = {};
44430                         bindingsByRoot[ rootUuid ] = bindingByName;
44431
44432                 }
44433
44434                 bindingByName[ trackName ] = binding;
44435
44436                 binding._cacheIndex = bindings.length;
44437                 bindings.push( binding );
44438
44439         },
44440
44441         _removeInactiveBinding: function ( binding ) {
44442
44443                 const bindings = this._bindings,
44444                         propBinding = binding.binding,
44445                         rootUuid = propBinding.rootNode.uuid,
44446                         trackName = propBinding.path,
44447                         bindingsByRoot = this._bindingsByRootAndName,
44448                         bindingByName = bindingsByRoot[ rootUuid ],
44449
44450                         lastInactiveBinding = bindings[ bindings.length - 1 ],
44451                         cacheIndex = binding._cacheIndex;
44452
44453                 lastInactiveBinding._cacheIndex = cacheIndex;
44454                 bindings[ cacheIndex ] = lastInactiveBinding;
44455                 bindings.pop();
44456
44457                 delete bindingByName[ trackName ];
44458
44459                 if ( Object.keys( bindingByName ).length === 0 ) {
44460
44461                         delete bindingsByRoot[ rootUuid ];
44462
44463                 }
44464
44465         },
44466
44467         _lendBinding: function ( binding ) {
44468
44469                 const bindings = this._bindings,
44470                         prevIndex = binding._cacheIndex,
44471
44472                         lastActiveIndex = this._nActiveBindings ++,
44473
44474                         firstInactiveBinding = bindings[ lastActiveIndex ];
44475
44476                 binding._cacheIndex = lastActiveIndex;
44477                 bindings[ lastActiveIndex ] = binding;
44478
44479                 firstInactiveBinding._cacheIndex = prevIndex;
44480                 bindings[ prevIndex ] = firstInactiveBinding;
44481
44482         },
44483
44484         _takeBackBinding: function ( binding ) {
44485
44486                 const bindings = this._bindings,
44487                         prevIndex = binding._cacheIndex,
44488
44489                         firstInactiveIndex = -- this._nActiveBindings,
44490
44491                         lastActiveBinding = bindings[ firstInactiveIndex ];
44492
44493                 binding._cacheIndex = firstInactiveIndex;
44494                 bindings[ firstInactiveIndex ] = binding;
44495
44496                 lastActiveBinding._cacheIndex = prevIndex;
44497                 bindings[ prevIndex ] = lastActiveBinding;
44498
44499         },
44500
44501
44502         // Memory management of Interpolants for weight and time scale
44503
44504         _lendControlInterpolant: function () {
44505
44506                 const interpolants = this._controlInterpolants,
44507                         lastActiveIndex = this._nActiveControlInterpolants ++;
44508
44509                 let interpolant = interpolants[ lastActiveIndex ];
44510
44511                 if ( interpolant === undefined ) {
44512
44513                         interpolant = new LinearInterpolant(
44514                                 new Float32Array( 2 ), new Float32Array( 2 ),
44515                                 1, this._controlInterpolantsResultBuffer );
44516
44517                         interpolant.__cacheIndex = lastActiveIndex;
44518                         interpolants[ lastActiveIndex ] = interpolant;
44519
44520                 }
44521
44522                 return interpolant;
44523
44524         },
44525
44526         _takeBackControlInterpolant: function ( interpolant ) {
44527
44528                 const interpolants = this._controlInterpolants,
44529                         prevIndex = interpolant.__cacheIndex,
44530
44531                         firstInactiveIndex = -- this._nActiveControlInterpolants,
44532
44533                         lastActiveInterpolant = interpolants[ firstInactiveIndex ];
44534
44535                 interpolant.__cacheIndex = firstInactiveIndex;
44536                 interpolants[ firstInactiveIndex ] = interpolant;
44537
44538                 lastActiveInterpolant.__cacheIndex = prevIndex;
44539                 interpolants[ prevIndex ] = lastActiveInterpolant;
44540
44541         },
44542
44543         _controlInterpolantsResultBuffer: new Float32Array( 1 ),
44544
44545         // return an action for a clip optionally using a custom root target
44546         // object (this method allocates a lot of dynamic memory in case a
44547         // previously unknown clip/root combination is specified)
44548         clipAction: function ( clip, optionalRoot, blendMode ) {
44549
44550                 const root = optionalRoot || this._root,
44551                         rootUuid = root.uuid;
44552
44553                 let clipObject = typeof clip === 'string' ? AnimationClip.findByName( root, clip ) : clip;
44554
44555                 const clipUuid = clipObject !== null ? clipObject.uuid : clip;
44556
44557                 const actionsForClip = this._actionsByClip[ clipUuid ];
44558                 let prototypeAction = null;
44559
44560                 if ( blendMode === undefined ) {
44561
44562                         if ( clipObject !== null ) {
44563
44564                                 blendMode = clipObject.blendMode;
44565
44566                         } else {
44567
44568                                 blendMode = NormalAnimationBlendMode;
44569
44570                         }
44571
44572                 }
44573
44574                 if ( actionsForClip !== undefined ) {
44575
44576                         const existingAction = actionsForClip.actionByRoot[ rootUuid ];
44577
44578                         if ( existingAction !== undefined && existingAction.blendMode === blendMode ) {
44579
44580                                 return existingAction;
44581
44582                         }
44583
44584                         // we know the clip, so we don't have to parse all
44585                         // the bindings again but can just copy
44586                         prototypeAction = actionsForClip.knownActions[ 0 ];
44587
44588                         // also, take the clip from the prototype action
44589                         if ( clipObject === null )
44590                                 clipObject = prototypeAction._clip;
44591
44592                 }
44593
44594                 // clip must be known when specified via string
44595                 if ( clipObject === null ) return null;
44596
44597                 // allocate all resources required to run it
44598                 const newAction = new AnimationAction( this, clipObject, optionalRoot, blendMode );
44599
44600                 this._bindAction( newAction, prototypeAction );
44601
44602                 // and make the action known to the memory manager
44603                 this._addInactiveAction( newAction, clipUuid, rootUuid );
44604
44605                 return newAction;
44606
44607         },
44608
44609         // get an existing action
44610         existingAction: function ( clip, optionalRoot ) {
44611
44612                 const root = optionalRoot || this._root,
44613                         rootUuid = root.uuid,
44614
44615                         clipObject = typeof clip === 'string' ?
44616                                 AnimationClip.findByName( root, clip ) : clip,
44617
44618                         clipUuid = clipObject ? clipObject.uuid : clip,
44619
44620                         actionsForClip = this._actionsByClip[ clipUuid ];
44621
44622                 if ( actionsForClip !== undefined ) {
44623
44624                         return actionsForClip.actionByRoot[ rootUuid ] || null;
44625
44626                 }
44627
44628                 return null;
44629
44630         },
44631
44632         // deactivates all previously scheduled actions
44633         stopAllAction: function () {
44634
44635                 const actions = this._actions,
44636                         nActions = this._nActiveActions;
44637
44638                 for ( let i = nActions - 1; i >= 0; -- i ) {
44639
44640                         actions[ i ].stop();
44641
44642                 }
44643
44644                 return this;
44645
44646         },
44647
44648         // advance the time and update apply the animation
44649         update: function ( deltaTime ) {
44650
44651                 deltaTime *= this.timeScale;
44652
44653                 const actions = this._actions,
44654                         nActions = this._nActiveActions,
44655
44656                         time = this.time += deltaTime,
44657                         timeDirection = Math.sign( deltaTime ),
44658
44659                         accuIndex = this._accuIndex ^= 1;
44660
44661                 // run active actions
44662
44663                 for ( let i = 0; i !== nActions; ++ i ) {
44664
44665                         const action = actions[ i ];
44666
44667                         action._update( time, deltaTime, timeDirection, accuIndex );
44668
44669                 }
44670
44671                 // update scene graph
44672
44673                 const bindings = this._bindings,
44674                         nBindings = this._nActiveBindings;
44675
44676                 for ( let i = 0; i !== nBindings; ++ i ) {
44677
44678                         bindings[ i ].apply( accuIndex );
44679
44680                 }
44681
44682                 return this;
44683
44684         },
44685
44686         // Allows you to seek to a specific time in an animation.
44687         setTime: function ( timeInSeconds ) {
44688
44689                 this.time = 0; // Zero out time attribute for AnimationMixer object;
44690                 for ( let i = 0; i < this._actions.length; i ++ ) {
44691
44692                         this._actions[ i ].time = 0; // Zero out time attribute for all associated AnimationAction objects.
44693
44694                 }
44695
44696                 return this.update( timeInSeconds ); // Update used to set exact time. Returns "this" AnimationMixer object.
44697
44698         },
44699
44700         // return this mixer's root target object
44701         getRoot: function () {
44702
44703                 return this._root;
44704
44705         },
44706
44707         // free all resources specific to a particular clip
44708         uncacheClip: function ( clip ) {
44709
44710                 const actions = this._actions,
44711                         clipUuid = clip.uuid,
44712                         actionsByClip = this._actionsByClip,
44713                         actionsForClip = actionsByClip[ clipUuid ];
44714
44715                 if ( actionsForClip !== undefined ) {
44716
44717                         // note: just calling _removeInactiveAction would mess up the
44718                         // iteration state and also require updating the state we can
44719                         // just throw away
44720
44721                         const actionsToRemove = actionsForClip.knownActions;
44722
44723                         for ( let i = 0, n = actionsToRemove.length; i !== n; ++ i ) {
44724
44725                                 const action = actionsToRemove[ i ];
44726
44727                                 this._deactivateAction( action );
44728
44729                                 const cacheIndex = action._cacheIndex,
44730                                         lastInactiveAction = actions[ actions.length - 1 ];
44731
44732                                 action._cacheIndex = null;
44733                                 action._byClipCacheIndex = null;
44734
44735                                 lastInactiveAction._cacheIndex = cacheIndex;
44736                                 actions[ cacheIndex ] = lastInactiveAction;
44737                                 actions.pop();
44738
44739                                 this._removeInactiveBindingsForAction( action );
44740
44741                         }
44742
44743                         delete actionsByClip[ clipUuid ];
44744
44745                 }
44746
44747         },
44748
44749         // free all resources specific to a particular root target object
44750         uncacheRoot: function ( root ) {
44751
44752                 const rootUuid = root.uuid,
44753                         actionsByClip = this._actionsByClip;
44754
44755                 for ( const clipUuid in actionsByClip ) {
44756
44757                         const actionByRoot = actionsByClip[ clipUuid ].actionByRoot,
44758                                 action = actionByRoot[ rootUuid ];
44759
44760                         if ( action !== undefined ) {
44761
44762                                 this._deactivateAction( action );
44763                                 this._removeInactiveAction( action );
44764
44765                         }
44766
44767                 }
44768
44769                 const bindingsByRoot = this._bindingsByRootAndName,
44770                         bindingByName = bindingsByRoot[ rootUuid ];
44771
44772                 if ( bindingByName !== undefined ) {
44773
44774                         for ( const trackName in bindingByName ) {
44775
44776                                 const binding = bindingByName[ trackName ];
44777                                 binding.restoreOriginalState();
44778                                 this._removeInactiveBinding( binding );
44779
44780                         }
44781
44782                 }
44783
44784         },
44785
44786         // remove a targeted clip from the cache
44787         uncacheAction: function ( clip, optionalRoot ) {
44788
44789                 const action = this.existingAction( clip, optionalRoot );
44790
44791                 if ( action !== null ) {
44792
44793                         this._deactivateAction( action );
44794                         this._removeInactiveAction( action );
44795
44796                 }
44797
44798         }
44799
44800 } );
44801
44802 class Uniform {
44803
44804         constructor( value ) {
44805
44806                 if ( typeof value === 'string' ) {
44807
44808                         console.warn( 'THREE.Uniform: Type parameter is no longer needed.' );
44809                         value = arguments[ 1 ];
44810
44811                 }
44812
44813                 this.value = value;
44814
44815         }
44816
44817         clone() {
44818
44819                 return new Uniform( this.value.clone === undefined ? this.value : this.value.clone() );
44820
44821         }
44822
44823 }
44824
44825 function InstancedInterleavedBuffer( array, stride, meshPerAttribute ) {
44826
44827         InterleavedBuffer.call( this, array, stride );
44828
44829         this.meshPerAttribute = meshPerAttribute || 1;
44830
44831 }
44832
44833 InstancedInterleavedBuffer.prototype = Object.assign( Object.create( InterleavedBuffer.prototype ), {
44834
44835         constructor: InstancedInterleavedBuffer,
44836
44837         isInstancedInterleavedBuffer: true,
44838
44839         copy: function ( source ) {
44840
44841                 InterleavedBuffer.prototype.copy.call( this, source );
44842
44843                 this.meshPerAttribute = source.meshPerAttribute;
44844
44845                 return this;
44846
44847         },
44848
44849         clone: function ( data ) {
44850
44851                 const ib = InterleavedBuffer.prototype.clone.call( this, data );
44852
44853                 ib.meshPerAttribute = this.meshPerAttribute;
44854
44855                 return ib;
44856
44857         },
44858
44859         toJSON: function ( data ) {
44860
44861                 const json = InterleavedBuffer.prototype.toJSON.call( this, data );
44862
44863                 json.isInstancedInterleavedBuffer = true;
44864                 json.meshPerAttribute = this.meshPerAttribute;
44865
44866                 return json;
44867
44868         }
44869
44870 } );
44871
44872 function GLBufferAttribute( buffer, type, itemSize, elementSize, count ) {
44873
44874         this.buffer = buffer;
44875         this.type = type;
44876         this.itemSize = itemSize;
44877         this.elementSize = elementSize;
44878         this.count = count;
44879
44880         this.version = 0;
44881
44882 }
44883
44884 Object.defineProperty( GLBufferAttribute.prototype, 'needsUpdate', {
44885
44886         set: function ( value ) {
44887
44888                 if ( value === true ) this.version ++;
44889
44890         }
44891
44892 } );
44893
44894 Object.assign( GLBufferAttribute.prototype, {
44895
44896         isGLBufferAttribute: true,
44897
44898         setBuffer: function ( buffer ) {
44899
44900                 this.buffer = buffer;
44901
44902                 return this;
44903
44904         },
44905
44906         setType: function ( type, elementSize ) {
44907
44908                 this.type = type;
44909                 this.elementSize = elementSize;
44910
44911                 return this;
44912
44913         },
44914
44915         setItemSize: function ( itemSize ) {
44916
44917                 this.itemSize = itemSize;
44918
44919                 return this;
44920
44921         },
44922
44923         setCount: function ( count ) {
44924
44925                 this.count = count;
44926
44927                 return this;
44928
44929         },
44930
44931 } );
44932
44933 function Raycaster( origin, direction, near, far ) {
44934
44935         this.ray = new Ray( origin, direction );
44936         // direction is assumed to be normalized (for accurate distance calculations)
44937
44938         this.near = near || 0;
44939         this.far = far || Infinity;
44940         this.camera = null;
44941         this.layers = new Layers();
44942
44943         this.params = {
44944                 Mesh: {},
44945                 Line: { threshold: 1 },
44946                 LOD: {},
44947                 Points: { threshold: 1 },
44948                 Sprite: {}
44949         };
44950
44951         Object.defineProperties( this.params, {
44952                 PointCloud: {
44953                         get: function () {
44954
44955                                 console.warn( 'THREE.Raycaster: params.PointCloud has been renamed to params.Points.' );
44956                                 return this.Points;
44957
44958                         }
44959                 }
44960         } );
44961
44962 }
44963
44964 function ascSort( a, b ) {
44965
44966         return a.distance - b.distance;
44967
44968 }
44969
44970 function intersectObject( object, raycaster, intersects, recursive ) {
44971
44972         if ( object.layers.test( raycaster.layers ) ) {
44973
44974                 object.raycast( raycaster, intersects );
44975
44976         }
44977
44978         if ( recursive === true ) {
44979
44980                 const children = object.children;
44981
44982                 for ( let i = 0, l = children.length; i < l; i ++ ) {
44983
44984                         intersectObject( children[ i ], raycaster, intersects, true );
44985
44986                 }
44987
44988         }
44989
44990 }
44991
44992 Object.assign( Raycaster.prototype, {
44993
44994         set: function ( origin, direction ) {
44995
44996                 // direction is assumed to be normalized (for accurate distance calculations)
44997
44998                 this.ray.set( origin, direction );
44999
45000         },
45001
45002         setFromCamera: function ( coords, camera ) {
45003
45004                 if ( camera && camera.isPerspectiveCamera ) {
45005
45006                         this.ray.origin.setFromMatrixPosition( camera.matrixWorld );
45007                         this.ray.direction.set( coords.x, coords.y, 0.5 ).unproject( camera ).sub( this.ray.origin ).normalize();
45008                         this.camera = camera;
45009
45010                 } else if ( camera && camera.isOrthographicCamera ) {
45011
45012                         this.ray.origin.set( coords.x, coords.y, ( camera.near + camera.far ) / ( camera.near - camera.far ) ).unproject( camera ); // set origin in plane of camera
45013                         this.ray.direction.set( 0, 0, - 1 ).transformDirection( camera.matrixWorld );
45014                         this.camera = camera;
45015
45016                 } else {
45017
45018                         console.error( 'THREE.Raycaster: Unsupported camera type: ' + camera.type );
45019
45020                 }
45021
45022         },
45023
45024         intersectObject: function ( object, recursive, optionalTarget ) {
45025
45026                 const intersects = optionalTarget || [];
45027
45028                 intersectObject( object, this, intersects, recursive );
45029
45030                 intersects.sort( ascSort );
45031
45032                 return intersects;
45033
45034         },
45035
45036         intersectObjects: function ( objects, recursive, optionalTarget ) {
45037
45038                 const intersects = optionalTarget || [];
45039
45040                 if ( Array.isArray( objects ) === false ) {
45041
45042                         console.warn( 'THREE.Raycaster.intersectObjects: objects is not an Array.' );
45043                         return intersects;
45044
45045                 }
45046
45047                 for ( let i = 0, l = objects.length; i < l; i ++ ) {
45048
45049                         intersectObject( objects[ i ], this, intersects, recursive );
45050
45051                 }
45052
45053                 intersects.sort( ascSort );
45054
45055                 return intersects;
45056
45057         }
45058
45059 } );
45060
45061 const _vector$8 = /*@__PURE__*/ new Vector2();
45062
45063 class Box2 {
45064
45065         constructor( min, max ) {
45066
45067                 Object.defineProperty( this, 'isBox2', { value: true } );
45068
45069                 this.min = ( min !== undefined ) ? min : new Vector2( + Infinity, + Infinity );
45070                 this.max = ( max !== undefined ) ? max : new Vector2( - Infinity, - Infinity );
45071
45072         }
45073
45074         set( min, max ) {
45075
45076                 this.min.copy( min );
45077                 this.max.copy( max );
45078
45079                 return this;
45080
45081         }
45082
45083         setFromPoints( points ) {
45084
45085                 this.makeEmpty();
45086
45087                 for ( let i = 0, il = points.length; i < il; i ++ ) {
45088
45089                         this.expandByPoint( points[ i ] );
45090
45091                 }
45092
45093                 return this;
45094
45095         }
45096
45097         setFromCenterAndSize( center, size ) {
45098
45099                 const halfSize = _vector$8.copy( size ).multiplyScalar( 0.5 );
45100                 this.min.copy( center ).sub( halfSize );
45101                 this.max.copy( center ).add( halfSize );
45102
45103                 return this;
45104
45105         }
45106
45107         clone() {
45108
45109                 return new this.constructor().copy( this );
45110
45111         }
45112
45113         copy( box ) {
45114
45115                 this.min.copy( box.min );
45116                 this.max.copy( box.max );
45117
45118                 return this;
45119
45120         }
45121
45122         makeEmpty() {
45123
45124                 this.min.x = this.min.y = + Infinity;
45125                 this.max.x = this.max.y = - Infinity;
45126
45127                 return this;
45128
45129         }
45130
45131         isEmpty() {
45132
45133                 // this is a more robust check for empty than ( volume <= 0 ) because volume can get positive with two negative axes
45134
45135                 return ( this.max.x < this.min.x ) || ( this.max.y < this.min.y );
45136
45137         }
45138
45139         getCenter( target ) {
45140
45141                 if ( target === undefined ) {
45142
45143                         console.warn( 'THREE.Box2: .getCenter() target is now required' );
45144                         target = new Vector2();
45145
45146                 }
45147
45148                 return this.isEmpty() ? target.set( 0, 0 ) : target.addVectors( this.min, this.max ).multiplyScalar( 0.5 );
45149
45150         }
45151
45152         getSize( target ) {
45153
45154                 if ( target === undefined ) {
45155
45156                         console.warn( 'THREE.Box2: .getSize() target is now required' );
45157                         target = new Vector2();
45158
45159                 }
45160
45161                 return this.isEmpty() ? target.set( 0, 0 ) : target.subVectors( this.max, this.min );
45162
45163         }
45164
45165         expandByPoint( point ) {
45166
45167                 this.min.min( point );
45168                 this.max.max( point );
45169
45170                 return this;
45171
45172         }
45173
45174         expandByVector( vector ) {
45175
45176                 this.min.sub( vector );
45177                 this.max.add( vector );
45178
45179                 return this;
45180
45181         }
45182
45183         expandByScalar( scalar ) {
45184
45185                 this.min.addScalar( - scalar );
45186                 this.max.addScalar( scalar );
45187
45188                 return this;
45189
45190         }
45191
45192         containsPoint( point ) {
45193
45194                 return point.x < this.min.x || point.x > this.max.x ||
45195                         point.y < this.min.y || point.y > this.max.y ? false : true;
45196
45197         }
45198
45199         containsBox( box ) {
45200
45201                 return this.min.x <= box.min.x && box.max.x <= this.max.x &&
45202                         this.min.y <= box.min.y && box.max.y <= this.max.y;
45203
45204         }
45205
45206         getParameter( point, target ) {
45207
45208                 // This can potentially have a divide by zero if the box
45209                 // has a size dimension of 0.
45210
45211                 if ( target === undefined ) {
45212
45213                         console.warn( 'THREE.Box2: .getParameter() target is now required' );
45214                         target = new Vector2();
45215
45216                 }
45217
45218                 return target.set(
45219                         ( point.x - this.min.x ) / ( this.max.x - this.min.x ),
45220                         ( point.y - this.min.y ) / ( this.max.y - this.min.y )
45221                 );
45222
45223         }
45224
45225         intersectsBox( box ) {
45226
45227                 // using 4 splitting planes to rule out intersections
45228
45229                 return box.max.x < this.min.x || box.min.x > this.max.x ||
45230                         box.max.y < this.min.y || box.min.y > this.max.y ? false : true;
45231
45232         }
45233
45234         clampPoint( point, target ) {
45235
45236                 if ( target === undefined ) {
45237
45238                         console.warn( 'THREE.Box2: .clampPoint() target is now required' );
45239                         target = new Vector2();
45240
45241                 }
45242
45243                 return target.copy( point ).clamp( this.min, this.max );
45244
45245         }
45246
45247         distanceToPoint( point ) {
45248
45249                 const clampedPoint = _vector$8.copy( point ).clamp( this.min, this.max );
45250                 return clampedPoint.sub( point ).length();
45251
45252         }
45253
45254         intersect( box ) {
45255
45256                 this.min.max( box.min );
45257                 this.max.min( box.max );
45258
45259                 return this;
45260
45261         }
45262
45263         union( box ) {
45264
45265                 this.min.min( box.min );
45266                 this.max.max( box.max );
45267
45268                 return this;
45269
45270         }
45271
45272         translate( offset ) {
45273
45274                 this.min.add( offset );
45275                 this.max.add( offset );
45276
45277                 return this;
45278
45279         }
45280
45281         equals( box ) {
45282
45283                 return box.min.equals( this.min ) && box.max.equals( this.max );
45284
45285         }
45286
45287 }
45288
45289 function ImmediateRenderObject( material ) {
45290
45291         Object3D.call( this );
45292
45293         this.material = material;
45294         this.render = function ( /* renderCallback */ ) {};
45295
45296         this.hasPositions = false;
45297         this.hasNormals = false;
45298         this.hasColors = false;
45299         this.hasUvs = false;
45300
45301         this.positionArray = null;
45302         this.normalArray = null;
45303         this.colorArray = null;
45304         this.uvArray = null;
45305
45306         this.count = 0;
45307
45308 }
45309
45310 ImmediateRenderObject.prototype = Object.create( Object3D.prototype );
45311 ImmediateRenderObject.prototype.constructor = ImmediateRenderObject;
45312
45313 ImmediateRenderObject.prototype.isImmediateRenderObject = true;
45314
45315 const backgroundMaterial = new MeshBasicMaterial( {
45316         side: BackSide,
45317         depthWrite: false,
45318         depthTest: false,
45319 } );
45320 new Mesh( new BoxGeometry(), backgroundMaterial );
45321
45322 //
45323
45324 Curve.create = function ( construct, getPoint ) {
45325
45326         console.log( 'THREE.Curve.create() has been deprecated' );
45327
45328         construct.prototype = Object.create( Curve.prototype );
45329         construct.prototype.constructor = construct;
45330         construct.prototype.getPoint = getPoint;
45331
45332         return construct;
45333
45334 };
45335
45336 //
45337
45338 Object.assign( Path.prototype, {
45339
45340         fromPoints: function ( points ) {
45341
45342                 console.warn( 'THREE.Path: .fromPoints() has been renamed to .setFromPoints().' );
45343                 return this.setFromPoints( points );
45344
45345         }
45346
45347 } );
45348
45349 //
45350
45351 function Spline( points ) {
45352
45353         console.warn( 'THREE.Spline has been removed. Use THREE.CatmullRomCurve3 instead.' );
45354
45355         CatmullRomCurve3.call( this, points );
45356         this.type = 'catmullrom';
45357
45358 }
45359
45360 Spline.prototype = Object.create( CatmullRomCurve3.prototype );
45361
45362 Object.assign( Spline.prototype, {
45363
45364         initFromArray: function ( /* a */ ) {
45365
45366                 console.error( 'THREE.Spline: .initFromArray() has been removed.' );
45367
45368         },
45369         getControlPointsArray: function ( /* optionalTarget */ ) {
45370
45371                 console.error( 'THREE.Spline: .getControlPointsArray() has been removed.' );
45372
45373         },
45374         reparametrizeByArcLength: function ( /* samplingCoef */ ) {
45375
45376                 console.error( 'THREE.Spline: .reparametrizeByArcLength() has been removed.' );
45377
45378         }
45379
45380 } );
45381
45382 //
45383
45384 Object.assign( Loader.prototype, {
45385
45386         extractUrlBase: function ( url ) {
45387
45388                 console.warn( 'THREE.Loader: .extractUrlBase() has been deprecated. Use THREE.LoaderUtils.extractUrlBase() instead.' );
45389                 return LoaderUtils.extractUrlBase( url );
45390
45391         }
45392
45393 } );
45394
45395 Loader.Handlers = {
45396
45397         add: function ( /* regex, loader */ ) {
45398
45399                 console.error( 'THREE.Loader: Handlers.add() has been removed. Use LoadingManager.addHandler() instead.' );
45400
45401         },
45402
45403         get: function ( /* file */ ) {
45404
45405                 console.error( 'THREE.Loader: Handlers.get() has been removed. Use LoadingManager.getHandler() instead.' );
45406
45407         }
45408
45409 };
45410
45411 //
45412
45413 Object.assign( Box2.prototype, {
45414
45415         center: function ( optionalTarget ) {
45416
45417                 console.warn( 'THREE.Box2: .center() has been renamed to .getCenter().' );
45418                 return this.getCenter( optionalTarget );
45419
45420         },
45421         empty: function () {
45422
45423                 console.warn( 'THREE.Box2: .empty() has been renamed to .isEmpty().' );
45424                 return this.isEmpty();
45425
45426         },
45427         isIntersectionBox: function ( box ) {
45428
45429                 console.warn( 'THREE.Box2: .isIntersectionBox() has been renamed to .intersectsBox().' );
45430                 return this.intersectsBox( box );
45431
45432         },
45433         size: function ( optionalTarget ) {
45434
45435                 console.warn( 'THREE.Box2: .size() has been renamed to .getSize().' );
45436                 return this.getSize( optionalTarget );
45437
45438         }
45439 } );
45440
45441 Object.assign( Box3.prototype, {
45442
45443         center: function ( optionalTarget ) {
45444
45445                 console.warn( 'THREE.Box3: .center() has been renamed to .getCenter().' );
45446                 return this.getCenter( optionalTarget );
45447
45448         },
45449         empty: function () {
45450
45451                 console.warn( 'THREE.Box3: .empty() has been renamed to .isEmpty().' );
45452                 return this.isEmpty();
45453
45454         },
45455         isIntersectionBox: function ( box ) {
45456
45457                 console.warn( 'THREE.Box3: .isIntersectionBox() has been renamed to .intersectsBox().' );
45458                 return this.intersectsBox( box );
45459
45460         },
45461         isIntersectionSphere: function ( sphere ) {
45462
45463                 console.warn( 'THREE.Box3: .isIntersectionSphere() has been renamed to .intersectsSphere().' );
45464                 return this.intersectsSphere( sphere );
45465
45466         },
45467         size: function ( optionalTarget ) {
45468
45469                 console.warn( 'THREE.Box3: .size() has been renamed to .getSize().' );
45470                 return this.getSize( optionalTarget );
45471
45472         }
45473 } );
45474
45475 Object.assign( Sphere.prototype, {
45476
45477         empty: function () {
45478
45479                 console.warn( 'THREE.Sphere: .empty() has been renamed to .isEmpty().' );
45480                 return this.isEmpty();
45481
45482         },
45483
45484 } );
45485
45486 Frustum.prototype.setFromMatrix = function ( m ) {
45487
45488         console.warn( 'THREE.Frustum: .setFromMatrix() has been renamed to .setFromProjectionMatrix().' );
45489         return this.setFromProjectionMatrix( m );
45490
45491 };
45492
45493 Object.assign( MathUtils, {
45494
45495         random16: function () {
45496
45497                 console.warn( 'THREE.Math: .random16() has been deprecated. Use Math.random() instead.' );
45498                 return Math.random();
45499
45500         },
45501
45502         nearestPowerOfTwo: function ( value ) {
45503
45504                 console.warn( 'THREE.Math: .nearestPowerOfTwo() has been renamed to .floorPowerOfTwo().' );
45505                 return MathUtils.floorPowerOfTwo( value );
45506
45507         },
45508
45509         nextPowerOfTwo: function ( value ) {
45510
45511                 console.warn( 'THREE.Math: .nextPowerOfTwo() has been renamed to .ceilPowerOfTwo().' );
45512                 return MathUtils.ceilPowerOfTwo( value );
45513
45514         }
45515
45516 } );
45517
45518 Object.assign( Matrix3.prototype, {
45519
45520         flattenToArrayOffset: function ( array, offset ) {
45521
45522                 console.warn( 'THREE.Matrix3: .flattenToArrayOffset() has been deprecated. Use .toArray() instead.' );
45523                 return this.toArray( array, offset );
45524
45525         },
45526         multiplyVector3: function ( vector ) {
45527
45528                 console.warn( 'THREE.Matrix3: .multiplyVector3() has been removed. Use vector.applyMatrix3( matrix ) instead.' );
45529                 return vector.applyMatrix3( this );
45530
45531         },
45532         multiplyVector3Array: function ( /* a */ ) {
45533
45534                 console.error( 'THREE.Matrix3: .multiplyVector3Array() has been removed.' );
45535
45536         },
45537         applyToBufferAttribute: function ( attribute ) {
45538
45539                 console.warn( 'THREE.Matrix3: .applyToBufferAttribute() has been removed. Use attribute.applyMatrix3( matrix ) instead.' );
45540                 return attribute.applyMatrix3( this );
45541
45542         },
45543         applyToVector3Array: function ( /* array, offset, length */ ) {
45544
45545                 console.error( 'THREE.Matrix3: .applyToVector3Array() has been removed.' );
45546
45547         },
45548         getInverse: function ( matrix ) {
45549
45550                 console.warn( 'THREE.Matrix3: .getInverse() has been removed. Use matrixInv.copy( matrix ).invert(); instead.' );
45551                 return this.copy( matrix ).invert();
45552
45553         }
45554
45555 } );
45556
45557 Object.assign( Matrix4.prototype, {
45558
45559         extractPosition: function ( m ) {
45560
45561                 console.warn( 'THREE.Matrix4: .extractPosition() has been renamed to .copyPosition().' );
45562                 return this.copyPosition( m );
45563
45564         },
45565         flattenToArrayOffset: function ( array, offset ) {
45566
45567                 console.warn( 'THREE.Matrix4: .flattenToArrayOffset() has been deprecated. Use .toArray() instead.' );
45568                 return this.toArray( array, offset );
45569
45570         },
45571         getPosition: function () {
45572
45573                 console.warn( 'THREE.Matrix4: .getPosition() has been removed. Use Vector3.setFromMatrixPosition( matrix ) instead.' );
45574                 return new Vector3().setFromMatrixColumn( this, 3 );
45575
45576         },
45577         setRotationFromQuaternion: function ( q ) {
45578
45579                 console.warn( 'THREE.Matrix4: .setRotationFromQuaternion() has been renamed to .makeRotationFromQuaternion().' );
45580                 return this.makeRotationFromQuaternion( q );
45581
45582         },
45583         multiplyToArray: function () {
45584
45585                 console.warn( 'THREE.Matrix4: .multiplyToArray() has been removed.' );
45586
45587         },
45588         multiplyVector3: function ( vector ) {
45589
45590                 console.warn( 'THREE.Matrix4: .multiplyVector3() has been removed. Use vector.applyMatrix4( matrix ) instead.' );
45591                 return vector.applyMatrix4( this );
45592
45593         },
45594         multiplyVector4: function ( vector ) {
45595
45596                 console.warn( 'THREE.Matrix4: .multiplyVector4() has been removed. Use vector.applyMatrix4( matrix ) instead.' );
45597                 return vector.applyMatrix4( this );
45598
45599         },
45600         multiplyVector3Array: function ( /* a */ ) {
45601
45602                 console.error( 'THREE.Matrix4: .multiplyVector3Array() has been removed.' );
45603
45604         },
45605         rotateAxis: function ( v ) {
45606
45607                 console.warn( 'THREE.Matrix4: .rotateAxis() has been removed. Use Vector3.transformDirection( matrix ) instead.' );
45608                 v.transformDirection( this );
45609
45610         },
45611         crossVector: function ( vector ) {
45612
45613                 console.warn( 'THREE.Matrix4: .crossVector() has been removed. Use vector.applyMatrix4( matrix ) instead.' );
45614                 return vector.applyMatrix4( this );
45615
45616         },
45617         translate: function () {
45618
45619                 console.error( 'THREE.Matrix4: .translate() has been removed.' );
45620
45621         },
45622         rotateX: function () {
45623
45624                 console.error( 'THREE.Matrix4: .rotateX() has been removed.' );
45625
45626         },
45627         rotateY: function () {
45628
45629                 console.error( 'THREE.Matrix4: .rotateY() has been removed.' );
45630
45631         },
45632         rotateZ: function () {
45633
45634                 console.error( 'THREE.Matrix4: .rotateZ() has been removed.' );
45635
45636         },
45637         rotateByAxis: function () {
45638
45639                 console.error( 'THREE.Matrix4: .rotateByAxis() has been removed.' );
45640
45641         },
45642         applyToBufferAttribute: function ( attribute ) {
45643
45644                 console.warn( 'THREE.Matrix4: .applyToBufferAttribute() has been removed. Use attribute.applyMatrix4( matrix ) instead.' );
45645                 return attribute.applyMatrix4( this );
45646
45647         },
45648         applyToVector3Array: function ( /* array, offset, length */ ) {
45649
45650                 console.error( 'THREE.Matrix4: .applyToVector3Array() has been removed.' );
45651
45652         },
45653         makeFrustum: function ( left, right, bottom, top, near, far ) {
45654
45655                 console.warn( 'THREE.Matrix4: .makeFrustum() has been removed. Use .makePerspective( left, right, top, bottom, near, far ) instead.' );
45656                 return this.makePerspective( left, right, top, bottom, near, far );
45657
45658         },
45659         getInverse: function ( matrix ) {
45660
45661                 console.warn( 'THREE.Matrix4: .getInverse() has been removed. Use matrixInv.copy( matrix ).invert(); instead.' );
45662                 return this.copy( matrix ).invert();
45663
45664         }
45665
45666 } );
45667
45668 Plane.prototype.isIntersectionLine = function ( line ) {
45669
45670         console.warn( 'THREE.Plane: .isIntersectionLine() has been renamed to .intersectsLine().' );
45671         return this.intersectsLine( line );
45672
45673 };
45674
45675 Object.assign( Quaternion.prototype, {
45676
45677         multiplyVector3: function ( vector ) {
45678
45679                 console.warn( 'THREE.Quaternion: .multiplyVector3() has been removed. Use is now vector.applyQuaternion( quaternion ) instead.' );
45680                 return vector.applyQuaternion( this );
45681
45682         },
45683         inverse: function ( ) {
45684
45685                 console.warn( 'THREE.Quaternion: .inverse() has been renamed to invert().' );
45686                 return this.invert();
45687
45688         }
45689
45690 } );
45691
45692 Object.assign( Ray.prototype, {
45693
45694         isIntersectionBox: function ( box ) {
45695
45696                 console.warn( 'THREE.Ray: .isIntersectionBox() has been renamed to .intersectsBox().' );
45697                 return this.intersectsBox( box );
45698
45699         },
45700         isIntersectionPlane: function ( plane ) {
45701
45702                 console.warn( 'THREE.Ray: .isIntersectionPlane() has been renamed to .intersectsPlane().' );
45703                 return this.intersectsPlane( plane );
45704
45705         },
45706         isIntersectionSphere: function ( sphere ) {
45707
45708                 console.warn( 'THREE.Ray: .isIntersectionSphere() has been renamed to .intersectsSphere().' );
45709                 return this.intersectsSphere( sphere );
45710
45711         }
45712
45713 } );
45714
45715 Object.assign( Triangle.prototype, {
45716
45717         area: function () {
45718
45719                 console.warn( 'THREE.Triangle: .area() has been renamed to .getArea().' );
45720                 return this.getArea();
45721
45722         },
45723         barycoordFromPoint: function ( point, target ) {
45724
45725                 console.warn( 'THREE.Triangle: .barycoordFromPoint() has been renamed to .getBarycoord().' );
45726                 return this.getBarycoord( point, target );
45727
45728         },
45729         midpoint: function ( target ) {
45730
45731                 console.warn( 'THREE.Triangle: .midpoint() has been renamed to .getMidpoint().' );
45732                 return this.getMidpoint( target );
45733
45734         },
45735         normal: function ( target ) {
45736
45737                 console.warn( 'THREE.Triangle: .normal() has been renamed to .getNormal().' );
45738                 return this.getNormal( target );
45739
45740         },
45741         plane: function ( target ) {
45742
45743                 console.warn( 'THREE.Triangle: .plane() has been renamed to .getPlane().' );
45744                 return this.getPlane( target );
45745
45746         }
45747
45748 } );
45749
45750 Object.assign( Triangle, {
45751
45752         barycoordFromPoint: function ( point, a, b, c, target ) {
45753
45754                 console.warn( 'THREE.Triangle: .barycoordFromPoint() has been renamed to .getBarycoord().' );
45755                 return Triangle.getBarycoord( point, a, b, c, target );
45756
45757         },
45758         normal: function ( a, b, c, target ) {
45759
45760                 console.warn( 'THREE.Triangle: .normal() has been renamed to .getNormal().' );
45761                 return Triangle.getNormal( a, b, c, target );
45762
45763         }
45764
45765 } );
45766
45767 Object.assign( Shape.prototype, {
45768
45769         extractAllPoints: function ( divisions ) {
45770
45771                 console.warn( 'THREE.Shape: .extractAllPoints() has been removed. Use .extractPoints() instead.' );
45772                 return this.extractPoints( divisions );
45773
45774         },
45775         extrude: function ( options ) {
45776
45777                 console.warn( 'THREE.Shape: .extrude() has been removed. Use ExtrudeGeometry() instead.' );
45778                 return new ExtrudeGeometry( this, options );
45779
45780         },
45781         makeGeometry: function ( options ) {
45782
45783                 console.warn( 'THREE.Shape: .makeGeometry() has been removed. Use ShapeGeometry() instead.' );
45784                 return new ShapeGeometry( this, options );
45785
45786         }
45787
45788 } );
45789
45790 Object.assign( Vector2.prototype, {
45791
45792         fromAttribute: function ( attribute, index, offset ) {
45793
45794                 console.warn( 'THREE.Vector2: .fromAttribute() has been renamed to .fromBufferAttribute().' );
45795                 return this.fromBufferAttribute( attribute, index, offset );
45796
45797         },
45798         distanceToManhattan: function ( v ) {
45799
45800                 console.warn( 'THREE.Vector2: .distanceToManhattan() has been renamed to .manhattanDistanceTo().' );
45801                 return this.manhattanDistanceTo( v );
45802
45803         },
45804         lengthManhattan: function () {
45805
45806                 console.warn( 'THREE.Vector2: .lengthManhattan() has been renamed to .manhattanLength().' );
45807                 return this.manhattanLength();
45808
45809         }
45810
45811 } );
45812
45813 Object.assign( Vector3.prototype, {
45814
45815         setEulerFromRotationMatrix: function () {
45816
45817                 console.error( 'THREE.Vector3: .setEulerFromRotationMatrix() has been removed. Use Euler.setFromRotationMatrix() instead.' );
45818
45819         },
45820         setEulerFromQuaternion: function () {
45821
45822                 console.error( 'THREE.Vector3: .setEulerFromQuaternion() has been removed. Use Euler.setFromQuaternion() instead.' );
45823
45824         },
45825         getPositionFromMatrix: function ( m ) {
45826
45827                 console.warn( 'THREE.Vector3: .getPositionFromMatrix() has been renamed to .setFromMatrixPosition().' );
45828                 return this.setFromMatrixPosition( m );
45829
45830         },
45831         getScaleFromMatrix: function ( m ) {
45832
45833                 console.warn( 'THREE.Vector3: .getScaleFromMatrix() has been renamed to .setFromMatrixScale().' );
45834                 return this.setFromMatrixScale( m );
45835
45836         },
45837         getColumnFromMatrix: function ( index, matrix ) {
45838
45839                 console.warn( 'THREE.Vector3: .getColumnFromMatrix() has been renamed to .setFromMatrixColumn().' );
45840                 return this.setFromMatrixColumn( matrix, index );
45841
45842         },
45843         applyProjection: function ( m ) {
45844
45845                 console.warn( 'THREE.Vector3: .applyProjection() has been removed. Use .applyMatrix4( m ) instead.' );
45846                 return this.applyMatrix4( m );
45847
45848         },
45849         fromAttribute: function ( attribute, index, offset ) {
45850
45851                 console.warn( 'THREE.Vector3: .fromAttribute() has been renamed to .fromBufferAttribute().' );
45852                 return this.fromBufferAttribute( attribute, index, offset );
45853
45854         },
45855         distanceToManhattan: function ( v ) {
45856
45857                 console.warn( 'THREE.Vector3: .distanceToManhattan() has been renamed to .manhattanDistanceTo().' );
45858                 return this.manhattanDistanceTo( v );
45859
45860         },
45861         lengthManhattan: function () {
45862
45863                 console.warn( 'THREE.Vector3: .lengthManhattan() has been renamed to .manhattanLength().' );
45864                 return this.manhattanLength();
45865
45866         }
45867
45868 } );
45869
45870 Object.assign( Vector4.prototype, {
45871
45872         fromAttribute: function ( attribute, index, offset ) {
45873
45874                 console.warn( 'THREE.Vector4: .fromAttribute() has been renamed to .fromBufferAttribute().' );
45875                 return this.fromBufferAttribute( attribute, index, offset );
45876
45877         },
45878         lengthManhattan: function () {
45879
45880                 console.warn( 'THREE.Vector4: .lengthManhattan() has been renamed to .manhattanLength().' );
45881                 return this.manhattanLength();
45882
45883         }
45884
45885 } );
45886
45887 //
45888
45889 Object.assign( Object3D.prototype, {
45890
45891         getChildByName: function ( name ) {
45892
45893                 console.warn( 'THREE.Object3D: .getChildByName() has been renamed to .getObjectByName().' );
45894                 return this.getObjectByName( name );
45895
45896         },
45897         renderDepth: function () {
45898
45899                 console.warn( 'THREE.Object3D: .renderDepth has been removed. Use .renderOrder, instead.' );
45900
45901         },
45902         translate: function ( distance, axis ) {
45903
45904                 console.warn( 'THREE.Object3D: .translate() has been removed. Use .translateOnAxis( axis, distance ) instead.' );
45905                 return this.translateOnAxis( axis, distance );
45906
45907         },
45908         getWorldRotation: function () {
45909
45910                 console.error( 'THREE.Object3D: .getWorldRotation() has been removed. Use THREE.Object3D.getWorldQuaternion( target ) instead.' );
45911
45912         },
45913         applyMatrix: function ( matrix ) {
45914
45915                 console.warn( 'THREE.Object3D: .applyMatrix() has been renamed to .applyMatrix4().' );
45916                 return this.applyMatrix4( matrix );
45917
45918         }
45919
45920 } );
45921
45922 Object.defineProperties( Object3D.prototype, {
45923
45924         eulerOrder: {
45925                 get: function () {
45926
45927                         console.warn( 'THREE.Object3D: .eulerOrder is now .rotation.order.' );
45928                         return this.rotation.order;
45929
45930                 },
45931                 set: function ( value ) {
45932
45933                         console.warn( 'THREE.Object3D: .eulerOrder is now .rotation.order.' );
45934                         this.rotation.order = value;
45935
45936                 }
45937         },
45938         useQuaternion: {
45939                 get: function () {
45940
45941                         console.warn( 'THREE.Object3D: .useQuaternion has been removed. The library now uses quaternions by default.' );
45942
45943                 },
45944                 set: function () {
45945
45946                         console.warn( 'THREE.Object3D: .useQuaternion has been removed. The library now uses quaternions by default.' );
45947
45948                 }
45949         }
45950
45951 } );
45952
45953 Object.assign( Mesh.prototype, {
45954
45955         setDrawMode: function () {
45956
45957                 console.error( 'THREE.Mesh: .setDrawMode() has been removed. The renderer now always assumes THREE.TrianglesDrawMode. Transform your geometry via BufferGeometryUtils.toTrianglesDrawMode() if necessary.' );
45958
45959         },
45960
45961 } );
45962
45963 Object.defineProperties( Mesh.prototype, {
45964
45965         drawMode: {
45966                 get: function () {
45967
45968                         console.error( 'THREE.Mesh: .drawMode has been removed. The renderer now always assumes THREE.TrianglesDrawMode.' );
45969                         return TrianglesDrawMode;
45970
45971                 },
45972                 set: function () {
45973
45974                         console.error( 'THREE.Mesh: .drawMode has been removed. The renderer now always assumes THREE.TrianglesDrawMode. Transform your geometry via BufferGeometryUtils.toTrianglesDrawMode() if necessary.' );
45975
45976                 }
45977         }
45978
45979 } );
45980
45981 Object.defineProperties( LOD.prototype, {
45982
45983         objects: {
45984                 get: function () {
45985
45986                         console.warn( 'THREE.LOD: .objects has been renamed to .levels.' );
45987                         return this.levels;
45988
45989                 }
45990         }
45991
45992 } );
45993
45994 Object.defineProperty( Skeleton.prototype, 'useVertexTexture', {
45995
45996         get: function () {
45997
45998                 console.warn( 'THREE.Skeleton: useVertexTexture has been removed.' );
45999
46000         },
46001         set: function () {
46002
46003                 console.warn( 'THREE.Skeleton: useVertexTexture has been removed.' );
46004
46005         }
46006
46007 } );
46008
46009 SkinnedMesh.prototype.initBones = function () {
46010
46011         console.error( 'THREE.SkinnedMesh: initBones() has been removed.' );
46012
46013 };
46014
46015 Object.defineProperty( Curve.prototype, '__arcLengthDivisions', {
46016
46017         get: function () {
46018
46019                 console.warn( 'THREE.Curve: .__arcLengthDivisions is now .arcLengthDivisions.' );
46020                 return this.arcLengthDivisions;
46021
46022         },
46023         set: function ( value ) {
46024
46025                 console.warn( 'THREE.Curve: .__arcLengthDivisions is now .arcLengthDivisions.' );
46026                 this.arcLengthDivisions = value;
46027
46028         }
46029
46030 } );
46031
46032 //
46033
46034 PerspectiveCamera.prototype.setLens = function ( focalLength, filmGauge ) {
46035
46036         console.warn( 'THREE.PerspectiveCamera.setLens is deprecated. ' +
46037                         'Use .setFocalLength and .filmGauge for a photographic setup.' );
46038
46039         if ( filmGauge !== undefined ) this.filmGauge = filmGauge;
46040         this.setFocalLength( focalLength );
46041
46042 };
46043
46044 //
46045
46046 Object.defineProperties( Light.prototype, {
46047         onlyShadow: {
46048                 set: function () {
46049
46050                         console.warn( 'THREE.Light: .onlyShadow has been removed.' );
46051
46052                 }
46053         },
46054         shadowCameraFov: {
46055                 set: function ( value ) {
46056
46057                         console.warn( 'THREE.Light: .shadowCameraFov is now .shadow.camera.fov.' );
46058                         this.shadow.camera.fov = value;
46059
46060                 }
46061         },
46062         shadowCameraLeft: {
46063                 set: function ( value ) {
46064
46065                         console.warn( 'THREE.Light: .shadowCameraLeft is now .shadow.camera.left.' );
46066                         this.shadow.camera.left = value;
46067
46068                 }
46069         },
46070         shadowCameraRight: {
46071                 set: function ( value ) {
46072
46073                         console.warn( 'THREE.Light: .shadowCameraRight is now .shadow.camera.right.' );
46074                         this.shadow.camera.right = value;
46075
46076                 }
46077         },
46078         shadowCameraTop: {
46079                 set: function ( value ) {
46080
46081                         console.warn( 'THREE.Light: .shadowCameraTop is now .shadow.camera.top.' );
46082                         this.shadow.camera.top = value;
46083
46084                 }
46085         },
46086         shadowCameraBottom: {
46087                 set: function ( value ) {
46088
46089                         console.warn( 'THREE.Light: .shadowCameraBottom is now .shadow.camera.bottom.' );
46090                         this.shadow.camera.bottom = value;
46091
46092                 }
46093         },
46094         shadowCameraNear: {
46095                 set: function ( value ) {
46096
46097                         console.warn( 'THREE.Light: .shadowCameraNear is now .shadow.camera.near.' );
46098                         this.shadow.camera.near = value;
46099
46100                 }
46101         },
46102         shadowCameraFar: {
46103                 set: function ( value ) {
46104
46105                         console.warn( 'THREE.Light: .shadowCameraFar is now .shadow.camera.far.' );
46106                         this.shadow.camera.far = value;
46107
46108                 }
46109         },
46110         shadowCameraVisible: {
46111                 set: function () {
46112
46113                         console.warn( 'THREE.Light: .shadowCameraVisible has been removed. Use new THREE.CameraHelper( light.shadow.camera ) instead.' );
46114
46115                 }
46116         },
46117         shadowBias: {
46118                 set: function ( value ) {
46119
46120                         console.warn( 'THREE.Light: .shadowBias is now .shadow.bias.' );
46121                         this.shadow.bias = value;
46122
46123                 }
46124         },
46125         shadowDarkness: {
46126                 set: function () {
46127
46128                         console.warn( 'THREE.Light: .shadowDarkness has been removed.' );
46129
46130                 }
46131         },
46132         shadowMapWidth: {
46133                 set: function ( value ) {
46134
46135                         console.warn( 'THREE.Light: .shadowMapWidth is now .shadow.mapSize.width.' );
46136                         this.shadow.mapSize.width = value;
46137
46138                 }
46139         },
46140         shadowMapHeight: {
46141                 set: function ( value ) {
46142
46143                         console.warn( 'THREE.Light: .shadowMapHeight is now .shadow.mapSize.height.' );
46144                         this.shadow.mapSize.height = value;
46145
46146                 }
46147         }
46148 } );
46149
46150 //
46151
46152 Object.defineProperties( BufferAttribute.prototype, {
46153
46154         length: {
46155                 get: function () {
46156
46157                         console.warn( 'THREE.BufferAttribute: .length has been deprecated. Use .count instead.' );
46158                         return this.array.length;
46159
46160                 }
46161         },
46162         dynamic: {
46163                 get: function () {
46164
46165                         console.warn( 'THREE.BufferAttribute: .dynamic has been deprecated. Use .usage instead.' );
46166                         return this.usage === DynamicDrawUsage;
46167
46168                 },
46169                 set: function ( /* value */ ) {
46170
46171                         console.warn( 'THREE.BufferAttribute: .dynamic has been deprecated. Use .usage instead.' );
46172                         this.setUsage( DynamicDrawUsage );
46173
46174                 }
46175         }
46176
46177 } );
46178
46179 Object.assign( BufferAttribute.prototype, {
46180         setDynamic: function ( value ) {
46181
46182                 console.warn( 'THREE.BufferAttribute: .setDynamic() has been deprecated. Use .setUsage() instead.' );
46183                 this.setUsage( value === true ? DynamicDrawUsage : StaticDrawUsage );
46184                 return this;
46185
46186         },
46187         copyIndicesArray: function ( /* indices */ ) {
46188
46189                 console.error( 'THREE.BufferAttribute: .copyIndicesArray() has been removed.' );
46190
46191         },
46192         setArray: function ( /* array */ ) {
46193
46194                 console.error( 'THREE.BufferAttribute: .setArray has been removed. Use BufferGeometry .setAttribute to replace/resize attribute buffers' );
46195
46196         }
46197 } );
46198
46199 Object.assign( BufferGeometry.prototype, {
46200
46201         addIndex: function ( index ) {
46202
46203                 console.warn( 'THREE.BufferGeometry: .addIndex() has been renamed to .setIndex().' );
46204                 this.setIndex( index );
46205
46206         },
46207         addAttribute: function ( name, attribute ) {
46208
46209                 console.warn( 'THREE.BufferGeometry: .addAttribute() has been renamed to .setAttribute().' );
46210
46211                 if ( ! ( attribute && attribute.isBufferAttribute ) && ! ( attribute && attribute.isInterleavedBufferAttribute ) ) {
46212
46213                         console.warn( 'THREE.BufferGeometry: .addAttribute() now expects ( name, attribute ).' );
46214
46215                         return this.setAttribute( name, new BufferAttribute( arguments[ 1 ], arguments[ 2 ] ) );
46216
46217                 }
46218
46219                 if ( name === 'index' ) {
46220
46221                         console.warn( 'THREE.BufferGeometry.addAttribute: Use .setIndex() for index attribute.' );
46222                         this.setIndex( attribute );
46223
46224                         return this;
46225
46226                 }
46227
46228                 return this.setAttribute( name, attribute );
46229
46230         },
46231         addDrawCall: function ( start, count, indexOffset ) {
46232
46233                 if ( indexOffset !== undefined ) {
46234
46235                         console.warn( 'THREE.BufferGeometry: .addDrawCall() no longer supports indexOffset.' );
46236
46237                 }
46238
46239                 console.warn( 'THREE.BufferGeometry: .addDrawCall() is now .addGroup().' );
46240                 this.addGroup( start, count );
46241
46242         },
46243         clearDrawCalls: function () {
46244
46245                 console.warn( 'THREE.BufferGeometry: .clearDrawCalls() is now .clearGroups().' );
46246                 this.clearGroups();
46247
46248         },
46249         computeOffsets: function () {
46250
46251                 console.warn( 'THREE.BufferGeometry: .computeOffsets() has been removed.' );
46252
46253         },
46254         removeAttribute: function ( name ) {
46255
46256                 console.warn( 'THREE.BufferGeometry: .removeAttribute() has been renamed to .deleteAttribute().' );
46257
46258                 return this.deleteAttribute( name );
46259
46260         },
46261         applyMatrix: function ( matrix ) {
46262
46263                 console.warn( 'THREE.BufferGeometry: .applyMatrix() has been renamed to .applyMatrix4().' );
46264                 return this.applyMatrix4( matrix );
46265
46266         }
46267
46268 } );
46269
46270 Object.defineProperties( BufferGeometry.prototype, {
46271
46272         drawcalls: {
46273                 get: function () {
46274
46275                         console.error( 'THREE.BufferGeometry: .drawcalls has been renamed to .groups.' );
46276                         return this.groups;
46277
46278                 }
46279         },
46280         offsets: {
46281                 get: function () {
46282
46283                         console.warn( 'THREE.BufferGeometry: .offsets has been renamed to .groups.' );
46284                         return this.groups;
46285
46286                 }
46287         }
46288
46289 } );
46290
46291 Object.defineProperties( InstancedBufferGeometry.prototype, {
46292
46293         maxInstancedCount: {
46294                 get: function () {
46295
46296                         console.warn( 'THREE.InstancedBufferGeometry: .maxInstancedCount has been renamed to .instanceCount.' );
46297                         return this.instanceCount;
46298
46299                 },
46300                 set: function ( value ) {
46301
46302                         console.warn( 'THREE.InstancedBufferGeometry: .maxInstancedCount has been renamed to .instanceCount.' );
46303                         this.instanceCount = value;
46304
46305                 }
46306         }
46307
46308 } );
46309
46310 Object.defineProperties( Raycaster.prototype, {
46311
46312         linePrecision: {
46313                 get: function () {
46314
46315                         console.warn( 'THREE.Raycaster: .linePrecision has been deprecated. Use .params.Line.threshold instead.' );
46316                         return this.params.Line.threshold;
46317
46318                 },
46319                 set: function ( value ) {
46320
46321                         console.warn( 'THREE.Raycaster: .linePrecision has been deprecated. Use .params.Line.threshold instead.' );
46322                         this.params.Line.threshold = value;
46323
46324                 }
46325         }
46326
46327 } );
46328
46329 Object.defineProperties( InterleavedBuffer.prototype, {
46330
46331         dynamic: {
46332                 get: function () {
46333
46334                         console.warn( 'THREE.InterleavedBuffer: .length has been deprecated. Use .usage instead.' );
46335                         return this.usage === DynamicDrawUsage;
46336
46337                 },
46338                 set: function ( value ) {
46339
46340                         console.warn( 'THREE.InterleavedBuffer: .length has been deprecated. Use .usage instead.' );
46341                         this.setUsage( value );
46342
46343                 }
46344         }
46345
46346 } );
46347
46348 Object.assign( InterleavedBuffer.prototype, {
46349         setDynamic: function ( value ) {
46350
46351                 console.warn( 'THREE.InterleavedBuffer: .setDynamic() has been deprecated. Use .setUsage() instead.' );
46352                 this.setUsage( value === true ? DynamicDrawUsage : StaticDrawUsage );
46353                 return this;
46354
46355         },
46356         setArray: function ( /* array */ ) {
46357
46358                 console.error( 'THREE.InterleavedBuffer: .setArray has been removed. Use BufferGeometry .setAttribute to replace/resize attribute buffers' );
46359
46360         }
46361 } );
46362
46363 //
46364
46365 Object.assign( ExtrudeGeometry.prototype, {
46366
46367         getArrays: function () {
46368
46369                 console.error( 'THREE.ExtrudeGeometry: .getArrays() has been removed.' );
46370
46371         },
46372
46373         addShapeList: function () {
46374
46375                 console.error( 'THREE.ExtrudeGeometry: .addShapeList() has been removed.' );
46376
46377         },
46378
46379         addShape: function () {
46380
46381                 console.error( 'THREE.ExtrudeGeometry: .addShape() has been removed.' );
46382
46383         }
46384
46385 } );
46386
46387 //
46388
46389 Object.assign( Scene.prototype, {
46390
46391         dispose: function () {
46392
46393                 console.error( 'THREE.Scene: .dispose() has been removed.' );
46394
46395         }
46396
46397 } );
46398
46399 //
46400
46401 Object.defineProperties( Uniform.prototype, {
46402
46403         dynamic: {
46404                 set: function () {
46405
46406                         console.warn( 'THREE.Uniform: .dynamic has been removed. Use object.onBeforeRender() instead.' );
46407
46408                 }
46409         },
46410         onUpdate: {
46411                 value: function () {
46412
46413                         console.warn( 'THREE.Uniform: .onUpdate() has been removed. Use object.onBeforeRender() instead.' );
46414                         return this;
46415
46416                 }
46417         }
46418
46419 } );
46420
46421 //
46422
46423 Object.defineProperties( Material.prototype, {
46424
46425         wrapAround: {
46426                 get: function () {
46427
46428                         console.warn( 'THREE.Material: .wrapAround has been removed.' );
46429
46430                 },
46431                 set: function () {
46432
46433                         console.warn( 'THREE.Material: .wrapAround has been removed.' );
46434
46435                 }
46436         },
46437
46438         overdraw: {
46439                 get: function () {
46440
46441                         console.warn( 'THREE.Material: .overdraw has been removed.' );
46442
46443                 },
46444                 set: function () {
46445
46446                         console.warn( 'THREE.Material: .overdraw has been removed.' );
46447
46448                 }
46449         },
46450
46451         wrapRGB: {
46452                 get: function () {
46453
46454                         console.warn( 'THREE.Material: .wrapRGB has been removed.' );
46455                         return new Color();
46456
46457                 }
46458         },
46459
46460         shading: {
46461                 get: function () {
46462
46463                         console.error( 'THREE.' + this.type + ': .shading has been removed. Use the boolean .flatShading instead.' );
46464
46465                 },
46466                 set: function ( value ) {
46467
46468                         console.warn( 'THREE.' + this.type + ': .shading has been removed. Use the boolean .flatShading instead.' );
46469                         this.flatShading = ( value === FlatShading );
46470
46471                 }
46472         },
46473
46474         stencilMask: {
46475                 get: function () {
46476
46477                         console.warn( 'THREE.' + this.type + ': .stencilMask has been removed. Use .stencilFuncMask instead.' );
46478                         return this.stencilFuncMask;
46479
46480                 },
46481                 set: function ( value ) {
46482
46483                         console.warn( 'THREE.' + this.type + ': .stencilMask has been removed. Use .stencilFuncMask instead.' );
46484                         this.stencilFuncMask = value;
46485
46486                 }
46487         }
46488
46489 } );
46490
46491 Object.defineProperties( MeshPhongMaterial.prototype, {
46492
46493         metal: {
46494                 get: function () {
46495
46496                         console.warn( 'THREE.MeshPhongMaterial: .metal has been removed. Use THREE.MeshStandardMaterial instead.' );
46497                         return false;
46498
46499                 },
46500                 set: function () {
46501
46502                         console.warn( 'THREE.MeshPhongMaterial: .metal has been removed. Use THREE.MeshStandardMaterial instead' );
46503
46504                 }
46505         }
46506
46507 } );
46508
46509 Object.defineProperties( MeshPhysicalMaterial.prototype, {
46510
46511         transparency: {
46512                 get: function () {
46513
46514                         console.warn( 'THREE.MeshPhysicalMaterial: .transparency has been renamed to .transmission.' );
46515                         return this.transmission;
46516
46517                 },
46518                 set: function ( value ) {
46519
46520                         console.warn( 'THREE.MeshPhysicalMaterial: .transparency has been renamed to .transmission.' );
46521                         this.transmission = value;
46522
46523                 }
46524         }
46525
46526 } );
46527
46528 Object.defineProperties( ShaderMaterial.prototype, {
46529
46530         derivatives: {
46531                 get: function () {
46532
46533                         console.warn( 'THREE.ShaderMaterial: .derivatives has been moved to .extensions.derivatives.' );
46534                         return this.extensions.derivatives;
46535
46536                 },
46537                 set: function ( value ) {
46538
46539                         console.warn( 'THREE. ShaderMaterial: .derivatives has been moved to .extensions.derivatives.' );
46540                         this.extensions.derivatives = value;
46541
46542                 }
46543         }
46544
46545 } );
46546
46547 //
46548
46549 Object.assign( WebGLRenderer.prototype, {
46550
46551         clearTarget: function ( renderTarget, color, depth, stencil ) {
46552
46553                 console.warn( 'THREE.WebGLRenderer: .clearTarget() has been deprecated. Use .setRenderTarget() and .clear() instead.' );
46554                 this.setRenderTarget( renderTarget );
46555                 this.clear( color, depth, stencil );
46556
46557         },
46558         animate: function ( callback ) {
46559
46560                 console.warn( 'THREE.WebGLRenderer: .animate() is now .setAnimationLoop().' );
46561                 this.setAnimationLoop( callback );
46562
46563         },
46564         getCurrentRenderTarget: function () {
46565
46566                 console.warn( 'THREE.WebGLRenderer: .getCurrentRenderTarget() is now .getRenderTarget().' );
46567                 return this.getRenderTarget();
46568
46569         },
46570         getMaxAnisotropy: function () {
46571
46572                 console.warn( 'THREE.WebGLRenderer: .getMaxAnisotropy() is now .capabilities.getMaxAnisotropy().' );
46573                 return this.capabilities.getMaxAnisotropy();
46574
46575         },
46576         getPrecision: function () {
46577
46578                 console.warn( 'THREE.WebGLRenderer: .getPrecision() is now .capabilities.precision.' );
46579                 return this.capabilities.precision;
46580
46581         },
46582         resetGLState: function () {
46583
46584                 console.warn( 'THREE.WebGLRenderer: .resetGLState() is now .state.reset().' );
46585                 return this.state.reset();
46586
46587         },
46588         supportsFloatTextures: function () {
46589
46590                 console.warn( 'THREE.WebGLRenderer: .supportsFloatTextures() is now .extensions.get( \'OES_texture_float\' ).' );
46591                 return this.extensions.get( 'OES_texture_float' );
46592
46593         },
46594         supportsHalfFloatTextures: function () {
46595
46596                 console.warn( 'THREE.WebGLRenderer: .supportsHalfFloatTextures() is now .extensions.get( \'OES_texture_half_float\' ).' );
46597                 return this.extensions.get( 'OES_texture_half_float' );
46598
46599         },
46600         supportsStandardDerivatives: function () {
46601
46602                 console.warn( 'THREE.WebGLRenderer: .supportsStandardDerivatives() is now .extensions.get( \'OES_standard_derivatives\' ).' );
46603                 return this.extensions.get( 'OES_standard_derivatives' );
46604
46605         },
46606         supportsCompressedTextureS3TC: function () {
46607
46608                 console.warn( 'THREE.WebGLRenderer: .supportsCompressedTextureS3TC() is now .extensions.get( \'WEBGL_compressed_texture_s3tc\' ).' );
46609                 return this.extensions.get( 'WEBGL_compressed_texture_s3tc' );
46610
46611         },
46612         supportsCompressedTexturePVRTC: function () {
46613
46614                 console.warn( 'THREE.WebGLRenderer: .supportsCompressedTexturePVRTC() is now .extensions.get( \'WEBGL_compressed_texture_pvrtc\' ).' );
46615                 return this.extensions.get( 'WEBGL_compressed_texture_pvrtc' );
46616
46617         },
46618         supportsBlendMinMax: function () {
46619
46620                 console.warn( 'THREE.WebGLRenderer: .supportsBlendMinMax() is now .extensions.get( \'EXT_blend_minmax\' ).' );
46621                 return this.extensions.get( 'EXT_blend_minmax' );
46622
46623         },
46624         supportsVertexTextures: function () {
46625
46626                 console.warn( 'THREE.WebGLRenderer: .supportsVertexTextures() is now .capabilities.vertexTextures.' );
46627                 return this.capabilities.vertexTextures;
46628
46629         },
46630         supportsInstancedArrays: function () {
46631
46632                 console.warn( 'THREE.WebGLRenderer: .supportsInstancedArrays() is now .extensions.get( \'ANGLE_instanced_arrays\' ).' );
46633                 return this.extensions.get( 'ANGLE_instanced_arrays' );
46634
46635         },
46636         enableScissorTest: function ( boolean ) {
46637
46638                 console.warn( 'THREE.WebGLRenderer: .enableScissorTest() is now .setScissorTest().' );
46639                 this.setScissorTest( boolean );
46640
46641         },
46642         initMaterial: function () {
46643
46644                 console.warn( 'THREE.WebGLRenderer: .initMaterial() has been removed.' );
46645
46646         },
46647         addPrePlugin: function () {
46648
46649                 console.warn( 'THREE.WebGLRenderer: .addPrePlugin() has been removed.' );
46650
46651         },
46652         addPostPlugin: function () {
46653
46654                 console.warn( 'THREE.WebGLRenderer: .addPostPlugin() has been removed.' );
46655
46656         },
46657         updateShadowMap: function () {
46658
46659                 console.warn( 'THREE.WebGLRenderer: .updateShadowMap() has been removed.' );
46660
46661         },
46662         setFaceCulling: function () {
46663
46664                 console.warn( 'THREE.WebGLRenderer: .setFaceCulling() has been removed.' );
46665
46666         },
46667         allocTextureUnit: function () {
46668
46669                 console.warn( 'THREE.WebGLRenderer: .allocTextureUnit() has been removed.' );
46670
46671         },
46672         setTexture: function () {
46673
46674                 console.warn( 'THREE.WebGLRenderer: .setTexture() has been removed.' );
46675
46676         },
46677         setTexture2D: function () {
46678
46679                 console.warn( 'THREE.WebGLRenderer: .setTexture2D() has been removed.' );
46680
46681         },
46682         setTextureCube: function () {
46683
46684                 console.warn( 'THREE.WebGLRenderer: .setTextureCube() has been removed.' );
46685
46686         },
46687         getActiveMipMapLevel: function () {
46688
46689                 console.warn( 'THREE.WebGLRenderer: .getActiveMipMapLevel() is now .getActiveMipmapLevel().' );
46690                 return this.getActiveMipmapLevel();
46691
46692         }
46693
46694 } );
46695
46696 Object.defineProperties( WebGLRenderer.prototype, {
46697
46698         shadowMapEnabled: {
46699                 get: function () {
46700
46701                         return this.shadowMap.enabled;
46702
46703                 },
46704                 set: function ( value ) {
46705
46706                         console.warn( 'THREE.WebGLRenderer: .shadowMapEnabled is now .shadowMap.enabled.' );
46707                         this.shadowMap.enabled = value;
46708
46709                 }
46710         },
46711         shadowMapType: {
46712                 get: function () {
46713
46714                         return this.shadowMap.type;
46715
46716                 },
46717                 set: function ( value ) {
46718
46719                         console.warn( 'THREE.WebGLRenderer: .shadowMapType is now .shadowMap.type.' );
46720                         this.shadowMap.type = value;
46721
46722                 }
46723         },
46724         shadowMapCullFace: {
46725                 get: function () {
46726
46727                         console.warn( 'THREE.WebGLRenderer: .shadowMapCullFace has been removed. Set Material.shadowSide instead.' );
46728                         return undefined;
46729
46730                 },
46731                 set: function ( /* value */ ) {
46732
46733                         console.warn( 'THREE.WebGLRenderer: .shadowMapCullFace has been removed. Set Material.shadowSide instead.' );
46734
46735                 }
46736         },
46737         context: {
46738                 get: function () {
46739
46740                         console.warn( 'THREE.WebGLRenderer: .context has been removed. Use .getContext() instead.' );
46741                         return this.getContext();
46742
46743                 }
46744         },
46745         vr: {
46746                 get: function () {
46747
46748                         console.warn( 'THREE.WebGLRenderer: .vr has been renamed to .xr' );
46749                         return this.xr;
46750
46751                 }
46752         },
46753         gammaInput: {
46754                 get: function () {
46755
46756                         console.warn( 'THREE.WebGLRenderer: .gammaInput has been removed. Set the encoding for textures via Texture.encoding instead.' );
46757                         return false;
46758
46759                 },
46760                 set: function () {
46761
46762                         console.warn( 'THREE.WebGLRenderer: .gammaInput has been removed. Set the encoding for textures via Texture.encoding instead.' );
46763
46764                 }
46765         },
46766         gammaOutput: {
46767                 get: function () {
46768
46769                         console.warn( 'THREE.WebGLRenderer: .gammaOutput has been removed. Set WebGLRenderer.outputEncoding instead.' );
46770                         return false;
46771
46772                 },
46773                 set: function ( value ) {
46774
46775                         console.warn( 'THREE.WebGLRenderer: .gammaOutput has been removed. Set WebGLRenderer.outputEncoding instead.' );
46776                         this.outputEncoding = ( value === true ) ? sRGBEncoding : LinearEncoding;
46777
46778                 }
46779         },
46780         toneMappingWhitePoint: {
46781                 get: function () {
46782
46783                         console.warn( 'THREE.WebGLRenderer: .toneMappingWhitePoint has been removed.' );
46784                         return 1.0;
46785
46786                 },
46787                 set: function () {
46788
46789                         console.warn( 'THREE.WebGLRenderer: .toneMappingWhitePoint has been removed.' );
46790
46791                 }
46792         },
46793
46794 } );
46795
46796 Object.defineProperties( WebGLShadowMap.prototype, {
46797
46798         cullFace: {
46799                 get: function () {
46800
46801                         console.warn( 'THREE.WebGLRenderer: .shadowMap.cullFace has been removed. Set Material.shadowSide instead.' );
46802                         return undefined;
46803
46804                 },
46805                 set: function ( /* cullFace */ ) {
46806
46807                         console.warn( 'THREE.WebGLRenderer: .shadowMap.cullFace has been removed. Set Material.shadowSide instead.' );
46808
46809                 }
46810         },
46811         renderReverseSided: {
46812                 get: function () {
46813
46814                         console.warn( 'THREE.WebGLRenderer: .shadowMap.renderReverseSided has been removed. Set Material.shadowSide instead.' );
46815                         return undefined;
46816
46817                 },
46818                 set: function () {
46819
46820                         console.warn( 'THREE.WebGLRenderer: .shadowMap.renderReverseSided has been removed. Set Material.shadowSide instead.' );
46821
46822                 }
46823         },
46824         renderSingleSided: {
46825                 get: function () {
46826
46827                         console.warn( 'THREE.WebGLRenderer: .shadowMap.renderSingleSided has been removed. Set Material.shadowSide instead.' );
46828                         return undefined;
46829
46830                 },
46831                 set: function () {
46832
46833                         console.warn( 'THREE.WebGLRenderer: .shadowMap.renderSingleSided has been removed. Set Material.shadowSide instead.' );
46834
46835                 }
46836         }
46837
46838 } );
46839
46840 //
46841
46842 Object.defineProperties( WebGLRenderTarget.prototype, {
46843
46844         wrapS: {
46845                 get: function () {
46846
46847                         console.warn( 'THREE.WebGLRenderTarget: .wrapS is now .texture.wrapS.' );
46848                         return this.texture.wrapS;
46849
46850                 },
46851                 set: function ( value ) {
46852
46853                         console.warn( 'THREE.WebGLRenderTarget: .wrapS is now .texture.wrapS.' );
46854                         this.texture.wrapS = value;
46855
46856                 }
46857         },
46858         wrapT: {
46859                 get: function () {
46860
46861                         console.warn( 'THREE.WebGLRenderTarget: .wrapT is now .texture.wrapT.' );
46862                         return this.texture.wrapT;
46863
46864                 },
46865                 set: function ( value ) {
46866
46867                         console.warn( 'THREE.WebGLRenderTarget: .wrapT is now .texture.wrapT.' );
46868                         this.texture.wrapT = value;
46869
46870                 }
46871         },
46872         magFilter: {
46873                 get: function () {
46874
46875                         console.warn( 'THREE.WebGLRenderTarget: .magFilter is now .texture.magFilter.' );
46876                         return this.texture.magFilter;
46877
46878                 },
46879                 set: function ( value ) {
46880
46881                         console.warn( 'THREE.WebGLRenderTarget: .magFilter is now .texture.magFilter.' );
46882                         this.texture.magFilter = value;
46883
46884                 }
46885         },
46886         minFilter: {
46887                 get: function () {
46888
46889                         console.warn( 'THREE.WebGLRenderTarget: .minFilter is now .texture.minFilter.' );
46890                         return this.texture.minFilter;
46891
46892                 },
46893                 set: function ( value ) {
46894
46895                         console.warn( 'THREE.WebGLRenderTarget: .minFilter is now .texture.minFilter.' );
46896                         this.texture.minFilter = value;
46897
46898                 }
46899         },
46900         anisotropy: {
46901                 get: function () {
46902
46903                         console.warn( 'THREE.WebGLRenderTarget: .anisotropy is now .texture.anisotropy.' );
46904                         return this.texture.anisotropy;
46905
46906                 },
46907                 set: function ( value ) {
46908
46909                         console.warn( 'THREE.WebGLRenderTarget: .anisotropy is now .texture.anisotropy.' );
46910                         this.texture.anisotropy = value;
46911
46912                 }
46913         },
46914         offset: {
46915                 get: function () {
46916
46917                         console.warn( 'THREE.WebGLRenderTarget: .offset is now .texture.offset.' );
46918                         return this.texture.offset;
46919
46920                 },
46921                 set: function ( value ) {
46922
46923                         console.warn( 'THREE.WebGLRenderTarget: .offset is now .texture.offset.' );
46924                         this.texture.offset = value;
46925
46926                 }
46927         },
46928         repeat: {
46929                 get: function () {
46930
46931                         console.warn( 'THREE.WebGLRenderTarget: .repeat is now .texture.repeat.' );
46932                         return this.texture.repeat;
46933
46934                 },
46935                 set: function ( value ) {
46936
46937                         console.warn( 'THREE.WebGLRenderTarget: .repeat is now .texture.repeat.' );
46938                         this.texture.repeat = value;
46939
46940                 }
46941         },
46942         format: {
46943                 get: function () {
46944
46945                         console.warn( 'THREE.WebGLRenderTarget: .format is now .texture.format.' );
46946                         return this.texture.format;
46947
46948                 },
46949                 set: function ( value ) {
46950
46951                         console.warn( 'THREE.WebGLRenderTarget: .format is now .texture.format.' );
46952                         this.texture.format = value;
46953
46954                 }
46955         },
46956         type: {
46957                 get: function () {
46958
46959                         console.warn( 'THREE.WebGLRenderTarget: .type is now .texture.type.' );
46960                         return this.texture.type;
46961
46962                 },
46963                 set: function ( value ) {
46964
46965                         console.warn( 'THREE.WebGLRenderTarget: .type is now .texture.type.' );
46966                         this.texture.type = value;
46967
46968                 }
46969         },
46970         generateMipmaps: {
46971                 get: function () {
46972
46973                         console.warn( 'THREE.WebGLRenderTarget: .generateMipmaps is now .texture.generateMipmaps.' );
46974                         return this.texture.generateMipmaps;
46975
46976                 },
46977                 set: function ( value ) {
46978
46979                         console.warn( 'THREE.WebGLRenderTarget: .generateMipmaps is now .texture.generateMipmaps.' );
46980                         this.texture.generateMipmaps = value;
46981
46982                 }
46983         }
46984
46985 } );
46986
46987 //
46988
46989 Object.defineProperties( Audio.prototype, {
46990
46991         load: {
46992                 value: function ( file ) {
46993
46994                         console.warn( 'THREE.Audio: .load has been deprecated. Use THREE.AudioLoader instead.' );
46995                         const scope = this;
46996                         const audioLoader = new AudioLoader();
46997                         audioLoader.load( file, function ( buffer ) {
46998
46999                                 scope.setBuffer( buffer );
47000
47001                         } );
47002                         return this;
47003
47004                 }
47005         },
47006         startTime: {
47007                 set: function () {
47008
47009                         console.warn( 'THREE.Audio: .startTime is now .play( delay ).' );
47010
47011                 }
47012         }
47013
47014 } );
47015
47016 //
47017
47018 CubeCamera.prototype.updateCubeMap = function ( renderer, scene ) {
47019
47020         console.warn( 'THREE.CubeCamera: .updateCubeMap() is now .update().' );
47021         return this.update( renderer, scene );
47022
47023 };
47024
47025 CubeCamera.prototype.clear = function ( renderer, color, depth, stencil ) {
47026
47027         console.warn( 'THREE.CubeCamera: .clear() is now .renderTarget.clear().' );
47028         return this.renderTarget.clear( renderer, color, depth, stencil );
47029
47030 };
47031
47032 ImageUtils.crossOrigin = undefined;
47033
47034 ImageUtils.loadTexture = function ( url, mapping, onLoad, onError ) {
47035
47036         console.warn( 'THREE.ImageUtils.loadTexture has been deprecated. Use THREE.TextureLoader() instead.' );
47037
47038         const loader = new TextureLoader();
47039         loader.setCrossOrigin( this.crossOrigin );
47040
47041         const texture = loader.load( url, onLoad, undefined, onError );
47042
47043         if ( mapping ) texture.mapping = mapping;
47044
47045         return texture;
47046
47047 };
47048
47049 ImageUtils.loadTextureCube = function ( urls, mapping, onLoad, onError ) {
47050
47051         console.warn( 'THREE.ImageUtils.loadTextureCube has been deprecated. Use THREE.CubeTextureLoader() instead.' );
47052
47053         const loader = new CubeTextureLoader();
47054         loader.setCrossOrigin( this.crossOrigin );
47055
47056         const texture = loader.load( urls, onLoad, undefined, onError );
47057
47058         if ( mapping ) texture.mapping = mapping;
47059
47060         return texture;
47061
47062 };
47063
47064 ImageUtils.loadCompressedTexture = function () {
47065
47066         console.error( 'THREE.ImageUtils.loadCompressedTexture has been removed. Use THREE.DDSLoader instead.' );
47067
47068 };
47069
47070 ImageUtils.loadCompressedTextureCube = function () {
47071
47072         console.error( 'THREE.ImageUtils.loadCompressedTextureCube has been removed. Use THREE.DDSLoader instead.' );
47073
47074 };
47075
47076 if ( typeof __THREE_DEVTOOLS__ !== 'undefined' ) {
47077
47078         /* eslint-disable no-undef */
47079         __THREE_DEVTOOLS__.dispatchEvent( new CustomEvent( 'register', { detail: {
47080                 revision: REVISION,
47081         } } ) );
47082         /* eslint-enable no-undef */
47083
47084 }
47085
47086 if ( typeof window !== 'undefined' ) {
47087
47088         if ( window.__THREE__ ) {
47089
47090                 console.warn( 'WARNING: Multiple instances of Three.js being imported.' );
47091
47092         } else {
47093
47094                 window.__THREE__ = REVISION;
47095
47096         }
47097
47098 }
47099
47100 const DEG2RAD = Math.PI / 180;
47101 const RAD2DEG = 180 / Math.PI;
47102 const WGS84A = 6378137.0;
47103 const WGS84B = 6356752.31424518;
47104 /**
47105  * Convert coordinates from geodetic (WGS84) reference to local topocentric
47106  * (ENU) reference.
47107  *
47108  * @param {number} lng Longitude in degrees.
47109  * @param {number} lat Latitude in degrees.
47110  * @param {number} alt Altitude in meters.
47111  * @param {number} refLng Reference longitude in degrees.
47112  * @param {number} refLat Reference latitude in degrees.
47113  * @param {number} refAlt Reference altitude in meters.
47114  * @returns {Array<number>} The x, y, z local topocentric ENU coordinates.
47115  */
47116 function geodeticToEnu(lng, lat, alt, refLng, refLat, refAlt) {
47117     const ecef = geodeticToEcef(lng, lat, alt);
47118     return ecefToEnu(ecef[0], ecef[1], ecef[2], refLng, refLat, refAlt);
47119 }
47120 /**
47121  * Convert coordinates from local topocentric (ENU) reference to
47122  * geodetic (WGS84) reference.
47123  *
47124  * @param {number} x Topocentric ENU coordinate in East direction.
47125  * @param {number} y Topocentric ENU coordinate in North direction.
47126  * @param {number} z Topocentric ENU coordinate in Up direction.
47127  * @param {number} refLng Reference longitude in degrees.
47128  * @param {number} refLat Reference latitude in degrees.
47129  * @param {number} refAlt Reference altitude in meters.
47130  * @returns {Array<number>} The longitude, latitude in degrees
47131  * and altitude in meters.
47132  */
47133 function enuToGeodetic(x, y, z, refLng, refLat, refAlt) {
47134     const ecef = enuToEcef(x, y, z, refLng, refLat, refAlt);
47135     return ecefToGeodetic(ecef[0], ecef[1], ecef[2]);
47136 }
47137 /**
47138  * Convert coordinates from Earth-Centered, Earth-Fixed (ECEF) reference
47139  * to local topocentric (ENU) reference.
47140  *
47141  * @param {number} X ECEF X-value.
47142  * @param {number} Y ECEF Y-value.
47143  * @param {number} Z ECEF Z-value.
47144  * @param {number} refLng Reference longitude in degrees.
47145  * @param {number} refLat Reference latitude in degrees.
47146  * @param {number} refAlt Reference altitude in meters.
47147  * @returns {Array<number>} The x, y, z topocentric ENU coordinates in East, North
47148  * and Up directions respectively.
47149  */
47150 function ecefToEnu(X, Y, Z, refLng, refLat, refAlt) {
47151     const refEcef = geodeticToEcef(refLng, refLat, refAlt);
47152     const V = [
47153         X - refEcef[0],
47154         Y - refEcef[1],
47155         Z - refEcef[2],
47156     ];
47157     refLng = refLng * DEG2RAD;
47158     refLat = refLat * DEG2RAD;
47159     const cosLng = Math.cos(refLng);
47160     const sinLng = Math.sin(refLng);
47161     const cosLat = Math.cos(refLat);
47162     const sinLat = Math.sin(refLat);
47163     const x = -sinLng * V[0] + cosLng * V[1];
47164     const y = -sinLat * cosLng * V[0] - sinLat * sinLng * V[1] + cosLat * V[2];
47165     const z = cosLat * cosLng * V[0] + cosLat * sinLng * V[1] + sinLat * V[2];
47166     return [x, y, z];
47167 }
47168 /**
47169  * Convert coordinates from local topocentric (ENU) reference
47170  * to Earth-Centered, Earth-Fixed (ECEF) reference.
47171  *
47172  * @param {number} x Topocentric ENU coordinate in East direction.
47173  * @param {number} y Topocentric ENU coordinate in North direction.
47174  * @param {number} z Topocentric ENU coordinate in Up direction.
47175  * @param {number} refLng Reference longitude in degrees.
47176  * @param {number} refLat Reference latitude in degrees.
47177  * @param {number} refAlt Reference altitude in meters.
47178  * @returns {Array<number>} The X, Y, Z ECEF coordinates.
47179  */
47180 function enuToEcef(x, y, z, refLng, refLat, refAlt) {
47181     const refEcef = geodeticToEcef(refLng, refLat, refAlt);
47182     refLng = refLng * DEG2RAD;
47183     refLat = refLat * DEG2RAD;
47184     const cosLng = Math.cos(refLng);
47185     const sinLng = Math.sin(refLng);
47186     const cosLat = Math.cos(refLat);
47187     const sinLat = Math.sin(refLat);
47188     const X = -sinLng * x
47189         - sinLat * cosLng * y
47190         + cosLat * cosLng * z
47191         + refEcef[0];
47192     const Y = cosLng * x
47193         - sinLat * sinLng * y
47194         + cosLat * sinLng * z
47195         + refEcef[1];
47196     const Z = cosLat * y +
47197         sinLat * z +
47198         refEcef[2];
47199     return [X, Y, Z];
47200 }
47201 /**
47202  * Convert coordinates from geodetic reference (WGS84) to Earth-Centered,
47203  * Earth-Fixed (ECEF) reference.
47204  *
47205  * @param {number} lng Longitude in degrees.
47206  * @param {number} lat Latitude in degrees.
47207  * @param {number} alt Altitude in meters.
47208  * @returns {Array<number>} The X, Y, Z ECEF coordinates.
47209  */
47210 function geodeticToEcef(lng, lat, alt) {
47211     const a = WGS84A;
47212     const b = WGS84B;
47213     lng = lng * DEG2RAD;
47214     lat = lat * DEG2RAD;
47215     const cosLng = Math.cos(lng);
47216     const sinLng = Math.sin(lng);
47217     const cosLat = Math.cos(lat);
47218     const sinLat = Math.sin(lat);
47219     const a2 = a * a;
47220     const b2 = b * b;
47221     const L = 1.0 / Math.sqrt(a2 * cosLat * cosLat + b2 * sinLat * sinLat);
47222     const nhcl = (a2 * L + alt) * cosLat;
47223     const X = nhcl * cosLng;
47224     const Y = nhcl * sinLng;
47225     const Z = (b2 * L + alt) * sinLat;
47226     return [X, Y, Z];
47227 }
47228 /**
47229  * Convert coordinates from Earth-Centered, Earth-Fixed (ECEF) reference
47230  * to geodetic reference (WGS84).
47231  *
47232  * @param {number} X ECEF X-value.
47233  * @param {number} Y ECEF Y-value.
47234  * @param {number} Z ECEF Z-value.
47235  * @returns {Array<number>} The longitude, latitude in degrees
47236  * and altitude in meters.
47237  */
47238 function ecefToGeodetic(X, Y, Z) {
47239     const a = WGS84A;
47240     const b = WGS84B;
47241     const a2 = a * a;
47242     const b2 = b * b;
47243     const a2mb2 = a2 - b2;
47244     const ea = Math.sqrt(a2mb2 / a2);
47245     const eb = Math.sqrt(a2mb2 / b2);
47246     const p = Math.sqrt(X * X + Y * Y);
47247     const theta = Math.atan2(Z * a, p * b);
47248     const sinTheta = Math.sin(theta);
47249     const cosTheta = Math.cos(theta);
47250     const lng = Math.atan2(Y, X);
47251     const lat = Math.atan2(Z + eb * eb * b * sinTheta * sinTheta * sinTheta, p - ea * ea * a * cosTheta * cosTheta * cosTheta);
47252     const sinLat = Math.sin(lat);
47253     const cosLat = Math.cos(lat);
47254     const N = a / Math.sqrt(1 - ea * ea * sinLat * sinLat);
47255     const alt = p / cosLat - N;
47256     return [
47257         lng * RAD2DEG,
47258         lat * RAD2DEG,
47259         alt
47260     ];
47261 }
47262
47263 /**
47264  * @class GraphCalculator
47265  *
47266  * @classdesc Represents a calculator for graph entities.
47267  */
47268 class GraphCalculator {
47269     /**
47270      * Get the bounding box corners for a circle with radius of a threshold
47271      * with center in a geodetic position.
47272      *
47273      * @param {LngLat} lngLat - Longitude, latitude to encode.
47274      * @param {number} threshold - Threshold distance from the position in meters.
47275      *
47276      * @returns {Array<LngLat>} The south west and north east corners of the
47277      * bounding box.
47278      */
47279     boundingBoxCorners(lngLat, threshold) {
47280         const sw = enuToGeodetic(-threshold, -threshold, 0, lngLat.lng, lngLat.lat, 0);
47281         const ne = enuToGeodetic(threshold, threshold, 0, lngLat.lng, lngLat.lat, 0);
47282         return [
47283             { lat: sw[1], lng: sw[0] },
47284             { lat: ne[1], lng: ne[0] },
47285         ];
47286     }
47287     /**
47288      * Convert a compass angle to an angle axis rotation vector.
47289      *
47290      * @param {number} compassAngle - The compass angle in degrees.
47291      * @param {number} orientation - The orientation of the original image.
47292      *
47293      * @returns {Array<number>} Angle axis rotation vector.
47294      */
47295     rotationFromCompass(compassAngle, orientation) {
47296         let x = 0;
47297         let y = 0;
47298         let z = 0;
47299         switch (orientation) {
47300             case 1:
47301                 x = Math.PI / 2;
47302                 break;
47303             case 3:
47304                 x = -Math.PI / 2;
47305                 z = Math.PI;
47306                 break;
47307             case 6:
47308                 y = -Math.PI / 2;
47309                 z = -Math.PI / 2;
47310                 break;
47311             case 8:
47312                 y = Math.PI / 2;
47313                 z = Math.PI / 2;
47314                 break;
47315         }
47316         const rz = new Matrix4()
47317             .makeRotationZ(z);
47318         const euler = new Euler(x, y, compassAngle * Math.PI / 180, "XYZ");
47319         const re = new Matrix4()
47320             .makeRotationFromEuler(euler);
47321         const rotation = new Vector4()
47322             .setAxisAngleFromRotationMatrix(re.multiply(rz));
47323         return rotation
47324             .multiplyScalar(rotation.w)
47325             .toArray()
47326             .slice(0, 3);
47327     }
47328 }
47329
47330 /**
47331  * @class Image
47332  *
47333  * @classdesc Represents a image in the navigation graph.
47334  *
47335  * Explanation of position and bearing properties:
47336  *
47337  * When images are uploaded they will have GPS information in the EXIF, this is what
47338  * is called `originalLngLat` {@link Image.originalLngLat}.
47339  *
47340  * When Structure from Motions has been run for a image a `computedLngLat` that
47341  * differs from the `originalLngLat` will be created. It is different because
47342  * GPS positions are not very exact and SfM aligns the camera positions according
47343  * to the 3D reconstruction {@link Image.computedLngLat}.
47344  *
47345  * At last there exist a `lngLat` property which evaluates to
47346  * the `computedLngLat` from SfM if it exists but falls back
47347  * to the `originalLngLat` from the EXIF GPS otherwise {@link Image.lngLat}.
47348  *
47349  * Everything that is done in in the Viewer is based on the SfM positions,
47350  * i.e. `computedLngLat`. That is why the smooth transitions go in the right
47351  * direction (nd not in strange directions because of bad GPS).
47352  *
47353  * E.g. when placing a marker in the Viewer it is relative to the SfM
47354  * position i.e. the `computedLngLat`.
47355  *
47356  * The same concept as above also applies to the compass angle (or bearing) properties
47357  * `originalCa`, `computedCa` and `ca`.
47358  */
47359 class Image$1 {
47360     /**
47361      * Create a new image instance.
47362      *
47363      * @description Images are always created internally by the library.
47364      * Images can not be added to the library through any API method.
47365      *
47366      * @param {CoreImageEnt} core- Raw core image data.
47367      * @ignore
47368      */
47369     constructor(core) {
47370         if (!core) {
47371             throw new Error(`Incorrect core image data ${core}`);
47372         }
47373         this._cache = null;
47374         this._core = core;
47375         this._spatial = null;
47376     }
47377     /**
47378      * Get assets cached.
47379      *
47380      * @description The assets that need to be cached for this property
47381      * to report true are the following: fill properties, image and mesh.
47382      * The library ensures that the current image will always have the
47383      * assets cached.
47384      *
47385      * @returns {boolean} Value indicating whether all assets have been
47386      * cached.
47387      *
47388      * @ignore
47389      */
47390     get assetsCached() {
47391         return this._core != null &&
47392             this._spatial != null &&
47393             this._cache != null &&
47394             this._cache.image != null &&
47395             this._cache.mesh != null;
47396     }
47397     /**
47398      * Get cameraParameters.
47399      *
47400      * @description Will be undefined if SfM has
47401      * not been run.
47402      *
47403      * Camera type dependent parameters.
47404      *
47405      * For perspective and fisheye camera types,
47406      * the camera parameters array should be
47407      * constructed according to
47408      *
47409      * `[focal, k1, k2]`
47410      *
47411      * where focal is the camera focal length,
47412      * and k1, k2 are radial distortion parameters.
47413      *
47414      * For spherical camera type the camera
47415      * parameters are unset or emtpy array.
47416      *
47417      * @returns {Array<number>} The parameters
47418      * related to the camera type.
47419      */
47420     get cameraParameters() {
47421         return this._spatial.camera_parameters;
47422     }
47423     /**
47424      * Get cameraType.
47425      *
47426      * @description Will be undefined if SfM has not been run.
47427      *
47428      * @returns {string} The camera type that captured the image.
47429      */
47430     get cameraType() {
47431         return this._spatial.camera_type;
47432     }
47433     /**
47434      * Get capturedAt.
47435      *
47436      * @description Timestamp of the image capture date
47437      * and time represented as a Unix epoch timestamp in milliseconds.
47438      *
47439      * @returns {number} Timestamp when the image was captured.
47440      */
47441     get capturedAt() {
47442         return this._spatial.captured_at;
47443     }
47444     /**
47445      * Get clusterId.
47446      *
47447      * @returns {string} Globally unique id of the SfM cluster to which
47448      * the image belongs.
47449      */
47450     get clusterId() {
47451         return !!this._spatial.cluster ?
47452             this._spatial.cluster.id :
47453             null;
47454     }
47455     /**
47456      * Get clusterUrl.
47457      *
47458      * @returns {string} Url to the cluster reconstruction file.
47459      *
47460      * @ignore
47461      */
47462     get clusterUrl() {
47463         return !!this._spatial.cluster ?
47464             this._spatial.cluster.url :
47465             null;
47466     }
47467     /**
47468      * Get compassAngle.
47469      *
47470      * @description If the SfM computed compass angle exists it will
47471      * be returned, otherwise the original EXIF compass angle.
47472      *
47473      * @returns {number} Compass angle, measured in degrees
47474      * clockwise with respect to north.
47475      */
47476     get compassAngle() {
47477         return this._spatial.computed_compass_angle != null ?
47478             this._spatial.computed_compass_angle :
47479             this._spatial.compass_angle;
47480     }
47481     /**
47482      * Get complete.
47483      *
47484      * @description The library ensures that the current image will
47485      * always be full.
47486      *
47487      * @returns {boolean} Value indicating whether the image has all
47488      * properties filled.
47489      *
47490      * @ignore
47491      */
47492     get complete() {
47493         return this._spatial != null;
47494     }
47495     /**
47496      * Get computedAltitude.
47497      *
47498      * @description If SfM has not been run the computed altitude is
47499      * set to a default value of two meters.
47500      *
47501      * @returns {number} Altitude, in meters.
47502      */
47503     get computedAltitude() {
47504         return this._spatial.computed_altitude;
47505     }
47506     /**
47507      * Get computedCompassAngle.
47508      *
47509      * @description Will not be set if SfM has not been run.
47510      *
47511      * @returns {number} SfM computed compass angle, measured
47512      * in degrees clockwise with respect to north.
47513      */
47514     get computedCompassAngle() {
47515         return this._spatial.computed_compass_angle;
47516     }
47517     /**
47518      * Get computedLngLat.
47519      *
47520      * @description Will not be set if SfM has not been run.
47521      *
47522      * @returns {LngLat} SfM computed longitude, latitude in WGS84 datum,
47523      * measured in degrees.
47524      */
47525     get computedLngLat() {
47526         return this._core.computed_geometry;
47527     }
47528     /**
47529      * Get creatorId.
47530      *
47531      * @description Note that the creator ID will not be set when using
47532      * the Mapillary API.
47533      *
47534      * @returns {string} Globally unique id of the user who uploaded
47535      * the image.
47536      */
47537     get creatorId() {
47538         return this._spatial.creator.id;
47539     }
47540     /**
47541      * Get creatorUsername.
47542      *
47543      * @description Note that the creator username will not be set when
47544      * using the Mapillary API.
47545      *
47546      * @returns {string} Username of the creator who uploaded
47547      * the image.
47548      */
47549     get creatorUsername() {
47550         return this._spatial.creator.username;
47551     }
47552     /**
47553      * Get exifOrientation.
47554      *
47555      * @returns {number} EXIF orientation of original image.
47556      */
47557     get exifOrientation() {
47558         return this._spatial.exif_orientation;
47559     }
47560     /**
47561      * Get height.
47562      *
47563      * @returns {number} Height of original image, not adjusted
47564      * for orientation.
47565      */
47566     get height() {
47567         return this._spatial.height;
47568     }
47569     /**
47570      * Get image.
47571      *
47572      * @description The image will always be set on the current image.
47573      *
47574      * @returns {HTMLImageElement} Cached image element of the image.
47575      */
47576     get image() {
47577         return this._cache.image;
47578     }
47579     /**
47580      * Get image$.
47581      *
47582      * @returns {Observable<HTMLImageElement>} Observable emitting
47583      * the cached image when it is updated.
47584      *
47585      * @ignore
47586      */
47587     get image$() {
47588         return this._cache.image$;
47589     }
47590     /**
47591      * Get id.
47592      *
47593      * @returns {string} Globally unique id of the image.
47594      */
47595     get id() {
47596         return this._core.id;
47597     }
47598     /**
47599      * Get lngLat.
47600      *
47601      * @description If the SfM computed longitude, latitude exist
47602      * it will be returned, otherwise the original EXIF latitude
47603      * longitude.
47604      *
47605      * @returns {LngLat} Longitude, latitude in WGS84 datum,
47606      * measured in degrees.
47607      */
47608     get lngLat() {
47609         return this._core.computed_geometry != null ?
47610             this._core.computed_geometry :
47611             this._core.geometry;
47612     }
47613     /**
47614      * Get merged.
47615      *
47616      * @returns {boolean} Value indicating whether SfM has been
47617      * run on the image and the image has been merged into a
47618      * connected component.
47619      */
47620     get merged() {
47621         return this._spatial != null &&
47622             this._spatial.merge_id != null;
47623     }
47624     /**
47625      * Get mergeId.
47626      *
47627      * @description Will not be set if SfM has not yet been run on
47628      * image.
47629      *
47630      * @returns {stirng} Id of connected component to which image
47631      * belongs after the aligning merge.
47632      */
47633     get mergeId() {
47634         return this._spatial.merge_id;
47635     }
47636     /**
47637      * Get mesh.
47638      *
47639      * @description The mesh will always be set on the current image.
47640      *
47641      * @returns {MeshContract} SfM triangulated mesh of reconstructed
47642      * atomic 3D points.
47643      */
47644     get mesh() {
47645         return this._cache.mesh;
47646     }
47647     /**
47648      * Get originalAltitude.
47649      *
47650      * @returns {number} EXIF altitude, in meters, if available.
47651      */
47652     get originalAltitude() {
47653         return this._spatial.altitude;
47654     }
47655     /**
47656      * Get originalCompassAngle.
47657      *
47658      * @returns {number} Original EXIF compass angle, measured in
47659      * degrees.
47660      */
47661     get originalCompassAngle() {
47662         return this._spatial.compass_angle;
47663     }
47664     /**
47665      * Get originalLngLat.
47666      *
47667      * @returns {LngLat} Original EXIF longitude, latitude in
47668      * WGS84 datum, measured in degrees.
47669      */
47670     get originalLngLat() {
47671         return this._core.geometry;
47672     }
47673     /**
47674      * Get ownerId.
47675      *
47676      * @returns {string} Globally unique id of the owner to which
47677      * the image belongs. If the image does not belong to an
47678      * owner the owner id will be undefined.
47679      */
47680     get ownerId() {
47681         return !!this._spatial.owner ?
47682             this._spatial.owner.id :
47683             null;
47684     }
47685     /**
47686      * Get private.
47687      *
47688      * @returns {boolean} Value specifying if image is accessible to
47689      * organization members only or to everyone.
47690      */
47691     get private() {
47692         return this._spatial.private;
47693     }
47694     /**
47695      * Get qualityScore.
47696      *
47697      * @returns {number} A number between zero and one
47698      * determining the quality of the image. Blurriness
47699      * (motion blur / out-of-focus), occlusion (camera
47700      * mount, ego vehicle, water-drops), windshield
47701      * reflections, bad illumination (exposure, glare),
47702      * and bad weather condition (fog, rain, snow)
47703      * affect the quality score.
47704      *
47705      * @description Value should be on the interval [0, 1].
47706      */
47707     get qualityScore() {
47708         return this._spatial.quality_score;
47709     }
47710     /**
47711      * Get rotation.
47712      *
47713      * @description Will not be set if SfM has not been run.
47714      *
47715      * @returns {Array<number>} Rotation vector in angle axis representation.
47716      */
47717     get rotation() {
47718         return this._spatial.computed_rotation;
47719     }
47720     /**
47721      * Get scale.
47722      *
47723      * @description Will not be set if SfM has not been run.
47724      *
47725      * @returns {number} Scale of reconstruction the image
47726      * belongs to.
47727      */
47728     get scale() {
47729         return this._spatial.atomic_scale;
47730     }
47731     /**
47732      * Get sequenceId.
47733      *
47734      * @returns {string} Globally unique id of the sequence
47735      * to which the image belongs.
47736      */
47737     get sequenceId() {
47738         return !!this._core.sequence ?
47739             this._core.sequence.id :
47740             null;
47741     }
47742     /**
47743      * Get sequenceEdges.
47744      *
47745      * @returns {NavigationEdgeStatus} Value describing the status of the
47746      * sequence edges.
47747      *
47748      * @ignore
47749      */
47750     get sequenceEdges() {
47751         return this._cache.sequenceEdges;
47752     }
47753     /**
47754      * Get sequenceEdges$.
47755      *
47756      * @description Internal observable, should not be used as an API.
47757      *
47758      * @returns {Observable<NavigationEdgeStatus>} Observable emitting
47759      * values describing the status of the sequence edges.
47760      *
47761      * @ignore
47762      */
47763     get sequenceEdges$() {
47764         return this._cache.sequenceEdges$;
47765     }
47766     /**
47767      * Get spatialEdges.
47768      *
47769      * @returns {NavigationEdgeStatus} Value describing the status of the
47770      * spatial edges.
47771      *
47772      * @ignore
47773      */
47774     get spatialEdges() {
47775         return this._cache.spatialEdges;
47776     }
47777     /**
47778      * Get spatialEdges$.
47779      *
47780      * @description Internal observable, should not be used as an API.
47781      *
47782      * @returns {Observable<NavigationEdgeStatus>} Observable emitting
47783      * values describing the status of the spatial edges.
47784      *
47785      * @ignore
47786      */
47787     get spatialEdges$() {
47788         return this._cache.spatialEdges$;
47789     }
47790     /**
47791      * Get width.
47792      *
47793      * @returns {number} Width of original image, not
47794      * adjusted for orientation.
47795      */
47796     get width() {
47797         return this._spatial.width;
47798     }
47799     /**
47800      * Cache the image and mesh assets.
47801      *
47802      * @description The assets are always cached internally by the
47803      * library prior to setting a image as the current image.
47804      *
47805      * @returns {Observable<Image>} Observable emitting this image whenever the
47806      * load status has changed and when the mesh or image has been fully loaded.
47807      *
47808      * @ignore
47809      */
47810     cacheAssets$() {
47811         return this._cache
47812             .cacheAssets$(this._spatial, this.merged)
47813             .pipe(map(() => { return this; }));
47814     }
47815     /**
47816      * Cache the image asset.
47817      *
47818      * @description Use for caching a differently sized image than
47819      * the one currently held by the image.
47820      *
47821      * @returns {Observable<Image>} Observable emitting this image whenever the
47822      * load status has changed and when the mesh or image has been fully loaded.
47823      *
47824      * @ignore
47825      */
47826     cacheImage$() {
47827         return this._cache
47828             .cacheImage$(this._spatial)
47829             .pipe(map(() => { return this; }));
47830     }
47831     /**
47832      * Cache the sequence edges.
47833      *
47834      * @description The sequence edges are cached asynchronously
47835      * internally by the library.
47836      *
47837      * @param {Array<NavigationEdge>} edges - Sequence edges to cache.
47838      * @ignore
47839      */
47840     cacheSequenceEdges(edges) {
47841         this._cache.cacheSequenceEdges(edges);
47842     }
47843     /**
47844      * Cache the spatial edges.
47845      *
47846      * @description The spatial edges are cached asynchronously
47847      * internally by the library.
47848      *
47849      * @param {Array<NavigationEdge>} edges - Spatial edges to cache.
47850      * @ignore
47851      */
47852     cacheSpatialEdges(edges) {
47853         this._cache.cacheSpatialEdges(edges);
47854     }
47855     /**
47856      * Dispose the image.
47857      *
47858      * @description Disposes all cached assets.
47859      * @ignore
47860      */
47861     dispose() {
47862         if (this._cache != null) {
47863             this._cache.dispose();
47864             this._cache = null;
47865         }
47866         this._core = null;
47867         this._spatial = null;
47868     }
47869     /**
47870      * Initialize the image cache.
47871      *
47872      * @description The image cache is initialized internally by
47873      * the library.
47874      *
47875      * @param {ImageCache} cache - The image cache to set as cache.
47876      * @ignore
47877      */
47878     initializeCache(cache) {
47879         if (this._cache != null) {
47880             throw new Error(`Image cache already initialized (${this.id}).`);
47881         }
47882         this._cache = cache;
47883     }
47884     /**
47885      * Complete an image with spatial properties.
47886      *
47887      * @description The image is completed internally by
47888      * the library.
47889      *
47890      * @param {SpatialImageEnt} fill - The spatial image struct.
47891      * @ignore
47892      */
47893     makeComplete(fill) {
47894         if (fill == null) {
47895             throw new Error("Fill can not be null.");
47896         }
47897         this._spatial = fill;
47898     }
47899     /**
47900      * Reset the sequence edges.
47901      *
47902      * @ignore
47903      */
47904     resetSequenceEdges() {
47905         this._cache.resetSequenceEdges();
47906     }
47907     /**
47908      * Reset the spatial edges.
47909      *
47910      * @ignore
47911      */
47912     resetSpatialEdges() {
47913         this._cache.resetSpatialEdges();
47914     }
47915     /**
47916      * Clears the image and mesh assets, aborts
47917      * any outstanding requests and resets edges.
47918      *
47919      * @ignore
47920      */
47921     uncache() {
47922         if (this._cache == null) {
47923             return;
47924         }
47925         this._cache.dispose();
47926         this._cache = null;
47927     }
47928 }
47929
47930 /**
47931  * @class ImageCache
47932  *
47933  * @classdesc Represents the cached properties of a image.
47934  */
47935 class ImageCache {
47936     /**
47937      * Create a new image cache instance.
47938      */
47939     constructor(provider) {
47940         this._disposed = false;
47941         this._provider = provider;
47942         this._image = null;
47943         this._mesh = null;
47944         this._sequenceEdges = { cached: false, edges: [] };
47945         this._spatialEdges = { cached: false, edges: [] };
47946         this._imageChanged$ = new Subject();
47947         this._image$ = this._imageChanged$.pipe(startWith(null), publishReplay(1), refCount());
47948         this._iamgeSubscription = this._image$.subscribe();
47949         this._sequenceEdgesChanged$ = new Subject();
47950         this._sequenceEdges$ = this._sequenceEdgesChanged$.pipe(startWith(this._sequenceEdges), publishReplay(1), refCount());
47951         this._sequenceEdgesSubscription = this._sequenceEdges$.subscribe(() => { });
47952         this._spatialEdgesChanged$ = new Subject();
47953         this._spatialEdges$ = this._spatialEdgesChanged$.pipe(startWith(this._spatialEdges), publishReplay(1), refCount());
47954         this._spatialEdgesSubscription = this._spatialEdges$.subscribe(() => { });
47955         this._cachingAssets$ = null;
47956     }
47957     /**
47958      * Get image.
47959      *
47960      * @description Will not be set when assets have not been cached
47961      * or when the object has been disposed.
47962      *
47963      * @returns {HTMLImageElement} Cached image element of the image.
47964      */
47965     get image() {
47966         return this._image;
47967     }
47968     /**
47969      * Get image$.
47970      *
47971      * @returns {Observable<HTMLImageElement>} Observable emitting
47972      * the cached image when it is updated.
47973      */
47974     get image$() {
47975         return this._image$;
47976     }
47977     /**
47978      * Get mesh.
47979      *
47980      * @description Will not be set when assets have not been cached
47981      * or when the object has been disposed.
47982      *
47983      * @returns {MeshContract} SfM triangulated mesh of reconstructed
47984      * atomic 3D points.
47985      */
47986     get mesh() {
47987         return this._mesh;
47988     }
47989     /**
47990      * Get sequenceEdges.
47991      *
47992      * @returns {NavigationEdgeStatus} Value describing the status of the
47993      * sequence edges.
47994      */
47995     get sequenceEdges() {
47996         return this._sequenceEdges;
47997     }
47998     /**
47999      * Get sequenceEdges$.
48000      *
48001      * @returns {Observable<NavigationEdgeStatus>} Observable emitting
48002      * values describing the status of the sequence edges.
48003      */
48004     get sequenceEdges$() {
48005         return this._sequenceEdges$;
48006     }
48007     /**
48008      * Get spatialEdges.
48009      *
48010      * @returns {NavigationEdgeStatus} Value describing the status of the
48011      * spatial edges.
48012      */
48013     get spatialEdges() {
48014         return this._spatialEdges;
48015     }
48016     /**
48017      * Get spatialEdges$.
48018      *
48019      * @returns {Observable<NavigationEdgeStatus>} Observable emitting
48020      * values describing the status of the spatial edges.
48021      */
48022     get spatialEdges$() {
48023         return this._spatialEdges$;
48024     }
48025     /**
48026      * Cache the image and mesh assets.
48027      *
48028      * @param {SpatialImageEnt} spatial - Spatial props of the image to cache.
48029      * @param {boolean} spherical - Value indicating whether image is a spherical.
48030      * @param {boolean} merged - Value indicating whether image is merged.
48031      * @returns {Observable<ImageCache>} Observable emitting this image
48032      * cache whenever the load status has changed and when the mesh or image
48033      * has been fully loaded.
48034      */
48035     cacheAssets$(spatial, merged) {
48036         if (this._cachingAssets$ != null) {
48037             return this._cachingAssets$;
48038         }
48039         this._cachingAssets$ = combineLatest(this._cacheImage$(spatial), this._cacheMesh$(spatial, merged)).pipe(map(([image, mesh]) => {
48040             this._image = image;
48041             this._mesh = mesh;
48042             return this;
48043         }), finalize(() => {
48044             this._cachingAssets$ = null;
48045         }), publishReplay(1), refCount());
48046         this._cachingAssets$.pipe(first((imageCache) => {
48047             return !!imageCache._image;
48048         }))
48049             .subscribe(() => {
48050             this._imageChanged$.next(this._image);
48051         }, () => { });
48052         return this._cachingAssets$;
48053     }
48054     /**
48055      * Cache an image with a higher resolution than the current one.
48056      *
48057      * @param {SpatialImageEnt} spatial - Spatial props.
48058      * @returns {Observable<ImageCache>} Observable emitting a single item,
48059      * the image cache, when the image has been cached. If supplied image
48060      * size is not larger than the current image size the image cache is
48061      * returned immediately.
48062      */
48063     cacheImage$(spatial) {
48064         if (this._image != null) {
48065             return of(this);
48066         }
48067         const cacheImage$ = this._cacheImage$(spatial)
48068             .pipe(first((image) => {
48069             return !!image;
48070         }), tap((image) => {
48071             this._disposeImage();
48072             this._image = image;
48073         }), map(() => {
48074             return this;
48075         }), publishReplay(1), refCount());
48076         cacheImage$
48077             .subscribe(() => {
48078             this._imageChanged$.next(this._image);
48079         }, () => { });
48080         return cacheImage$;
48081     }
48082     /**
48083      * Cache the sequence edges.
48084      *
48085      * @param {Array<NavigationEdge>} edges - Sequence edges to cache.
48086      */
48087     cacheSequenceEdges(edges) {
48088         this._sequenceEdges = { cached: true, edges: edges };
48089         this._sequenceEdgesChanged$.next(this._sequenceEdges);
48090     }
48091     /**
48092      * Cache the spatial edges.
48093      *
48094      * @param {Array<NavigationEdge>} edges - Spatial edges to cache.
48095      */
48096     cacheSpatialEdges(edges) {
48097         this._spatialEdges = { cached: true, edges: edges };
48098         this._spatialEdgesChanged$.next(this._spatialEdges);
48099     }
48100     /**
48101      * Dispose the image cache.
48102      *
48103      * @description Disposes all cached assets and unsubscribes to
48104      * all streams.
48105      */
48106     dispose() {
48107         this._iamgeSubscription.unsubscribe();
48108         this._sequenceEdgesSubscription.unsubscribe();
48109         this._spatialEdgesSubscription.unsubscribe();
48110         this._disposeImage();
48111         this._mesh = null;
48112         this._sequenceEdges = { cached: false, edges: [] };
48113         this._spatialEdges = { cached: false, edges: [] };
48114         this._imageChanged$.next(null);
48115         this._sequenceEdgesChanged$.next(this._sequenceEdges);
48116         this._spatialEdgesChanged$.next(this._spatialEdges);
48117         this._disposed = true;
48118         if (this._imageAborter != null) {
48119             this._imageAborter();
48120             this._imageAborter = null;
48121         }
48122         if (this._meshAborter != null) {
48123             this._meshAborter();
48124             this._meshAborter = null;
48125         }
48126     }
48127     /**
48128      * Reset the sequence edges.
48129      */
48130     resetSequenceEdges() {
48131         this._sequenceEdges = { cached: false, edges: [] };
48132         this._sequenceEdgesChanged$.next(this._sequenceEdges);
48133     }
48134     /**
48135      * Reset the spatial edges.
48136      */
48137     resetSpatialEdges() {
48138         this._spatialEdges = { cached: false, edges: [] };
48139         this._spatialEdgesChanged$.next(this._spatialEdges);
48140     }
48141     /**
48142      * Cache the image.
48143      *
48144      * @param {SpatialImageEnt} spatial - Spatial image.
48145      * @param {boolean} spherical - Value indicating whether image is a spherical.
48146      * @returns {Observable<ILoadStatusObject<HTMLImageElement>>} Observable
48147      * emitting a load status object every time the load status changes
48148      * and completes when the image is fully loaded.
48149      */
48150     _cacheImage$(spatial) {
48151         return Observable.create((subscriber) => {
48152             const abort = new Promise((_, reject) => {
48153                 this._imageAborter = reject;
48154             });
48155             const url = spatial.thumb.url;
48156             if (!url) {
48157                 const thumbId = spatial.thumb.id;
48158                 const message = `Incorrect thumb URL for ${spatial.id} ` +
48159                     `(${thumbId}, ${url})`;
48160                 subscriber.error(new Error(message));
48161                 return;
48162             }
48163             this._provider.getImageBuffer(url, abort)
48164                 .then((buffer) => {
48165                 this._imageAborter = null;
48166                 const image = new Image();
48167                 image.crossOrigin = "Anonymous";
48168                 image.onload = () => {
48169                     if (this._disposed) {
48170                         window.URL.revokeObjectURL(image.src);
48171                         const message = `Image load was aborted (${url})`;
48172                         subscriber.error(new Error(message));
48173                         return;
48174                     }
48175                     subscriber.next(image);
48176                     subscriber.complete();
48177                 };
48178                 image.onerror = () => {
48179                     this._imageAborter = null;
48180                     subscriber.error(new Error(`Failed to load image (${url})`));
48181                 };
48182                 const blob = new Blob([buffer]);
48183                 image.src = window.URL.createObjectURL(blob);
48184             }, (error) => {
48185                 this._imageAborter = null;
48186                 subscriber.error(error);
48187             });
48188         });
48189     }
48190     /**
48191      * Cache the mesh.
48192      *
48193      * @param {SpatialImageEnt} spatial - Spatial props.
48194      * @param {boolean} merged - Value indicating whether image is merged.
48195      * @returns {Observable<ILoadStatusObject<MeshContract>>} Observable emitting
48196      * a load status object every time the load status changes and completes
48197      * when the mesh is fully loaded.
48198      */
48199     _cacheMesh$(spatial, merged) {
48200         return Observable.create((subscriber) => {
48201             if (!merged) {
48202                 subscriber.next(this._createEmptyMesh());
48203                 subscriber.complete();
48204                 return;
48205             }
48206             const url = spatial.mesh.url;
48207             if (!url) {
48208                 const meshId = spatial.mesh.id;
48209                 const message = `Incorrect mesh URL for ${spatial.id} ` +
48210                     `(${meshId}, ${url})`;
48211                 console.warn(message);
48212                 subscriber.next(this._createEmptyMesh());
48213                 subscriber.complete();
48214                 return;
48215             }
48216             const abort = new Promise((_, reject) => {
48217                 this._meshAborter = reject;
48218             });
48219             this._provider.getMesh(url, abort)
48220                 .then((mesh) => {
48221                 this._meshAborter = null;
48222                 if (this._disposed) {
48223                     return;
48224                 }
48225                 subscriber.next(mesh);
48226                 subscriber.complete();
48227             }, (error) => {
48228                 this._meshAborter = null;
48229                 console.error(error);
48230                 subscriber.next(this._createEmptyMesh());
48231                 subscriber.complete();
48232             });
48233         });
48234     }
48235     /**
48236      * Create a load status object with an empty mesh.
48237      *
48238      * @returns {ILoadStatusObject<MeshContract>} Load status object
48239      * with empty mesh.
48240      */
48241     _createEmptyMesh() {
48242         return { faces: [], vertices: [] };
48243     }
48244     _disposeImage() {
48245         if (this._image != null) {
48246             window.URL.revokeObjectURL(this._image.src);
48247         }
48248         this._image = null;
48249     }
48250 }
48251
48252 /**
48253  * @class Sequence
48254  *
48255  * @classdesc Represents a sequence of ordered images.
48256  */
48257 class Sequence {
48258     /**
48259      * Create a new sequene instance.
48260      *
48261      * @param {SequenceEnt} sequence - Raw sequence data.
48262      */
48263     constructor(sequence) {
48264         this._id = sequence.id;
48265         this._imageIds = sequence.image_ids;
48266     }
48267     /**
48268      * Get id.
48269      *
48270      * @returns {string} Unique sequence id.
48271      */
48272     get id() {
48273         return this._id;
48274     }
48275     /**
48276      * Get ids.
48277      *
48278      * @returns {Array<string>} Array of ordered image ids in the sequence.
48279      */
48280     get imageIds() {
48281         return this._imageIds;
48282     }
48283     /**
48284      * Dispose the sequence.
48285      *
48286      * @description Disposes all cached assets.
48287      */
48288     dispose() {
48289         this._id = null;
48290         this._imageIds = null;
48291     }
48292     /**
48293      * Find the next image id in the sequence with respect to
48294      * the provided image id.
48295      *
48296      * @param {string} id - Reference image id.
48297      * @returns {string} Next id in sequence if it exists, null otherwise.
48298      */
48299     findNext(id) {
48300         let i = this._imageIds.indexOf(id);
48301         if ((i + 1) >= this._imageIds.length || i === -1) {
48302             return null;
48303         }
48304         else {
48305             return this._imageIds[i + 1];
48306         }
48307     }
48308     /**
48309      * Find the previous image id in the sequence with respect to
48310      * the provided image id.
48311      *
48312      * @param {string} id - Reference image id.
48313      * @returns {string} Previous id in sequence if it exists, null otherwise.
48314      */
48315     findPrev(id) {
48316         let i = this._imageIds.indexOf(id);
48317         if (i === 0 || i === -1) {
48318             return null;
48319         }
48320         else {
48321             return this._imageIds[i - 1];
48322         }
48323     }
48324 }
48325
48326 class EdgeCalculatorCoefficients {
48327     constructor() {
48328         this.sphericalPreferredDistance = 2;
48329         this.sphericalMotion = 2;
48330         this.sphericalSequencePenalty = 1;
48331         this.sphericalMergeCCPenalty = 4;
48332         this.stepPreferredDistance = 4;
48333         this.stepMotion = 3;
48334         this.stepRotation = 4;
48335         this.stepSequencePenalty = 2;
48336         this.stepMergeCCPenalty = 6;
48337         this.similarDistance = 2;
48338         this.similarRotation = 3;
48339         this.turnDistance = 4;
48340         this.turnMotion = 2;
48341         this.turnSequencePenalty = 1;
48342         this.turnMergeCCPenalty = 4;
48343     }
48344 }
48345
48346 /**
48347  * Enumeration for edge directions
48348  * @enum {number}
48349  * @readonly
48350  * @description Directions for edges in image graph describing
48351  * sequence, spatial and image type relations between nodes.
48352  */
48353 var NavigationDirection;
48354 (function (NavigationDirection) {
48355     /**
48356      * Next image in the sequence.
48357      */
48358     NavigationDirection[NavigationDirection["Next"] = 0] = "Next";
48359     /**
48360      * Previous image in the sequence.
48361      */
48362     NavigationDirection[NavigationDirection["Prev"] = 1] = "Prev";
48363     /**
48364      * Step to the left keeping viewing direction.
48365      */
48366     NavigationDirection[NavigationDirection["StepLeft"] = 2] = "StepLeft";
48367     /**
48368      * Step to the right keeping viewing direction.
48369      */
48370     NavigationDirection[NavigationDirection["StepRight"] = 3] = "StepRight";
48371     /**
48372      * Step forward keeping viewing direction.
48373      */
48374     NavigationDirection[NavigationDirection["StepForward"] = 4] = "StepForward";
48375     /**
48376      * Step backward keeping viewing direction.
48377      */
48378     NavigationDirection[NavigationDirection["StepBackward"] = 5] = "StepBackward";
48379     /**
48380      * Turn 90 degrees counter clockwise.
48381      */
48382     NavigationDirection[NavigationDirection["TurnLeft"] = 6] = "TurnLeft";
48383     /**
48384      * Turn 90 degrees clockwise.
48385      */
48386     NavigationDirection[NavigationDirection["TurnRight"] = 7] = "TurnRight";
48387     /**
48388      * Turn 180 degrees.
48389      */
48390     NavigationDirection[NavigationDirection["TurnU"] = 8] = "TurnU";
48391     /**
48392      * Spherical in general direction.
48393      */
48394     NavigationDirection[NavigationDirection["Spherical"] = 9] = "Spherical";
48395     /**
48396      * Looking in roughly the same direction at rougly the same position.
48397      */
48398     NavigationDirection[NavigationDirection["Similar"] = 10] = "Similar";
48399 })(NavigationDirection || (NavigationDirection = {}));
48400
48401 class EdgeCalculatorDirections {
48402     constructor() {
48403         this.steps = {};
48404         this.turns = {};
48405         this.spherical = {};
48406         this.steps[NavigationDirection.StepForward] = {
48407             direction: NavigationDirection.StepForward,
48408             motionChange: 0,
48409             useFallback: true,
48410         };
48411         this.steps[NavigationDirection.StepBackward] = {
48412             direction: NavigationDirection.StepBackward,
48413             motionChange: Math.PI,
48414             useFallback: true,
48415         };
48416         this.steps[NavigationDirection.StepLeft] = {
48417             direction: NavigationDirection.StepLeft,
48418             motionChange: Math.PI / 2,
48419             useFallback: false,
48420         };
48421         this.steps[NavigationDirection.StepRight] = {
48422             direction: NavigationDirection.StepRight,
48423             motionChange: -Math.PI / 2,
48424             useFallback: false,
48425         };
48426         this.turns[NavigationDirection.TurnLeft] = {
48427             direction: NavigationDirection.TurnLeft,
48428             directionChange: Math.PI / 2,
48429             motionChange: Math.PI / 4,
48430         };
48431         this.turns[NavigationDirection.TurnRight] = {
48432             direction: NavigationDirection.TurnRight,
48433             directionChange: -Math.PI / 2,
48434             motionChange: -Math.PI / 4,
48435         };
48436         this.turns[NavigationDirection.TurnU] = {
48437             direction: NavigationDirection.TurnU,
48438             directionChange: Math.PI,
48439             motionChange: null,
48440         };
48441         this.spherical[NavigationDirection.StepForward] = {
48442             direction: NavigationDirection.StepForward,
48443             directionChange: 0,
48444             next: NavigationDirection.StepLeft,
48445             prev: NavigationDirection.StepRight,
48446         };
48447         this.spherical[NavigationDirection.StepBackward] = {
48448             direction: NavigationDirection.StepBackward,
48449             directionChange: Math.PI,
48450             next: NavigationDirection.StepRight,
48451             prev: NavigationDirection.StepLeft,
48452         };
48453         this.spherical[NavigationDirection.StepLeft] = {
48454             direction: NavigationDirection.StepLeft,
48455             directionChange: Math.PI / 2,
48456             next: NavigationDirection.StepBackward,
48457             prev: NavigationDirection.StepForward,
48458         };
48459         this.spherical[NavigationDirection.StepRight] = {
48460             direction: NavigationDirection.StepRight,
48461             directionChange: -Math.PI / 2,
48462             next: NavigationDirection.StepForward,
48463             prev: NavigationDirection.StepBackward,
48464         };
48465     }
48466 }
48467
48468 class EdgeCalculatorSettings {
48469     constructor() {
48470         this.sphericalMinDistance = 0.1;
48471         this.sphericalMaxDistance = 20;
48472         this.sphericalPreferredDistance = 5;
48473         this.sphericalMaxItems = 4;
48474         this.sphericalMaxStepTurnChange = Math.PI / 8;
48475         this.rotationMaxDistance = this.turnMaxRigDistance;
48476         this.rotationMaxDirectionChange = Math.PI / 6;
48477         this.rotationMaxVerticalDirectionChange = Math.PI / 8;
48478         this.similarMaxDirectionChange = Math.PI / 8;
48479         this.similarMaxDistance = 12;
48480         this.similarMinTimeDifference = 12 * 3600 * 1000;
48481         this.stepMaxDistance = 20;
48482         this.stepMaxDirectionChange = Math.PI / 6;
48483         this.stepMaxDrift = Math.PI / 6;
48484         this.stepPreferredDistance = 4;
48485         this.turnMaxDistance = 15;
48486         this.turnMaxDirectionChange = 2 * Math.PI / 9;
48487         this.turnMaxRigDistance = 0.65;
48488         this.turnMinRigDirectionChange = Math.PI / 6;
48489     }
48490     get maxDistance() {
48491         return Math.max(this.sphericalMaxDistance, this.similarMaxDistance, this.stepMaxDistance, this.turnMaxDistance);
48492     }
48493 }
48494
48495 /**
48496  * @class MapillaryError
48497  *
48498  * @classdesc Generic Mapillary error.
48499  */
48500 class MapillaryError extends Error {
48501     constructor(message) {
48502         super(message);
48503         Object.setPrototypeOf(this, MapillaryError.prototype);
48504         this.name = "MapillaryError";
48505     }
48506 }
48507
48508 class ArgumentMapillaryError extends MapillaryError {
48509     constructor(message) {
48510         super(message != null ? message : "The argument is not valid.");
48511         Object.setPrototypeOf(this, ArgumentMapillaryError.prototype);
48512         this.name = "ArgumentMapillaryError";
48513     }
48514 }
48515
48516 /**
48517  * @class Spatial
48518  *
48519  * @classdesc Provides methods for scalar, vector and matrix calculations.
48520  */
48521 class Spatial {
48522     constructor() {
48523         this._epsilon = 1e-9;
48524     }
48525     /**
48526      * Converts azimuthal phi rotation (counter-clockwise with origin on X-axis) to
48527      * bearing (clockwise with origin at north or Y-axis).
48528      *
48529      * @param {number} phi - Azimuthal phi angle in radians.
48530      * @returns {number} Bearing in radians.
48531      */
48532     azimuthalToBearing(phi) {
48533         return -phi + Math.PI / 2;
48534     }
48535     /**
48536      * Converts degrees to radians.
48537      *
48538      * @param {number} deg - Degrees.
48539      * @returns {number} Radians.
48540      */
48541     degToRad(deg) {
48542         return Math.PI * deg / 180;
48543     }
48544     /**
48545      * Converts radians to degrees.
48546      *
48547      * @param {number} rad - Radians.
48548      * @returns {number} Degrees.
48549      */
48550     radToDeg(rad) {
48551         return 180 * rad / Math.PI;
48552     }
48553     /**
48554      * Creates a rotation matrix from an angle-axis vector.
48555      *
48556      * @param {Array<number>} angleAxis - Angle-axis representation of a rotation.
48557      * @returns {THREE.Matrix4} Rotation matrix.
48558      */
48559     rotationMatrix(angleAxis) {
48560         let axis = new Vector3(angleAxis[0], angleAxis[1], angleAxis[2]);
48561         let angle = axis.length();
48562         if (angle > 0) {
48563             axis.normalize();
48564         }
48565         return new Matrix4().makeRotationAxis(axis, angle);
48566     }
48567     /**
48568      * Rotates a vector according to a angle-axis rotation vector.
48569      *
48570      * @param {Array<number>} vector - Vector to rotate.
48571      * @param {Array<number>} angleAxis - Angle-axis representation of a rotation.
48572      * @returns {THREE.Vector3} Rotated vector.
48573      */
48574     rotate(vector, angleAxis) {
48575         let v = new Vector3(vector[0], vector[1], vector[2]);
48576         let rotationMatrix = this.rotationMatrix(angleAxis);
48577         v.applyMatrix4(rotationMatrix);
48578         return v;
48579     }
48580     /**
48581      * Calculates the optical center from a rotation vector
48582      * on the angle-axis representation and a translation vector
48583      * according to C = -R^T t.
48584      *
48585      * @param {Array<number>} rotation - Angle-axis representation of a rotation.
48586      * @param {Array<number>} translation - Translation vector.
48587      * @returns {THREE.Vector3} Optical center.
48588      */
48589     opticalCenter(rotation, translation) {
48590         let angleAxis = [-rotation[0], -rotation[1], -rotation[2]];
48591         let vector = [-translation[0], -translation[1], -translation[2]];
48592         return this.rotate(vector, angleAxis);
48593     }
48594     /**
48595      * Calculates the viewing direction from a rotation vector
48596      * on the angle-axis representation.
48597      *
48598      * @param {number[]} rotation - Angle-axis representation of a rotation.
48599      * @returns {THREE.Vector3} Viewing direction.
48600      */
48601     viewingDirection(rotation) {
48602         let angleAxis = [-rotation[0], -rotation[1], -rotation[2]];
48603         return this.rotate([0, 0, 1], angleAxis);
48604     }
48605     /**
48606      * Wrap a number on the interval [min, max].
48607      *
48608      * @param {number} value - Value to wrap.
48609      * @param {number} min - Lower endpoint of interval.
48610      * @param {number} max - Upper endpoint of interval.
48611      * @returns {number} The wrapped number.
48612      */
48613     wrap(value, min, max) {
48614         if (max < min) {
48615             throw new Error("Invalid arguments: max must be larger than min.");
48616         }
48617         let interval = (max - min);
48618         while (value > max || value < min) {
48619             if (value > max) {
48620                 value = value - interval;
48621             }
48622             else if (value < min) {
48623                 value = value + interval;
48624             }
48625         }
48626         return value;
48627     }
48628     /**
48629      * Wrap an angle on the interval [-Pi, Pi].
48630      *
48631      * @param {number} angle - Value to wrap.
48632      * @returns {number} Wrapped angle.
48633      */
48634     wrapAngle(angle) {
48635         return this.wrap(angle, -Math.PI, Math.PI);
48636     }
48637     /**
48638      * Limit the value to the interval [min, max] by changing the value to
48639      * the nearest available one when it is outside the interval.
48640      *
48641      * @param {number} value - Value to clamp.
48642      * @param {number} min - Minimum of the interval.
48643      * @param {number} max - Maximum of the interval.
48644      * @returns {number} Clamped value.
48645      */
48646     clamp(value, min, max) {
48647         if (value < min) {
48648             return min;
48649         }
48650         if (value > max) {
48651             return max;
48652         }
48653         return value;
48654     }
48655     /**
48656      * Calculates the counter-clockwise angle from the first
48657      * vector (x1, y1)^T to the second (x2, y2)^T.
48658      *
48659      * @param {number} x1 - X coordinate of first vector.
48660      * @param {number} y1 - Y coordinate of first vector.
48661      * @param {number} x2 - X coordinate of second vector.
48662      * @param {number} y2 - Y coordinate of second vector.
48663      * @returns {number} Counter clockwise angle between the vectors.
48664      */
48665     angleBetweenVector2(x1, y1, x2, y2) {
48666         let angle = Math.atan2(y2, x2) - Math.atan2(y1, x1);
48667         return this.wrapAngle(angle);
48668     }
48669     /**
48670      * Calculates the minimum (absolute) angle change for rotation
48671      * from one angle to another on the [-Pi, Pi] interval.
48672      *
48673      * @param {number} angle1 - Start angle.
48674      * @param {number} angle2 - Destination angle.
48675      * @returns {number} Absolute angle change between angles.
48676      */
48677     angleDifference(angle1, angle2) {
48678         let angle = angle2 - angle1;
48679         return this.wrapAngle(angle);
48680     }
48681     /**
48682      * Calculates the relative rotation angle between two
48683      * angle-axis vectors.
48684      *
48685      * @param {number} rotation1 - First angle-axis vector.
48686      * @param {number} rotation2 - Second angle-axis vector.
48687      * @returns {number} Relative rotation angle.
48688      */
48689     relativeRotationAngle(rotation1, rotation2) {
48690         let R1T = this.rotationMatrix([-rotation1[0], -rotation1[1], -rotation1[2]]);
48691         let R2 = this.rotationMatrix(rotation2);
48692         let R = R1T.multiply(R2);
48693         let elements = R.elements;
48694         // from Tr(R) = 1 + 2 * cos(theta)
48695         let tr = elements[0] + elements[5] + elements[10];
48696         let theta = Math.acos(Math.max(Math.min((tr - 1) / 2, 1), -1));
48697         return theta;
48698     }
48699     /**
48700      * Calculates the angle from a vector to a plane.
48701      *
48702      * @param {Array<number>} vector - The vector.
48703      * @param {Array<number>} planeNormal - Normal of the plane.
48704      * @returns {number} Angle from between plane and vector.
48705      */
48706     angleToPlane(vector, planeNormal) {
48707         let v = new Vector3().fromArray(vector);
48708         let norm = v.length();
48709         if (norm < this._epsilon) {
48710             return 0;
48711         }
48712         let projection = v.dot(new Vector3().fromArray(planeNormal));
48713         return Math.asin(projection / norm);
48714     }
48715     azimuthal(direction, up) {
48716         const directionVector = new Vector3().fromArray(direction);
48717         const upVector = new Vector3().fromArray(up);
48718         const upProjection = directionVector.clone().dot(upVector);
48719         const planeProjection = directionVector.clone().sub(upVector.clone().multiplyScalar(upProjection));
48720         return Math.atan2(planeProjection.y, planeProjection.x);
48721     }
48722     /**
48723      * Calculates the distance between two coordinates
48724      * (longitude, latitude pairs) in meters according to
48725      * the haversine formula.
48726      *
48727      * @param {number} lat1 - Latitude of the first coordinate in degrees.
48728      * @param {number} lng1 - Longitude of the first coordinate in degrees.
48729      * @param {number} lat2 - Latitude of the second coordinate in degrees.
48730      * @param {number} lng2 - Longitude of the second coordinate in degrees.
48731      * @returns {number} Distance between lat lon positions in meters.
48732      */
48733     distanceFromLngLat(lng1, lat1, lng2, lat2) {
48734         let r = 6371000;
48735         let dLat = this.degToRad(lat2 - lat1);
48736         let dLng = this.degToRad(lng2 - lng1);
48737         let hav = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
48738             Math.cos(this.degToRad(lat1)) * Math.cos(this.degToRad(lat2)) *
48739                 Math.sin(dLng / 2) * Math.sin(dLng / 2);
48740         let d = 2 * r * Math.atan2(Math.sqrt(hav), Math.sqrt(1 - hav));
48741         return d;
48742     }
48743 }
48744
48745 const spatial = new Spatial();
48746 function isSpherical(cameraType) {
48747     return cameraType === "spherical";
48748 }
48749 function isFisheye(cameraType) {
48750     return cameraType === "fisheye";
48751 }
48752 function computeTranslation(position, rotation, reference) {
48753     const C = geodeticToEnu(position.lng, position.lat, position.alt, reference.lng, reference.lat, reference.alt);
48754     const RC = spatial.rotate(C, rotation);
48755     const translation = [-RC.x, -RC.y, -RC.z];
48756     return translation;
48757 }
48758 function computeProjectedPoints(transform, basicVertices, basicDirections, pointsPerLine, viewportCoords) {
48759     const basicPoints = [];
48760     for (let side = 0; side < basicVertices.length; ++side) {
48761         const v = basicVertices[side];
48762         const d = basicDirections[side];
48763         for (let i = 0; i <= pointsPerLine; ++i) {
48764             basicPoints.push([v[0] + d[0] * i / pointsPerLine,
48765                 v[1] + d[1] * i / pointsPerLine]);
48766         }
48767     }
48768     const camera = new Camera$1();
48769     camera.up.copy(transform.upVector());
48770     camera.position.copy(new Vector3().fromArray(transform.unprojectSfM([0, 0], 0)));
48771     camera.lookAt(new Vector3().fromArray(transform.unprojectSfM([0, 0], 10)));
48772     camera.updateMatrix();
48773     camera.updateMatrixWorld(true);
48774     const projectedPoints = basicPoints
48775         .map((basicPoint) => {
48776         const worldPoint = transform.unprojectBasic(basicPoint, 10000);
48777         const cameraPoint = viewportCoords.worldToCamera(worldPoint, camera);
48778         return [
48779             Math.abs(cameraPoint[0] / cameraPoint[2]),
48780             Math.abs(cameraPoint[1] / cameraPoint[2]),
48781         ];
48782     });
48783     return projectedPoints;
48784 }
48785
48786 /**
48787  * @class EdgeCalculator
48788  *
48789  * @classdesc Represents a class for calculating node edges.
48790  */
48791 class EdgeCalculator {
48792     /**
48793      * Create a new edge calculator instance.
48794      *
48795      * @param {EdgeCalculatorSettings} settings - Settings struct.
48796      * @param {EdgeCalculatorDirections} directions - Directions struct.
48797      * @param {EdgeCalculatorCoefficients} coefficients - Coefficients struct.
48798      */
48799     constructor(settings, directions, coefficients) {
48800         this._spatial = new Spatial();
48801         this._settings = settings != null ? settings : new EdgeCalculatorSettings();
48802         this._directions = directions != null ? directions : new EdgeCalculatorDirections();
48803         this._coefficients = coefficients != null ? coefficients : new EdgeCalculatorCoefficients();
48804     }
48805     /**
48806      * Returns the potential edges to destination nodes for a set
48807      * of nodes with respect to a source node.
48808      *
48809      * @param {Image} node - Source node.
48810      * @param {Array<Image>} nodes - Potential destination nodes.
48811      * @param {Array<string>} fallbackIds - Ids for destination nodes
48812      * that should be returned even if they do not meet the
48813      * criteria for a potential edge.
48814      * @throws {ArgumentMapillaryError} If node is not full.
48815      */
48816     getPotentialEdges(node, potentialImages, fallbackIds) {
48817         if (!node.complete) {
48818             throw new ArgumentMapillaryError("Image has to be full.");
48819         }
48820         if (!node.merged) {
48821             return [];
48822         }
48823         let currentDirection = this._spatial.viewingDirection(node.rotation);
48824         let currentVerticalDirection = this._spatial.angleToPlane(currentDirection.toArray(), [0, 0, 1]);
48825         let potentialEdges = [];
48826         for (let potential of potentialImages) {
48827             if (!potential.merged ||
48828                 potential.id === node.id) {
48829                 continue;
48830             }
48831             let enu = geodeticToEnu(potential.lngLat.lng, potential.lngLat.lat, potential.computedAltitude, node.lngLat.lng, node.lngLat.lat, node.computedAltitude);
48832             let motion = new Vector3(enu[0], enu[1], enu[2]);
48833             let distance = motion.length();
48834             if (distance > this._settings.maxDistance &&
48835                 fallbackIds.indexOf(potential.id) < 0) {
48836                 continue;
48837             }
48838             let motionChange = this._spatial.angleBetweenVector2(currentDirection.x, currentDirection.y, motion.x, motion.y);
48839             let verticalMotion = this._spatial.angleToPlane(motion.toArray(), [0, 0, 1]);
48840             let direction = this._spatial.viewingDirection(potential.rotation);
48841             let directionChange = this._spatial.angleBetweenVector2(currentDirection.x, currentDirection.y, direction.x, direction.y);
48842             let verticalDirection = this._spatial.angleToPlane(direction.toArray(), [0, 0, 1]);
48843             let verticalDirectionChange = verticalDirection - currentVerticalDirection;
48844             let rotation = this._spatial.relativeRotationAngle(node.rotation, potential.rotation);
48845             let worldMotionAzimuth = this._spatial.angleBetweenVector2(1, 0, motion.x, motion.y);
48846             let sameSequence = potential.sequenceId != null &&
48847                 node.sequenceId != null &&
48848                 potential.sequenceId === node.sequenceId;
48849             let sameMergeCC = potential.mergeId === node.mergeId;
48850             let sameUser = potential.creatorId === node.creatorId;
48851             let potentialEdge = {
48852                 capturedAt: potential.capturedAt,
48853                 directionChange: directionChange,
48854                 distance: distance,
48855                 spherical: isSpherical(potential.cameraType),
48856                 id: potential.id,
48857                 motionChange: motionChange,
48858                 rotation: rotation,
48859                 sameMergeCC: sameMergeCC,
48860                 sameSequence: sameSequence,
48861                 sameUser: sameUser,
48862                 sequenceId: potential.sequenceId,
48863                 verticalDirectionChange: verticalDirectionChange,
48864                 verticalMotion: verticalMotion,
48865                 worldMotionAzimuth: worldMotionAzimuth,
48866             };
48867             potentialEdges.push(potentialEdge);
48868         }
48869         return potentialEdges;
48870     }
48871     /**
48872      * Computes the sequence edges for a node.
48873      *
48874      * @param {Image} node - Source node.
48875      * @throws {ArgumentMapillaryError} If node is not full.
48876      */
48877     computeSequenceEdges(node, sequence) {
48878         if (!node.complete) {
48879             throw new ArgumentMapillaryError("Image has to be full.");
48880         }
48881         if (node.sequenceId !== sequence.id) {
48882             throw new ArgumentMapillaryError("Image and sequence does not correspond.");
48883         }
48884         let edges = [];
48885         let nextId = sequence.findNext(node.id);
48886         if (nextId != null) {
48887             edges.push({
48888                 data: {
48889                     direction: NavigationDirection.Next,
48890                     worldMotionAzimuth: Number.NaN,
48891                 },
48892                 source: node.id,
48893                 target: nextId,
48894             });
48895         }
48896         let prevId = sequence.findPrev(node.id);
48897         if (prevId != null) {
48898             edges.push({
48899                 data: {
48900                     direction: NavigationDirection.Prev,
48901                     worldMotionAzimuth: Number.NaN,
48902                 },
48903                 source: node.id,
48904                 target: prevId,
48905             });
48906         }
48907         return edges;
48908     }
48909     /**
48910      * Computes the similar edges for a node.
48911      *
48912      * @description Similar edges for perspective images
48913      * look roughly in the same direction and are positioned closed to the node.
48914      * Similar edges for spherical only target other spherical.
48915      *
48916      * @param {Image} node - Source node.
48917      * @param {Array<PotentialEdge>} potentialEdges - Potential edges.
48918      * @throws {ArgumentMapillaryError} If node is not full.
48919      */
48920     computeSimilarEdges(node, potentialEdges) {
48921         if (!node.complete) {
48922             throw new ArgumentMapillaryError("Image has to be full.");
48923         }
48924         let nodeSpherical = isSpherical(node.cameraType);
48925         let sequenceGroups = {};
48926         for (let potentialEdge of potentialEdges) {
48927             if (potentialEdge.sequenceId == null) {
48928                 continue;
48929             }
48930             if (potentialEdge.sameSequence) {
48931                 continue;
48932             }
48933             if (nodeSpherical) {
48934                 if (!potentialEdge.spherical) {
48935                     continue;
48936                 }
48937             }
48938             else {
48939                 if (!potentialEdge.spherical &&
48940                     Math.abs(potentialEdge.directionChange) > this._settings.similarMaxDirectionChange) {
48941                     continue;
48942                 }
48943             }
48944             if (potentialEdge.distance > this._settings.similarMaxDistance) {
48945                 continue;
48946             }
48947             if (potentialEdge.sameUser &&
48948                 Math.abs(potentialEdge.capturedAt - node.capturedAt) <
48949                     this._settings.similarMinTimeDifference) {
48950                 continue;
48951             }
48952             if (sequenceGroups[potentialEdge.sequenceId] == null) {
48953                 sequenceGroups[potentialEdge.sequenceId] = [];
48954             }
48955             sequenceGroups[potentialEdge.sequenceId].push(potentialEdge);
48956         }
48957         let similarEdges = [];
48958         let calculateScore = isSpherical(node.cameraType) ?
48959             (potentialEdge) => {
48960                 return potentialEdge.distance;
48961             } :
48962             (potentialEdge) => {
48963                 return this._coefficients.similarDistance * potentialEdge.distance +
48964                     this._coefficients.similarRotation * potentialEdge.rotation;
48965             };
48966         for (let sequenceId in sequenceGroups) {
48967             if (!sequenceGroups.hasOwnProperty(sequenceId)) {
48968                 continue;
48969             }
48970             let lowestScore = Number.MAX_VALUE;
48971             let similarEdge = null;
48972             for (let potentialEdge of sequenceGroups[sequenceId]) {
48973                 let score = calculateScore(potentialEdge);
48974                 if (score < lowestScore) {
48975                     lowestScore = score;
48976                     similarEdge = potentialEdge;
48977                 }
48978             }
48979             if (similarEdge == null) {
48980                 continue;
48981             }
48982             similarEdges.push(similarEdge);
48983         }
48984         return similarEdges
48985             .map((potentialEdge) => {
48986             return {
48987                 data: {
48988                     direction: NavigationDirection.Similar,
48989                     worldMotionAzimuth: potentialEdge.worldMotionAzimuth,
48990                 },
48991                 source: node.id,
48992                 target: potentialEdge.id,
48993             };
48994         });
48995     }
48996     /**
48997      * Computes the step edges for a perspective node.
48998      *
48999      * @description Step edge targets can only be other perspective nodes.
49000      * Returns an empty array for spherical.
49001      *
49002      * @param {Image} node - Source node.
49003      * @param {Array<PotentialEdge>} potentialEdges - Potential edges.
49004      * @param {string} prevId - Id of previous node in sequence.
49005      * @param {string} nextId - Id of next node in sequence.
49006      * @throws {ArgumentMapillaryError} If node is not full.
49007      */
49008     computeStepEdges(node, potentialEdges, prevId, nextId) {
49009         if (!node.complete) {
49010             throw new ArgumentMapillaryError("Image has to be full.");
49011         }
49012         let edges = [];
49013         if (isSpherical(node.cameraType)) {
49014             return edges;
49015         }
49016         for (let k in this._directions.steps) {
49017             if (!this._directions.steps.hasOwnProperty(k)) {
49018                 continue;
49019             }
49020             let step = this._directions.steps[k];
49021             let lowestScore = Number.MAX_VALUE;
49022             let edge = null;
49023             let fallback = null;
49024             for (let potential of potentialEdges) {
49025                 if (potential.spherical) {
49026                     continue;
49027                 }
49028                 if (Math.abs(potential.directionChange) > this._settings.stepMaxDirectionChange) {
49029                     continue;
49030                 }
49031                 let motionDifference = this._spatial.angleDifference(step.motionChange, potential.motionChange);
49032                 let directionMotionDifference = this._spatial.angleDifference(potential.directionChange, motionDifference);
49033                 let drift = Math.max(Math.abs(motionDifference), Math.abs(directionMotionDifference));
49034                 if (Math.abs(drift) > this._settings.stepMaxDrift) {
49035                     continue;
49036                 }
49037                 let potentialId = potential.id;
49038                 if (step.useFallback && (potentialId === prevId || potentialId === nextId)) {
49039                     fallback = potential;
49040                 }
49041                 if (potential.distance > this._settings.stepMaxDistance) {
49042                     continue;
49043                 }
49044                 motionDifference = Math.sqrt(motionDifference * motionDifference +
49045                     potential.verticalMotion * potential.verticalMotion);
49046                 let score = this._coefficients.stepPreferredDistance *
49047                     Math.abs(potential.distance - this._settings.stepPreferredDistance) /
49048                     this._settings.stepMaxDistance +
49049                     this._coefficients.stepMotion * motionDifference / this._settings.stepMaxDrift +
49050                     this._coefficients.stepRotation * potential.rotation / this._settings.stepMaxDirectionChange +
49051                     this._coefficients.stepSequencePenalty * (potential.sameSequence ? 0 : 1) +
49052                     this._coefficients.stepMergeCCPenalty * (potential.sameMergeCC ? 0 : 1);
49053                 if (score < lowestScore) {
49054                     lowestScore = score;
49055                     edge = potential;
49056                 }
49057             }
49058             edge = edge == null ? fallback : edge;
49059             if (edge != null) {
49060                 edges.push({
49061                     data: {
49062                         direction: step.direction,
49063                         worldMotionAzimuth: edge.worldMotionAzimuth,
49064                     },
49065                     source: node.id,
49066                     target: edge.id,
49067                 });
49068             }
49069         }
49070         return edges;
49071     }
49072     /**
49073      * Computes the turn edges for a perspective node.
49074      *
49075      * @description Turn edge targets can only be other perspective images.
49076      * Returns an empty array for spherical.
49077      *
49078      * @param {Image} node - Source node.
49079      * @param {Array<PotentialEdge>} potentialEdges - Potential edges.
49080      * @throws {ArgumentMapillaryError} If node is not full.
49081      */
49082     computeTurnEdges(node, potentialEdges) {
49083         if (!node.complete) {
49084             throw new ArgumentMapillaryError("Image has to be full.");
49085         }
49086         let edges = [];
49087         if (isSpherical(node.cameraType)) {
49088             return edges;
49089         }
49090         for (let k in this._directions.turns) {
49091             if (!this._directions.turns.hasOwnProperty(k)) {
49092                 continue;
49093             }
49094             let turn = this._directions.turns[k];
49095             let lowestScore = Number.MAX_VALUE;
49096             let edge = null;
49097             for (let potential of potentialEdges) {
49098                 if (potential.spherical) {
49099                     continue;
49100                 }
49101                 if (potential.distance > this._settings.turnMaxDistance) {
49102                     continue;
49103                 }
49104                 let rig = turn.direction !== NavigationDirection.TurnU &&
49105                     potential.distance < this._settings.turnMaxRigDistance &&
49106                     Math.abs(potential.directionChange) > this._settings.turnMinRigDirectionChange;
49107                 let directionDifference = this._spatial.angleDifference(turn.directionChange, potential.directionChange);
49108                 let score;
49109                 if (rig &&
49110                     potential.directionChange * turn.directionChange > 0 &&
49111                     Math.abs(potential.directionChange) < Math.abs(turn.directionChange)) {
49112                     score = -Math.PI / 2 + Math.abs(potential.directionChange);
49113                 }
49114                 else {
49115                     if (Math.abs(directionDifference) > this._settings.turnMaxDirectionChange) {
49116                         continue;
49117                     }
49118                     let motionDifference = turn.motionChange ?
49119                         this._spatial.angleDifference(turn.motionChange, potential.motionChange) : 0;
49120                     motionDifference = Math.sqrt(motionDifference * motionDifference +
49121                         potential.verticalMotion * potential.verticalMotion);
49122                     score =
49123                         this._coefficients.turnDistance * potential.distance /
49124                             this._settings.turnMaxDistance +
49125                             this._coefficients.turnMotion * motionDifference / Math.PI +
49126                             this._coefficients.turnSequencePenalty * (potential.sameSequence ? 0 : 1) +
49127                             this._coefficients.turnMergeCCPenalty * (potential.sameMergeCC ? 0 : 1);
49128                 }
49129                 if (score < lowestScore) {
49130                     lowestScore = score;
49131                     edge = potential;
49132                 }
49133             }
49134             if (edge != null) {
49135                 edges.push({
49136                     data: {
49137                         direction: turn.direction,
49138                         worldMotionAzimuth: edge.worldMotionAzimuth,
49139                     },
49140                     source: node.id,
49141                     target: edge.id,
49142                 });
49143             }
49144         }
49145         return edges;
49146     }
49147     /**
49148      * Computes the spherical edges for a perspective node.
49149      *
49150      * @description Perspective to spherical edge targets can only be
49151      * spherical nodes. Returns an empty array for spherical.
49152      *
49153      * @param {Image} node - Source node.
49154      * @param {Array<PotentialEdge>} potentialEdges - Potential edges.
49155      * @throws {ArgumentMapillaryError} If node is not full.
49156      */
49157     computePerspectiveToSphericalEdges(node, potentialEdges) {
49158         if (!node.complete) {
49159             throw new ArgumentMapillaryError("Image has to be full.");
49160         }
49161         if (isSpherical(node.cameraType)) {
49162             return [];
49163         }
49164         let lowestScore = Number.MAX_VALUE;
49165         let edge = null;
49166         for (let potential of potentialEdges) {
49167             if (!potential.spherical) {
49168                 continue;
49169             }
49170             let score = this._coefficients.sphericalPreferredDistance *
49171                 Math.abs(potential.distance - this._settings.sphericalPreferredDistance) /
49172                 this._settings.sphericalMaxDistance +
49173                 this._coefficients.sphericalMotion * Math.abs(potential.motionChange) / Math.PI +
49174                 this._coefficients.sphericalMergeCCPenalty * (potential.sameMergeCC ? 0 : 1);
49175             if (score < lowestScore) {
49176                 lowestScore = score;
49177                 edge = potential;
49178             }
49179         }
49180         if (edge == null) {
49181             return [];
49182         }
49183         return [
49184             {
49185                 data: {
49186                     direction: NavigationDirection.Spherical,
49187                     worldMotionAzimuth: edge.worldMotionAzimuth,
49188                 },
49189                 source: node.id,
49190                 target: edge.id,
49191             },
49192         ];
49193     }
49194     /**
49195      * Computes the spherical and step edges for a spherical node.
49196      *
49197      * @description Spherical to spherical edge targets can only be
49198      * spherical nodes. spherical to step edge targets can only be perspective
49199      * nodes.
49200      *
49201      * @param {Image} node - Source node.
49202      * @param {Array<PotentialEdge>} potentialEdges - Potential edges.
49203      * @throws {ArgumentMapillaryError} If node is not full.
49204      */
49205     computeSphericalEdges(node, potentialEdges) {
49206         if (!node.complete) {
49207             throw new ArgumentMapillaryError("Image has to be full.");
49208         }
49209         if (!isSpherical(node.cameraType)) {
49210             return [];
49211         }
49212         let sphericalEdges = [];
49213         let potentialSpherical = [];
49214         let potentialSteps = [];
49215         for (let potential of potentialEdges) {
49216             if (potential.distance > this._settings.sphericalMaxDistance) {
49217                 continue;
49218             }
49219             if (potential.spherical) {
49220                 if (potential.distance < this._settings.sphericalMinDistance) {
49221                     continue;
49222                 }
49223                 potentialSpherical.push(potential);
49224             }
49225             else {
49226                 for (let k in this._directions.spherical) {
49227                     if (!this._directions.spherical.hasOwnProperty(k)) {
49228                         continue;
49229                     }
49230                     let spherical = this._directions.spherical[k];
49231                     let turn = this._spatial.angleDifference(potential.directionChange, potential.motionChange);
49232                     let turnChange = this._spatial.angleDifference(spherical.directionChange, turn);
49233                     if (Math.abs(turnChange) > this._settings.sphericalMaxStepTurnChange) {
49234                         continue;
49235                     }
49236                     potentialSteps.push([spherical.direction, potential]);
49237                     // break if step direction found
49238                     break;
49239                 }
49240             }
49241         }
49242         let maxRotationDifference = Math.PI / this._settings.sphericalMaxItems;
49243         let occupiedAngles = [];
49244         let stepAngles = [];
49245         for (let index = 0; index < this._settings.sphericalMaxItems; index++) {
49246             let rotation = index / this._settings.sphericalMaxItems * 2 * Math.PI;
49247             let lowestScore = Number.MAX_VALUE;
49248             let edge = null;
49249             for (let potential of potentialSpherical) {
49250                 let motionDifference = this._spatial.angleDifference(rotation, potential.motionChange);
49251                 if (Math.abs(motionDifference) > maxRotationDifference) {
49252                     continue;
49253                 }
49254                 let occupiedDifference = Number.MAX_VALUE;
49255                 for (let occupiedAngle of occupiedAngles) {
49256                     let difference = Math.abs(this._spatial.angleDifference(occupiedAngle, potential.motionChange));
49257                     if (difference < occupiedDifference) {
49258                         occupiedDifference = difference;
49259                     }
49260                 }
49261                 if (occupiedDifference <= maxRotationDifference) {
49262                     continue;
49263                 }
49264                 let score = this._coefficients.sphericalPreferredDistance *
49265                     Math.abs(potential.distance - this._settings.sphericalPreferredDistance) /
49266                     this._settings.sphericalMaxDistance +
49267                     this._coefficients.sphericalMotion * Math.abs(motionDifference) / maxRotationDifference +
49268                     this._coefficients.sphericalSequencePenalty * (potential.sameSequence ? 0 : 1) +
49269                     this._coefficients.sphericalMergeCCPenalty * (potential.sameMergeCC ? 0 : 1);
49270                 if (score < lowestScore) {
49271                     lowestScore = score;
49272                     edge = potential;
49273                 }
49274             }
49275             if (edge != null) {
49276                 occupiedAngles.push(edge.motionChange);
49277                 sphericalEdges.push({
49278                     data: {
49279                         direction: NavigationDirection.Spherical,
49280                         worldMotionAzimuth: edge.worldMotionAzimuth,
49281                     },
49282                     source: node.id,
49283                     target: edge.id,
49284                 });
49285             }
49286             else {
49287                 stepAngles.push(rotation);
49288             }
49289         }
49290         let occupiedStepAngles = {};
49291         occupiedStepAngles[NavigationDirection.Spherical] = occupiedAngles;
49292         occupiedStepAngles[NavigationDirection.StepForward] = [];
49293         occupiedStepAngles[NavigationDirection.StepLeft] = [];
49294         occupiedStepAngles[NavigationDirection.StepBackward] = [];
49295         occupiedStepAngles[NavigationDirection.StepRight] = [];
49296         for (let stepAngle of stepAngles) {
49297             let occupations = [];
49298             for (let k in this._directions.spherical) {
49299                 if (!this._directions.spherical.hasOwnProperty(k)) {
49300                     continue;
49301                 }
49302                 let spherical = this._directions.spherical[k];
49303                 let allOccupiedAngles = occupiedStepAngles[NavigationDirection.Spherical]
49304                     .concat(occupiedStepAngles[spherical.direction])
49305                     .concat(occupiedStepAngles[spherical.prev])
49306                     .concat(occupiedStepAngles[spherical.next]);
49307                 let lowestScore = Number.MAX_VALUE;
49308                 let edge = null;
49309                 for (let potential of potentialSteps) {
49310                     if (potential[0] !== spherical.direction) {
49311                         continue;
49312                     }
49313                     let motionChange = this._spatial.angleDifference(stepAngle, potential[1].motionChange);
49314                     if (Math.abs(motionChange) > maxRotationDifference) {
49315                         continue;
49316                     }
49317                     let minOccupiedDifference = Number.MAX_VALUE;
49318                     for (let occupiedAngle of allOccupiedAngles) {
49319                         let occupiedDifference = Math.abs(this._spatial.angleDifference(occupiedAngle, potential[1].motionChange));
49320                         if (occupiedDifference < minOccupiedDifference) {
49321                             minOccupiedDifference = occupiedDifference;
49322                         }
49323                     }
49324                     if (minOccupiedDifference <= maxRotationDifference) {
49325                         continue;
49326                     }
49327                     let score = this._coefficients.sphericalPreferredDistance *
49328                         Math.abs(potential[1].distance - this._settings.sphericalPreferredDistance) /
49329                         this._settings.sphericalMaxDistance +
49330                         this._coefficients.sphericalMotion * Math.abs(motionChange) / maxRotationDifference +
49331                         this._coefficients.sphericalMergeCCPenalty * (potential[1].sameMergeCC ? 0 : 1);
49332                     if (score < lowestScore) {
49333                         lowestScore = score;
49334                         edge = potential;
49335                     }
49336                 }
49337                 if (edge != null) {
49338                     occupations.push(edge);
49339                     sphericalEdges.push({
49340                         data: {
49341                             direction: edge[0],
49342                             worldMotionAzimuth: edge[1].worldMotionAzimuth,
49343                         },
49344                         source: node.id,
49345                         target: edge[1].id,
49346                     });
49347                 }
49348             }
49349             for (let occupation of occupations) {
49350                 occupiedStepAngles[occupation[0]].push(occupation[1].motionChange);
49351             }
49352         }
49353         return sphericalEdges;
49354     }
49355 }
49356
49357 class GraphMapillaryError extends MapillaryError {
49358     constructor(message) {
49359         super(message);
49360         Object.setPrototypeOf(this, GraphMapillaryError.prototype);
49361         this.name = "GraphMapillaryError";
49362     }
49363 }
49364
49365 /**
49366  * @class Graph
49367  *
49368  * @classdesc Represents a graph of nodes with edges.
49369  */
49370 class Graph {
49371     /**
49372      * Create a new graph instance.
49373      *
49374      * @param {APIWrapper} [api] - API instance for retrieving data.
49375      * @param {rbush.RBush<NodeIndexItem>} [nodeIndex] - Node index for fast spatial retreival.
49376      * @param {GraphCalculator} [graphCalculator] - Instance for graph calculations.
49377      * @param {EdgeCalculator} [edgeCalculator] - Instance for edge calculations.
49378      * @param {FilterCreator} [filterCreator] - Instance for  filter creation.
49379      * @param {GraphConfiguration} [configuration] - Configuration struct.
49380      */
49381     constructor(api, nodeIndex, graphCalculator, edgeCalculator, filterCreator, configuration) {
49382         this._api = api;
49383         this._cachedNodes = {};
49384         this._cachedNodeTiles = {};
49385         this._cachedSequenceNodes = {};
49386         this._cachedSpatialEdges = {};
49387         this._cachedTiles = {};
49388         this._cachingFill$ = {};
49389         this._cachingFull$ = {};
49390         this._cachingSequenceNodes$ = {};
49391         this._cachingSequences$ = {};
49392         this._cachingSpatialArea$ = {};
49393         this._cachingTiles$ = {};
49394         this._changed$ = new Subject();
49395         this._filterCreator = filterCreator !== null && filterCreator !== void 0 ? filterCreator : new FilterCreator();
49396         this._filter = this._filterCreator.createFilter(undefined);
49397         this._filterSubject$ = new Subject();
49398         this._filter$ =
49399             concat(of(this._filter), this._filterSubject$).pipe(publishReplay(1), refCount());
49400         this._filterSubscription = this._filter$.subscribe(() => { });
49401         this._defaultAlt = 2;
49402         this._edgeCalculator = edgeCalculator !== null && edgeCalculator !== void 0 ? edgeCalculator : new EdgeCalculator();
49403         this._graphCalculator = graphCalculator !== null && graphCalculator !== void 0 ? graphCalculator : new GraphCalculator();
49404         this._configuration = configuration !== null && configuration !== void 0 ? configuration : {
49405             maxSequences: 50,
49406             maxUnusedImages: 100,
49407             maxUnusedPreStoredImages: 30,
49408             maxUnusedTiles: 20,
49409         };
49410         this._nodes = {};
49411         this._nodeIndex = nodeIndex !== null && nodeIndex !== void 0 ? nodeIndex : new Graph._spatialIndex(16);
49412         this._nodeIndexTiles = {};
49413         this._nodeToTile = {};
49414         this._preStored = {};
49415         this._requiredNodeTiles = {};
49416         this._requiredSpatialArea = {};
49417         this._sequences = {};
49418         this._tileThreshold = 20;
49419     }
49420     static register(spatialIndex) {
49421         Graph._spatialIndex = spatialIndex;
49422     }
49423     /**
49424      * Get api.
49425      *
49426      * @returns {APIWrapper} The API instance used by
49427      * the graph.
49428      */
49429     get api() {
49430         return this._api;
49431     }
49432     /**
49433      * Get changed$.
49434      *
49435      * @returns {Observable<Graph>} Observable emitting
49436      * the graph every time it has changed.
49437      */
49438     get changed$() {
49439         return this._changed$;
49440     }
49441     /**
49442      * Get filter$.
49443      *
49444      * @returns {Observable<FilterFunction>} Observable emitting
49445      * the filter every time it has changed.
49446      */
49447     get filter$() {
49448         return this._filter$;
49449     }
49450     /**
49451      * Caches the full node data for all images within a bounding
49452      * box.
49453      *
49454      * @description The node assets are not cached.
49455      *
49456      * @param {LngLat} sw - South west corner of bounding box.
49457      * @param {LngLat} ne - North east corner of bounding box.
49458      * @returns {Observable<Array<Image>>} Observable emitting
49459      * the full nodes in the bounding box.
49460      */
49461     cacheBoundingBox$(sw, ne) {
49462         const cacheTiles$ = this._api.data.geometry.bboxToCellIds(sw, ne)
49463             .filter((h) => {
49464             return !(h in this._cachedTiles);
49465         })
49466             .map((h) => {
49467             return h in this._cachingTiles$ ?
49468                 this._cachingTiles$[h] :
49469                 this._cacheTile$(h);
49470         });
49471         if (cacheTiles$.length === 0) {
49472             cacheTiles$.push(of(this));
49473         }
49474         return from(cacheTiles$).pipe(mergeAll(), last(), mergeMap(() => {
49475             const nodes = this._nodeIndex
49476                 .search({
49477                 maxX: ne.lng,
49478                 maxY: ne.lat,
49479                 minX: sw.lng,
49480                 minY: sw.lat,
49481             })
49482                 .map((item) => {
49483                 return item.node;
49484             });
49485             const fullNodes = [];
49486             const coreNodes = [];
49487             for (const node of nodes) {
49488                 if (node.complete) {
49489                     fullNodes.push(node);
49490                 }
49491                 else {
49492                     coreNodes.push(node.id);
49493                 }
49494             }
49495             const coreNodeBatches = [];
49496             const batchSize = 200;
49497             while (coreNodes.length > 0) {
49498                 coreNodeBatches.push(coreNodes.splice(0, batchSize));
49499             }
49500             const fullNodes$ = of(fullNodes);
49501             const fillNodes$ = coreNodeBatches
49502                 .map((batch) => {
49503                 return this._api
49504                     .getSpatialImages$(batch)
49505                     .pipe(map((items) => {
49506                     const result = [];
49507                     for (const item of items) {
49508                         const exists = this
49509                             .hasNode(item.node_id);
49510                         if (!exists) {
49511                             continue;
49512                         }
49513                         const node = this
49514                             .getNode(item.node_id);
49515                         if (!node.complete) {
49516                             this._makeFull(node, item.node);
49517                         }
49518                         result.push(node);
49519                     }
49520                     return result;
49521                 }));
49522             });
49523             return merge(fullNodes$, from(fillNodes$).pipe(mergeAll()));
49524         }), reduce((acc, value) => {
49525             return acc.concat(value);
49526         }));
49527     }
49528     /**
49529      * Caches the full node data for all images of a cell.
49530      *
49531      * @description The node assets are not cached.
49532      *
49533      * @param {string} cellId - Cell id.
49534      * @returns {Observable<Array<Image>>} Observable
49535      * emitting the full nodes of the cell.
49536      */
49537     cacheCell$(cellId) {
49538         const cacheCell$ = cellId in this._cachedTiles ?
49539             of(this) :
49540             cellId in this._cachingTiles$ ?
49541                 this._cachingTiles$[cellId] :
49542                 this._cacheTile$(cellId);
49543         return cacheCell$.pipe(mergeMap(() => {
49544             const cachedCell = this._cachedTiles[cellId];
49545             cachedCell.accessed = new Date().getTime();
49546             const cellNodes = cachedCell.nodes;
49547             const fullNodes = [];
49548             const coreNodes = [];
49549             for (const node of cellNodes) {
49550                 if (node.complete) {
49551                     fullNodes.push(node);
49552                 }
49553                 else {
49554                     coreNodes.push(node.id);
49555                 }
49556             }
49557             const coreNodeBatches = [];
49558             const batchSize = 200;
49559             while (coreNodes.length > 0) {
49560                 coreNodeBatches.push(coreNodes.splice(0, batchSize));
49561             }
49562             const fullNodes$ = of(fullNodes);
49563             const fillNodes$ = coreNodeBatches
49564                 .map((batch) => {
49565                 return this._api.getSpatialImages$(batch).pipe(map((items) => {
49566                     const filled = [];
49567                     for (const item of items) {
49568                         if (!item.node) {
49569                             console.warn(`Image is empty (${item.node})`);
49570                             continue;
49571                         }
49572                         const id = item.node_id;
49573                         if (!this.hasNode(id)) {
49574                             continue;
49575                         }
49576                         const node = this.getNode(id);
49577                         if (!node.complete) {
49578                             this._makeFull(node, item.node);
49579                         }
49580                         filled.push(node);
49581                     }
49582                     return filled;
49583                 }));
49584             });
49585             return merge(fullNodes$, from(fillNodes$).pipe(mergeAll()));
49586         }), reduce((acc, value) => {
49587             return acc.concat(value);
49588         }));
49589     }
49590     /**
49591      * Retrieve and cache node fill properties.
49592      *
49593      * @param {string} key - Key of node to fill.
49594      * @returns {Observable<Graph>} Observable emitting the graph
49595      * when the node has been updated.
49596      * @throws {GraphMapillaryError} When the operation is not valid on the
49597      * current graph.
49598      */
49599     cacheFill$(key) {
49600         if (key in this._cachingFull$) {
49601             throw new GraphMapillaryError(`Cannot fill node while caching full (${key}).`);
49602         }
49603         if (!this.hasNode(key)) {
49604             throw new GraphMapillaryError(`Cannot fill node that does not exist in graph (${key}).`);
49605         }
49606         if (key in this._cachingFill$) {
49607             return this._cachingFill$[key];
49608         }
49609         const node = this.getNode(key);
49610         if (node.complete) {
49611             throw new GraphMapillaryError(`Cannot fill node that is already full (${key}).`);
49612         }
49613         this._cachingFill$[key] = this._api.getSpatialImages$([key]).pipe(tap((items) => {
49614             for (const item of items) {
49615                 if (!item.node) {
49616                     console.warn(`Image is empty ${item.node_id}`);
49617                 }
49618                 if (!node.complete) {
49619                     this._makeFull(node, item.node);
49620                 }
49621                 delete this._cachingFill$[item.node_id];
49622             }
49623         }), map(() => { return this; }), finalize(() => {
49624             if (key in this._cachingFill$) {
49625                 delete this._cachingFill$[key];
49626             }
49627             this._changed$.next(this);
49628         }), publish(), refCount());
49629         return this._cachingFill$[key];
49630     }
49631     /**
49632      * Retrieve and cache full node properties.
49633      *
49634      * @param {string} key - Key of node to fill.
49635      * @returns {Observable<Graph>} Observable emitting the graph
49636      * when the node has been updated.
49637      * @throws {GraphMapillaryError} When the operation is not valid on the
49638      * current graph.
49639      */
49640     cacheFull$(key) {
49641         if (key in this._cachingFull$) {
49642             return this._cachingFull$[key];
49643         }
49644         if (this.hasNode(key)) {
49645             throw new GraphMapillaryError(`Cannot cache full node that already exist in graph (${key}).`);
49646         }
49647         this._cachingFull$[key] = this._api.getImages$([key]).pipe(tap((items) => {
49648             for (const item of items) {
49649                 if (!item.node) {
49650                     throw new GraphMapillaryError(`Image does not exist (${key}, ${item.node}).`);
49651                 }
49652                 const id = item.node_id;
49653                 if (this.hasNode(id)) {
49654                     const node = this.getNode(key);
49655                     if (!node.complete) {
49656                         this._makeFull(node, item.node);
49657                     }
49658                 }
49659                 else {
49660                     if (item.node.sequence.id == null) {
49661                         throw new GraphMapillaryError(`Image has no sequence key (${key}).`);
49662                     }
49663                     const node = new Image$1(item.node);
49664                     this._makeFull(node, item.node);
49665                     const cellId = this._api.data.geometry
49666                         .lngLatToCellId(node.originalLngLat);
49667                     this._preStore(cellId, node);
49668                     this._setNode(node);
49669                     delete this._cachingFull$[id];
49670                 }
49671             }
49672         }), map(() => this), finalize(() => {
49673             if (key in this._cachingFull$) {
49674                 delete this._cachingFull$[key];
49675             }
49676             this._changed$.next(this);
49677         }), publish(), refCount());
49678         return this._cachingFull$[key];
49679     }
49680     /**
49681      * Retrieve and cache a node sequence.
49682      *
49683      * @param {string} key - Key of node for which to retrieve sequence.
49684      * @returns {Observable<Graph>} Observable emitting the graph
49685      * when the sequence has been retrieved.
49686      * @throws {GraphMapillaryError} When the operation is not valid on the
49687      * current graph.
49688      */
49689     cacheNodeSequence$(key) {
49690         if (!this.hasNode(key)) {
49691             throw new GraphMapillaryError(`Cannot cache sequence edges of node that does not exist in graph (${key}).`);
49692         }
49693         let node = this.getNode(key);
49694         if (node.sequenceId in this._sequences) {
49695             throw new GraphMapillaryError(`Sequence already cached (${key}), (${node.sequenceId}).`);
49696         }
49697         return this._cacheSequence$(node.sequenceId);
49698     }
49699     /**
49700      * Retrieve and cache a sequence.
49701      *
49702      * @param {string} sequenceKey - Key of sequence to cache.
49703      * @returns {Observable<Graph>} Observable emitting the graph
49704      * when the sequence has been retrieved.
49705      * @throws {GraphMapillaryError} When the operation is not valid on the
49706      * current graph.
49707      */
49708     cacheSequence$(sequenceKey) {
49709         if (sequenceKey in this._sequences) {
49710             throw new GraphMapillaryError(`Sequence already cached (${sequenceKey})`);
49711         }
49712         return this._cacheSequence$(sequenceKey);
49713     }
49714     /**
49715      * Cache sequence edges for a node.
49716      *
49717      * @param {string} key - Key of node.
49718      * @throws {GraphMapillaryError} When the operation is not valid on the
49719      * current graph.
49720      */
49721     cacheSequenceEdges(key) {
49722         let node = this.getNode(key);
49723         if (!(node.sequenceId in this._sequences)) {
49724             throw new GraphMapillaryError(`Sequence is not cached (${key}), (${node.sequenceId})`);
49725         }
49726         let sequence = this._sequences[node.sequenceId].sequence;
49727         let edges = this._edgeCalculator.computeSequenceEdges(node, sequence);
49728         node.cacheSequenceEdges(edges);
49729     }
49730     /**
49731      * Retrieve and cache full nodes for all keys in a sequence.
49732      *
49733      * @param {string} sequenceKey - Key of sequence.
49734      * @param {string} referenceNodeKey - Key of node to use as reference
49735      * for optimized caching.
49736      * @returns {Observable<Graph>} Observable emitting the graph
49737      * when the nodes of the sequence has been cached.
49738      */
49739     cacheSequenceNodes$(sequenceKey, referenceNodeKey) {
49740         if (!this.hasSequence(sequenceKey)) {
49741             throw new GraphMapillaryError(`Cannot cache sequence nodes of sequence that does not exist in graph (${sequenceKey}).`);
49742         }
49743         if (this.hasSequenceNodes(sequenceKey)) {
49744             throw new GraphMapillaryError(`Sequence nodes already cached (${sequenceKey}).`);
49745         }
49746         const sequence = this.getSequence(sequenceKey);
49747         if (sequence.id in this._cachingSequenceNodes$) {
49748             return this._cachingSequenceNodes$[sequence.id];
49749         }
49750         const batches = [];
49751         const keys = sequence.imageIds.slice();
49752         const referenceBatchSize = 50;
49753         if (!!referenceNodeKey && keys.length > referenceBatchSize) {
49754             const referenceIndex = keys.indexOf(referenceNodeKey);
49755             const startIndex = Math.max(0, Math.min(referenceIndex - referenceBatchSize / 2, keys.length - referenceBatchSize));
49756             batches.push(keys.splice(startIndex, referenceBatchSize));
49757         }
49758         const batchSize = 200;
49759         while (keys.length > 0) {
49760             batches.push(keys.splice(0, batchSize));
49761         }
49762         let batchesToCache = batches.length;
49763         const sequenceNodes$ = from(batches).pipe(mergeMap((batch) => {
49764             return this._api.getImages$(batch).pipe(tap((items) => {
49765                 for (const item of items) {
49766                     if (!item.node) {
49767                         console.warn(`Image empty (${item.node_id})`);
49768                         continue;
49769                     }
49770                     const id = item.node_id;
49771                     if (this.hasNode(id)) {
49772                         const node = this.getNode(id);
49773                         if (!node.complete) {
49774                             this._makeFull(node, item.node);
49775                         }
49776                     }
49777                     else {
49778                         if (item.node.sequence.id == null) {
49779                             console.warn(`Sequence missing, discarding node (${item.node_id})`);
49780                         }
49781                         const node = new Image$1(item.node);
49782                         this._makeFull(node, item.node);
49783                         const cellId = this._api.data.geometry
49784                             .lngLatToCellId(node.originalLngLat);
49785                         this._preStore(cellId, node);
49786                         this._setNode(node);
49787                     }
49788                 }
49789                 batchesToCache--;
49790             }), map(() => this));
49791         }, 6), last(), finalize(() => {
49792             delete this._cachingSequenceNodes$[sequence.id];
49793             if (batchesToCache === 0) {
49794                 this._cachedSequenceNodes[sequence.id] = true;
49795             }
49796         }), publish(), refCount());
49797         this._cachingSequenceNodes$[sequence.id] = sequenceNodes$;
49798         return sequenceNodes$;
49799     }
49800     /**
49801      * Retrieve and cache full nodes for a node spatial area.
49802      *
49803      * @param {string} key - Key of node for which to retrieve sequence.
49804      * @returns {Observable<Graph>} Observable emitting the graph
49805      * when the nodes in the spatial area has been made full.
49806      * @throws {GraphMapillaryError} When the operation is not valid on the
49807      * current graph.
49808      */
49809     cacheSpatialArea$(key) {
49810         if (!this.hasNode(key)) {
49811             throw new GraphMapillaryError(`Cannot cache spatial area of node that does not exist in graph (${key}).`);
49812         }
49813         if (key in this._cachedSpatialEdges) {
49814             throw new GraphMapillaryError(`Image already spatially cached (${key}).`);
49815         }
49816         if (!(key in this._requiredSpatialArea)) {
49817             throw new GraphMapillaryError(`Spatial area not determined (${key}).`);
49818         }
49819         let spatialArea = this._requiredSpatialArea[key];
49820         if (Object.keys(spatialArea.cacheNodes).length === 0) {
49821             throw new GraphMapillaryError(`Spatial nodes already cached (${key}).`);
49822         }
49823         if (key in this._cachingSpatialArea$) {
49824             return this._cachingSpatialArea$[key];
49825         }
49826         let batches = [];
49827         while (spatialArea.cacheKeys.length > 0) {
49828             batches.push(spatialArea.cacheKeys.splice(0, 200));
49829         }
49830         let batchesToCache = batches.length;
49831         let spatialNodes$ = [];
49832         for (let batch of batches) {
49833             let spatialNodeBatch$ = this._api.getSpatialImages$(batch).pipe(tap((items) => {
49834                 for (const item of items) {
49835                     if (!item.node) {
49836                         console.warn(`Image is empty (${item.node_id})`);
49837                         continue;
49838                     }
49839                     const id = item.node_id;
49840                     const spatialNode = spatialArea.cacheNodes[id];
49841                     if (spatialNode.complete) {
49842                         delete spatialArea.cacheNodes[id];
49843                         continue;
49844                     }
49845                     this._makeFull(spatialNode, item.node);
49846                     delete spatialArea.cacheNodes[id];
49847                 }
49848                 if (--batchesToCache === 0) {
49849                     delete this._cachingSpatialArea$[key];
49850                 }
49851             }), map(() => { return this; }), catchError((error) => {
49852                 for (let batchKey of batch) {
49853                     if (batchKey in spatialArea.all) {
49854                         delete spatialArea.all[batchKey];
49855                     }
49856                     if (batchKey in spatialArea.cacheNodes) {
49857                         delete spatialArea.cacheNodes[batchKey];
49858                     }
49859                 }
49860                 if (--batchesToCache === 0) {
49861                     delete this._cachingSpatialArea$[key];
49862                 }
49863                 throw error;
49864             }), finalize(() => {
49865                 if (Object.keys(spatialArea.cacheNodes).length === 0) {
49866                     this._changed$.next(this);
49867                 }
49868             }), publish(), refCount());
49869             spatialNodes$.push(spatialNodeBatch$);
49870         }
49871         this._cachingSpatialArea$[key] = spatialNodes$;
49872         return spatialNodes$;
49873     }
49874     /**
49875      * Cache spatial edges for a node.
49876      *
49877      * @param {string} key - Key of node.
49878      * @throws {GraphMapillaryError} When the operation is not valid on the
49879      * current graph.
49880      */
49881     cacheSpatialEdges(key) {
49882         if (key in this._cachedSpatialEdges) {
49883             throw new GraphMapillaryError(`Spatial edges already cached (${key}).`);
49884         }
49885         let node = this.getNode(key);
49886         let sequence = this._sequences[node.sequenceId].sequence;
49887         let fallbackKeys = [];
49888         let prevKey = sequence.findPrev(node.id);
49889         if (prevKey != null) {
49890             fallbackKeys.push(prevKey);
49891         }
49892         let nextKey = sequence.findNext(node.id);
49893         if (nextKey != null) {
49894             fallbackKeys.push(nextKey);
49895         }
49896         let allSpatialNodes = this._requiredSpatialArea[key].all;
49897         let potentialNodes = [];
49898         let filter = this._filter;
49899         for (let spatialNodeKey in allSpatialNodes) {
49900             if (!allSpatialNodes.hasOwnProperty(spatialNodeKey)) {
49901                 continue;
49902             }
49903             let spatialNode = allSpatialNodes[spatialNodeKey];
49904             if (filter(spatialNode)) {
49905                 potentialNodes.push(spatialNode);
49906             }
49907         }
49908         let potentialEdges = this._edgeCalculator.getPotentialEdges(node, potentialNodes, fallbackKeys);
49909         let edges = this._edgeCalculator.computeStepEdges(node, potentialEdges, prevKey, nextKey);
49910         edges = edges.concat(this._edgeCalculator.computeTurnEdges(node, potentialEdges));
49911         edges = edges.concat(this._edgeCalculator.computeSphericalEdges(node, potentialEdges));
49912         edges = edges.concat(this._edgeCalculator.computePerspectiveToSphericalEdges(node, potentialEdges));
49913         edges = edges.concat(this._edgeCalculator.computeSimilarEdges(node, potentialEdges));
49914         node.cacheSpatialEdges(edges);
49915         this._cachedSpatialEdges[key] = node;
49916         delete this._requiredSpatialArea[key];
49917         delete this._cachedNodeTiles[key];
49918     }
49919     /**
49920      * Retrieve and cache tiles for a node.
49921      *
49922      * @param {string} key - Key of node for which to retrieve tiles.
49923      * @returns {Array<Observable<Graph>>} Array of observables emitting
49924      * the graph for each tile required for the node has been cached.
49925      * @throws {GraphMapillaryError} When the operation is not valid on the
49926      * current graph.
49927      */
49928     cacheTiles$(key) {
49929         if (key in this._cachedNodeTiles) {
49930             throw new GraphMapillaryError(`Tiles already cached (${key}).`);
49931         }
49932         if (key in this._cachedSpatialEdges) {
49933             throw new GraphMapillaryError(`Spatial edges already cached so tiles considered cached (${key}).`);
49934         }
49935         if (!(key in this._requiredNodeTiles)) {
49936             throw new GraphMapillaryError(`Tiles have not been determined (${key}).`);
49937         }
49938         let nodeTiles = this._requiredNodeTiles[key];
49939         if (nodeTiles.cache.length === 0 &&
49940             nodeTiles.caching.length === 0) {
49941             throw new GraphMapillaryError(`Tiles already cached (${key}).`);
49942         }
49943         if (!this.hasNode(key)) {
49944             throw new GraphMapillaryError(`Cannot cache tiles of node that does not exist in graph (${key}).`);
49945         }
49946         let hs = nodeTiles.cache.slice();
49947         nodeTiles.caching = this._requiredNodeTiles[key].caching.concat(hs);
49948         nodeTiles.cache = [];
49949         let cacheTiles$ = [];
49950         for (let h of nodeTiles.caching) {
49951             const cacheTile$ = h in this._cachingTiles$ ?
49952                 this._cachingTiles$[h] :
49953                 this._cacheTile$(h);
49954             cacheTiles$.push(cacheTile$.pipe(tap((graph) => {
49955                 let index = nodeTiles.caching.indexOf(h);
49956                 if (index > -1) {
49957                     nodeTiles.caching.splice(index, 1);
49958                 }
49959                 if (nodeTiles.caching.length === 0 &&
49960                     nodeTiles.cache.length === 0) {
49961                     delete this._requiredNodeTiles[key];
49962                     this._cachedNodeTiles[key] = true;
49963                 }
49964             }), catchError((error) => {
49965                 let index = nodeTiles.caching.indexOf(h);
49966                 if (index > -1) {
49967                     nodeTiles.caching.splice(index, 1);
49968                 }
49969                 if (nodeTiles.caching.length === 0 &&
49970                     nodeTiles.cache.length === 0) {
49971                     delete this._requiredNodeTiles[key];
49972                     this._cachedNodeTiles[key] = true;
49973                 }
49974                 throw error;
49975             }), finalize(() => {
49976                 this._changed$.next(this);
49977             }), publish(), refCount()));
49978         }
49979         return cacheTiles$;
49980     }
49981     /**
49982      * Initialize the cache for a node.
49983      *
49984      * @param {string} key - Key of node.
49985      * @throws {GraphMapillaryError} When the operation is not valid on the
49986      * current graph.
49987      */
49988     initializeCache(key) {
49989         if (key in this._cachedNodes) {
49990             throw new GraphMapillaryError(`Image already in cache (${key}).`);
49991         }
49992         const node = this.getNode(key);
49993         const provider = this._api.data;
49994         node.initializeCache(new ImageCache(provider));
49995         const accessed = new Date().getTime();
49996         this._cachedNodes[key] = { accessed: accessed, node: node };
49997         this._updateCachedTileAccess(key, accessed);
49998     }
49999     /**
50000      * Get a value indicating if the graph is fill caching a node.
50001      *
50002      * @param {string} key - Key of node.
50003      * @returns {boolean} Value indicating if the node is being fill cached.
50004      */
50005     isCachingFill(key) {
50006         return key in this._cachingFill$;
50007     }
50008     /**
50009      * Get a value indicating if the graph is fully caching a node.
50010      *
50011      * @param {string} key - Key of node.
50012      * @returns {boolean} Value indicating if the node is being fully cached.
50013      */
50014     isCachingFull(key) {
50015         return key in this._cachingFull$;
50016     }
50017     /**
50018      * Get a value indicating if the graph is caching a sequence of a node.
50019      *
50020      * @param {string} key - Key of node.
50021      * @returns {boolean} Value indicating if the sequence of a node is
50022      * being cached.
50023      */
50024     isCachingNodeSequence(key) {
50025         let node = this.getNode(key);
50026         return node.sequenceId in this._cachingSequences$;
50027     }
50028     /**
50029      * Get a value indicating if the graph is caching a sequence.
50030      *
50031      * @param {string} sequenceKey - Key of sequence.
50032      * @returns {boolean} Value indicating if the sequence is
50033      * being cached.
50034      */
50035     isCachingSequence(sequenceKey) {
50036         return sequenceKey in this._cachingSequences$;
50037     }
50038     /**
50039      * Get a value indicating if the graph is caching sequence nodes.
50040      *
50041      * @param {string} sequenceKey - Key of sequence.
50042      * @returns {boolean} Value indicating if the sequence nodes are
50043      * being cached.
50044      */
50045     isCachingSequenceNodes(sequenceKey) {
50046         return sequenceKey in this._cachingSequenceNodes$;
50047     }
50048     /**
50049      * Get a value indicating if the graph is caching the tiles
50050      * required for calculating spatial edges of a node.
50051      *
50052      * @param {string} key - Key of node.
50053      * @returns {boolean} Value indicating if the tiles of
50054      * a node are being cached.
50055      */
50056     isCachingTiles(key) {
50057         return key in this._requiredNodeTiles &&
50058             this._requiredNodeTiles[key].cache.length === 0 &&
50059             this._requiredNodeTiles[key].caching.length > 0;
50060     }
50061     /**
50062      * Get a value indicating if the cache has been initialized
50063      * for a node.
50064      *
50065      * @param {string} key - Key of node.
50066      * @returns {boolean} Value indicating if the cache has been
50067      * initialized for a node.
50068      */
50069     hasInitializedCache(key) {
50070         return key in this._cachedNodes;
50071     }
50072     /**
50073      * Get a value indicating if a node exist in the graph.
50074      *
50075      * @param {string} key - Key of node.
50076      * @returns {boolean} Value indicating if a node exist in the graph.
50077      */
50078     hasNode(key) {
50079         let accessed = new Date().getTime();
50080         this._updateCachedNodeAccess(key, accessed);
50081         this._updateCachedTileAccess(key, accessed);
50082         return key in this._nodes;
50083     }
50084     /**
50085      * Get a value indicating if a node sequence exist in the graph.
50086      *
50087      * @param {string} key - Key of node.
50088      * @returns {boolean} Value indicating if a node sequence exist
50089      * in the graph.
50090      */
50091     hasNodeSequence(key) {
50092         let node = this.getNode(key);
50093         let sequenceKey = node.sequenceId;
50094         let hasNodeSequence = sequenceKey in this._sequences;
50095         if (hasNodeSequence) {
50096             this._sequences[sequenceKey].accessed = new Date().getTime();
50097         }
50098         return hasNodeSequence;
50099     }
50100     /**
50101      * Get a value indicating if a sequence exist in the graph.
50102      *
50103      * @param {string} sequenceKey - Key of sequence.
50104      * @returns {boolean} Value indicating if a sequence exist
50105      * in the graph.
50106      */
50107     hasSequence(sequenceKey) {
50108         let hasSequence = sequenceKey in this._sequences;
50109         if (hasSequence) {
50110             this._sequences[sequenceKey].accessed = new Date().getTime();
50111         }
50112         return hasSequence;
50113     }
50114     /**
50115      * Get a value indicating if sequence nodes has been cached in the graph.
50116      *
50117      * @param {string} sequenceKey - Key of sequence.
50118      * @returns {boolean} Value indicating if a sequence nodes has been
50119      * cached in the graph.
50120      */
50121     hasSequenceNodes(sequenceKey) {
50122         return sequenceKey in this._cachedSequenceNodes;
50123     }
50124     /**
50125      * Get a value indicating if the graph has fully cached
50126      * all nodes in the spatial area of a node.
50127      *
50128      * @param {string} key - Key of node.
50129      * @returns {boolean} Value indicating if the spatial area
50130      * of a node has been cached.
50131      */
50132     hasSpatialArea(key) {
50133         if (!this.hasNode(key)) {
50134             throw new GraphMapillaryError(`Spatial area nodes cannot be determined if node not in graph (${key}).`);
50135         }
50136         if (key in this._cachedSpatialEdges) {
50137             return true;
50138         }
50139         if (key in this._requiredSpatialArea) {
50140             return Object
50141                 .keys(this._requiredSpatialArea[key].cacheNodes)
50142                 .length === 0;
50143         }
50144         let node = this.getNode(key);
50145         let bbox = this._graphCalculator
50146             .boundingBoxCorners(node.lngLat, this._tileThreshold);
50147         let spatialItems = this._nodeIndex
50148             .search({
50149             maxX: bbox[1].lng,
50150             maxY: bbox[1].lat,
50151             minX: bbox[0].lng,
50152             minY: bbox[0].lat,
50153         });
50154         let spatialNodes = {
50155             all: {},
50156             cacheKeys: [],
50157             cacheNodes: {},
50158         };
50159         for (let spatialItem of spatialItems) {
50160             spatialNodes.all[spatialItem.node.id] = spatialItem.node;
50161             if (!spatialItem.node.complete) {
50162                 spatialNodes.cacheKeys.push(spatialItem.node.id);
50163                 spatialNodes.cacheNodes[spatialItem.node.id] = spatialItem.node;
50164             }
50165         }
50166         this._requiredSpatialArea[key] = spatialNodes;
50167         return spatialNodes.cacheKeys.length === 0;
50168     }
50169     /**
50170      * Get a value indicating if the graph has a tiles required
50171      * for a node.
50172      *
50173      * @param {string} key - Key of node.
50174      * @returns {boolean} Value indicating if the the tiles required
50175      * by a node has been cached.
50176      */
50177     hasTiles(key) {
50178         if (key in this._cachedNodeTiles) {
50179             return true;
50180         }
50181         if (key in this._cachedSpatialEdges) {
50182             return true;
50183         }
50184         if (!this.hasNode(key)) {
50185             throw new GraphMapillaryError(`Image does not exist in graph (${key}).`);
50186         }
50187         let nodeTiles = { cache: [], caching: [] };
50188         if (!(key in this._requiredNodeTiles)) {
50189             const node = this.getNode(key);
50190             const [sw, ne] = this._graphCalculator
50191                 .boundingBoxCorners(node.lngLat, this._tileThreshold);
50192             nodeTiles.cache = this._api.data.geometry
50193                 .bboxToCellIds(sw, ne)
50194                 .filter((h) => {
50195                 return !(h in this._cachedTiles);
50196             });
50197             if (nodeTiles.cache.length > 0) {
50198                 this._requiredNodeTiles[key] = nodeTiles;
50199             }
50200         }
50201         else {
50202             nodeTiles = this._requiredNodeTiles[key];
50203         }
50204         return nodeTiles.cache.length === 0 && nodeTiles.caching.length === 0;
50205     }
50206     /**
50207      * Get a node.
50208      *
50209      * @param {string} key - Key of node.
50210      * @returns {Image} Retrieved node.
50211      */
50212     getNode(key) {
50213         let accessed = new Date().getTime();
50214         this._updateCachedNodeAccess(key, accessed);
50215         this._updateCachedTileAccess(key, accessed);
50216         return this._nodes[key];
50217     }
50218     /**
50219      * Get a sequence.
50220      *
50221      * @param {string} sequenceKey - Key of sequence.
50222      * @returns {Image} Retrieved sequence.
50223      */
50224     getSequence(sequenceKey) {
50225         let sequenceAccess = this._sequences[sequenceKey];
50226         sequenceAccess.accessed = new Date().getTime();
50227         return sequenceAccess.sequence;
50228     }
50229     /**
50230      * Reset all spatial edges of the graph nodes.
50231      */
50232     resetSpatialEdges() {
50233         let cachedKeys = Object.keys(this._cachedSpatialEdges);
50234         for (let cachedKey of cachedKeys) {
50235             let node = this._cachedSpatialEdges[cachedKey];
50236             node.resetSpatialEdges();
50237             delete this._cachedSpatialEdges[cachedKey];
50238         }
50239     }
50240     /**
50241      * Reset the complete graph but keep the nodes corresponding
50242      * to the supplied keys. All other nodes will be disposed.
50243      *
50244      * @param {Array<string>} keepKeys - Keys for nodes to keep
50245      * in graph after reset.
50246      */
50247     reset(keepKeys) {
50248         const nodes = [];
50249         for (const key of keepKeys) {
50250             if (!this.hasNode(key)) {
50251                 throw new Error(`Image does not exist ${key}`);
50252             }
50253             const node = this.getNode(key);
50254             node.resetSequenceEdges();
50255             node.resetSpatialEdges();
50256             nodes.push(node);
50257         }
50258         for (let cachedKey of Object.keys(this._cachedNodes)) {
50259             if (keepKeys.indexOf(cachedKey) !== -1) {
50260                 continue;
50261             }
50262             this._cachedNodes[cachedKey].node.dispose();
50263             delete this._cachedNodes[cachedKey];
50264         }
50265         this._cachedNodeTiles = {};
50266         this._cachedSpatialEdges = {};
50267         this._cachedTiles = {};
50268         this._cachingFill$ = {};
50269         this._cachingFull$ = {};
50270         this._cachingSequences$ = {};
50271         this._cachingSpatialArea$ = {};
50272         this._cachingTiles$ = {};
50273         this._nodes = {};
50274         this._nodeToTile = {};
50275         this._preStored = {};
50276         for (const node of nodes) {
50277             this._nodes[node.id] = node;
50278             const h = this._api.data.geometry.lngLatToCellId(node.originalLngLat);
50279             this._preStore(h, node);
50280         }
50281         this._requiredNodeTiles = {};
50282         this._requiredSpatialArea = {};
50283         this._sequences = {};
50284         this._nodeIndexTiles = {};
50285         this._nodeIndex.clear();
50286     }
50287     /**
50288      * Set the spatial node filter.
50289      *
50290      * @emits FilterFunction The filter function to the {@link Graph.filter$}
50291      * observable.
50292      *
50293      * @param {FilterExpression} filter - Filter expression to be applied
50294      * when calculating spatial edges.
50295      */
50296     setFilter(filter) {
50297         this._filter = this._filterCreator.createFilter(filter);
50298         this._filterSubject$.next(this._filter);
50299     }
50300     /**
50301      * Uncache the graph according to the graph configuration.
50302      *
50303      * @description Uncaches unused tiles, unused nodes and
50304      * sequences according to the numbers specified in the
50305      * graph configuration. Sequences does not have a direct
50306      * reference to either tiles or nodes and may be uncached
50307      * even if they are related to the nodes that should be kept.
50308      *
50309      * @param {Array<string>} keepIds - Ids of nodes to keep in
50310      * graph unrelated to last access. Tiles related to those keys
50311      * will also be kept in graph.
50312      * @param {Array<string>} keepCellIds - Ids of cells to keep in
50313      * graph unrelated to last access. The nodes of the cells may
50314      * still be uncached if not specified in the keep ids param
50315      * but are guaranteed to not be disposed.
50316      * @param {string} keepSequenceId - Optional id of sequence
50317      * for which the belonging nodes should not be disposed or
50318      * removed from the graph. These nodes may still be uncached if
50319      * not specified in keep ids param but are guaranteed to not
50320      * be disposed.
50321      */
50322     uncache(keepIds, keepCellIds, keepSequenceId) {
50323         const idsInUse = {};
50324         this._addNewKeys(idsInUse, this._cachingFull$);
50325         this._addNewKeys(idsInUse, this._cachingFill$);
50326         this._addNewKeys(idsInUse, this._cachingSpatialArea$);
50327         this._addNewKeys(idsInUse, this._requiredNodeTiles);
50328         this._addNewKeys(idsInUse, this._requiredSpatialArea);
50329         for (const key of keepIds) {
50330             if (key in idsInUse) {
50331                 continue;
50332             }
50333             idsInUse[key] = true;
50334         }
50335         const tileThreshold = this._tileThreshold;
50336         const calculator = this._graphCalculator;
50337         const geometry = this._api.data.geometry;
50338         const keepCells = new Set(keepCellIds);
50339         for (let id in idsInUse) {
50340             if (!idsInUse.hasOwnProperty(id)) {
50341                 continue;
50342             }
50343             const node = this._nodes[id];
50344             const [sw, ne] = calculator
50345                 .boundingBoxCorners(node.lngLat, tileThreshold);
50346             const nodeCellIds = geometry.bboxToCellIds(sw, ne);
50347             for (const nodeCellId of nodeCellIds) {
50348                 if (!keepCells.has(nodeCellId)) {
50349                     keepCells.add(nodeCellId);
50350                 }
50351             }
50352         }
50353         const potentialCells = [];
50354         for (let cellId in this._cachedTiles) {
50355             if (!this._cachedTiles.hasOwnProperty(cellId) ||
50356                 keepCells.has(cellId)) {
50357                 continue;
50358             }
50359             potentialCells.push([cellId, this._cachedTiles[cellId]]);
50360         }
50361         const uncacheCells = potentialCells
50362             .sort((h1, h2) => {
50363             return h2[1].accessed - h1[1].accessed;
50364         })
50365             .slice(this._configuration.maxUnusedTiles)
50366             .map((h) => {
50367             return h[0];
50368         });
50369         for (let uncacheCell of uncacheCells) {
50370             this._uncacheTile(uncacheCell, keepSequenceId);
50371         }
50372         const potentialPreStored = [];
50373         const nonCachedPreStored = [];
50374         for (let cellId in this._preStored) {
50375             if (!this._preStored.hasOwnProperty(cellId) ||
50376                 cellId in this._cachingTiles$) {
50377                 continue;
50378             }
50379             const prestoredNodes = this._preStored[cellId];
50380             for (let id in prestoredNodes) {
50381                 if (!prestoredNodes.hasOwnProperty(id) || id in idsInUse) {
50382                     continue;
50383                 }
50384                 if (prestoredNodes[id].sequenceId === keepSequenceId) {
50385                     continue;
50386                 }
50387                 if (id in this._cachedNodes) {
50388                     potentialPreStored.push([this._cachedNodes[id], cellId]);
50389                 }
50390                 else {
50391                     nonCachedPreStored.push([id, cellId]);
50392                 }
50393             }
50394         }
50395         const uncachePreStored = potentialPreStored
50396             .sort(([na1], [na2]) => {
50397             return na2.accessed - na1.accessed;
50398         })
50399             .slice(this._configuration.maxUnusedPreStoredImages)
50400             .map(([na, h]) => {
50401             return [na.node.id, h];
50402         });
50403         this._uncachePreStored(nonCachedPreStored);
50404         this._uncachePreStored(uncachePreStored);
50405         const potentialNodes = [];
50406         for (let id in this._cachedNodes) {
50407             if (!this._cachedNodes.hasOwnProperty(id) || id in idsInUse) {
50408                 continue;
50409             }
50410             potentialNodes.push(this._cachedNodes[id]);
50411         }
50412         const uncacheNodes = potentialNodes
50413             .sort((n1, n2) => {
50414             return n2.accessed - n1.accessed;
50415         })
50416             .slice(this._configuration.maxUnusedImages);
50417         for (const nodeAccess of uncacheNodes) {
50418             nodeAccess.node.uncache();
50419             const id = nodeAccess.node.id;
50420             delete this._cachedNodes[id];
50421             if (id in this._cachedNodeTiles) {
50422                 delete this._cachedNodeTiles[id];
50423             }
50424             if (id in this._cachedSpatialEdges) {
50425                 delete this._cachedSpatialEdges[id];
50426             }
50427         }
50428         const potentialSequences = [];
50429         for (let sequenceId in this._sequences) {
50430             if (!this._sequences.hasOwnProperty(sequenceId) ||
50431                 sequenceId in this._cachingSequences$ ||
50432                 sequenceId === keepSequenceId) {
50433                 continue;
50434             }
50435             potentialSequences.push(this._sequences[sequenceId]);
50436         }
50437         const uncacheSequences = potentialSequences
50438             .sort((s1, s2) => {
50439             return s2.accessed - s1.accessed;
50440         })
50441             .slice(this._configuration.maxSequences);
50442         for (const sequenceAccess of uncacheSequences) {
50443             const sequenceId = sequenceAccess.sequence.id;
50444             delete this._sequences[sequenceId];
50445             if (sequenceId in this._cachedSequenceNodes) {
50446                 delete this._cachedSequenceNodes[sequenceId];
50447             }
50448             sequenceAccess.sequence.dispose();
50449         }
50450     }
50451     /**
50452      * Updates existing cells with new core nodes.
50453      *
50454      * @description Non-existing cells are discarded
50455      * and not requested at all.
50456      *
50457      * Existing nodes are not changed.
50458      *
50459      * New nodes are not made full or getting assets
50460      * cached.
50461      *
50462      * @param {Array<string>} cellIds - Cell ids.
50463      * @returns {Observable<Array<Image>>} Observable
50464      * emitting the updated cells.
50465      */
50466     updateCells$(cellIds) {
50467         const cachedCells = this._cachedTiles;
50468         const cachingCells = this._cachingTiles$;
50469         return from(cellIds)
50470             .pipe(mergeMap((cellId) => {
50471             if (cellId in cachedCells) {
50472                 return this._updateCell$(cellId);
50473             }
50474             if (cellId in cachingCells) {
50475                 return cachingCells[cellId]
50476                     .pipe(catchError(() => {
50477                     return of(this);
50478                 }), mergeMap(() => this._updateCell$(cellId)));
50479             }
50480             return empty();
50481         }));
50482     }
50483     /**
50484      * Unsubscribes all subscriptions.
50485      *
50486      * @description Afterwards, you must not call any other methods
50487      * on the graph instance.
50488      */
50489     unsubscribe() {
50490         this._filterSubscription.unsubscribe();
50491     }
50492     _addNewKeys(keys, dict) {
50493         for (let key in dict) {
50494             if (!dict.hasOwnProperty(key) || !this.hasNode(key)) {
50495                 continue;
50496             }
50497             if (!(key in keys)) {
50498                 keys[key] = true;
50499             }
50500         }
50501     }
50502     _cacheSequence$(sequenceId) {
50503         if (sequenceId in this._cachingSequences$) {
50504             return this._cachingSequences$[sequenceId];
50505         }
50506         this._cachingSequences$[sequenceId] = this._api
50507             .getSequence$(sequenceId)
50508             .pipe(tap((sequence) => {
50509             if (!sequence) {
50510                 console.warn(`Sequence does not exist ` +
50511                     `(${sequenceId})`);
50512             }
50513             else {
50514                 if (!(sequence.id in this._sequences)) {
50515                     this._sequences[sequence.id] = {
50516                         accessed: new Date().getTime(),
50517                         sequence: new Sequence(sequence),
50518                     };
50519                 }
50520                 delete this._cachingSequences$[sequenceId];
50521             }
50522         }), map(() => { return this; }), finalize(() => {
50523             if (sequenceId in this._cachingSequences$) {
50524                 delete this._cachingSequences$[sequenceId];
50525             }
50526             this._changed$.next(this);
50527         }), publish(), refCount());
50528         return this._cachingSequences$[sequenceId];
50529     }
50530     _cacheTile$(cellId) {
50531         this._cachingTiles$[cellId] = this._api
50532             .getCoreImages$(cellId)
50533             .pipe(tap((contract) => {
50534             if (cellId in this._cachedTiles) {
50535                 return;
50536             }
50537             const cores = contract.images;
50538             this._nodeIndexTiles[cellId] = [];
50539             this._cachedTiles[cellId] = {
50540                 accessed: new Date().getTime(),
50541                 nodes: [],
50542             };
50543             const hCache = this._cachedTiles[cellId].nodes;
50544             const preStored = this._removeFromPreStore(cellId);
50545             for (const core of cores) {
50546                 if (!core) {
50547                     break;
50548                 }
50549                 if (core.sequence.id == null) {
50550                     console.warn(`Sequence missing, discarding ` +
50551                         `node (${core.id})`);
50552                     continue;
50553                 }
50554                 if (preStored != null && core.id in preStored) {
50555                     const preStoredNode = preStored[core.id];
50556                     delete preStored[core.id];
50557                     hCache.push(preStoredNode);
50558                     const preStoredNodeIndexItem = {
50559                         lat: preStoredNode.lngLat.lat,
50560                         lng: preStoredNode.lngLat.lng,
50561                         node: preStoredNode,
50562                     };
50563                     this._nodeIndex.insert(preStoredNodeIndexItem);
50564                     this._nodeIndexTiles[cellId]
50565                         .push(preStoredNodeIndexItem);
50566                     this._nodeToTile[preStoredNode.id] = cellId;
50567                     continue;
50568                 }
50569                 const node = new Image$1(core);
50570                 hCache.push(node);
50571                 const nodeIndexItem = {
50572                     lat: node.lngLat.lat,
50573                     lng: node.lngLat.lng,
50574                     node: node,
50575                 };
50576                 this._nodeIndex.insert(nodeIndexItem);
50577                 this._nodeIndexTiles[cellId].push(nodeIndexItem);
50578                 this._nodeToTile[node.id] = cellId;
50579                 this._setNode(node);
50580             }
50581             delete this._cachingTiles$[cellId];
50582         }), map(() => this), catchError((error) => {
50583             delete this._cachingTiles$[cellId];
50584             throw error;
50585         }), publish(), refCount());
50586         return this._cachingTiles$[cellId];
50587     }
50588     _makeFull(node, fillNode) {
50589         if (fillNode.computed_altitude == null) {
50590             fillNode.computed_altitude = this._defaultAlt;
50591         }
50592         if (fillNode.computed_rotation == null) {
50593             fillNode.computed_rotation = this._graphCalculator.rotationFromCompass(fillNode.compass_angle, fillNode.exif_orientation);
50594         }
50595         node.makeComplete(fillNode);
50596     }
50597     _preStore(h, node) {
50598         if (!(h in this._preStored)) {
50599             this._preStored[h] = {};
50600         }
50601         this._preStored[h][node.id] = node;
50602     }
50603     _removeFromPreStore(h) {
50604         let preStored = null;
50605         if (h in this._preStored) {
50606             preStored = this._preStored[h];
50607             delete this._preStored[h];
50608         }
50609         return preStored;
50610     }
50611     _setNode(node) {
50612         let key = node.id;
50613         if (this.hasNode(key)) {
50614             throw new GraphMapillaryError(`Image already exist (${key}).`);
50615         }
50616         this._nodes[key] = node;
50617     }
50618     _uncacheTile(h, keepSequenceKey) {
50619         for (let node of this._cachedTiles[h].nodes) {
50620             let key = node.id;
50621             delete this._nodeToTile[key];
50622             if (key in this._cachedNodes) {
50623                 delete this._cachedNodes[key];
50624             }
50625             if (key in this._cachedNodeTiles) {
50626                 delete this._cachedNodeTiles[key];
50627             }
50628             if (key in this._cachedSpatialEdges) {
50629                 delete this._cachedSpatialEdges[key];
50630             }
50631             if (node.sequenceId === keepSequenceKey) {
50632                 this._preStore(h, node);
50633                 node.uncache();
50634             }
50635             else {
50636                 delete this._nodes[key];
50637                 if (node.sequenceId in this._cachedSequenceNodes) {
50638                     delete this._cachedSequenceNodes[node.sequenceId];
50639                 }
50640                 node.dispose();
50641             }
50642         }
50643         for (let nodeIndexItem of this._nodeIndexTiles[h]) {
50644             this._nodeIndex.remove(nodeIndexItem);
50645         }
50646         delete this._nodeIndexTiles[h];
50647         delete this._cachedTiles[h];
50648     }
50649     _uncachePreStored(preStored) {
50650         let hs = {};
50651         for (let [key, h] of preStored) {
50652             if (key in this._nodes) {
50653                 delete this._nodes[key];
50654             }
50655             if (key in this._cachedNodes) {
50656                 delete this._cachedNodes[key];
50657             }
50658             let node = this._preStored[h][key];
50659             if (node.sequenceId in this._cachedSequenceNodes) {
50660                 delete this._cachedSequenceNodes[node.sequenceId];
50661             }
50662             delete this._preStored[h][key];
50663             node.dispose();
50664             hs[h] = true;
50665         }
50666         for (let h in hs) {
50667             if (!hs.hasOwnProperty(h)) {
50668                 continue;
50669             }
50670             if (Object.keys(this._preStored[h]).length === 0) {
50671                 delete this._preStored[h];
50672             }
50673         }
50674     }
50675     _updateCachedTileAccess(key, accessed) {
50676         if (key in this._nodeToTile) {
50677             this._cachedTiles[this._nodeToTile[key]].accessed = accessed;
50678         }
50679     }
50680     _updateCachedNodeAccess(key, accessed) {
50681         if (key in this._cachedNodes) {
50682             this._cachedNodes[key].accessed = accessed;
50683         }
50684     }
50685     _updateCell$(cellId) {
50686         return this._api.getCoreImages$(cellId).pipe(mergeMap((contract) => {
50687             if (!(cellId in this._cachedTiles)) {
50688                 return empty();
50689             }
50690             const nodeIndex = this._nodeIndex;
50691             const nodeIndexCell = this._nodeIndexTiles[cellId];
50692             const nodeToCell = this._nodeToTile;
50693             const cell = this._cachedTiles[cellId];
50694             cell.accessed = new Date().getTime();
50695             const cellNodes = cell.nodes;
50696             const cores = contract.images;
50697             for (const core of cores) {
50698                 if (core == null) {
50699                     break;
50700                 }
50701                 if (this.hasNode(core.id)) {
50702                     continue;
50703                 }
50704                 if (core.sequence.id == null) {
50705                     console.warn(`Sequence missing, discarding ` +
50706                         `node (${core.id})`);
50707                     continue;
50708                 }
50709                 const node = new Image$1(core);
50710                 cellNodes.push(node);
50711                 const nodeIndexItem = {
50712                     lat: node.lngLat.lat,
50713                     lng: node.lngLat.lng,
50714                     node: node,
50715                 };
50716                 nodeIndex.insert(nodeIndexItem);
50717                 nodeIndexCell.push(nodeIndexItem);
50718                 nodeToCell[node.id] = cellId;
50719                 this._setNode(node);
50720             }
50721             return of(cellId);
50722         }), catchError((error) => {
50723             console.error(error);
50724             return empty();
50725         }));
50726     }
50727 }
50728
50729 class MarkerSet {
50730     constructor() {
50731         this._hash = {};
50732         this._index = new MarkerSet._spatialIndex(16);
50733         this._indexChanged$ = new Subject();
50734         this._updated$ = new Subject();
50735     }
50736     static register(spatialIndex) {
50737         MarkerSet._spatialIndex = spatialIndex;
50738     }
50739     get changed$() {
50740         return this._indexChanged$;
50741     }
50742     get updated$() {
50743         return this._updated$;
50744     }
50745     add(markers) {
50746         const updated = [];
50747         const hash = this._hash;
50748         const index = this._index;
50749         for (const marker of markers) {
50750             const id = marker.id;
50751             if (id in hash) {
50752                 index.remove(hash[id]);
50753                 updated.push(marker);
50754             }
50755             const item = {
50756                 lat: marker.lngLat.lat,
50757                 lng: marker.lngLat.lng,
50758                 marker: marker,
50759             };
50760             hash[id] = item;
50761             index.insert(item);
50762         }
50763         if (updated.length > 0) {
50764             this._updated$.next(updated);
50765         }
50766         if (markers.length > updated.length) {
50767             this._indexChanged$.next(this);
50768         }
50769     }
50770     has(id) {
50771         return id in this._hash;
50772     }
50773     get(id) {
50774         return this.has(id) ? this._hash[id].marker : undefined;
50775     }
50776     getAll() {
50777         return this._index
50778             .all()
50779             .map((indexItem) => {
50780             return indexItem.marker;
50781         });
50782     }
50783     remove(ids) {
50784         const hash = this._hash;
50785         const index = this._index;
50786         let changed = false;
50787         for (const id of ids) {
50788             if (!(id in hash)) {
50789                 continue;
50790             }
50791             const item = hash[id];
50792             index.remove(item);
50793             delete hash[id];
50794             changed = true;
50795         }
50796         if (changed) {
50797             this._indexChanged$.next(this);
50798         }
50799     }
50800     removeAll() {
50801         this._hash = {};
50802         this._index.clear();
50803         this._indexChanged$.next(this);
50804     }
50805     search([sw, ne]) {
50806         return this._index
50807             .search({
50808             maxX: ne.lng,
50809             maxY: ne.lat,
50810             minX: sw.lng,
50811             minY: sw.lat,
50812         })
50813             .map((indexItem) => {
50814             return indexItem.marker;
50815         });
50816     }
50817     update(marker) {
50818         const hash = this._hash;
50819         const index = this._index;
50820         const id = marker.id;
50821         if (!(id in hash)) {
50822             return;
50823         }
50824         index.remove(hash[id]);
50825         const item = {
50826             lat: marker.lngLat.lat,
50827             lng: marker.lngLat.lng,
50828             marker: marker,
50829         };
50830         hash[id] = item;
50831         index.insert(item);
50832     }
50833 }
50834
50835 function quickselect(arr, k, left, right, compare) {
50836     quickselectStep(arr, k, left || 0, right || (arr.length - 1), compare || defaultCompare$2);
50837 }
50838
50839 function quickselectStep(arr, k, left, right, compare) {
50840
50841     while (right > left) {
50842         if (right - left > 600) {
50843             var n = right - left + 1;
50844             var m = k - left + 1;
50845             var z = Math.log(n);
50846             var s = 0.5 * Math.exp(2 * z / 3);
50847             var sd = 0.5 * Math.sqrt(z * s * (n - s) / n) * (m - n / 2 < 0 ? -1 : 1);
50848             var newLeft = Math.max(left, Math.floor(k - m * s / n + sd));
50849             var newRight = Math.min(right, Math.floor(k + (n - m) * s / n + sd));
50850             quickselectStep(arr, k, newLeft, newRight, compare);
50851         }
50852
50853         var t = arr[k];
50854         var i = left;
50855         var j = right;
50856
50857         swap(arr, left, k);
50858         if (compare(arr[right], t) > 0) swap(arr, left, right);
50859
50860         while (i < j) {
50861             swap(arr, i, j);
50862             i++;
50863             j--;
50864             while (compare(arr[i], t) < 0) i++;
50865             while (compare(arr[j], t) > 0) j--;
50866         }
50867
50868         if (compare(arr[left], t) === 0) swap(arr, left, j);
50869         else {
50870             j++;
50871             swap(arr, j, right);
50872         }
50873
50874         if (j <= k) left = j + 1;
50875         if (k <= j) right = j - 1;
50876     }
50877 }
50878
50879 function swap(arr, i, j) {
50880     var tmp = arr[i];
50881     arr[i] = arr[j];
50882     arr[j] = tmp;
50883 }
50884
50885 function defaultCompare$2(a, b) {
50886     return a < b ? -1 : a > b ? 1 : 0;
50887 }
50888
50889 class RBush {
50890     constructor(maxEntries = 9) {
50891         // max entries in a node is 9 by default; min node fill is 40% for best performance
50892         this._maxEntries = Math.max(4, maxEntries);
50893         this._minEntries = Math.max(2, Math.ceil(this._maxEntries * 0.4));
50894         this.clear();
50895     }
50896
50897     all() {
50898         return this._all(this.data, []);
50899     }
50900
50901     search(bbox) {
50902         let node = this.data;
50903         const result = [];
50904
50905         if (!intersects$1(bbox, node)) return result;
50906
50907         const toBBox = this.toBBox;
50908         const nodesToSearch = [];
50909
50910         while (node) {
50911             for (let i = 0; i < node.children.length; i++) {
50912                 const child = node.children[i];
50913                 const childBBox = node.leaf ? toBBox(child) : child;
50914
50915                 if (intersects$1(bbox, childBBox)) {
50916                     if (node.leaf) result.push(child);
50917                     else if (contains(bbox, childBBox)) this._all(child, result);
50918                     else nodesToSearch.push(child);
50919                 }
50920             }
50921             node = nodesToSearch.pop();
50922         }
50923
50924         return result;
50925     }
50926
50927     collides(bbox) {
50928         let node = this.data;
50929
50930         if (!intersects$1(bbox, node)) return false;
50931
50932         const nodesToSearch = [];
50933         while (node) {
50934             for (let i = 0; i < node.children.length; i++) {
50935                 const child = node.children[i];
50936                 const childBBox = node.leaf ? this.toBBox(child) : child;
50937
50938                 if (intersects$1(bbox, childBBox)) {
50939                     if (node.leaf || contains(bbox, childBBox)) return true;
50940                     nodesToSearch.push(child);
50941                 }
50942             }
50943             node = nodesToSearch.pop();
50944         }
50945
50946         return false;
50947     }
50948
50949     load(data) {
50950         if (!(data && data.length)) return this;
50951
50952         if (data.length < this._minEntries) {
50953             for (let i = 0; i < data.length; i++) {
50954                 this.insert(data[i]);
50955             }
50956             return this;
50957         }
50958
50959         // recursively build the tree with the given data from scratch using OMT algorithm
50960         let node = this._build(data.slice(), 0, data.length - 1, 0);
50961
50962         if (!this.data.children.length) {
50963             // save as is if tree is empty
50964             this.data = node;
50965
50966         } else if (this.data.height === node.height) {
50967             // split root if trees have the same height
50968             this._splitRoot(this.data, node);
50969
50970         } else {
50971             if (this.data.height < node.height) {
50972                 // swap trees if inserted one is bigger
50973                 const tmpNode = this.data;
50974                 this.data = node;
50975                 node = tmpNode;
50976             }
50977
50978             // insert the small tree into the large tree at appropriate level
50979             this._insert(node, this.data.height - node.height - 1, true);
50980         }
50981
50982         return this;
50983     }
50984
50985     insert(item) {
50986         if (item) this._insert(item, this.data.height - 1);
50987         return this;
50988     }
50989
50990     clear() {
50991         this.data = createNode([]);
50992         return this;
50993     }
50994
50995     remove(item, equalsFn) {
50996         if (!item) return this;
50997
50998         let node = this.data;
50999         const bbox = this.toBBox(item);
51000         const path = [];
51001         const indexes = [];
51002         let i, parent, goingUp;
51003
51004         // depth-first iterative tree traversal
51005         while (node || path.length) {
51006
51007             if (!node) { // go up
51008                 node = path.pop();
51009                 parent = path[path.length - 1];
51010                 i = indexes.pop();
51011                 goingUp = true;
51012             }
51013
51014             if (node.leaf) { // check current node
51015                 const index = findItem(item, node.children, equalsFn);
51016
51017                 if (index !== -1) {
51018                     // item found, remove the item and condense tree upwards
51019                     node.children.splice(index, 1);
51020                     path.push(node);
51021                     this._condense(path);
51022                     return this;
51023                 }
51024             }
51025
51026             if (!goingUp && !node.leaf && contains(node, bbox)) { // go down
51027                 path.push(node);
51028                 indexes.push(i);
51029                 i = 0;
51030                 parent = node;
51031                 node = node.children[0];
51032
51033             } else if (parent) { // go right
51034                 i++;
51035                 node = parent.children[i];
51036                 goingUp = false;
51037
51038             } else node = null; // nothing found
51039         }
51040
51041         return this;
51042     }
51043
51044     toBBox(item) { return item; }
51045
51046     compareMinX(a, b) { return a.minX - b.minX; }
51047     compareMinY(a, b) { return a.minY - b.minY; }
51048
51049     toJSON() { return this.data; }
51050
51051     fromJSON(data) {
51052         this.data = data;
51053         return this;
51054     }
51055
51056     _all(node, result) {
51057         const nodesToSearch = [];
51058         while (node) {
51059             if (node.leaf) result.push(...node.children);
51060             else nodesToSearch.push(...node.children);
51061
51062             node = nodesToSearch.pop();
51063         }
51064         return result;
51065     }
51066
51067     _build(items, left, right, height) {
51068
51069         const N = right - left + 1;
51070         let M = this._maxEntries;
51071         let node;
51072
51073         if (N <= M) {
51074             // reached leaf level; return leaf
51075             node = createNode(items.slice(left, right + 1));
51076             calcBBox(node, this.toBBox);
51077             return node;
51078         }
51079
51080         if (!height) {
51081             // target height of the bulk-loaded tree
51082             height = Math.ceil(Math.log(N) / Math.log(M));
51083
51084             // target number of root entries to maximize storage utilization
51085             M = Math.ceil(N / Math.pow(M, height - 1));
51086         }
51087
51088         node = createNode([]);
51089         node.leaf = false;
51090         node.height = height;
51091
51092         // split the items into M mostly square tiles
51093
51094         const N2 = Math.ceil(N / M);
51095         const N1 = N2 * Math.ceil(Math.sqrt(M));
51096
51097         multiSelect(items, left, right, N1, this.compareMinX);
51098
51099         for (let i = left; i <= right; i += N1) {
51100
51101             const right2 = Math.min(i + N1 - 1, right);
51102
51103             multiSelect(items, i, right2, N2, this.compareMinY);
51104
51105             for (let j = i; j <= right2; j += N2) {
51106
51107                 const right3 = Math.min(j + N2 - 1, right2);
51108
51109                 // pack each entry recursively
51110                 node.children.push(this._build(items, j, right3, height - 1));
51111             }
51112         }
51113
51114         calcBBox(node, this.toBBox);
51115
51116         return node;
51117     }
51118
51119     _chooseSubtree(bbox, node, level, path) {
51120         while (true) {
51121             path.push(node);
51122
51123             if (node.leaf || path.length - 1 === level) break;
51124
51125             let minArea = Infinity;
51126             let minEnlargement = Infinity;
51127             let targetNode;
51128
51129             for (let i = 0; i < node.children.length; i++) {
51130                 const child = node.children[i];
51131                 const area = bboxArea(child);
51132                 const enlargement = enlargedArea(bbox, child) - area;
51133
51134                 // choose entry with the least area enlargement
51135                 if (enlargement < minEnlargement) {
51136                     minEnlargement = enlargement;
51137                     minArea = area < minArea ? area : minArea;
51138                     targetNode = child;
51139
51140                 } else if (enlargement === minEnlargement) {
51141                     // otherwise choose one with the smallest area
51142                     if (area < minArea) {
51143                         minArea = area;
51144                         targetNode = child;
51145                     }
51146                 }
51147             }
51148
51149             node = targetNode || node.children[0];
51150         }
51151
51152         return node;
51153     }
51154
51155     _insert(item, level, isNode) {
51156         const bbox = isNode ? item : this.toBBox(item);
51157         const insertPath = [];
51158
51159         // find the best node for accommodating the item, saving all nodes along the path too
51160         const node = this._chooseSubtree(bbox, this.data, level, insertPath);
51161
51162         // put the item into the node
51163         node.children.push(item);
51164         extend(node, bbox);
51165
51166         // split on node overflow; propagate upwards if necessary
51167         while (level >= 0) {
51168             if (insertPath[level].children.length > this._maxEntries) {
51169                 this._split(insertPath, level);
51170                 level--;
51171             } else break;
51172         }
51173
51174         // adjust bboxes along the insertion path
51175         this._adjustParentBBoxes(bbox, insertPath, level);
51176     }
51177
51178     // split overflowed node into two
51179     _split(insertPath, level) {
51180         const node = insertPath[level];
51181         const M = node.children.length;
51182         const m = this._minEntries;
51183
51184         this._chooseSplitAxis(node, m, M);
51185
51186         const splitIndex = this._chooseSplitIndex(node, m, M);
51187
51188         const newNode = createNode(node.children.splice(splitIndex, node.children.length - splitIndex));
51189         newNode.height = node.height;
51190         newNode.leaf = node.leaf;
51191
51192         calcBBox(node, this.toBBox);
51193         calcBBox(newNode, this.toBBox);
51194
51195         if (level) insertPath[level - 1].children.push(newNode);
51196         else this._splitRoot(node, newNode);
51197     }
51198
51199     _splitRoot(node, newNode) {
51200         // split root node
51201         this.data = createNode([node, newNode]);
51202         this.data.height = node.height + 1;
51203         this.data.leaf = false;
51204         calcBBox(this.data, this.toBBox);
51205     }
51206
51207     _chooseSplitIndex(node, m, M) {
51208         let index;
51209         let minOverlap = Infinity;
51210         let minArea = Infinity;
51211
51212         for (let i = m; i <= M - m; i++) {
51213             const bbox1 = distBBox(node, 0, i, this.toBBox);
51214             const bbox2 = distBBox(node, i, M, this.toBBox);
51215
51216             const overlap = intersectionArea(bbox1, bbox2);
51217             const area = bboxArea(bbox1) + bboxArea(bbox2);
51218
51219             // choose distribution with minimum overlap
51220             if (overlap < minOverlap) {
51221                 minOverlap = overlap;
51222                 index = i;
51223
51224                 minArea = area < minArea ? area : minArea;
51225
51226             } else if (overlap === minOverlap) {
51227                 // otherwise choose distribution with minimum area
51228                 if (area < minArea) {
51229                     minArea = area;
51230                     index = i;
51231                 }
51232             }
51233         }
51234
51235         return index || M - m;
51236     }
51237
51238     // sorts node children by the best axis for split
51239     _chooseSplitAxis(node, m, M) {
51240         const compareMinX = node.leaf ? this.compareMinX : compareNodeMinX;
51241         const compareMinY = node.leaf ? this.compareMinY : compareNodeMinY;
51242         const xMargin = this._allDistMargin(node, m, M, compareMinX);
51243         const yMargin = this._allDistMargin(node, m, M, compareMinY);
51244
51245         // if total distributions margin value is minimal for x, sort by minX,
51246         // otherwise it's already sorted by minY
51247         if (xMargin < yMargin) node.children.sort(compareMinX);
51248     }
51249
51250     // total margin of all possible split distributions where each node is at least m full
51251     _allDistMargin(node, m, M, compare) {
51252         node.children.sort(compare);
51253
51254         const toBBox = this.toBBox;
51255         const leftBBox = distBBox(node, 0, m, toBBox);
51256         const rightBBox = distBBox(node, M - m, M, toBBox);
51257         let margin = bboxMargin(leftBBox) + bboxMargin(rightBBox);
51258
51259         for (let i = m; i < M - m; i++) {
51260             const child = node.children[i];
51261             extend(leftBBox, node.leaf ? toBBox(child) : child);
51262             margin += bboxMargin(leftBBox);
51263         }
51264
51265         for (let i = M - m - 1; i >= m; i--) {
51266             const child = node.children[i];
51267             extend(rightBBox, node.leaf ? toBBox(child) : child);
51268             margin += bboxMargin(rightBBox);
51269         }
51270
51271         return margin;
51272     }
51273
51274     _adjustParentBBoxes(bbox, path, level) {
51275         // adjust bboxes along the given tree path
51276         for (let i = level; i >= 0; i--) {
51277             extend(path[i], bbox);
51278         }
51279     }
51280
51281     _condense(path) {
51282         // go through the path, removing empty nodes and updating bboxes
51283         for (let i = path.length - 1, siblings; i >= 0; i--) {
51284             if (path[i].children.length === 0) {
51285                 if (i > 0) {
51286                     siblings = path[i - 1].children;
51287                     siblings.splice(siblings.indexOf(path[i]), 1);
51288
51289                 } else this.clear();
51290
51291             } else calcBBox(path[i], this.toBBox);
51292         }
51293     }
51294 }
51295
51296 function findItem(item, items, equalsFn) {
51297     if (!equalsFn) return items.indexOf(item);
51298
51299     for (let i = 0; i < items.length; i++) {
51300         if (equalsFn(item, items[i])) return i;
51301     }
51302     return -1;
51303 }
51304
51305 // calculate node's bbox from bboxes of its children
51306 function calcBBox(node, toBBox) {
51307     distBBox(node, 0, node.children.length, toBBox, node);
51308 }
51309
51310 // min bounding rectangle of node children from k to p-1
51311 function distBBox(node, k, p, toBBox, destNode) {
51312     if (!destNode) destNode = createNode(null);
51313     destNode.minX = Infinity;
51314     destNode.minY = Infinity;
51315     destNode.maxX = -Infinity;
51316     destNode.maxY = -Infinity;
51317
51318     for (let i = k; i < p; i++) {
51319         const child = node.children[i];
51320         extend(destNode, node.leaf ? toBBox(child) : child);
51321     }
51322
51323     return destNode;
51324 }
51325
51326 function extend(a, b) {
51327     a.minX = Math.min(a.minX, b.minX);
51328     a.minY = Math.min(a.minY, b.minY);
51329     a.maxX = Math.max(a.maxX, b.maxX);
51330     a.maxY = Math.max(a.maxY, b.maxY);
51331     return a;
51332 }
51333
51334 function compareNodeMinX(a, b) { return a.minX - b.minX; }
51335 function compareNodeMinY(a, b) { return a.minY - b.minY; }
51336
51337 function bboxArea(a)   { return (a.maxX - a.minX) * (a.maxY - a.minY); }
51338 function bboxMargin(a) { return (a.maxX - a.minX) + (a.maxY - a.minY); }
51339
51340 function enlargedArea(a, b) {
51341     return (Math.max(b.maxX, a.maxX) - Math.min(b.minX, a.minX)) *
51342            (Math.max(b.maxY, a.maxY) - Math.min(b.minY, a.minY));
51343 }
51344
51345 function intersectionArea(a, b) {
51346     const minX = Math.max(a.minX, b.minX);
51347     const minY = Math.max(a.minY, b.minY);
51348     const maxX = Math.min(a.maxX, b.maxX);
51349     const maxY = Math.min(a.maxY, b.maxY);
51350
51351     return Math.max(0, maxX - minX) *
51352            Math.max(0, maxY - minY);
51353 }
51354
51355 function contains(a, b) {
51356     return a.minX <= b.minX &&
51357            a.minY <= b.minY &&
51358            b.maxX <= a.maxX &&
51359            b.maxY <= a.maxY;
51360 }
51361
51362 function intersects$1(a, b) {
51363     return b.minX <= a.maxX &&
51364            b.minY <= a.maxY &&
51365            b.maxX >= a.minX &&
51366            b.maxY >= a.minY;
51367 }
51368
51369 function createNode(children) {
51370     return {
51371         children,
51372         height: 1,
51373         leaf: true,
51374         minX: Infinity,
51375         minY: Infinity,
51376         maxX: -Infinity,
51377         maxY: -Infinity
51378     };
51379 }
51380
51381 // sort an array so that items come in groups of n unsorted items, with groups sorted between each other;
51382 // combines selection algorithm with binary divide & conquer approach
51383
51384 function multiSelect(arr, left, right, n, compare) {
51385     const stack = [left, right];
51386
51387     while (stack.length) {
51388         right = stack.pop();
51389         left = stack.pop();
51390
51391         if (right - left <= n) continue;
51392
51393         const mid = left + Math.ceil((right - left) / n / 2) * n;
51394         quickselect(arr, mid, left, right, compare);
51395
51396         stack.push(left, mid, mid, right);
51397     }
51398 }
51399
51400 class GeoRBush extends RBush {
51401     compareMinX(a, b) {
51402         return a.lng - b.lng;
51403     }
51404     compareMinY(a, b) {
51405         return a.lat - b.lat;
51406     }
51407     toBBox(item) {
51408         return {
51409             minX: item.lng,
51410             minY: item.lat,
51411             maxX: item.lng,
51412             maxY: item.lat,
51413         };
51414     }
51415 }
51416
51417 /*
51418  * Copyright (C) 2008 Apple Inc. All Rights Reserved.
51419  *
51420  * Redistribution and use in source and binary forms, with or without
51421  * modification, are permitted provided that the following conditions
51422  * are met:
51423  * 1. Redistributions of source code must retain the above copyright
51424  *    notice, this list of conditions and the following disclaimer.
51425  * 2. Redistributions in binary form must reproduce the above copyright
51426  *    notice, this list of conditions and the following disclaimer in the
51427  *    documentation and/or other materials provided with the distribution.
51428  *
51429  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
51430  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
51431  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
51432  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
51433  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
51434  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
51435  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
51436  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
51437  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
51438  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
51439  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
51440  *
51441  * Ported from Webkit
51442  * http://svn.webkit.org/repository/webkit/trunk/Source/WebCore/platform/graphics/UnitBezier.h
51443  */
51444 var unitbezier = UnitBezier;
51445
51446 function UnitBezier(p1x, p1y, p2x, p2y) {
51447     // Calculate the polynomial coefficients, implicit first and last control points are (0,0) and (1,1).
51448     this.cx = 3.0 * p1x;
51449     this.bx = 3.0 * (p2x - p1x) - this.cx;
51450     this.ax = 1.0 - this.cx - this.bx;
51451
51452     this.cy = 3.0 * p1y;
51453     this.by = 3.0 * (p2y - p1y) - this.cy;
51454     this.ay = 1.0 - this.cy - this.by;
51455
51456     this.p1x = p1x;
51457     this.p1y = p2y;
51458     this.p2x = p2x;
51459     this.p2y = p2y;
51460 }
51461
51462 UnitBezier.prototype.sampleCurveX = function(t) {
51463     // `ax t^3 + bx t^2 + cx t' expanded using Horner's rule.
51464     return ((this.ax * t + this.bx) * t + this.cx) * t;
51465 };
51466
51467 UnitBezier.prototype.sampleCurveY = function(t) {
51468     return ((this.ay * t + this.by) * t + this.cy) * t;
51469 };
51470
51471 UnitBezier.prototype.sampleCurveDerivativeX = function(t) {
51472     return (3.0 * this.ax * t + 2.0 * this.bx) * t + this.cx;
51473 };
51474
51475 UnitBezier.prototype.solveCurveX = function(x, epsilon) {
51476     if (typeof epsilon === 'undefined') epsilon = 1e-6;
51477
51478     var t0, t1, t2, x2, i;
51479
51480     // First try a few iterations of Newton's method -- normally very fast.
51481     for (t2 = x, i = 0; i < 8; i++) {
51482
51483         x2 = this.sampleCurveX(t2) - x;
51484         if (Math.abs(x2) < epsilon) return t2;
51485
51486         var d2 = this.sampleCurveDerivativeX(t2);
51487         if (Math.abs(d2) < 1e-6) break;
51488
51489         t2 = t2 - x2 / d2;
51490     }
51491
51492     // Fall back to the bisection method for reliability.
51493     t0 = 0.0;
51494     t1 = 1.0;
51495     t2 = x;
51496
51497     if (t2 < t0) return t0;
51498     if (t2 > t1) return t1;
51499
51500     while (t0 < t1) {
51501
51502         x2 = this.sampleCurveX(t2);
51503         if (Math.abs(x2 - x) < epsilon) return t2;
51504
51505         if (x > x2) {
51506             t0 = t2;
51507         } else {
51508             t1 = t2;
51509         }
51510
51511         t2 = (t1 - t0) * 0.5 + t0;
51512     }
51513
51514     // Failure.
51515     return t2;
51516 };
51517
51518 UnitBezier.prototype.solve = function(x, epsilon) {
51519     return this.sampleCurveY(this.solveCurveX(x, epsilon));
51520 };
51521
51522 /**
51523  * Enumeration for transition mode
51524  * @enum {number}
51525  * @readonly
51526  * @description Modes for specifying how transitions
51527  * between images are performed.
51528  */
51529 var TransitionMode;
51530 (function (TransitionMode) {
51531     /**
51532      * Default transitions.
51533      *
51534      * @description The viewer dynamically determines
51535      * whether transitions should be performed with or
51536      * without motion and blending for each transition
51537      * based on the underlying data.
51538      */
51539     TransitionMode[TransitionMode["Default"] = 0] = "Default";
51540     /**
51541      * Instantaneous transitions.
51542      *
51543      * @description All transitions are performed
51544      * without motion or blending.
51545      */
51546     TransitionMode[TransitionMode["Instantaneous"] = 1] = "Instantaneous";
51547 })(TransitionMode || (TransitionMode = {}));
51548
51549 /**
51550  * @class Camera
51551  *
51552  * @classdesc Holds information about a camera.
51553  */
51554 class Camera {
51555     /**
51556      * Create a new camera instance.
51557      * @param {Transform} [transform] - Optional transform instance.
51558      */
51559     constructor(transform) {
51560         if (transform != null) {
51561             this._position = new Vector3().fromArray(transform.unprojectSfM([0, 0], 0));
51562             this._lookat = new Vector3().fromArray(transform.unprojectSfM([0, 0], 10));
51563             this._up = transform.upVector();
51564             this._focal = this._getFocal(transform);
51565         }
51566         else {
51567             this._position = new Vector3(0, 0, 0);
51568             this._lookat = new Vector3(1, 0, 0);
51569             this._up = new Vector3(0, 0, 1);
51570             this._focal = 1;
51571         }
51572     }
51573     /**
51574      * Get position.
51575      * @returns {THREE.Vector3} The position vector.
51576      */
51577     get position() {
51578         return this._position;
51579     }
51580     /**
51581      * Get lookat.
51582      * @returns {THREE.Vector3} The lookat vector.
51583      */
51584     get lookat() {
51585         return this._lookat;
51586     }
51587     /**
51588      * Get up.
51589      * @returns {THREE.Vector3} The up vector.
51590      */
51591     get up() {
51592         return this._up;
51593     }
51594     /**
51595      * Get focal.
51596      * @returns {number} The focal length.
51597      */
51598     get focal() {
51599         return this._focal;
51600     }
51601     /**
51602      * Set focal.
51603      */
51604     set focal(value) {
51605         this._focal = value;
51606     }
51607     /**
51608      * Update this camera to the linearly interpolated value of two other cameras.
51609      *
51610      * @param {Camera} a - First camera.
51611      * @param {Camera} b - Second camera.
51612      * @param {number} alpha - Interpolation value on the interval [0, 1].
51613      */
51614     lerpCameras(a, b, alpha) {
51615         this._position.subVectors(b.position, a.position).multiplyScalar(alpha).add(a.position);
51616         this._lookat.subVectors(b.lookat, a.lookat).multiplyScalar(alpha).add(a.lookat);
51617         this._up.subVectors(b.up, a.up).multiplyScalar(alpha).add(a.up);
51618         this._focal = (1 - alpha) * a.focal + alpha * b.focal;
51619     }
51620     /**
51621      * Copy the properties of another camera to this camera.
51622      *
51623      * @param {Camera} other - Another camera.
51624      */
51625     copy(other) {
51626         this._position.copy(other.position);
51627         this._lookat.copy(other.lookat);
51628         this._up.copy(other.up);
51629         this._focal = other.focal;
51630     }
51631     /**
51632      * Clone this camera.
51633      *
51634      * @returns {Camera} A camera with cloned properties equal to this camera.
51635      */
51636     clone() {
51637         let camera = new Camera();
51638         camera.position.copy(this._position);
51639         camera.lookat.copy(this._lookat);
51640         camera.up.copy(this._up);
51641         camera.focal = this._focal;
51642         return camera;
51643     }
51644     /**
51645      * Determine the distance between this camera and another camera.
51646      *
51647      * @param {Camera} other - Another camera.
51648      * @returns {number} The distance between the cameras.
51649      */
51650     diff(other) {
51651         let pd = this._position.distanceToSquared(other.position);
51652         let ld = this._lookat.distanceToSquared(other.lookat);
51653         let ud = this._up.distanceToSquared(other.up);
51654         let fd = 100 * Math.abs(this._focal - other.focal);
51655         return Math.max(pd, ld, ud, fd);
51656     }
51657     /**
51658      * Get the focal length based on the transform.
51659      *
51660      * @description Returns the focal length corresponding
51661      * to a 90 degree field of view for spherical
51662      * transforms.
51663      *
51664      * Returns the transform focal length for other
51665      * projection types.
51666      *
51667      * @returns {number} Focal length.
51668      */
51669     _getFocal(transform) {
51670         if (!isSpherical(transform.cameraType)) {
51671             return transform.focal;
51672         }
51673         return 0.5 / Math.tan(Math.PI / 2);
51674     }
51675 }
51676
51677 const EPSILON = 1e-8;
51678 /**
51679  * @class Transform
51680  *
51681  * @classdesc Class used for calculating coordinate transformations
51682  * and projections.
51683  */
51684 class Transform {
51685     /**
51686      * Create a new transform instance.
51687      * @param {number} orientation - Image orientation.
51688      * @param {number} width - Image height.
51689      * @param {number} height - Image width.
51690      * @param {number} focal - Focal length.
51691      * @param {number} scale - Atomic scale.
51692      * @param {Array<number>} rotation - Rotation vector in three dimensions.
51693      * @param {Array<number>} translation - Translation vector in three dimensions.
51694      * @param {HTMLImageElement} image - Image for fallback size calculations.
51695      */
51696     constructor(orientation, width, height, scale, rotation, translation, image, textureScale, cameraParameters, cameraType) {
51697         this._orientation = this._getValue(orientation, 1);
51698         let imageWidth = image != null ? image.width : 4;
51699         let imageHeight = image != null ? image.height : 3;
51700         let keepOrientation = this._orientation < 5;
51701         this._width = this._getValue(width, keepOrientation ? imageWidth : imageHeight);
51702         this._height = this._getValue(height, keepOrientation ? imageHeight : imageWidth);
51703         this._basicAspect = keepOrientation ?
51704             this._width / this._height :
51705             this._height / this._width;
51706         this._basicWidth = keepOrientation ? width : height;
51707         this._basicHeight = keepOrientation ? height : width;
51708         const parameters = this._getCameraParameters(cameraParameters, cameraType);
51709         const focal = parameters[0];
51710         const ck1 = parameters[1];
51711         const ck2 = parameters[2];
51712         this._focal = this._getValue(focal, 1);
51713         this._scale = this._getValue(scale, 0);
51714         this._worldToCamera = this.createWorldToCamera(rotation, translation);
51715         this._worldToCameraInverse = new Matrix4()
51716             .copy(this._worldToCamera)
51717             .invert();
51718         this._scaledWorldToCamera =
51719             this._createScaledWorldToCamera(this._worldToCamera, this._scale);
51720         this._scaledWorldToCameraInverse = new Matrix4()
51721             .copy(this._scaledWorldToCamera)
51722             .invert();
51723         this._basicWorldToCamera = this._createBasicWorldToCamera(this._worldToCamera, orientation);
51724         this._textureScale = !!textureScale ? textureScale : [1, 1];
51725         this._ck1 = !!ck1 ? ck1 : 0;
51726         this._ck2 = !!ck2 ? ck2 : 0;
51727         this._cameraType = !!cameraType ?
51728             cameraType :
51729             "perspective";
51730         this._radialPeak = this._getRadialPeak(this._ck1, this._ck2);
51731     }
51732     get ck1() {
51733         return this._ck1;
51734     }
51735     get ck2() {
51736         return this._ck2;
51737     }
51738     get cameraType() {
51739         return this._cameraType;
51740     }
51741     /**
51742      * Get basic aspect.
51743      * @returns {number} The orientation adjusted aspect ratio.
51744      */
51745     get basicAspect() {
51746         return this._basicAspect;
51747     }
51748     /**
51749      * Get basic height.
51750      *
51751      * @description Does not fall back to image image height but
51752      * uses original value from API so can be faulty.
51753      *
51754      * @returns {number} The height of the basic version image
51755      * (adjusted for orientation).
51756      */
51757     get basicHeight() {
51758         return this._basicHeight;
51759     }
51760     get basicRt() {
51761         return this._basicWorldToCamera;
51762     }
51763     /**
51764      * Get basic width.
51765      *
51766      * @description Does not fall back to image image width but
51767      * uses original value from API so can be faulty.
51768      *
51769      * @returns {number} The width of the basic version image
51770      * (adjusted for orientation).
51771      */
51772     get basicWidth() {
51773         return this._basicWidth;
51774     }
51775     /**
51776      * Get focal.
51777      * @returns {number} The image focal length.
51778      */
51779     get focal() {
51780         return this._focal;
51781     }
51782     /**
51783      * Get height.
51784      *
51785      * @description Falls back to the image image height if
51786      * the API data is faulty.
51787      *
51788      * @returns {number} The orientation adjusted image height.
51789      */
51790     get height() {
51791         return this._height;
51792     }
51793     /**
51794      * Get orientation.
51795      * @returns {number} The image orientation.
51796      */
51797     get orientation() {
51798         return this._orientation;
51799     }
51800     /**
51801      * Get rt.
51802      * @returns {THREE.Matrix4} The extrinsic camera matrix.
51803      */
51804     get rt() {
51805         return this._worldToCamera;
51806     }
51807     /**
51808      * Get srt.
51809      * @returns {THREE.Matrix4} The scaled extrinsic camera matrix.
51810      */
51811     get srt() {
51812         return this._scaledWorldToCamera;
51813     }
51814     /**
51815      * Get srtInverse.
51816      * @returns {THREE.Matrix4} The scaled extrinsic camera matrix.
51817      */
51818     get srtInverse() {
51819         return this._scaledWorldToCameraInverse;
51820     }
51821     /**
51822      * Get scale.
51823      * @returns {number} The image atomic reconstruction scale.
51824      */
51825     get scale() {
51826         return this._scale;
51827     }
51828     /**
51829      * Get has valid scale.
51830      * @returns {boolean} Value indicating if the scale of the transform is valid.
51831      */
51832     get hasValidScale() {
51833         return this._scale > 1e-2 && this._scale < 50;
51834     }
51835     /**
51836      * Get radial peak.
51837      * @returns {number} Value indicating the radius where the radial
51838      * undistortion function peaks.
51839      */
51840     get radialPeak() {
51841         return this._radialPeak;
51842     }
51843     /**
51844      * Get width.
51845      *
51846      * @description Falls back to the image image width if
51847      * the API data is faulty.
51848      *
51849      * @returns {number} The orientation adjusted image width.
51850      */
51851     get width() {
51852         return this._width;
51853     }
51854     /**
51855      * Calculate the up vector for the image transform.
51856      *
51857      * @returns {THREE.Vector3} Normalized and orientation adjusted up vector.
51858      */
51859     upVector() {
51860         let rte = this._worldToCamera.elements;
51861         switch (this._orientation) {
51862             case 1:
51863                 return new Vector3(-rte[1], -rte[5], -rte[9]);
51864             case 3:
51865                 return new Vector3(rte[1], rte[5], rte[9]);
51866             case 6:
51867                 return new Vector3(-rte[0], -rte[4], -rte[8]);
51868             case 8:
51869                 return new Vector3(rte[0], rte[4], rte[8]);
51870             default:
51871                 return new Vector3(-rte[1], -rte[5], -rte[9]);
51872         }
51873     }
51874     /**
51875      * Calculate projector matrix for projecting 3D points to texture map
51876      * coordinates (u and v).
51877      *
51878      * @returns {THREE.Matrix4} Projection matrix for 3D point to texture
51879      * map coordinate calculations.
51880      */
51881     projectorMatrix() {
51882         let projector = this._normalizedToTextureMatrix();
51883         let f = this._focal;
51884         let projection = new Matrix4().set(f, 0, 0, 0, 0, f, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0);
51885         projector.multiply(projection);
51886         projector.multiply(this._worldToCamera);
51887         return projector;
51888     }
51889     /**
51890      * Project 3D world coordinates to basic coordinates.
51891      *
51892      * @param {Array<number>} point3d - 3D world coordinates.
51893      * @return {Array<number>} 2D basic coordinates.
51894      */
51895     projectBasic(point3d) {
51896         let sfm = this.projectSfM(point3d);
51897         return this._sfmToBasic(sfm);
51898     }
51899     /**
51900      * Unproject basic coordinates to 3D world coordinates.
51901      *
51902      * @param {Array<number>} basic - 2D basic coordinates.
51903      * @param {Array<number>} distance - Distance to unproject from camera center.
51904      * @param {boolean} [depth] - Treat the distance value as depth from camera center.
51905      *                            Only applicable for perspective images. Will be
51906      *                            ignored for spherical.
51907      * @returns {Array<number>} Unprojected 3D world coordinates.
51908      */
51909     unprojectBasic(basic, distance, depth) {
51910         let sfm = this._basicToSfm(basic);
51911         return this.unprojectSfM(sfm, distance, depth);
51912     }
51913     /**
51914      * Project 3D world coordinates to SfM coordinates.
51915      *
51916      * @param {Array<number>} point3d - 3D world coordinates.
51917      * @return {Array<number>} 2D SfM coordinates.
51918      */
51919     projectSfM(point3d) {
51920         let v = new Vector4(point3d[0], point3d[1], point3d[2], 1);
51921         v.applyMatrix4(this._worldToCamera);
51922         return this._bearingToSfm([v.x, v.y, v.z]);
51923     }
51924     /**
51925      * Unproject SfM coordinates to a 3D world coordinates.
51926      *
51927      * @param {Array<number>} sfm - 2D SfM coordinates.
51928      * @param {Array<number>} distance - Distance to unproject
51929      * from camera center.
51930      * @param {boolean} [depth] - Treat the distance value as
51931      * depth from camera center. Only applicable for perspective
51932      * images. Will be ignored for spherical.
51933      * @returns {Array<number>} Unprojected 3D world coordinates.
51934      */
51935     unprojectSfM(sfm, distance, depth) {
51936         const bearing = this._sfmToBearing(sfm);
51937         const unprojectedCamera = depth && !isSpherical(this._cameraType) ?
51938             new Vector4(distance * bearing[0] / bearing[2], distance * bearing[1] / bearing[2], distance, 1) :
51939             new Vector4(distance * bearing[0], distance * bearing[1], distance * bearing[2], 1);
51940         const unprojectedWorld = unprojectedCamera
51941             .applyMatrix4(this._worldToCameraInverse);
51942         return [
51943             unprojectedWorld.x / unprojectedWorld.w,
51944             unprojectedWorld.y / unprojectedWorld.w,
51945             unprojectedWorld.z / unprojectedWorld.w,
51946         ];
51947     }
51948     /**
51949      * Transform SfM coordinates to bearing vector (3D cartesian
51950      * coordinates on the unit sphere).
51951      *
51952      * @param {Array<number>} sfm - 2D SfM coordinates.
51953      * @returns {Array<number>} Bearing vector (3D cartesian coordinates
51954      * on the unit sphere).
51955      */
51956     _sfmToBearing(sfm) {
51957         if (isSpherical(this._cameraType)) {
51958             let lng = sfm[0] * 2 * Math.PI;
51959             let lat = -sfm[1] * 2 * Math.PI;
51960             let x = Math.cos(lat) * Math.sin(lng);
51961             let y = -Math.sin(lat);
51962             let z = Math.cos(lat) * Math.cos(lng);
51963             return [x, y, z];
51964         }
51965         else if (isFisheye(this._cameraType)) {
51966             let [dxn, dyn] = [sfm[0] / this._focal, sfm[1] / this._focal];
51967             const dTheta = Math.sqrt(dxn * dxn + dyn * dyn);
51968             let d = this._distortionFromDistortedRadius(dTheta, this._ck1, this._ck2, this._radialPeak);
51969             let theta = dTheta / d;
51970             let z = Math.cos(theta);
51971             let r = Math.sin(theta);
51972             const denomTheta = dTheta > EPSILON ? 1 / dTheta : 1;
51973             let x = r * dxn * denomTheta;
51974             let y = r * dyn * denomTheta;
51975             return [x, y, z];
51976         }
51977         else {
51978             let [dxn, dyn] = [sfm[0] / this._focal, sfm[1] / this._focal];
51979             const dr = Math.sqrt(dxn * dxn + dyn * dyn);
51980             let d = this._distortionFromDistortedRadius(dr, this._ck1, this._ck2, this._radialPeak);
51981             const xn = dxn / d;
51982             const yn = dyn / d;
51983             let v = new Vector3(xn, yn, 1);
51984             v.normalize();
51985             return [v.x, v.y, v.z];
51986         }
51987     }
51988     /** Compute distortion given the distorted radius.
51989      *
51990      *  Solves for d in the equation
51991      *    y = d(x, k1, k2) * x
51992      * given the distorted radius, y.
51993      */
51994     _distortionFromDistortedRadius(distortedRadius, k1, k2, radialPeak) {
51995         let d = 1.0;
51996         for (let i = 0; i < 10; i++) {
51997             let radius = distortedRadius / d;
51998             if (radius > radialPeak) {
51999                 radius = radialPeak;
52000             }
52001             d = 1 + k1 * Math.pow(radius, 2) + k2 * Math.pow(radius, 4);
52002         }
52003         return d;
52004     }
52005     /**
52006      * Transform bearing vector (3D cartesian coordiantes on the unit sphere) to
52007      * SfM coordinates.
52008      *
52009      * @param {Array<number>} bearing - Bearing vector (3D cartesian coordinates on the
52010      * unit sphere).
52011      * @returns {Array<number>} 2D SfM coordinates.
52012      */
52013     _bearingToSfm(bearing) {
52014         if (isSpherical(this._cameraType)) {
52015             let x = bearing[0];
52016             let y = bearing[1];
52017             let z = bearing[2];
52018             let lng = Math.atan2(x, z);
52019             let lat = Math.atan2(-y, Math.sqrt(x * x + z * z));
52020             return [lng / (2 * Math.PI), -lat / (2 * Math.PI)];
52021         }
52022         else if (isFisheye(this._cameraType)) {
52023             if (bearing[2] > 0) {
52024                 const [x, y, z] = bearing;
52025                 const r = Math.sqrt(x * x + y * y);
52026                 let theta = Math.atan2(r, z);
52027                 if (theta > this._radialPeak) {
52028                     theta = this._radialPeak;
52029                 }
52030                 const distortion = 1.0 + Math.pow(theta, 2) * (this._ck1 + Math.pow(theta, 2) * this._ck2);
52031                 const s = this._focal * distortion * theta / r;
52032                 return [s * x, s * y];
52033             }
52034             else {
52035                 return [
52036                     bearing[0] < 0 ? Number.NEGATIVE_INFINITY : Number.POSITIVE_INFINITY,
52037                     bearing[1] < 0 ? Number.NEGATIVE_INFINITY : Number.POSITIVE_INFINITY,
52038                 ];
52039             }
52040         }
52041         else {
52042             if (bearing[2] > 0) {
52043                 let [xn, yn] = [bearing[0] / bearing[2], bearing[1] / bearing[2]];
52044                 let r2 = xn * xn + yn * yn;
52045                 const rp2 = Math.pow(this._radialPeak, 2);
52046                 if (r2 > rp2) {
52047                     r2 = rp2;
52048                 }
52049                 const d = 1 + this._ck1 * r2 + this._ck2 * Math.pow(r2, 2);
52050                 return [
52051                     this._focal * d * xn,
52052                     this._focal * d * yn,
52053                 ];
52054             }
52055             else {
52056                 return [
52057                     bearing[0] < 0 ? Number.NEGATIVE_INFINITY : Number.POSITIVE_INFINITY,
52058                     bearing[1] < 0 ? Number.NEGATIVE_INFINITY : Number.POSITIVE_INFINITY,
52059                 ];
52060             }
52061         }
52062     }
52063     /**
52064      * Convert basic coordinates to SfM coordinates.
52065      *
52066      * @param {Array<number>} basic - 2D basic coordinates.
52067      * @returns {Array<number>} 2D SfM coordinates.
52068      */
52069     _basicToSfm(basic) {
52070         let rotatedX;
52071         let rotatedY;
52072         switch (this._orientation) {
52073             case 1:
52074                 rotatedX = basic[0];
52075                 rotatedY = basic[1];
52076                 break;
52077             case 3:
52078                 rotatedX = 1 - basic[0];
52079                 rotatedY = 1 - basic[1];
52080                 break;
52081             case 6:
52082                 rotatedX = basic[1];
52083                 rotatedY = 1 - basic[0];
52084                 break;
52085             case 8:
52086                 rotatedX = 1 - basic[1];
52087                 rotatedY = basic[0];
52088                 break;
52089             default:
52090                 rotatedX = basic[0];
52091                 rotatedY = basic[1];
52092                 break;
52093         }
52094         let w = this._width;
52095         let h = this._height;
52096         let s = Math.max(w, h);
52097         let sfmX = rotatedX * w / s - w / s / 2;
52098         let sfmY = rotatedY * h / s - h / s / 2;
52099         return [sfmX, sfmY];
52100     }
52101     /**
52102      * Convert SfM coordinates to basic coordinates.
52103      *
52104      * @param {Array<number>} sfm - 2D SfM coordinates.
52105      * @returns {Array<number>} 2D basic coordinates.
52106      */
52107     _sfmToBasic(sfm) {
52108         let w = this._width;
52109         let h = this._height;
52110         let s = Math.max(w, h);
52111         let rotatedX = (sfm[0] + w / s / 2) / w * s;
52112         let rotatedY = (sfm[1] + h / s / 2) / h * s;
52113         let basicX;
52114         let basicY;
52115         switch (this._orientation) {
52116             case 1:
52117                 basicX = rotatedX;
52118                 basicY = rotatedY;
52119                 break;
52120             case 3:
52121                 basicX = 1 - rotatedX;
52122                 basicY = 1 - rotatedY;
52123                 break;
52124             case 6:
52125                 basicX = 1 - rotatedY;
52126                 basicY = rotatedX;
52127                 break;
52128             case 8:
52129                 basicX = rotatedY;
52130                 basicY = 1 - rotatedX;
52131                 break;
52132             default:
52133                 basicX = rotatedX;
52134                 basicY = rotatedY;
52135                 break;
52136         }
52137         return [basicX, basicY];
52138     }
52139     /**
52140      * Checks a value and returns it if it exists and is larger than 0.
52141      * Fallbacks if it is null.
52142      *
52143      * @param {number} value - Value to check.
52144      * @param {number} fallback - Value to fall back to.
52145      * @returns {number} The value or its fallback value if it is not defined or negative.
52146      */
52147     _getValue(value, fallback) {
52148         return value != null && value > 0 ? value : fallback;
52149     }
52150     _getCameraParameters(value, cameraType) {
52151         if (isSpherical(cameraType)) {
52152             return [];
52153         }
52154         if (!value || value.length === 0) {
52155             return [1, 0, 0];
52156         }
52157         const padding = 3 - value.length;
52158         if (padding <= 0) {
52159             return value;
52160         }
52161         return value
52162             .concat(new Array(padding)
52163             .fill(0));
52164     }
52165     /**
52166      * Creates the extrinsic camera matrix [ R | t ].
52167      *
52168      * @param {Array<number>} rotation - Rotation vector in angle axis representation.
52169      * @param {Array<number>} translation - Translation vector.
52170      * @returns {THREE.Matrix4} Extrisic camera matrix.
52171      */
52172     createWorldToCamera(rotation, translation) {
52173         const axis = new Vector3(rotation[0], rotation[1], rotation[2]);
52174         const angle = axis.length();
52175         if (angle > 0) {
52176             axis.normalize();
52177         }
52178         const worldToCamera = new Matrix4();
52179         worldToCamera.makeRotationAxis(axis, angle);
52180         worldToCamera.setPosition(new Vector3(translation[0], translation[1], translation[2]));
52181         return worldToCamera;
52182     }
52183     /**
52184      * Calculates the scaled extrinsic camera matrix scale * [ R | t ].
52185      *
52186      * @param {THREE.Matrix4} worldToCamera - Extrisic camera matrix.
52187      * @param {number} scale - Scale factor.
52188      * @returns {THREE.Matrix4} Scaled extrisic camera matrix.
52189      */
52190     _createScaledWorldToCamera(worldToCamera, scale) {
52191         const scaledWorldToCamera = worldToCamera.clone();
52192         const elements = scaledWorldToCamera.elements;
52193         elements[12] = scale * elements[12];
52194         elements[13] = scale * elements[13];
52195         elements[14] = scale * elements[14];
52196         scaledWorldToCamera.scale(new Vector3(scale, scale, scale));
52197         return scaledWorldToCamera;
52198     }
52199     _createBasicWorldToCamera(rt, orientation) {
52200         const axis = new Vector3(0, 0, 1);
52201         let angle = 0;
52202         switch (orientation) {
52203             case 3:
52204                 angle = Math.PI;
52205                 break;
52206             case 6:
52207                 angle = Math.PI / 2;
52208                 break;
52209             case 8:
52210                 angle = 3 * Math.PI / 2;
52211                 break;
52212         }
52213         return new Matrix4()
52214             .makeRotationAxis(axis, angle)
52215             .multiply(rt);
52216     }
52217     _getRadialPeak(k1, k2) {
52218         const a = 5 * k2;
52219         const b = 3 * k1;
52220         const c = 1;
52221         const d = Math.pow(b, 2) - 4 * a * c;
52222         if (d < 0) {
52223             return undefined;
52224         }
52225         const root1 = (-b - Math.sqrt(d)) / 2 / a;
52226         const root2 = (-b + Math.sqrt(d)) / 2 / a;
52227         const minRoot = Math.min(root1, root2);
52228         const maxRoot = Math.max(root1, root2);
52229         return minRoot > 0 ?
52230             Math.sqrt(minRoot) :
52231             maxRoot > 0 ?
52232                 Math.sqrt(maxRoot) :
52233                 undefined;
52234     }
52235     /**
52236      * Calculate a transformation matrix from normalized coordinates for
52237      * texture map coordinates.
52238      *
52239      * @returns {THREE.Matrix4} Normalized coordinates to texture map
52240      * coordinates transformation matrix.
52241      */
52242     _normalizedToTextureMatrix() {
52243         const size = Math.max(this._width, this._height);
52244         const scaleX = this._orientation < 5 ? this._textureScale[0] : this._textureScale[1];
52245         const scaleY = this._orientation < 5 ? this._textureScale[1] : this._textureScale[0];
52246         const w = size / this._width * scaleX;
52247         const h = size / this._height * scaleY;
52248         switch (this._orientation) {
52249             case 1:
52250                 return new Matrix4().set(w, 0, 0, 0.5, 0, -h, 0, 0.5, 0, 0, 1, 0, 0, 0, 0, 1);
52251             case 3:
52252                 return new Matrix4().set(-w, 0, 0, 0.5, 0, h, 0, 0.5, 0, 0, 1, 0, 0, 0, 0, 1);
52253             case 6:
52254                 return new Matrix4().set(0, -h, 0, 0.5, -w, 0, 0, 0.5, 0, 0, 1, 0, 0, 0, 0, 1);
52255             case 8:
52256                 return new Matrix4().set(0, h, 0, 0.5, w, 0, 0, 0.5, 0, 0, 1, 0, 0, 0, 0, 1);
52257             default:
52258                 return new Matrix4().set(w, 0, 0, 0.5, 0, -h, 0, 0.5, 0, 0, 1, 0, 0, 0, 0, 1);
52259         }
52260     }
52261 }
52262
52263 class StateBase {
52264     constructor(state) {
52265         this._spatial = new Spatial();
52266         this._referenceThreshold = 0.01;
52267         this._transitionMode = state.transitionMode;
52268         this._reference = state.reference;
52269         this._alpha = state.alpha;
52270         this._camera = state.camera.clone();
52271         this._zoom = state.zoom;
52272         this._currentIndex = state.currentIndex;
52273         this._trajectory = state.trajectory.slice();
52274         this._trajectoryTransforms = [];
52275         this._trajectoryCameras = [];
52276         for (let image of this._trajectory) {
52277             let translation = this._imageToTranslation(image, this._reference);
52278             let transform = new Transform(image.exifOrientation, image.width, image.height, image.scale, image.rotation, translation, image.image, undefined, image.cameraParameters, image.cameraType);
52279             this._trajectoryTransforms.push(transform);
52280             this._trajectoryCameras.push(new Camera(transform));
52281         }
52282         this._currentImage = this._trajectory.length > 0 ?
52283             this._trajectory[this._currentIndex] :
52284             null;
52285         this._previousImage = this._trajectory.length > 1 && this.currentIndex > 0 ?
52286             this._trajectory[this._currentIndex - 1] :
52287             null;
52288         this._currentCamera = this._trajectoryCameras.length > 0 ?
52289             this._trajectoryCameras[this._currentIndex].clone() :
52290             new Camera();
52291         this._previousCamera = this._trajectoryCameras.length > 1 && this.currentIndex > 0 ?
52292             this._trajectoryCameras[this._currentIndex - 1].clone() :
52293             this._currentCamera.clone();
52294     }
52295     get reference() {
52296         return this._reference;
52297     }
52298     get alpha() {
52299         return this._getAlpha();
52300     }
52301     get camera() {
52302         return this._camera;
52303     }
52304     get zoom() {
52305         return this._zoom;
52306     }
52307     get trajectory() {
52308         return this._trajectory;
52309     }
52310     get currentIndex() {
52311         return this._currentIndex;
52312     }
52313     get currentImage() {
52314         return this._currentImage;
52315     }
52316     get previousImage() {
52317         return this._previousImage;
52318     }
52319     get currentCamera() {
52320         return this._currentCamera;
52321     }
52322     get currentTransform() {
52323         return this._trajectoryTransforms.length > 0 ?
52324             this._trajectoryTransforms[this.currentIndex] : null;
52325     }
52326     get previousTransform() {
52327         return this._trajectoryTransforms.length > 1 && this.currentIndex > 0 ?
52328             this._trajectoryTransforms[this.currentIndex - 1] : null;
52329     }
52330     get motionless() {
52331         return this._motionless;
52332     }
52333     get transitionMode() {
52334         return this._transitionMode;
52335     }
52336     move(delta) { }
52337     moveTo(position) { }
52338     rotate(delta) { }
52339     rotateUnbounded(delta) { }
52340     rotateWithoutInertia(delta) { }
52341     rotateBasic(basicRotation) { }
52342     rotateBasicUnbounded(basicRotation) { }
52343     rotateBasicWithoutInertia(basicRotation) { }
52344     rotateToBasic(basic) { }
52345     setSpeed(speed) { }
52346     zoomIn(delta, reference) { }
52347     update(fps) { }
52348     setCenter(center) { }
52349     setZoom(zoom) { }
52350     dolly(delta) { }
52351     orbit(rotation) { }
52352     setViewMatrix(matrix) { }
52353     truck(direction) { }
52354     append(images) {
52355         if (images.length < 1) {
52356             throw Error("Trajectory can not be empty");
52357         }
52358         if (this._currentIndex < 0) {
52359             this.set(images);
52360         }
52361         else {
52362             this._trajectory = this._trajectory.concat(images);
52363             this._appendToTrajectories(images);
52364         }
52365     }
52366     prepend(images) {
52367         if (images.length < 1) {
52368             throw Error("Trajectory can not be empty");
52369         }
52370         this._trajectory = images.slice().concat(this._trajectory);
52371         this._currentIndex += images.length;
52372         this._setCurrentImage();
52373         let referenceReset = this._setReference(this._currentImage);
52374         if (referenceReset) {
52375             this._setTrajectories();
52376         }
52377         else {
52378             this._prependToTrajectories(images);
52379         }
52380         this._setCurrentCamera();
52381     }
52382     remove(n) {
52383         if (n < 0) {
52384             throw Error("n must be a positive integer");
52385         }
52386         if (this._currentIndex - 1 < n) {
52387             throw Error("Current and previous images can not be removed");
52388         }
52389         for (let i = 0; i < n; i++) {
52390             this._trajectory.shift();
52391             this._trajectoryTransforms.shift();
52392             this._trajectoryCameras.shift();
52393             this._currentIndex--;
52394         }
52395         this._setCurrentImage();
52396     }
52397     clearPrior() {
52398         if (this._currentIndex > 0) {
52399             this.remove(this._currentIndex - 1);
52400         }
52401     }
52402     clear() {
52403         this.cut();
52404         if (this._currentIndex > 0) {
52405             this.remove(this._currentIndex - 1);
52406         }
52407     }
52408     cut() {
52409         while (this._trajectory.length - 1 > this._currentIndex) {
52410             this._trajectory.pop();
52411             this._trajectoryTransforms.pop();
52412             this._trajectoryCameras.pop();
52413         }
52414     }
52415     set(images) {
52416         this._setTrajectory(images);
52417         this._setCurrentImage();
52418         this._setReference(this._currentImage);
52419         this._setTrajectories();
52420         this._setCurrentCamera();
52421     }
52422     getCenter() {
52423         return this._currentImage != null ?
52424             this.currentTransform.projectBasic(this._camera.lookat.toArray()) :
52425             [0.5, 0.5];
52426     }
52427     setTransitionMode(mode) {
52428         this._transitionMode = mode;
52429     }
52430     _getAlpha() { return 1; }
52431     _setCurrent() {
52432         this._setCurrentImage();
52433         let referenceReset = this._setReference(this._currentImage);
52434         if (referenceReset) {
52435             this._setTrajectories();
52436         }
52437         this._setCurrentCamera();
52438     }
52439     _setCurrentCamera() {
52440         this._currentCamera = this._trajectoryCameras[this._currentIndex].clone();
52441         this._previousCamera = this._currentIndex > 0 ?
52442             this._trajectoryCameras[this._currentIndex - 1].clone() :
52443             this._currentCamera.clone();
52444     }
52445     _motionlessTransition() {
52446         let imagesSet = this._currentImage != null && this._previousImage != null;
52447         return imagesSet && (this._transitionMode === TransitionMode.Instantaneous || !(this._currentImage.merged &&
52448             this._previousImage.merged &&
52449             this._withinOriginalDistance() &&
52450             this._sameConnectedComponent()));
52451     }
52452     _setReference(image) {
52453         // do not reset reference if image is within threshold distance
52454         if (Math.abs(image.lngLat.lat - this.reference.lat) < this._referenceThreshold &&
52455             Math.abs(image.lngLat.lng - this.reference.lng) < this._referenceThreshold) {
52456             return false;
52457         }
52458         // do not reset reference if previous image exist and transition is with motion
52459         if (this._previousImage != null && !this._motionlessTransition()) {
52460             return false;
52461         }
52462         this._reference.lat = image.lngLat.lat;
52463         this._reference.lng = image.lngLat.lng;
52464         this._reference.alt = image.computedAltitude;
52465         return true;
52466     }
52467     _setCurrentImage() {
52468         this._currentImage = this._trajectory.length > 0 ?
52469             this._trajectory[this._currentIndex] :
52470             null;
52471         this._previousImage = this._currentIndex > 0 ?
52472             this._trajectory[this._currentIndex - 1] :
52473             null;
52474     }
52475     _setTrajectory(images) {
52476         if (images.length < 1) {
52477             throw new ArgumentMapillaryError("Trajectory can not be empty");
52478         }
52479         if (this._currentImage != null) {
52480             this._trajectory = [this._currentImage].concat(images);
52481             this._currentIndex = 1;
52482         }
52483         else {
52484             this._trajectory = images.slice();
52485             this._currentIndex = 0;
52486         }
52487     }
52488     _setTrajectories() {
52489         this._trajectoryTransforms.length = 0;
52490         this._trajectoryCameras.length = 0;
52491         this._appendToTrajectories(this._trajectory);
52492     }
52493     _appendToTrajectories(images) {
52494         for (let image of images) {
52495             if (!image.assetsCached) {
52496                 throw new ArgumentMapillaryError("Assets must be cached when image is added to trajectory");
52497             }
52498             let translation = this._imageToTranslation(image, this.reference);
52499             let transform = new Transform(image.exifOrientation, image.width, image.height, image.scale, image.rotation, translation, image.image, undefined, image.cameraParameters, image.cameraType);
52500             this._trajectoryTransforms.push(transform);
52501             this._trajectoryCameras.push(new Camera(transform));
52502         }
52503     }
52504     _prependToTrajectories(images) {
52505         for (let image of images.reverse()) {
52506             if (!image.assetsCached) {
52507                 throw new ArgumentMapillaryError("Assets must be cached when added to trajectory");
52508             }
52509             let translation = this._imageToTranslation(image, this.reference);
52510             let transform = new Transform(image.exifOrientation, image.width, image.height, image.scale, image.rotation, translation, image.image, undefined, image.cameraParameters, image.cameraType);
52511             this._trajectoryTransforms.unshift(transform);
52512             this._trajectoryCameras.unshift(new Camera(transform));
52513         }
52514     }
52515     _imageToTranslation(image, reference) {
52516         return computeTranslation({ alt: image.computedAltitude, lat: image.lngLat.lat, lng: image.lngLat.lng }, image.rotation, reference);
52517     }
52518     _sameConnectedComponent() {
52519         let current = this._currentImage;
52520         let previous = this._previousImage;
52521         return !!current && !!previous &&
52522             current.mergeId === previous.mergeId;
52523     }
52524     _withinOriginalDistance() {
52525         let current = this._currentImage;
52526         let previous = this._previousImage;
52527         if (!current || !previous) {
52528             return true;
52529         }
52530         // 50 km/h moves 28m in 2s
52531         let distance = this._spatial.distanceFromLngLat(current.originalLngLat.lng, current.originalLngLat.lat, previous.originalLngLat.lng, previous.originalLngLat.lat);
52532         return distance < 25;
52533     }
52534 }
52535
52536 class EulerRotationDelta {
52537     constructor(phi, theta) {
52538         this._phi = phi;
52539         this._theta = theta;
52540     }
52541     get phi() {
52542         return this._phi;
52543     }
52544     set phi(value) {
52545         this._phi = value;
52546     }
52547     get theta() {
52548         return this._theta;
52549     }
52550     set theta(value) {
52551         this._theta = value;
52552     }
52553     get isZero() {
52554         return this._phi === 0 && this._theta === 0;
52555     }
52556     copy(delta) {
52557         this._phi = delta.phi;
52558         this._theta = delta.theta;
52559     }
52560     lerp(other, alpha) {
52561         this._phi = (1 - alpha) * this._phi + alpha * other.phi;
52562         this._theta = (1 - alpha) * this._theta + alpha * other.theta;
52563     }
52564     multiply(value) {
52565         this._phi *= value;
52566         this._theta *= value;
52567     }
52568     threshold(value) {
52569         this._phi = Math.abs(this._phi) > value ? this._phi : 0;
52570         this._theta = Math.abs(this._theta) > value ? this._theta : 0;
52571     }
52572     lengthSquared() {
52573         return this._phi * this._phi + this._theta * this._theta;
52574     }
52575     reset() {
52576         this._phi = 0;
52577         this._theta = 0;
52578     }
52579 }
52580
52581 class InteractiveStateBase extends StateBase {
52582     constructor(state) {
52583         super(state);
52584         this._animationSpeed = 1 / 40;
52585         this._rotationDelta = new EulerRotationDelta(0, 0);
52586         this._requestedRotationDelta = null;
52587         this._basicRotation = [0, 0];
52588         this._requestedBasicRotation = null;
52589         this._requestedBasicRotationUnbounded = null;
52590         this._rotationAcceleration = 0.86;
52591         this._rotationIncreaseAlpha = 0.97;
52592         this._rotationDecreaseAlpha = 0.9;
52593         this._rotationThreshold = 1e-3;
52594         this._unboundedRotationAlpha = 0.8;
52595         this._desiredZoom = state.zoom;
52596         this._minZoom = 0;
52597         this._maxZoom = 3;
52598         this._lookatDepth = 10;
52599         this._desiredLookat = null;
52600         this._desiredCenter = null;
52601     }
52602     rotate(rotationDelta) {
52603         if (this._currentImage == null) {
52604             return;
52605         }
52606         if (rotationDelta.phi === 0 && rotationDelta.theta === 0) {
52607             return;
52608         }
52609         this._desiredZoom = this._zoom;
52610         this._desiredLookat = null;
52611         this._requestedBasicRotation = null;
52612         if (this._requestedRotationDelta != null) {
52613             this._requestedRotationDelta.phi = this._requestedRotationDelta.phi + rotationDelta.phi;
52614             this._requestedRotationDelta.theta = this._requestedRotationDelta.theta + rotationDelta.theta;
52615         }
52616         else {
52617             this._requestedRotationDelta = new EulerRotationDelta(rotationDelta.phi, rotationDelta.theta);
52618         }
52619     }
52620     rotateUnbounded(delta) {
52621         if (this._currentImage == null) {
52622             return;
52623         }
52624         this._requestedBasicRotation = null;
52625         this._requestedRotationDelta = null;
52626         this._applyRotation(delta, this._currentCamera);
52627         this._applyRotation(delta, this._previousCamera);
52628         if (!this._desiredLookat) {
52629             return;
52630         }
52631         const q = new Quaternion().setFromUnitVectors(this._currentCamera.up, new Vector3(0, 0, 1));
52632         const qInverse = q.clone().invert();
52633         const offset = new Vector3()
52634             .copy(this._desiredLookat)
52635             .sub(this._camera.position)
52636             .applyQuaternion(q);
52637         const length = offset.length();
52638         let phi = Math.atan2(offset.y, offset.x);
52639         phi += delta.phi;
52640         let theta = Math.atan2(Math.sqrt(offset.x * offset.x + offset.y * offset.y), offset.z);
52641         theta += delta.theta;
52642         theta = Math.max(0.1, Math.min(Math.PI - 0.1, theta));
52643         offset.x = Math.sin(theta) * Math.cos(phi);
52644         offset.y = Math.sin(theta) * Math.sin(phi);
52645         offset.z = Math.cos(theta);
52646         offset.applyQuaternion(qInverse);
52647         this._desiredLookat
52648             .copy(this._camera.position)
52649             .add(offset.multiplyScalar(length));
52650     }
52651     rotateWithoutInertia(rotationDelta) {
52652         if (this._currentImage == null) {
52653             return;
52654         }
52655         this._desiredZoom = this._zoom;
52656         this._desiredLookat = null;
52657         this._requestedBasicRotation = null;
52658         this._requestedRotationDelta = null;
52659         const threshold = Math.PI / (10 * Math.pow(2, this._zoom));
52660         const delta = {
52661             phi: this._spatial.clamp(rotationDelta.phi, -threshold, threshold),
52662             theta: this._spatial.clamp(rotationDelta.theta, -threshold, threshold),
52663         };
52664         this._applyRotation(delta, this._currentCamera);
52665         this._applyRotation(delta, this._previousCamera);
52666     }
52667     rotateBasic(basicRotation) {
52668         if (this._currentImage == null) {
52669             return;
52670         }
52671         this._desiredZoom = this._zoom;
52672         this._desiredLookat = null;
52673         this._requestedRotationDelta = null;
52674         if (this._requestedBasicRotation != null) {
52675             this._requestedBasicRotation[0] += basicRotation[0];
52676             this._requestedBasicRotation[1] += basicRotation[1];
52677             let threshold = 0.05 / Math.pow(2, this._zoom);
52678             this._requestedBasicRotation[0] =
52679                 this._spatial.clamp(this._requestedBasicRotation[0], -threshold, threshold);
52680             this._requestedBasicRotation[1] =
52681                 this._spatial.clamp(this._requestedBasicRotation[1], -threshold, threshold);
52682         }
52683         else {
52684             this._requestedBasicRotation = basicRotation.slice();
52685         }
52686     }
52687     rotateBasicUnbounded(basicRotation) {
52688         if (this._currentImage == null) {
52689             return;
52690         }
52691         if (this._requestedBasicRotationUnbounded != null) {
52692             this._requestedBasicRotationUnbounded[0] += basicRotation[0];
52693             this._requestedBasicRotationUnbounded[1] += basicRotation[1];
52694         }
52695         else {
52696             this._requestedBasicRotationUnbounded = basicRotation.slice();
52697         }
52698     }
52699     rotateBasicWithoutInertia(basic) {
52700         if (this._currentImage == null) {
52701             return;
52702         }
52703         this._desiredZoom = this._zoom;
52704         this._desiredLookat = null;
52705         this._requestedRotationDelta = null;
52706         this._requestedBasicRotation = null;
52707         const threshold = 0.05 / Math.pow(2, this._zoom);
52708         const basicRotation = basic.slice();
52709         basicRotation[0] = this._spatial.clamp(basicRotation[0], -threshold, threshold);
52710         basicRotation[1] = this._spatial.clamp(basicRotation[1], -threshold, threshold);
52711         this._applyRotationBasic(basicRotation);
52712     }
52713     rotateToBasic(basic) {
52714         if (this._currentImage == null) {
52715             return;
52716         }
52717         this._desiredZoom = this._zoom;
52718         this._desiredLookat = null;
52719         basic[0] = this._spatial.clamp(basic[0], 0, 1);
52720         basic[1] = this._spatial.clamp(basic[1], 0, 1);
52721         let lookat = this.currentTransform.unprojectBasic(basic, this._lookatDepth);
52722         this._currentCamera.lookat.fromArray(lookat);
52723     }
52724     zoomIn(delta, reference) {
52725         if (this._currentImage == null) {
52726             return;
52727         }
52728         this._desiredZoom = Math.max(this._minZoom, Math.min(this._maxZoom, this._desiredZoom + delta));
52729         let currentCenter = this.currentTransform.projectBasic(this._currentCamera.lookat.toArray());
52730         let currentCenterX = currentCenter[0];
52731         let currentCenterY = currentCenter[1];
52732         let zoom0 = Math.pow(2, this._zoom);
52733         let zoom1 = Math.pow(2, this._desiredZoom);
52734         let refX = reference[0];
52735         let refY = reference[1];
52736         if (isSpherical(this.currentTransform.cameraType)) {
52737             if (refX - currentCenterX > 0.5) {
52738                 refX = refX - 1;
52739             }
52740             else if (currentCenterX - refX > 0.5) {
52741                 refX = 1 + refX;
52742             }
52743         }
52744         let newCenterX = refX - zoom0 / zoom1 * (refX - currentCenterX);
52745         let newCenterY = refY - zoom0 / zoom1 * (refY - currentCenterY);
52746         if (isSpherical(this._currentImage.cameraType)) {
52747             newCenterX = this._spatial
52748                 .wrap(newCenterX + this._basicRotation[0], 0, 1);
52749             newCenterY = this._spatial
52750                 .clamp(newCenterY + this._basicRotation[1], 0.05, 0.95);
52751         }
52752         else {
52753             newCenterX = this._spatial.clamp(newCenterX, 0, 1);
52754             newCenterY = this._spatial.clamp(newCenterY, 0, 1);
52755         }
52756         this._desiredLookat = new Vector3()
52757             .fromArray(this.currentTransform.unprojectBasic([newCenterX, newCenterY], this._lookatDepth));
52758     }
52759     setCenter(center) {
52760         this._desiredLookat = null;
52761         this._requestedRotationDelta = null;
52762         this._requestedBasicRotation = null;
52763         this._desiredZoom = this._zoom;
52764         let clamped = [
52765             this._spatial.clamp(center[0], 0, 1),
52766             this._spatial.clamp(center[1], 0, 1),
52767         ];
52768         if (this._currentImage == null) {
52769             this._desiredCenter = clamped;
52770             return;
52771         }
52772         this._desiredCenter = null;
52773         let currentLookat = new Vector3()
52774             .fromArray(this.currentTransform.unprojectBasic(clamped, this._lookatDepth));
52775         let previousTransform = this.previousTransform != null ?
52776             this.previousTransform :
52777             this.currentTransform;
52778         let previousLookat = new Vector3()
52779             .fromArray(previousTransform.unprojectBasic(clamped, this._lookatDepth));
52780         this._currentCamera.lookat.copy(currentLookat);
52781         this._previousCamera.lookat.copy(previousLookat);
52782     }
52783     setZoom(zoom) {
52784         this._desiredLookat = null;
52785         this._requestedRotationDelta = null;
52786         this._requestedBasicRotation = null;
52787         this._zoom = this._spatial.clamp(zoom, this._minZoom, this._maxZoom);
52788         this._desiredZoom = this._zoom;
52789     }
52790     _applyRotation(delta, camera) {
52791         if (camera == null) {
52792             return;
52793         }
52794         let q = new Quaternion().setFromUnitVectors(camera.up, new Vector3(0, 0, 1));
52795         let qInverse = q.clone().invert();
52796         let offset = new Vector3();
52797         offset.copy(camera.lookat).sub(camera.position);
52798         offset.applyQuaternion(q);
52799         let length = offset.length();
52800         let phi = Math.atan2(offset.y, offset.x);
52801         phi += delta.phi;
52802         let theta = Math.atan2(Math.sqrt(offset.x * offset.x + offset.y * offset.y), offset.z);
52803         theta += delta.theta;
52804         theta = Math.max(0.1, Math.min(Math.PI - 0.1, theta));
52805         offset.x = Math.sin(theta) * Math.cos(phi);
52806         offset.y = Math.sin(theta) * Math.sin(phi);
52807         offset.z = Math.cos(theta);
52808         offset.applyQuaternion(qInverse);
52809         camera.lookat.copy(camera.position).add(offset.multiplyScalar(length));
52810     }
52811     _applyRotationBasic(basicRotation) {
52812         let currentImage = this._currentImage;
52813         let previousImage = this._previousImage != null ?
52814             this.previousImage :
52815             this.currentImage;
52816         let currentCamera = this._currentCamera;
52817         let previousCamera = this._previousCamera;
52818         let currentTransform = this.currentTransform;
52819         let previousTransform = this.previousTransform != null ?
52820             this.previousTransform :
52821             this.currentTransform;
52822         let currentBasic = currentTransform.projectBasic(currentCamera.lookat.toArray());
52823         let previousBasic = previousTransform.projectBasic(previousCamera.lookat.toArray());
52824         if (isSpherical(currentImage.cameraType)) {
52825             currentBasic[0] = this._spatial.wrap(currentBasic[0] + basicRotation[0], 0, 1);
52826             currentBasic[1] = this._spatial.clamp(currentBasic[1] + basicRotation[1], 0.05, 0.95);
52827         }
52828         else {
52829             currentBasic[0] = this._spatial.clamp(currentBasic[0] + basicRotation[0], 0, 1);
52830             currentBasic[1] = this._spatial.clamp(currentBasic[1] + basicRotation[1], 0, 1);
52831         }
52832         if (isSpherical(previousImage.cameraType)) {
52833             previousBasic[0] = this._spatial.wrap(previousBasic[0] + basicRotation[0], 0, 1);
52834             previousBasic[1] = this._spatial.clamp(previousBasic[1] + basicRotation[1], 0.05, 0.95);
52835         }
52836         else {
52837             previousBasic[0] = this._spatial.clamp(previousBasic[0] + basicRotation[0], 0, 1);
52838             previousBasic[1] = this._spatial.clamp(currentBasic[1] + basicRotation[1], 0, 1);
52839         }
52840         let currentLookat = currentTransform.unprojectBasic(currentBasic, this._lookatDepth);
52841         currentCamera.lookat.fromArray(currentLookat);
52842         let previousLookat = previousTransform.unprojectBasic(previousBasic, this._lookatDepth);
52843         previousCamera.lookat.fromArray(previousLookat);
52844     }
52845     _updateZoom(animationSpeed) {
52846         let diff = this._desiredZoom - this._zoom;
52847         let sign = diff > 0 ? 1 : diff < 0 ? -1 : 0;
52848         if (diff === 0) {
52849             return;
52850         }
52851         else if (Math.abs(diff) < 2e-3) {
52852             this._zoom = this._desiredZoom;
52853             if (this._desiredLookat != null) {
52854                 this._desiredLookat = null;
52855             }
52856         }
52857         else {
52858             this._zoom += sign * Math.max(Math.abs(5 * animationSpeed * diff), 2e-3);
52859         }
52860     }
52861     _updateLookat(animationSpeed) {
52862         if (this._desiredLookat === null) {
52863             return;
52864         }
52865         let diff = this._desiredLookat.distanceToSquared(this._currentCamera.lookat);
52866         if (Math.abs(diff) < 1e-6) {
52867             this._currentCamera.lookat.copy(this._desiredLookat);
52868             this._desiredLookat = null;
52869         }
52870         else {
52871             this._currentCamera.lookat.lerp(this._desiredLookat, 5 * animationSpeed);
52872         }
52873     }
52874     _updateRotation() {
52875         if (this._requestedRotationDelta != null) {
52876             let length = this._rotationDelta.lengthSquared();
52877             let requestedLength = this._requestedRotationDelta.lengthSquared();
52878             if (requestedLength > length) {
52879                 this._rotationDelta.lerp(this._requestedRotationDelta, this._rotationIncreaseAlpha);
52880             }
52881             else {
52882                 this._rotationDelta.lerp(this._requestedRotationDelta, this._rotationDecreaseAlpha);
52883             }
52884             this._requestedRotationDelta = null;
52885             return;
52886         }
52887         if (this._rotationDelta.isZero) {
52888             return;
52889         }
52890         const alpha = isSpherical(this.currentImage.cameraType) ?
52891             1 : this._alpha;
52892         this._rotationDelta.multiply(this._rotationAcceleration * alpha);
52893         this._rotationDelta.threshold(this._rotationThreshold);
52894     }
52895     _updateRotationBasic() {
52896         if (this._requestedBasicRotation != null) {
52897             let x = this._basicRotation[0];
52898             let y = this._basicRotation[1];
52899             let reqX = this._requestedBasicRotation[0];
52900             let reqY = this._requestedBasicRotation[1];
52901             if (Math.abs(reqX) > Math.abs(x)) {
52902                 this._basicRotation[0] = (1 - this._rotationIncreaseAlpha) * x + this._rotationIncreaseAlpha * reqX;
52903             }
52904             else {
52905                 this._basicRotation[0] = (1 - this._rotationDecreaseAlpha) * x + this._rotationDecreaseAlpha * reqX;
52906             }
52907             if (Math.abs(reqY) > Math.abs(y)) {
52908                 this._basicRotation[1] = (1 - this._rotationIncreaseAlpha) * y + this._rotationIncreaseAlpha * reqY;
52909             }
52910             else {
52911                 this._basicRotation[1] = (1 - this._rotationDecreaseAlpha) * y + this._rotationDecreaseAlpha * reqY;
52912             }
52913             this._requestedBasicRotation = null;
52914             return;
52915         }
52916         if (this._requestedBasicRotationUnbounded != null) {
52917             let reqX = this._requestedBasicRotationUnbounded[0];
52918             let reqY = this._requestedBasicRotationUnbounded[1];
52919             if (Math.abs(reqX) > 0) {
52920                 this._basicRotation[0] = (1 - this._unboundedRotationAlpha) * this._basicRotation[0] + this._unboundedRotationAlpha * reqX;
52921             }
52922             if (Math.abs(reqY) > 0) {
52923                 this._basicRotation[1] = (1 - this._unboundedRotationAlpha) * this._basicRotation[1] + this._unboundedRotationAlpha * reqY;
52924             }
52925             if (this._desiredLookat != null) {
52926                 let desiredBasicLookat = this.currentTransform.projectBasic(this._desiredLookat.toArray());
52927                 desiredBasicLookat[0] += reqX;
52928                 desiredBasicLookat[1] += reqY;
52929                 this._desiredLookat = new Vector3()
52930                     .fromArray(this.currentTransform.unprojectBasic(desiredBasicLookat, this._lookatDepth));
52931             }
52932             this._requestedBasicRotationUnbounded = null;
52933         }
52934         if (this._basicRotation[0] === 0 && this._basicRotation[1] === 0) {
52935             return;
52936         }
52937         this._basicRotation[0] = this._rotationAcceleration * this._basicRotation[0];
52938         this._basicRotation[1] = this._rotationAcceleration * this._basicRotation[1];
52939         if (Math.abs(this._basicRotation[0]) < this._rotationThreshold / Math.pow(2, this._zoom) &&
52940             Math.abs(this._basicRotation[1]) < this._rotationThreshold / Math.pow(2, this._zoom)) {
52941             this._basicRotation = [0, 0];
52942         }
52943     }
52944     _clearRotation() {
52945         if (isSpherical(this._currentImage.cameraType)) {
52946             return;
52947         }
52948         if (this._requestedRotationDelta != null) {
52949             this._requestedRotationDelta = null;
52950         }
52951         if (!this._rotationDelta.isZero) {
52952             this._rotationDelta.reset();
52953         }
52954         if (this._requestedBasicRotation != null) {
52955             this._requestedBasicRotation = null;
52956         }
52957         if (this._basicRotation[0] > 0 || this._basicRotation[1] > 0) {
52958             this._basicRotation = [0, 0];
52959         }
52960     }
52961     _setDesiredCenter() {
52962         if (this._desiredCenter == null) {
52963             return;
52964         }
52965         let lookatDirection = new Vector3()
52966             .fromArray(this.currentTransform.unprojectBasic(this._desiredCenter, this._lookatDepth))
52967             .sub(this._currentCamera.position);
52968         this._currentCamera.lookat.copy(this._currentCamera.position.clone().add(lookatDirection));
52969         this._previousCamera.lookat.copy(this._previousCamera.position.clone().add(lookatDirection));
52970         this._desiredCenter = null;
52971     }
52972     _setDesiredZoom() {
52973         this._desiredZoom =
52974             isSpherical(this._currentImage.cameraType) ||
52975                 this._previousImage == null ?
52976                 this._zoom : 0;
52977     }
52978 }
52979
52980 class TraversingState extends InteractiveStateBase {
52981     constructor(state) {
52982         super(state);
52983         this._adjustCameras();
52984         this._motionless = this._motionlessTransition();
52985         this._baseAlpha = this._alpha;
52986         this._speedCoefficient = 1;
52987         this._unitBezier =
52988             new TraversingState._interpolator(0.74, 0.67, 0.38, 0.96);
52989         this._useBezier = false;
52990     }
52991     static register(interpolator) {
52992         TraversingState._interpolator = interpolator;
52993     }
52994     append(images) {
52995         let emptyTrajectory = this._trajectory.length === 0;
52996         if (emptyTrajectory) {
52997             this._resetTransition();
52998         }
52999         super.append(images);
53000         if (emptyTrajectory) {
53001             this._setDesiredCenter();
53002             this._setDesiredZoom();
53003         }
53004     }
53005     prepend(images) {
53006         let emptyTrajectory = this._trajectory.length === 0;
53007         if (emptyTrajectory) {
53008             this._resetTransition();
53009         }
53010         super.prepend(images);
53011         if (emptyTrajectory) {
53012             this._setDesiredCenter();
53013             this._setDesiredZoom();
53014         }
53015     }
53016     set(images) {
53017         super.set(images);
53018         this._desiredLookat = null;
53019         this._resetTransition();
53020         this._clearRotation();
53021         this._setDesiredCenter();
53022         this._setDesiredZoom();
53023         if (this._trajectory.length < 3) {
53024             this._useBezier = true;
53025         }
53026     }
53027     setSpeed(speed) {
53028         this._speedCoefficient = this._spatial.clamp(speed, 0, 10);
53029     }
53030     update(fps) {
53031         if (this._alpha === 1 && this._currentIndex + this._alpha < this._trajectory.length) {
53032             this._currentIndex += 1;
53033             this._useBezier = this._trajectory.length < 3 &&
53034                 this._currentIndex + 1 === this._trajectory.length;
53035             this._setCurrent();
53036             this._resetTransition();
53037             this._clearRotation();
53038             this._desiredZoom =
53039                 isSpherical(this._currentImage.cameraType) ?
53040                     this._zoom : 0;
53041             this._desiredLookat = null;
53042         }
53043         let animationSpeed = this._animationSpeed * (60 / fps);
53044         this._baseAlpha = Math.min(1, this._baseAlpha + this._speedCoefficient * animationSpeed);
53045         if (this._useBezier) {
53046             this._alpha = this._unitBezier.solve(this._baseAlpha);
53047         }
53048         else {
53049             this._alpha = this._baseAlpha;
53050         }
53051         this._updateRotation();
53052         if (!this._rotationDelta.isZero) {
53053             this._applyRotation(this._rotationDelta, this._previousCamera);
53054             this._applyRotation(this._rotationDelta, this._currentCamera);
53055         }
53056         this._updateRotationBasic();
53057         if (this._basicRotation[0] !== 0 || this._basicRotation[1] !== 0) {
53058             this._applyRotationBasic(this._basicRotation);
53059         }
53060         this._updateZoom(animationSpeed);
53061         this._updateLookat(animationSpeed);
53062         this._camera.lerpCameras(this._previousCamera, this._currentCamera, this.alpha);
53063     }
53064     _getAlpha() {
53065         return this._motionless ? Math.ceil(this._alpha) : this._alpha;
53066     }
53067     _setCurrentCamera() {
53068         super._setCurrentCamera();
53069         this._adjustCameras();
53070     }
53071     _adjustCameras() {
53072         if (this._previousImage == null) {
53073             return;
53074         }
53075         let lookat = this._camera.lookat.clone().sub(this._camera.position);
53076         this._previousCamera.lookat.copy(lookat.clone().add(this._previousCamera.position));
53077         if (isSpherical(this._currentImage.cameraType)) {
53078             this._currentCamera.lookat.copy(lookat.clone().add(this._currentCamera.position));
53079         }
53080     }
53081     _resetTransition() {
53082         this._alpha = 0;
53083         this._baseAlpha = 0;
53084         this._motionless = this._motionlessTransition();
53085     }
53086 }
53087
53088 class ComponentService {
53089     constructor(container, navigator) {
53090         this._components = {};
53091         for (const componentName in ComponentService.registeredComponents) {
53092             if (!ComponentService.registeredComponents.hasOwnProperty(componentName)) {
53093                 continue;
53094             }
53095             const component = ComponentService.registeredComponents[componentName];
53096             this._components[componentName] = {
53097                 active: false,
53098                 component: new component(componentName, container, navigator),
53099             };
53100         }
53101         this._coverComponent = new ComponentService.registeredCoverComponent("cover", container, navigator);
53102         this._coverComponent.activate();
53103         this._coverActivated = true;
53104     }
53105     static register(component) {
53106         if (ComponentService.registeredComponents[component.componentName] === undefined) {
53107             ComponentService.registeredComponents[component.componentName] = component;
53108         }
53109     }
53110     static registerCover(coverComponent) {
53111         ComponentService.registeredCoverComponent = coverComponent;
53112     }
53113     get coverActivated() {
53114         return this._coverActivated;
53115     }
53116     activateCover() {
53117         if (this._coverActivated) {
53118             return;
53119         }
53120         this._coverActivated = true;
53121         for (const componentName in this._components) {
53122             if (!this._components.hasOwnProperty(componentName)) {
53123                 continue;
53124             }
53125             const component = this._components[componentName];
53126             if (component.active) {
53127                 component.component.deactivate();
53128             }
53129         }
53130     }
53131     deactivateCover() {
53132         if (!this._coverActivated) {
53133             return;
53134         }
53135         this._coverActivated = false;
53136         for (const componentName in this._components) {
53137             if (!this._components.hasOwnProperty(componentName)) {
53138                 continue;
53139             }
53140             const component = this._components[componentName];
53141             if (component.active) {
53142                 component.component.activate();
53143             }
53144         }
53145     }
53146     activate(name) {
53147         this._checkName(name);
53148         this._components[name].active = true;
53149         if (!this._coverActivated) {
53150             this.get(name).activate();
53151         }
53152     }
53153     configure(name, conf) {
53154         this._checkName(name);
53155         this.get(name).configure(conf);
53156     }
53157     deactivate(name) {
53158         this._checkName(name);
53159         this._components[name].active = false;
53160         if (!this._coverActivated) {
53161             this.get(name).deactivate();
53162         }
53163     }
53164     get(name) {
53165         return this._components[name].component;
53166     }
53167     getCover() {
53168         return this._coverComponent;
53169     }
53170     remove() {
53171         this._coverComponent.deactivate();
53172         for (const componentName in this._components) {
53173             if (!this._components.hasOwnProperty(componentName)) {
53174                 continue;
53175             }
53176             this._components[componentName].component.deactivate();
53177         }
53178     }
53179     _checkName(name) {
53180         if (!(name in this._components)) {
53181             throw new ArgumentMapillaryError(`Component does not exist: ${name}`);
53182         }
53183     }
53184 }
53185 ComponentService.registeredComponents = {};
53186
53187 var nativeIsArray = Array.isArray;
53188 var toString$2 = Object.prototype.toString;
53189
53190 var xIsArray = nativeIsArray || isArray;
53191
53192 function isArray(obj) {
53193     return toString$2.call(obj) === "[object Array]"
53194 }
53195
53196 var version = "2";
53197
53198 VirtualPatch.NONE = 0;
53199 VirtualPatch.VTEXT = 1;
53200 VirtualPatch.VNODE = 2;
53201 VirtualPatch.WIDGET = 3;
53202 VirtualPatch.PROPS = 4;
53203 VirtualPatch.ORDER = 5;
53204 VirtualPatch.INSERT = 6;
53205 VirtualPatch.REMOVE = 7;
53206 VirtualPatch.THUNK = 8;
53207
53208 var vpatch = VirtualPatch;
53209
53210 function VirtualPatch(type, vNode, patch) {
53211     this.type = Number(type);
53212     this.vNode = vNode;
53213     this.patch = patch;
53214 }
53215
53216 VirtualPatch.prototype.version = version;
53217 VirtualPatch.prototype.type = "VirtualPatch";
53218
53219 var isVnode = isVirtualNode;
53220
53221 function isVirtualNode(x) {
53222     return x && x.type === "VirtualNode" && x.version === version
53223 }
53224
53225 var isVtext = isVirtualText;
53226
53227 function isVirtualText(x) {
53228     return x && x.type === "VirtualText" && x.version === version
53229 }
53230
53231 var isWidget_1 = isWidget;
53232
53233 function isWidget(w) {
53234     return w && w.type === "Widget"
53235 }
53236
53237 var isThunk_1 = isThunk;
53238
53239 function isThunk(t) {
53240     return t && t.type === "Thunk"
53241 }
53242
53243 var handleThunk_1 = handleThunk;
53244
53245 function handleThunk(a, b) {
53246     var renderedA = a;
53247     var renderedB = b;
53248
53249     if (isThunk_1(b)) {
53250         renderedB = renderThunk(b, a);
53251     }
53252
53253     if (isThunk_1(a)) {
53254         renderedA = renderThunk(a, null);
53255     }
53256
53257     return {
53258         a: renderedA,
53259         b: renderedB
53260     }
53261 }
53262
53263 function renderThunk(thunk, previous) {
53264     var renderedThunk = thunk.vnode;
53265
53266     if (!renderedThunk) {
53267         renderedThunk = thunk.vnode = thunk.render(previous);
53268     }
53269
53270     if (!(isVnode(renderedThunk) ||
53271             isVtext(renderedThunk) ||
53272             isWidget_1(renderedThunk))) {
53273         throw new Error("thunk did not return a valid node");
53274     }
53275
53276     return renderedThunk
53277 }
53278
53279 var isObject = function isObject(x) {
53280         return typeof x === 'object' && x !== null;
53281 };
53282
53283 var isVhook = isHook;
53284
53285 function isHook(hook) {
53286     return hook &&
53287       (typeof hook.hook === "function" && !hook.hasOwnProperty("hook") ||
53288        typeof hook.unhook === "function" && !hook.hasOwnProperty("unhook"))
53289 }
53290
53291 var diffProps_1 = diffProps;
53292
53293 function diffProps(a, b) {
53294     var diff;
53295
53296     for (var aKey in a) {
53297         if (!(aKey in b)) {
53298             diff = diff || {};
53299             diff[aKey] = undefined;
53300         }
53301
53302         var aValue = a[aKey];
53303         var bValue = b[aKey];
53304
53305         if (aValue === bValue) {
53306             continue
53307         } else if (isObject(aValue) && isObject(bValue)) {
53308             if (getPrototype$1(bValue) !== getPrototype$1(aValue)) {
53309                 diff = diff || {};
53310                 diff[aKey] = bValue;
53311             } else if (isVhook(bValue)) {
53312                  diff = diff || {};
53313                  diff[aKey] = bValue;
53314             } else {
53315                 var objectDiff = diffProps(aValue, bValue);
53316                 if (objectDiff) {
53317                     diff = diff || {};
53318                     diff[aKey] = objectDiff;
53319                 }
53320             }
53321         } else {
53322             diff = diff || {};
53323             diff[aKey] = bValue;
53324         }
53325     }
53326
53327     for (var bKey in b) {
53328         if (!(bKey in a)) {
53329             diff = diff || {};
53330             diff[bKey] = b[bKey];
53331         }
53332     }
53333
53334     return diff
53335 }
53336
53337 function getPrototype$1(value) {
53338   if (Object.getPrototypeOf) {
53339     return Object.getPrototypeOf(value)
53340   } else if (value.__proto__) {
53341     return value.__proto__
53342   } else if (value.constructor) {
53343     return value.constructor.prototype
53344   }
53345 }
53346
53347 var diff_1$1 = diff;
53348
53349 function diff(a, b) {
53350     var patch = { a: a };
53351     walk(a, b, patch, 0);
53352     return patch
53353 }
53354
53355 function walk(a, b, patch, index) {
53356     if (a === b) {
53357         return
53358     }
53359
53360     var apply = patch[index];
53361     var applyClear = false;
53362
53363     if (isThunk_1(a) || isThunk_1(b)) {
53364         thunks(a, b, patch, index);
53365     } else if (b == null) {
53366
53367         // If a is a widget we will add a remove patch for it
53368         // Otherwise any child widgets/hooks must be destroyed.
53369         // This prevents adding two remove patches for a widget.
53370         if (!isWidget_1(a)) {
53371             clearState(a, patch, index);
53372             apply = patch[index];
53373         }
53374
53375         apply = appendPatch(apply, new vpatch(vpatch.REMOVE, a, b));
53376     } else if (isVnode(b)) {
53377         if (isVnode(a)) {
53378             if (a.tagName === b.tagName &&
53379                 a.namespace === b.namespace &&
53380                 a.key === b.key) {
53381                 var propsPatch = diffProps_1(a.properties, b.properties);
53382                 if (propsPatch) {
53383                     apply = appendPatch(apply,
53384                         new vpatch(vpatch.PROPS, a, propsPatch));
53385                 }
53386                 apply = diffChildren(a, b, patch, apply, index);
53387             } else {
53388                 apply = appendPatch(apply, new vpatch(vpatch.VNODE, a, b));
53389                 applyClear = true;
53390             }
53391         } else {
53392             apply = appendPatch(apply, new vpatch(vpatch.VNODE, a, b));
53393             applyClear = true;
53394         }
53395     } else if (isVtext(b)) {
53396         if (!isVtext(a)) {
53397             apply = appendPatch(apply, new vpatch(vpatch.VTEXT, a, b));
53398             applyClear = true;
53399         } else if (a.text !== b.text) {
53400             apply = appendPatch(apply, new vpatch(vpatch.VTEXT, a, b));
53401         }
53402     } else if (isWidget_1(b)) {
53403         if (!isWidget_1(a)) {
53404             applyClear = true;
53405         }
53406
53407         apply = appendPatch(apply, new vpatch(vpatch.WIDGET, a, b));
53408     }
53409
53410     if (apply) {
53411         patch[index] = apply;
53412     }
53413
53414     if (applyClear) {
53415         clearState(a, patch, index);
53416     }
53417 }
53418
53419 function diffChildren(a, b, patch, apply, index) {
53420     var aChildren = a.children;
53421     var orderedSet = reorder(aChildren, b.children);
53422     var bChildren = orderedSet.children;
53423
53424     var aLen = aChildren.length;
53425     var bLen = bChildren.length;
53426     var len = aLen > bLen ? aLen : bLen;
53427
53428     for (var i = 0; i < len; i++) {
53429         var leftNode = aChildren[i];
53430         var rightNode = bChildren[i];
53431         index += 1;
53432
53433         if (!leftNode) {
53434             if (rightNode) {
53435                 // Excess nodes in b need to be added
53436                 apply = appendPatch(apply,
53437                     new vpatch(vpatch.INSERT, null, rightNode));
53438             }
53439         } else {
53440             walk(leftNode, rightNode, patch, index);
53441         }
53442
53443         if (isVnode(leftNode) && leftNode.count) {
53444             index += leftNode.count;
53445         }
53446     }
53447
53448     if (orderedSet.moves) {
53449         // Reorder nodes last
53450         apply = appendPatch(apply, new vpatch(
53451             vpatch.ORDER,
53452             a,
53453             orderedSet.moves
53454         ));
53455     }
53456
53457     return apply
53458 }
53459
53460 function clearState(vNode, patch, index) {
53461     // TODO: Make this a single walk, not two
53462     unhook(vNode, patch, index);
53463     destroyWidgets(vNode, patch, index);
53464 }
53465
53466 // Patch records for all destroyed widgets must be added because we need
53467 // a DOM node reference for the destroy function
53468 function destroyWidgets(vNode, patch, index) {
53469     if (isWidget_1(vNode)) {
53470         if (typeof vNode.destroy === "function") {
53471             patch[index] = appendPatch(
53472                 patch[index],
53473                 new vpatch(vpatch.REMOVE, vNode, null)
53474             );
53475         }
53476     } else if (isVnode(vNode) && (vNode.hasWidgets || vNode.hasThunks)) {
53477         var children = vNode.children;
53478         var len = children.length;
53479         for (var i = 0; i < len; i++) {
53480             var child = children[i];
53481             index += 1;
53482
53483             destroyWidgets(child, patch, index);
53484
53485             if (isVnode(child) && child.count) {
53486                 index += child.count;
53487             }
53488         }
53489     } else if (isThunk_1(vNode)) {
53490         thunks(vNode, null, patch, index);
53491     }
53492 }
53493
53494 // Create a sub-patch for thunks
53495 function thunks(a, b, patch, index) {
53496     var nodes = handleThunk_1(a, b);
53497     var thunkPatch = diff(nodes.a, nodes.b);
53498     if (hasPatches(thunkPatch)) {
53499         patch[index] = new vpatch(vpatch.THUNK, null, thunkPatch);
53500     }
53501 }
53502
53503 function hasPatches(patch) {
53504     for (var index in patch) {
53505         if (index !== "a") {
53506             return true
53507         }
53508     }
53509
53510     return false
53511 }
53512
53513 // Execute hooks when two nodes are identical
53514 function unhook(vNode, patch, index) {
53515     if (isVnode(vNode)) {
53516         if (vNode.hooks) {
53517             patch[index] = appendPatch(
53518                 patch[index],
53519                 new vpatch(
53520                     vpatch.PROPS,
53521                     vNode,
53522                     undefinedKeys(vNode.hooks)
53523                 )
53524             );
53525         }
53526
53527         if (vNode.descendantHooks || vNode.hasThunks) {
53528             var children = vNode.children;
53529             var len = children.length;
53530             for (var i = 0; i < len; i++) {
53531                 var child = children[i];
53532                 index += 1;
53533
53534                 unhook(child, patch, index);
53535
53536                 if (isVnode(child) && child.count) {
53537                     index += child.count;
53538                 }
53539             }
53540         }
53541     } else if (isThunk_1(vNode)) {
53542         thunks(vNode, null, patch, index);
53543     }
53544 }
53545
53546 function undefinedKeys(obj) {
53547     var result = {};
53548
53549     for (var key in obj) {
53550         result[key] = undefined;
53551     }
53552
53553     return result
53554 }
53555
53556 // List diff, naive left to right reordering
53557 function reorder(aChildren, bChildren) {
53558     // O(M) time, O(M) memory
53559     var bChildIndex = keyIndex(bChildren);
53560     var bKeys = bChildIndex.keys;
53561     var bFree = bChildIndex.free;
53562
53563     if (bFree.length === bChildren.length) {
53564         return {
53565             children: bChildren,
53566             moves: null
53567         }
53568     }
53569
53570     // O(N) time, O(N) memory
53571     var aChildIndex = keyIndex(aChildren);
53572     var aKeys = aChildIndex.keys;
53573     var aFree = aChildIndex.free;
53574
53575     if (aFree.length === aChildren.length) {
53576         return {
53577             children: bChildren,
53578             moves: null
53579         }
53580     }
53581
53582     // O(MAX(N, M)) memory
53583     var newChildren = [];
53584
53585     var freeIndex = 0;
53586     var freeCount = bFree.length;
53587     var deletedItems = 0;
53588
53589     // Iterate through a and match a node in b
53590     // O(N) time,
53591     for (var i = 0 ; i < aChildren.length; i++) {
53592         var aItem = aChildren[i];
53593         var itemIndex;
53594
53595         if (aItem.key) {
53596             if (bKeys.hasOwnProperty(aItem.key)) {
53597                 // Match up the old keys
53598                 itemIndex = bKeys[aItem.key];
53599                 newChildren.push(bChildren[itemIndex]);
53600
53601             } else {
53602                 // Remove old keyed items
53603                 itemIndex = i - deletedItems++;
53604                 newChildren.push(null);
53605             }
53606         } else {
53607             // Match the item in a with the next free item in b
53608             if (freeIndex < freeCount) {
53609                 itemIndex = bFree[freeIndex++];
53610                 newChildren.push(bChildren[itemIndex]);
53611             } else {
53612                 // There are no free items in b to match with
53613                 // the free items in a, so the extra free nodes
53614                 // are deleted.
53615                 itemIndex = i - deletedItems++;
53616                 newChildren.push(null);
53617             }
53618         }
53619     }
53620
53621     var lastFreeIndex = freeIndex >= bFree.length ?
53622         bChildren.length :
53623         bFree[freeIndex];
53624
53625     // Iterate through b and append any new keys
53626     // O(M) time
53627     for (var j = 0; j < bChildren.length; j++) {
53628         var newItem = bChildren[j];
53629
53630         if (newItem.key) {
53631             if (!aKeys.hasOwnProperty(newItem.key)) {
53632                 // Add any new keyed items
53633                 // We are adding new items to the end and then sorting them
53634                 // in place. In future we should insert new items in place.
53635                 newChildren.push(newItem);
53636             }
53637         } else if (j >= lastFreeIndex) {
53638             // Add any leftover non-keyed items
53639             newChildren.push(newItem);
53640         }
53641     }
53642
53643     var simulate = newChildren.slice();
53644     var simulateIndex = 0;
53645     var removes = [];
53646     var inserts = [];
53647     var simulateItem;
53648
53649     for (var k = 0; k < bChildren.length;) {
53650         var wantedItem = bChildren[k];
53651         simulateItem = simulate[simulateIndex];
53652
53653         // remove items
53654         while (simulateItem === null && simulate.length) {
53655             removes.push(remove(simulate, simulateIndex, null));
53656             simulateItem = simulate[simulateIndex];
53657         }
53658
53659         if (!simulateItem || simulateItem.key !== wantedItem.key) {
53660             // if we need a key in this position...
53661             if (wantedItem.key) {
53662                 if (simulateItem && simulateItem.key) {
53663                     // if an insert doesn't put this key in place, it needs to move
53664                     if (bKeys[simulateItem.key] !== k + 1) {
53665                         removes.push(remove(simulate, simulateIndex, simulateItem.key));
53666                         simulateItem = simulate[simulateIndex];
53667                         // if the remove didn't put the wanted item in place, we need to insert it
53668                         if (!simulateItem || simulateItem.key !== wantedItem.key) {
53669                             inserts.push({key: wantedItem.key, to: k});
53670                         }
53671                         // items are matching, so skip ahead
53672                         else {
53673                             simulateIndex++;
53674                         }
53675                     }
53676                     else {
53677                         inserts.push({key: wantedItem.key, to: k});
53678                     }
53679                 }
53680                 else {
53681                     inserts.push({key: wantedItem.key, to: k});
53682                 }
53683                 k++;
53684             }
53685             // a key in simulate has no matching wanted key, remove it
53686             else if (simulateItem && simulateItem.key) {
53687                 removes.push(remove(simulate, simulateIndex, simulateItem.key));
53688             }
53689         }
53690         else {
53691             simulateIndex++;
53692             k++;
53693         }
53694     }
53695
53696     // remove all the remaining nodes from simulate
53697     while(simulateIndex < simulate.length) {
53698         simulateItem = simulate[simulateIndex];
53699         removes.push(remove(simulate, simulateIndex, simulateItem && simulateItem.key));
53700     }
53701
53702     // If the only moves we have are deletes then we can just
53703     // let the delete patch remove these items.
53704     if (removes.length === deletedItems && !inserts.length) {
53705         return {
53706             children: newChildren,
53707             moves: null
53708         }
53709     }
53710
53711     return {
53712         children: newChildren,
53713         moves: {
53714             removes: removes,
53715             inserts: inserts
53716         }
53717     }
53718 }
53719
53720 function remove(arr, index, key) {
53721     arr.splice(index, 1);
53722
53723     return {
53724         from: index,
53725         key: key
53726     }
53727 }
53728
53729 function keyIndex(children) {
53730     var keys = {};
53731     var free = [];
53732     var length = children.length;
53733
53734     for (var i = 0; i < length; i++) {
53735         var child = children[i];
53736
53737         if (child.key) {
53738             keys[child.key] = i;
53739         } else {
53740             free.push(i);
53741         }
53742     }
53743
53744     return {
53745         keys: keys,     // A hash of key name to index
53746         free: free      // An array of unkeyed item indices
53747     }
53748 }
53749
53750 function appendPatch(apply, patch) {
53751     if (apply) {
53752         if (xIsArray(apply)) {
53753             apply.push(patch);
53754         } else {
53755             apply = [apply, patch];
53756         }
53757
53758         return apply
53759     } else {
53760         return patch
53761     }
53762 }
53763
53764 var diff_1 = diff_1$1;
53765
53766 var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
53767
53768 function getAugmentedNamespace(n) {
53769         if (n.__esModule) return n;
53770         var a = Object.defineProperty({}, '__esModule', {value: true});
53771         Object.keys(n).forEach(function (k) {
53772                 var d = Object.getOwnPropertyDescriptor(n, k);
53773                 Object.defineProperty(a, k, d.get ? d : {
53774                         enumerable: true,
53775                         get: function () {
53776                                 return n[k];
53777                         }
53778                 });
53779         });
53780         return a;
53781 }
53782
53783 function createCommonjsModule(fn) {
53784   var module = { exports: {} };
53785         return fn(module, module.exports), module.exports;
53786 }
53787
53788 function commonjsRequire (target) {
53789         throw new Error('Could not dynamically require "' + target + '". Please configure the dynamicRequireTargets option of @rollup/plugin-commonjs appropriately for this require call to behave properly.');
53790 }
53791
53792 var slice = Array.prototype.slice;
53793
53794 var domWalk = iterativelyWalk;
53795
53796 function iterativelyWalk(nodes, cb) {
53797     if (!('length' in nodes)) {
53798         nodes = [nodes];
53799     }
53800     
53801     nodes = slice.call(nodes);
53802
53803     while(nodes.length) {
53804         var node = nodes.shift(),
53805             ret = cb(node);
53806
53807         if (ret) {
53808             return ret
53809         }
53810
53811         if (node.childNodes && node.childNodes.length) {
53812             nodes = slice.call(node.childNodes).concat(nodes);
53813         }
53814     }
53815 }
53816
53817 var domComment = Comment;
53818
53819 function Comment(data, owner) {
53820     if (!(this instanceof Comment)) {
53821         return new Comment(data, owner)
53822     }
53823
53824     this.data = data;
53825     this.nodeValue = data;
53826     this.length = data.length;
53827     this.ownerDocument = owner || null;
53828 }
53829
53830 Comment.prototype.nodeType = 8;
53831 Comment.prototype.nodeName = "#comment";
53832
53833 Comment.prototype.toString = function _Comment_toString() {
53834     return "[object Comment]"
53835 };
53836
53837 var domText = DOMText;
53838
53839 function DOMText(value, owner) {
53840     if (!(this instanceof DOMText)) {
53841         return new DOMText(value)
53842     }
53843
53844     this.data = value || "";
53845     this.length = this.data.length;
53846     this.ownerDocument = owner || null;
53847 }
53848
53849 DOMText.prototype.type = "DOMTextNode";
53850 DOMText.prototype.nodeType = 3;
53851 DOMText.prototype.nodeName = "#text";
53852
53853 DOMText.prototype.toString = function _Text_toString() {
53854     return this.data
53855 };
53856
53857 DOMText.prototype.replaceData = function replaceData(index, length, value) {
53858     var current = this.data;
53859     var left = current.substring(0, index);
53860     var right = current.substring(index + length, current.length);
53861     this.data = left + value + right;
53862     this.length = this.data.length;
53863 };
53864
53865 var dispatchEvent_1 = dispatchEvent;
53866
53867 function dispatchEvent(ev) {
53868     var elem = this;
53869     var type = ev.type;
53870
53871     if (!ev.target) {
53872         ev.target = elem;
53873     }
53874
53875     if (!elem.listeners) {
53876         elem.listeners = {};
53877     }
53878
53879     var listeners = elem.listeners[type];
53880
53881     if (listeners) {
53882         return listeners.forEach(function (listener) {
53883             ev.currentTarget = elem;
53884             if (typeof listener === 'function') {
53885                 listener(ev);
53886             } else {
53887                 listener.handleEvent(ev);
53888             }
53889         })
53890     }
53891
53892     if (elem.parentNode) {
53893         elem.parentNode.dispatchEvent(ev);
53894     }
53895 }
53896
53897 var addEventListener_1 = addEventListener;
53898
53899 function addEventListener(type, listener) {
53900     var elem = this;
53901
53902     if (!elem.listeners) {
53903         elem.listeners = {};
53904     }
53905
53906     if (!elem.listeners[type]) {
53907         elem.listeners[type] = [];
53908     }
53909
53910     if (elem.listeners[type].indexOf(listener) === -1) {
53911         elem.listeners[type].push(listener);
53912     }
53913 }
53914
53915 var removeEventListener_1 = removeEventListener;
53916
53917 function removeEventListener(type, listener) {
53918     var elem = this;
53919
53920     if (!elem.listeners) {
53921         return
53922     }
53923
53924     if (!elem.listeners[type]) {
53925         return
53926     }
53927
53928     var list = elem.listeners[type];
53929     var index = list.indexOf(listener);
53930     if (index !== -1) {
53931         list.splice(index, 1);
53932     }
53933 }
53934
53935 var serialize = serializeNode;
53936
53937 var voidElements = ["area","base","br","col","embed","hr","img","input","keygen","link","menuitem","meta","param","source","track","wbr"];
53938
53939 function serializeNode(node) {
53940     switch (node.nodeType) {
53941         case 3:
53942             return escapeText(node.data)
53943         case 8:
53944             return "<!--" + node.data + "-->"
53945         default:
53946             return serializeElement(node)
53947     }
53948 }
53949
53950 function serializeElement(elem) {
53951     var strings = [];
53952
53953     var tagname = elem.tagName;
53954
53955     if (elem.namespaceURI === "http://www.w3.org/1999/xhtml") {
53956         tagname = tagname.toLowerCase();
53957     }
53958
53959     strings.push("<" + tagname + properties(elem) + datasetify(elem));
53960
53961     if (voidElements.indexOf(tagname) > -1) {
53962         strings.push(" />");
53963     } else {
53964         strings.push(">");
53965
53966         if (elem.childNodes.length) {
53967             strings.push.apply(strings, elem.childNodes.map(serializeNode));
53968         } else if (elem.textContent || elem.innerText) {
53969             strings.push(escapeText(elem.textContent || elem.innerText));
53970         } else if (elem.innerHTML) {
53971             strings.push(elem.innerHTML);
53972         }
53973
53974         strings.push("</" + tagname + ">");
53975     }
53976
53977     return strings.join("")
53978 }
53979
53980 function isProperty(elem, key) {
53981     var type = typeof elem[key];
53982
53983     if (key === "style" && Object.keys(elem.style).length > 0) {
53984       return true
53985     }
53986
53987     return elem.hasOwnProperty(key) &&
53988         (type === "string" || type === "boolean" || type === "number") &&
53989         key !== "nodeName" && key !== "className" && key !== "tagName" &&
53990         key !== "textContent" && key !== "innerText" && key !== "namespaceURI" &&  key !== "innerHTML"
53991 }
53992
53993 function stylify(styles) {
53994     if (typeof styles === 'string') return styles
53995     var attr = "";
53996     Object.keys(styles).forEach(function (key) {
53997         var value = styles[key];
53998         key = key.replace(/[A-Z]/g, function(c) {
53999             return "-" + c.toLowerCase();
54000         });
54001         attr += key + ":" + value + ";";
54002     });
54003     return attr
54004 }
54005
54006 function datasetify(elem) {
54007     var ds = elem.dataset;
54008     var props = [];
54009
54010     for (var key in ds) {
54011         props.push({ name: "data-" + key, value: ds[key] });
54012     }
54013
54014     return props.length ? stringify(props) : ""
54015 }
54016
54017 function stringify(list) {
54018     var attributes = [];
54019     list.forEach(function (tuple) {
54020         var name = tuple.name;
54021         var value = tuple.value;
54022
54023         if (name === "style") {
54024             value = stylify(value);
54025         }
54026
54027         attributes.push(name + "=" + "\"" + escapeAttributeValue(value) + "\"");
54028     });
54029
54030     return attributes.length ? " " + attributes.join(" ") : ""
54031 }
54032
54033 function properties(elem) {
54034     var props = [];
54035     for (var key in elem) {
54036         if (isProperty(elem, key)) {
54037             props.push({ name: key, value: elem[key] });
54038         }
54039     }
54040
54041     for (var ns in elem._attributes) {
54042       for (var attribute in elem._attributes[ns]) {
54043         var prop = elem._attributes[ns][attribute];
54044         var name = (prop.prefix ? prop.prefix + ":" : "") + attribute;
54045         props.push({ name: name, value: prop.value });
54046       }
54047     }
54048
54049     if (elem.className) {
54050         props.push({ name: "class", value: elem.className });
54051     }
54052
54053     return props.length ? stringify(props) : ""
54054 }
54055
54056 function escapeText(s) {
54057     var str = '';
54058
54059     if (typeof(s) === 'string') { 
54060         str = s; 
54061     } else if (s) {
54062         str = s.toString();
54063     }
54064
54065     return str
54066         .replace(/&/g, "&amp;")
54067         .replace(/</g, "&lt;")
54068         .replace(/>/g, "&gt;")
54069 }
54070
54071 function escapeAttributeValue(str) {
54072     return escapeText(str).replace(/"/g, "&quot;")
54073 }
54074
54075 var htmlns = "http://www.w3.org/1999/xhtml";
54076
54077 var domElement = DOMElement;
54078
54079 function DOMElement(tagName, owner, namespace) {
54080     if (!(this instanceof DOMElement)) {
54081         return new DOMElement(tagName)
54082     }
54083
54084     var ns = namespace === undefined ? htmlns : (namespace || null);
54085
54086     this.tagName = ns === htmlns ? String(tagName).toUpperCase() : tagName;
54087     this.nodeName = this.tagName;
54088     this.className = "";
54089     this.dataset = {};
54090     this.childNodes = [];
54091     this.parentNode = null;
54092     this.style = {};
54093     this.ownerDocument = owner || null;
54094     this.namespaceURI = ns;
54095     this._attributes = {};
54096
54097     if (this.tagName === 'INPUT') {
54098       this.type = 'text';
54099     }
54100 }
54101
54102 DOMElement.prototype.type = "DOMElement";
54103 DOMElement.prototype.nodeType = 1;
54104
54105 DOMElement.prototype.appendChild = function _Element_appendChild(child) {
54106     if (child.parentNode) {
54107         child.parentNode.removeChild(child);
54108     }
54109
54110     this.childNodes.push(child);
54111     child.parentNode = this;
54112
54113     return child
54114 };
54115
54116 DOMElement.prototype.replaceChild =
54117     function _Element_replaceChild(elem, needle) {
54118         // TODO: Throw NotFoundError if needle.parentNode !== this
54119
54120         if (elem.parentNode) {
54121             elem.parentNode.removeChild(elem);
54122         }
54123
54124         var index = this.childNodes.indexOf(needle);
54125
54126         needle.parentNode = null;
54127         this.childNodes[index] = elem;
54128         elem.parentNode = this;
54129
54130         return needle
54131     };
54132
54133 DOMElement.prototype.removeChild = function _Element_removeChild(elem) {
54134     // TODO: Throw NotFoundError if elem.parentNode !== this
54135
54136     var index = this.childNodes.indexOf(elem);
54137     this.childNodes.splice(index, 1);
54138
54139     elem.parentNode = null;
54140     return elem
54141 };
54142
54143 DOMElement.prototype.insertBefore =
54144     function _Element_insertBefore(elem, needle) {
54145         // TODO: Throw NotFoundError if referenceElement is a dom node
54146         // and parentNode !== this
54147
54148         if (elem.parentNode) {
54149             elem.parentNode.removeChild(elem);
54150         }
54151
54152         var index = needle === null || needle === undefined ?
54153             -1 :
54154             this.childNodes.indexOf(needle);
54155
54156         if (index > -1) {
54157             this.childNodes.splice(index, 0, elem);
54158         } else {
54159             this.childNodes.push(elem);
54160         }
54161
54162         elem.parentNode = this;
54163         return elem
54164     };
54165
54166 DOMElement.prototype.setAttributeNS =
54167     function _Element_setAttributeNS(namespace, name, value) {
54168         var prefix = null;
54169         var localName = name;
54170         var colonPosition = name.indexOf(":");
54171         if (colonPosition > -1) {
54172             prefix = name.substr(0, colonPosition);
54173             localName = name.substr(colonPosition + 1);
54174         }
54175         if (this.tagName === 'INPUT' && name === 'type') {
54176           this.type = value;
54177         }
54178         else {
54179           var attributes = this._attributes[namespace] || (this._attributes[namespace] = {});
54180           attributes[localName] = {value: value, prefix: prefix};
54181         }
54182     };
54183
54184 DOMElement.prototype.getAttributeNS =
54185     function _Element_getAttributeNS(namespace, name) {
54186         var attributes = this._attributes[namespace];
54187         var value = attributes && attributes[name] && attributes[name].value;
54188         if (this.tagName === 'INPUT' && name === 'type') {
54189           return this.type;
54190         }
54191         if (typeof value !== "string") {
54192             return null
54193         }
54194         return value
54195     };
54196
54197 DOMElement.prototype.removeAttributeNS =
54198     function _Element_removeAttributeNS(namespace, name) {
54199         var attributes = this._attributes[namespace];
54200         if (attributes) {
54201             delete attributes[name];
54202         }
54203     };
54204
54205 DOMElement.prototype.hasAttributeNS =
54206     function _Element_hasAttributeNS(namespace, name) {
54207         var attributes = this._attributes[namespace];
54208         return !!attributes && name in attributes;
54209     };
54210
54211 DOMElement.prototype.setAttribute = function _Element_setAttribute(name, value) {
54212     return this.setAttributeNS(null, name, value)
54213 };
54214
54215 DOMElement.prototype.getAttribute = function _Element_getAttribute(name) {
54216     return this.getAttributeNS(null, name)
54217 };
54218
54219 DOMElement.prototype.removeAttribute = function _Element_removeAttribute(name) {
54220     return this.removeAttributeNS(null, name)
54221 };
54222
54223 DOMElement.prototype.hasAttribute = function _Element_hasAttribute(name) {
54224     return this.hasAttributeNS(null, name)
54225 };
54226
54227 DOMElement.prototype.removeEventListener = removeEventListener_1;
54228 DOMElement.prototype.addEventListener = addEventListener_1;
54229 DOMElement.prototype.dispatchEvent = dispatchEvent_1;
54230
54231 // Un-implemented
54232 DOMElement.prototype.focus = function _Element_focus() {
54233     return void 0
54234 };
54235
54236 DOMElement.prototype.toString = function _Element_toString() {
54237     return serialize(this)
54238 };
54239
54240 DOMElement.prototype.getElementsByClassName = function _Element_getElementsByClassName(classNames) {
54241     var classes = classNames.split(" ");
54242     var elems = [];
54243
54244     domWalk(this, function (node) {
54245         if (node.nodeType === 1) {
54246             var nodeClassName = node.className || "";
54247             var nodeClasses = nodeClassName.split(" ");
54248
54249             if (classes.every(function (item) {
54250                 return nodeClasses.indexOf(item) !== -1
54251             })) {
54252                 elems.push(node);
54253             }
54254         }
54255     });
54256
54257     return elems
54258 };
54259
54260 DOMElement.prototype.getElementsByTagName = function _Element_getElementsByTagName(tagName) {
54261     tagName = tagName.toLowerCase();
54262     var elems = [];
54263
54264     domWalk(this.childNodes, function (node) {
54265         if (node.nodeType === 1 && (tagName === '*' || node.tagName.toLowerCase() === tagName)) {
54266             elems.push(node);
54267         }
54268     });
54269
54270     return elems
54271 };
54272
54273 DOMElement.prototype.contains = function _Element_contains(element) {
54274     return domWalk(this, function (node) {
54275         return element === node
54276     }) || false
54277 };
54278
54279 var domFragment = DocumentFragment;
54280
54281 function DocumentFragment(owner) {
54282     if (!(this instanceof DocumentFragment)) {
54283         return new DocumentFragment()
54284     }
54285
54286     this.childNodes = [];
54287     this.parentNode = null;
54288     this.ownerDocument = owner || null;
54289 }
54290
54291 DocumentFragment.prototype.type = "DocumentFragment";
54292 DocumentFragment.prototype.nodeType = 11;
54293 DocumentFragment.prototype.nodeName = "#document-fragment";
54294
54295 DocumentFragment.prototype.appendChild  = domElement.prototype.appendChild;
54296 DocumentFragment.prototype.replaceChild = domElement.prototype.replaceChild;
54297 DocumentFragment.prototype.removeChild  = domElement.prototype.removeChild;
54298
54299 DocumentFragment.prototype.toString =
54300     function _DocumentFragment_toString() {
54301         return this.childNodes.map(function (node) {
54302             return String(node)
54303         }).join("")
54304     };
54305
54306 var event = Event;
54307
54308 function Event(family) {}
54309
54310 Event.prototype.initEvent = function _Event_initEvent(type, bubbles, cancelable) {
54311     this.type = type;
54312     this.bubbles = bubbles;
54313     this.cancelable = cancelable;
54314 };
54315
54316 Event.prototype.preventDefault = function _Event_preventDefault() {
54317     
54318 };
54319
54320 var document$1 = Document;
54321
54322 function Document() {
54323     if (!(this instanceof Document)) {
54324         return new Document();
54325     }
54326
54327     this.head = this.createElement("head");
54328     this.body = this.createElement("body");
54329     this.documentElement = this.createElement("html");
54330     this.documentElement.appendChild(this.head);
54331     this.documentElement.appendChild(this.body);
54332     this.childNodes = [this.documentElement];
54333     this.nodeType = 9;
54334 }
54335
54336 var proto = Document.prototype;
54337 proto.createTextNode = function createTextNode(value) {
54338     return new domText(value, this)
54339 };
54340
54341 proto.createElementNS = function createElementNS(namespace, tagName) {
54342     var ns = namespace === null ? null : String(namespace);
54343     return new domElement(tagName, this, ns)
54344 };
54345
54346 proto.createElement = function createElement(tagName) {
54347     return new domElement(tagName, this)
54348 };
54349
54350 proto.createDocumentFragment = function createDocumentFragment() {
54351     return new domFragment(this)
54352 };
54353
54354 proto.createEvent = function createEvent(family) {
54355     return new event(family)
54356 };
54357
54358 proto.createComment = function createComment(data) {
54359     return new domComment(data, this)
54360 };
54361
54362 proto.getElementById = function getElementById(id) {
54363     id = String(id);
54364
54365     var result = domWalk(this.childNodes, function (node) {
54366         if (String(node.id) === id) {
54367             return node
54368         }
54369     });
54370
54371     return result || null
54372 };
54373
54374 proto.getElementsByClassName = domElement.prototype.getElementsByClassName;
54375 proto.getElementsByTagName = domElement.prototype.getElementsByTagName;
54376 proto.contains = domElement.prototype.contains;
54377
54378 proto.removeEventListener = removeEventListener_1;
54379 proto.addEventListener = addEventListener_1;
54380 proto.dispatchEvent = dispatchEvent_1;
54381
54382 var minDocument = new document$1();
54383
54384 var topLevel = typeof commonjsGlobal !== 'undefined' ? commonjsGlobal :
54385     typeof window !== 'undefined' ? window : {};
54386
54387
54388 var doccy;
54389
54390 if (typeof document !== 'undefined') {
54391     doccy = document;
54392 } else {
54393     doccy = topLevel['__GLOBAL_DOCUMENT_CACHE@4'];
54394
54395     if (!doccy) {
54396         doccy = topLevel['__GLOBAL_DOCUMENT_CACHE@4'] = minDocument;
54397     }
54398 }
54399
54400 var document_1 = doccy;
54401
54402 var applyProperties_1 = applyProperties;
54403
54404 function applyProperties(node, props, previous) {
54405     for (var propName in props) {
54406         var propValue = props[propName];
54407
54408         if (propValue === undefined) {
54409             removeProperty(node, propName, propValue, previous);
54410         } else if (isVhook(propValue)) {
54411             removeProperty(node, propName, propValue, previous);
54412             if (propValue.hook) {
54413                 propValue.hook(node,
54414                     propName,
54415                     previous ? previous[propName] : undefined);
54416             }
54417         } else {
54418             if (isObject(propValue)) {
54419                 patchObject(node, props, previous, propName, propValue);
54420             } else {
54421                 node[propName] = propValue;
54422             }
54423         }
54424     }
54425 }
54426
54427 function removeProperty(node, propName, propValue, previous) {
54428     if (previous) {
54429         var previousValue = previous[propName];
54430
54431         if (!isVhook(previousValue)) {
54432             if (propName === "attributes") {
54433                 for (var attrName in previousValue) {
54434                     node.removeAttribute(attrName);
54435                 }
54436             } else if (propName === "style") {
54437                 for (var i in previousValue) {
54438                     node.style[i] = "";
54439                 }
54440             } else if (typeof previousValue === "string") {
54441                 node[propName] = "";
54442             } else {
54443                 node[propName] = null;
54444             }
54445         } else if (previousValue.unhook) {
54446             previousValue.unhook(node, propName, propValue);
54447         }
54448     }
54449 }
54450
54451 function patchObject(node, props, previous, propName, propValue) {
54452     var previousValue = previous ? previous[propName] : undefined;
54453
54454     // Set attributes
54455     if (propName === "attributes") {
54456         for (var attrName in propValue) {
54457             var attrValue = propValue[attrName];
54458
54459             if (attrValue === undefined) {
54460                 node.removeAttribute(attrName);
54461             } else {
54462                 node.setAttribute(attrName, attrValue);
54463             }
54464         }
54465
54466         return
54467     }
54468
54469     if(previousValue && isObject(previousValue) &&
54470         getPrototype(previousValue) !== getPrototype(propValue)) {
54471         node[propName] = propValue;
54472         return
54473     }
54474
54475     if (!isObject(node[propName])) {
54476         node[propName] = {};
54477     }
54478
54479     var replacer = propName === "style" ? "" : undefined;
54480
54481     for (var k in propValue) {
54482         var value = propValue[k];
54483         node[propName][k] = (value === undefined) ? replacer : value;
54484     }
54485 }
54486
54487 function getPrototype(value) {
54488     if (Object.getPrototypeOf) {
54489         return Object.getPrototypeOf(value)
54490     } else if (value.__proto__) {
54491         return value.__proto__
54492     } else if (value.constructor) {
54493         return value.constructor.prototype
54494     }
54495 }
54496
54497 var createElement_1$1 = createElement;
54498
54499 function createElement(vnode, opts) {
54500     var doc = opts ? opts.document || document_1 : document_1;
54501     var warn = opts ? opts.warn : null;
54502
54503     vnode = handleThunk_1(vnode).a;
54504
54505     if (isWidget_1(vnode)) {
54506         return vnode.init()
54507     } else if (isVtext(vnode)) {
54508         return doc.createTextNode(vnode.text)
54509     } else if (!isVnode(vnode)) {
54510         if (warn) {
54511             warn("Item is not a valid virtual dom node", vnode);
54512         }
54513         return null
54514     }
54515
54516     var node = (vnode.namespace === null) ?
54517         doc.createElement(vnode.tagName) :
54518         doc.createElementNS(vnode.namespace, vnode.tagName);
54519
54520     var props = vnode.properties;
54521     applyProperties_1(node, props);
54522
54523     var children = vnode.children;
54524
54525     for (var i = 0; i < children.length; i++) {
54526         var childNode = createElement(children[i], opts);
54527         if (childNode) {
54528             node.appendChild(childNode);
54529         }
54530     }
54531
54532     return node
54533 }
54534
54535 // Maps a virtual DOM tree onto a real DOM tree in an efficient manner.
54536 // We don't want to read all of the DOM nodes in the tree so we use
54537 // the in-order tree indexing to eliminate recursion down certain branches.
54538 // We only recurse into a DOM node if we know that it contains a child of
54539 // interest.
54540
54541 var noChild = {};
54542
54543 var domIndex_1 = domIndex;
54544
54545 function domIndex(rootNode, tree, indices, nodes) {
54546     if (!indices || indices.length === 0) {
54547         return {}
54548     } else {
54549         indices.sort(ascending);
54550         return recurse(rootNode, tree, indices, nodes, 0)
54551     }
54552 }
54553
54554 function recurse(rootNode, tree, indices, nodes, rootIndex) {
54555     nodes = nodes || {};
54556
54557
54558     if (rootNode) {
54559         if (indexInRange(indices, rootIndex, rootIndex)) {
54560             nodes[rootIndex] = rootNode;
54561         }
54562
54563         var vChildren = tree.children;
54564
54565         if (vChildren) {
54566
54567             var childNodes = rootNode.childNodes;
54568
54569             for (var i = 0; i < tree.children.length; i++) {
54570                 rootIndex += 1;
54571
54572                 var vChild = vChildren[i] || noChild;
54573                 var nextIndex = rootIndex + (vChild.count || 0);
54574
54575                 // skip recursion down the tree if there are no nodes down here
54576                 if (indexInRange(indices, rootIndex, nextIndex)) {
54577                     recurse(childNodes[i], vChild, indices, nodes, rootIndex);
54578                 }
54579
54580                 rootIndex = nextIndex;
54581             }
54582         }
54583     }
54584
54585     return nodes
54586 }
54587
54588 // Binary search for an index in the interval [left, right]
54589 function indexInRange(indices, left, right) {
54590     if (indices.length === 0) {
54591         return false
54592     }
54593
54594     var minIndex = 0;
54595     var maxIndex = indices.length - 1;
54596     var currentIndex;
54597     var currentItem;
54598
54599     while (minIndex <= maxIndex) {
54600         currentIndex = ((maxIndex + minIndex) / 2) >> 0;
54601         currentItem = indices[currentIndex];
54602
54603         if (minIndex === maxIndex) {
54604             return currentItem >= left && currentItem <= right
54605         } else if (currentItem < left) {
54606             minIndex = currentIndex + 1;
54607         } else  if (currentItem > right) {
54608             maxIndex = currentIndex - 1;
54609         } else {
54610             return true
54611         }
54612     }
54613
54614     return false;
54615 }
54616
54617 function ascending(a, b) {
54618     return a > b ? 1 : -1
54619 }
54620
54621 var updateWidget_1 = updateWidget;
54622
54623 function updateWidget(a, b) {
54624     if (isWidget_1(a) && isWidget_1(b)) {
54625         if ("name" in a && "name" in b) {
54626             return a.id === b.id
54627         } else {
54628             return a.init === b.init
54629         }
54630     }
54631
54632     return false
54633 }
54634
54635 var patchOp = applyPatch$1;
54636
54637 function applyPatch$1(vpatch$1, domNode, renderOptions) {
54638     var type = vpatch$1.type;
54639     var vNode = vpatch$1.vNode;
54640     var patch = vpatch$1.patch;
54641
54642     switch (type) {
54643         case vpatch.REMOVE:
54644             return removeNode$1(domNode, vNode)
54645         case vpatch.INSERT:
54646             return insertNode$1(domNode, patch, renderOptions)
54647         case vpatch.VTEXT:
54648             return stringPatch(domNode, vNode, patch, renderOptions)
54649         case vpatch.WIDGET:
54650             return widgetPatch(domNode, vNode, patch, renderOptions)
54651         case vpatch.VNODE:
54652             return vNodePatch(domNode, vNode, patch, renderOptions)
54653         case vpatch.ORDER:
54654             reorderChildren(domNode, patch);
54655             return domNode
54656         case vpatch.PROPS:
54657             applyProperties_1(domNode, patch, vNode.properties);
54658             return domNode
54659         case vpatch.THUNK:
54660             return replaceRoot(domNode,
54661                 renderOptions.patch(domNode, patch, renderOptions))
54662         default:
54663             return domNode
54664     }
54665 }
54666
54667 function removeNode$1(domNode, vNode) {
54668     var parentNode = domNode.parentNode;
54669
54670     if (parentNode) {
54671         parentNode.removeChild(domNode);
54672     }
54673
54674     destroyWidget(domNode, vNode);
54675
54676     return null
54677 }
54678
54679 function insertNode$1(parentNode, vNode, renderOptions) {
54680     var newNode = renderOptions.render(vNode, renderOptions);
54681
54682     if (parentNode) {
54683         parentNode.appendChild(newNode);
54684     }
54685
54686     return parentNode
54687 }
54688
54689 function stringPatch(domNode, leftVNode, vText, renderOptions) {
54690     var newNode;
54691
54692     if (domNode.nodeType === 3) {
54693         domNode.replaceData(0, domNode.length, vText.text);
54694         newNode = domNode;
54695     } else {
54696         var parentNode = domNode.parentNode;
54697         newNode = renderOptions.render(vText, renderOptions);
54698
54699         if (parentNode && newNode !== domNode) {
54700             parentNode.replaceChild(newNode, domNode);
54701         }
54702     }
54703
54704     return newNode
54705 }
54706
54707 function widgetPatch(domNode, leftVNode, widget, renderOptions) {
54708     var updating = updateWidget_1(leftVNode, widget);
54709     var newNode;
54710
54711     if (updating) {
54712         newNode = widget.update(leftVNode, domNode) || domNode;
54713     } else {
54714         newNode = renderOptions.render(widget, renderOptions);
54715     }
54716
54717     var parentNode = domNode.parentNode;
54718
54719     if (parentNode && newNode !== domNode) {
54720         parentNode.replaceChild(newNode, domNode);
54721     }
54722
54723     if (!updating) {
54724         destroyWidget(domNode, leftVNode);
54725     }
54726
54727     return newNode
54728 }
54729
54730 function vNodePatch(domNode, leftVNode, vNode, renderOptions) {
54731     var parentNode = domNode.parentNode;
54732     var newNode = renderOptions.render(vNode, renderOptions);
54733
54734     if (parentNode && newNode !== domNode) {
54735         parentNode.replaceChild(newNode, domNode);
54736     }
54737
54738     return newNode
54739 }
54740
54741 function destroyWidget(domNode, w) {
54742     if (typeof w.destroy === "function" && isWidget_1(w)) {
54743         w.destroy(domNode);
54744     }
54745 }
54746
54747 function reorderChildren(domNode, moves) {
54748     var childNodes = domNode.childNodes;
54749     var keyMap = {};
54750     var node;
54751     var remove;
54752     var insert;
54753
54754     for (var i = 0; i < moves.removes.length; i++) {
54755         remove = moves.removes[i];
54756         node = childNodes[remove.from];
54757         if (remove.key) {
54758             keyMap[remove.key] = node;
54759         }
54760         domNode.removeChild(node);
54761     }
54762
54763     var length = childNodes.length;
54764     for (var j = 0; j < moves.inserts.length; j++) {
54765         insert = moves.inserts[j];
54766         node = keyMap[insert.key];
54767         // this is the weirdest bug i've ever seen in webkit
54768         domNode.insertBefore(node, insert.to >= length++ ? null : childNodes[insert.to]);
54769     }
54770 }
54771
54772 function replaceRoot(oldRoot, newRoot) {
54773     if (oldRoot && newRoot && oldRoot !== newRoot && oldRoot.parentNode) {
54774         oldRoot.parentNode.replaceChild(newRoot, oldRoot);
54775     }
54776
54777     return newRoot;
54778 }
54779
54780 var patch_1$1 = patch;
54781
54782 function patch(rootNode, patches, renderOptions) {
54783     renderOptions = renderOptions || {};
54784     renderOptions.patch = renderOptions.patch && renderOptions.patch !== patch
54785         ? renderOptions.patch
54786         : patchRecursive;
54787     renderOptions.render = renderOptions.render || createElement_1$1;
54788
54789     return renderOptions.patch(rootNode, patches, renderOptions)
54790 }
54791
54792 function patchRecursive(rootNode, patches, renderOptions) {
54793     var indices = patchIndices(patches);
54794
54795     if (indices.length === 0) {
54796         return rootNode
54797     }
54798
54799     var index = domIndex_1(rootNode, patches.a, indices);
54800     var ownerDocument = rootNode.ownerDocument;
54801
54802     if (!renderOptions.document && ownerDocument !== document_1) {
54803         renderOptions.document = ownerDocument;
54804     }
54805
54806     for (var i = 0; i < indices.length; i++) {
54807         var nodeIndex = indices[i];
54808         rootNode = applyPatch(rootNode,
54809             index[nodeIndex],
54810             patches[nodeIndex],
54811             renderOptions);
54812     }
54813
54814     return rootNode
54815 }
54816
54817 function applyPatch(rootNode, domNode, patchList, renderOptions) {
54818     if (!domNode) {
54819         return rootNode
54820     }
54821
54822     var newNode;
54823
54824     if (xIsArray(patchList)) {
54825         for (var i = 0; i < patchList.length; i++) {
54826             newNode = patchOp(patchList[i], domNode, renderOptions);
54827
54828             if (domNode === rootNode) {
54829                 rootNode = newNode;
54830             }
54831         }
54832     } else {
54833         newNode = patchOp(patchList, domNode, renderOptions);
54834
54835         if (domNode === rootNode) {
54836             rootNode = newNode;
54837         }
54838     }
54839
54840     return rootNode
54841 }
54842
54843 function patchIndices(patches) {
54844     var indices = [];
54845
54846     for (var key in patches) {
54847         if (key !== "a") {
54848             indices.push(Number(key));
54849         }
54850     }
54851
54852     return indices
54853 }
54854
54855 var patch_1 = patch_1$1;
54856
54857 var vnode = VirtualNode;
54858
54859 var noProperties = {};
54860 var noChildren = [];
54861
54862 function VirtualNode(tagName, properties, children, key, namespace) {
54863     this.tagName = tagName;
54864     this.properties = properties || noProperties;
54865     this.children = children || noChildren;
54866     this.key = key != null ? String(key) : undefined;
54867     this.namespace = (typeof namespace === "string") ? namespace : null;
54868
54869     var count = (children && children.length) || 0;
54870     var descendants = 0;
54871     var hasWidgets = false;
54872     var hasThunks = false;
54873     var descendantHooks = false;
54874     var hooks;
54875
54876     for (var propName in properties) {
54877         if (properties.hasOwnProperty(propName)) {
54878             var property = properties[propName];
54879             if (isVhook(property) && property.unhook) {
54880                 if (!hooks) {
54881                     hooks = {};
54882                 }
54883
54884                 hooks[propName] = property;
54885             }
54886         }
54887     }
54888
54889     for (var i = 0; i < count; i++) {
54890         var child = children[i];
54891         if (isVnode(child)) {
54892             descendants += child.count || 0;
54893
54894             if (!hasWidgets && child.hasWidgets) {
54895                 hasWidgets = true;
54896             }
54897
54898             if (!hasThunks && child.hasThunks) {
54899                 hasThunks = true;
54900             }
54901
54902             if (!descendantHooks && (child.hooks || child.descendantHooks)) {
54903                 descendantHooks = true;
54904             }
54905         } else if (!hasWidgets && isWidget_1(child)) {
54906             if (typeof child.destroy === "function") {
54907                 hasWidgets = true;
54908             }
54909         } else if (!hasThunks && isThunk_1(child)) {
54910             hasThunks = true;
54911         }
54912     }
54913
54914     this.count = count + descendants;
54915     this.hasWidgets = hasWidgets;
54916     this.hasThunks = hasThunks;
54917     this.hooks = hooks;
54918     this.descendantHooks = descendantHooks;
54919 }
54920
54921 VirtualNode.prototype.version = version;
54922 VirtualNode.prototype.type = "VirtualNode";
54923
54924 var vtext = VirtualText;
54925
54926 function VirtualText(text) {
54927     this.text = String(text);
54928 }
54929
54930 VirtualText.prototype.version = version;
54931 VirtualText.prototype.type = "VirtualText";
54932
54933 /*!
54934  * Cross-Browser Split 1.1.1
54935  * Copyright 2007-2012 Steven Levithan <stevenlevithan.com>
54936  * Available under the MIT License
54937  * ECMAScript compliant, uniform cross-browser split method
54938  */
54939 /**
54940  * Splits a string into an array of strings using a regex or string separator. Matches of the
54941  * separator are not included in the result array. However, if `separator` is a regex that contains
54942  * capturing groups, backreferences are spliced into the result each time `separator` is matched.
54943  * Fixes browser bugs compared to the native `String.prototype.split` and can be used reliably
54944  * cross-browser.
54945  * @param {String} str String to split.
54946  * @param {RegExp|String} separator Regex or string to use for separating the string.
54947  * @param {Number} [limit] Maximum number of items to include in the result array.
54948  * @returns {Array} Array of substrings.
54949  * @example
54950  *
54951  * // Basic use
54952  * split('a b c d', ' ');
54953  * // -> ['a', 'b', 'c', 'd']
54954  *
54955  * // With limit
54956  * split('a b c d', ' ', 2);
54957  * // -> ['a', 'b']
54958  *
54959  * // Backreferences in result array
54960  * split('..word1 word2..', /([a-z]+)(\d+)/i);
54961  * // -> ['..', 'word', '1', ' ', 'word', '2', '..']
54962  */
54963 var browserSplit = (function split(undef) {
54964
54965   var nativeSplit = String.prototype.split,
54966     compliantExecNpcg = /()??/.exec("")[1] === undef,
54967     // NPCG: nonparticipating capturing group
54968     self;
54969
54970   self = function(str, separator, limit) {
54971     // If `separator` is not a regex, use `nativeSplit`
54972     if (Object.prototype.toString.call(separator) !== "[object RegExp]") {
54973       return nativeSplit.call(str, separator, limit);
54974     }
54975     var output = [],
54976       flags = (separator.ignoreCase ? "i" : "") + (separator.multiline ? "m" : "") + (separator.extended ? "x" : "") + // Proposed for ES6
54977       (separator.sticky ? "y" : ""),
54978       // Firefox 3+
54979       lastLastIndex = 0,
54980       // Make `global` and avoid `lastIndex` issues by working with a copy
54981       separator = new RegExp(separator.source, flags + "g"),
54982       separator2, match, lastIndex, lastLength;
54983     str += ""; // Type-convert
54984     if (!compliantExecNpcg) {
54985       // Doesn't need flags gy, but they don't hurt
54986       separator2 = new RegExp("^" + separator.source + "$(?!\\s)", flags);
54987     }
54988     /* Values for `limit`, per the spec:
54989      * If undefined: 4294967295 // Math.pow(2, 32) - 1
54990      * If 0, Infinity, or NaN: 0
54991      * If positive number: limit = Math.floor(limit); if (limit > 4294967295) limit -= 4294967296;
54992      * If negative number: 4294967296 - Math.floor(Math.abs(limit))
54993      * If other: Type-convert, then use the above rules
54994      */
54995     limit = limit === undef ? -1 >>> 0 : // Math.pow(2, 32) - 1
54996     limit >>> 0; // ToUint32(limit)
54997     while (match = separator.exec(str)) {
54998       // `separator.lastIndex` is not reliable cross-browser
54999       lastIndex = match.index + match[0].length;
55000       if (lastIndex > lastLastIndex) {
55001         output.push(str.slice(lastLastIndex, match.index));
55002         // Fix browsers whose `exec` methods don't consistently return `undefined` for
55003         // nonparticipating capturing groups
55004         if (!compliantExecNpcg && match.length > 1) {
55005           match[0].replace(separator2, function() {
55006             for (var i = 1; i < arguments.length - 2; i++) {
55007               if (arguments[i] === undef) {
55008                 match[i] = undef;
55009               }
55010             }
55011           });
55012         }
55013         if (match.length > 1 && match.index < str.length) {
55014           Array.prototype.push.apply(output, match.slice(1));
55015         }
55016         lastLength = match[0].length;
55017         lastLastIndex = lastIndex;
55018         if (output.length >= limit) {
55019           break;
55020         }
55021       }
55022       if (separator.lastIndex === match.index) {
55023         separator.lastIndex++; // Avoid an infinite loop
55024       }
55025     }
55026     if (lastLastIndex === str.length) {
55027       if (lastLength || !separator.test("")) {
55028         output.push("");
55029       }
55030     } else {
55031       output.push(str.slice(lastLastIndex));
55032     }
55033     return output.length > limit ? output.slice(0, limit) : output;
55034   };
55035
55036   return self;
55037 })();
55038
55039 var classIdSplit = /([\.#]?[a-zA-Z0-9\u007F-\uFFFF_:-]+)/;
55040 var notClassId = /^\.|#/;
55041
55042 var parseTag_1 = parseTag;
55043
55044 function parseTag(tag, props) {
55045     if (!tag) {
55046         return 'DIV';
55047     }
55048
55049     var noId = !(props.hasOwnProperty('id'));
55050
55051     var tagParts = browserSplit(tag, classIdSplit);
55052     var tagName = null;
55053
55054     if (notClassId.test(tagParts[1])) {
55055         tagName = 'DIV';
55056     }
55057
55058     var classes, part, type, i;
55059
55060     for (i = 0; i < tagParts.length; i++) {
55061         part = tagParts[i];
55062
55063         if (!part) {
55064             continue;
55065         }
55066
55067         type = part.charAt(0);
55068
55069         if (!tagName) {
55070             tagName = part;
55071         } else if (type === '.') {
55072             classes = classes || [];
55073             classes.push(part.substring(1, part.length));
55074         } else if (type === '#' && noId) {
55075             props.id = part.substring(1, part.length);
55076         }
55077     }
55078
55079     if (classes) {
55080         if (props.className) {
55081             classes.push(props.className);
55082         }
55083
55084         props.className = classes.join(' ');
55085     }
55086
55087     return props.namespace ? tagName : tagName.toUpperCase();
55088 }
55089
55090 var softSetHook = SoftSetHook;
55091
55092 function SoftSetHook(value) {
55093     if (!(this instanceof SoftSetHook)) {
55094         return new SoftSetHook(value);
55095     }
55096
55097     this.value = value;
55098 }
55099
55100 SoftSetHook.prototype.hook = function (node, propertyName) {
55101     if (node[propertyName] !== this.value) {
55102         node[propertyName] = this.value;
55103     }
55104 };
55105
55106 /*global window, global*/
55107
55108 var root = typeof window !== 'undefined' ?
55109     window : typeof commonjsGlobal !== 'undefined' ?
55110     commonjsGlobal : {};
55111
55112 var individual = Individual;
55113
55114 function Individual(key, value) {
55115     if (key in root) {
55116         return root[key];
55117     }
55118
55119     root[key] = value;
55120
55121     return value;
55122 }
55123
55124 var oneVersion = OneVersion;
55125
55126 function OneVersion(moduleName, version, defaultValue) {
55127     var key = '__INDIVIDUAL_ONE_VERSION_' + moduleName;
55128     var enforceKey = key + '_ENFORCE_SINGLETON';
55129
55130     var versionValue = individual(enforceKey, version);
55131
55132     if (versionValue !== version) {
55133         throw new Error('Can only have one copy of ' +
55134             moduleName + '.\n' +
55135             'You already have version ' + versionValue +
55136             ' installed.\n' +
55137             'This means you cannot install version ' + version);
55138     }
55139
55140     return individual(key, defaultValue);
55141 }
55142
55143 var MY_VERSION = '7';
55144 oneVersion('ev-store', MY_VERSION);
55145
55146 var hashKey = '__EV_STORE_KEY@' + MY_VERSION;
55147
55148 var evStore = EvStore;
55149
55150 function EvStore(elem) {
55151     var hash = elem[hashKey];
55152
55153     if (!hash) {
55154         hash = elem[hashKey] = {};
55155     }
55156
55157     return hash;
55158 }
55159
55160 var evHook = EvHook;
55161
55162 function EvHook(value) {
55163     if (!(this instanceof EvHook)) {
55164         return new EvHook(value);
55165     }
55166
55167     this.value = value;
55168 }
55169
55170 EvHook.prototype.hook = function (node, propertyName) {
55171     var es = evStore(node);
55172     var propName = propertyName.substr(3);
55173
55174     es[propName] = this.value;
55175 };
55176
55177 EvHook.prototype.unhook = function(node, propertyName) {
55178     var es = evStore(node);
55179     var propName = propertyName.substr(3);
55180
55181     es[propName] = undefined;
55182 };
55183
55184 var virtualHyperscript = h;
55185
55186 function h(tagName, properties, children) {
55187     var childNodes = [];
55188     var tag, props, key, namespace;
55189
55190     if (!children && isChildren(properties)) {
55191         children = properties;
55192         props = {};
55193     }
55194
55195     props = props || properties || {};
55196     tag = parseTag_1(tagName, props);
55197
55198     // support keys
55199     if (props.hasOwnProperty('key')) {
55200         key = props.key;
55201         props.key = undefined;
55202     }
55203
55204     // support namespace
55205     if (props.hasOwnProperty('namespace')) {
55206         namespace = props.namespace;
55207         props.namespace = undefined;
55208     }
55209
55210     // fix cursor bug
55211     if (tag === 'INPUT' &&
55212         !namespace &&
55213         props.hasOwnProperty('value') &&
55214         props.value !== undefined &&
55215         !isVhook(props.value)
55216     ) {
55217         props.value = softSetHook(props.value);
55218     }
55219
55220     transformProperties(props);
55221
55222     if (children !== undefined && children !== null) {
55223         addChild(children, childNodes, tag, props);
55224     }
55225
55226
55227     return new vnode(tag, props, childNodes, key, namespace);
55228 }
55229
55230 function addChild(c, childNodes, tag, props) {
55231     if (typeof c === 'string') {
55232         childNodes.push(new vtext(c));
55233     } else if (typeof c === 'number') {
55234         childNodes.push(new vtext(String(c)));
55235     } else if (isChild(c)) {
55236         childNodes.push(c);
55237     } else if (xIsArray(c)) {
55238         for (var i = 0; i < c.length; i++) {
55239             addChild(c[i], childNodes, tag, props);
55240         }
55241     } else if (c === null || c === undefined) {
55242         return;
55243     } else {
55244         throw UnexpectedVirtualElement({
55245             foreignObject: c,
55246             parentVnode: {
55247                 tagName: tag,
55248                 properties: props
55249             }
55250         });
55251     }
55252 }
55253
55254 function transformProperties(props) {
55255     for (var propName in props) {
55256         if (props.hasOwnProperty(propName)) {
55257             var value = props[propName];
55258
55259             if (isVhook(value)) {
55260                 continue;
55261             }
55262
55263             if (propName.substr(0, 3) === 'ev-') {
55264                 // add ev-foo support
55265                 props[propName] = evHook(value);
55266             }
55267         }
55268     }
55269 }
55270
55271 function isChild(x) {
55272     return isVnode(x) || isVtext(x) || isWidget_1(x) || isThunk_1(x);
55273 }
55274
55275 function isChildren(x) {
55276     return typeof x === 'string' || xIsArray(x) || isChild(x);
55277 }
55278
55279 function UnexpectedVirtualElement(data) {
55280     var err = new Error();
55281
55282     err.type = 'virtual-hyperscript.unexpected.virtual-element';
55283     err.message = 'Unexpected virtual child passed to h().\n' +
55284         'Expected a VNode / Vthunk / VWidget / string but:\n' +
55285         'got:\n' +
55286         errorString(data.foreignObject) +
55287         '.\n' +
55288         'The parent vnode is:\n' +
55289         errorString(data.parentVnode);
55290     err.foreignObject = data.foreignObject;
55291     err.parentVnode = data.parentVnode;
55292
55293     return err;
55294 }
55295
55296 function errorString(obj) {
55297     try {
55298         return JSON.stringify(obj, null, '    ');
55299     } catch (e) {
55300         return String(obj);
55301     }
55302 }
55303
55304 var h_1 = virtualHyperscript;
55305
55306 var createElement_1 = createElement_1$1;
55307
55308 var virtualDom = {
55309     diff: diff_1,
55310     patch: patch_1,
55311     h: h_1,
55312     create: createElement_1,
55313     VNode: vnode,
55314     VText: vtext
55315 };
55316
55317 class EventEmitter {
55318     constructor() { this._events = {}; }
55319     /**
55320      * Subscribe to an event by its name.
55321      * @param {string} type - The name of the event
55322      * to subscribe to.
55323      * @param {(event: T) => void} handler - The
55324      * handler called when the event occurs.
55325      */
55326     on(type, handler) {
55327         this._events[type] = this._events[type] || [];
55328         this._events[type].push(handler);
55329     }
55330     /**
55331      * Unsubscribe from an event by its name.
55332      * @param {string} type - The name of the event
55333      * to unsubscribe from.
55334      * @param {(event: T) => void} handler - The
55335      * handler to remove.
55336      */
55337     off(type, handler) {
55338         if (!type) {
55339             this._events = {};
55340             return;
55341         }
55342         if (this._listens(type)) {
55343             const index = this._events[type].indexOf(handler);
55344             if (index >= 0) {
55345                 this._events[type].splice(index, 1);
55346             }
55347             if (!this._events[type].length) {
55348                 delete this._events[type];
55349             }
55350         }
55351     }
55352     /**
55353      * @ignore
55354      */
55355     fire(type, event) {
55356         if (!this._listens(type)) {
55357             return;
55358         }
55359         for (const handler of this._events[type]) {
55360             handler(event);
55361         }
55362     }
55363     _listens(eventType) {
55364         return eventType in this._events;
55365     }
55366 }
55367
55368 class SubscriptionHolder {
55369     constructor() {
55370         this._subscriptions = [];
55371     }
55372     push(subscription) {
55373         this._subscriptions.push(subscription);
55374     }
55375     unsubscribe() {
55376         for (const sub of this._subscriptions) {
55377             sub.unsubscribe();
55378         }
55379         this._subscriptions = [];
55380     }
55381 }
55382
55383 class Component extends EventEmitter {
55384     constructor(name, container, navigator) {
55385         super();
55386         this._activated$ = new BehaviorSubject(false);
55387         this._configurationSubject$ = new Subject();
55388         this._activated = false;
55389         this._container = container;
55390         this._name = name;
55391         this._navigator = navigator;
55392         this._subscriptions = new SubscriptionHolder();
55393         this._configuration$ =
55394             this._configurationSubject$.pipe(startWith(this.defaultConfiguration), scan((conf, newConf) => {
55395                 for (let key in newConf) {
55396                     if (newConf.hasOwnProperty(key)) {
55397                         conf[key] = newConf[key];
55398                     }
55399                 }
55400                 return conf;
55401             }), publishReplay(1), refCount());
55402         this._configuration$.subscribe(() => { });
55403     }
55404     /**
55405      * Get activated.
55406      *
55407      * @returns {boolean} Value indicating if the component is
55408      * currently active.
55409      */
55410     get activated() {
55411         return this._activated;
55412     }
55413     /** @ignore */
55414     get activated$() {
55415         return this._activated$;
55416     }
55417     /**
55418      * Get default configuration.
55419      *
55420      * @returns {TConfiguration} Default configuration for component.
55421      */
55422     get defaultConfiguration() {
55423         return this._getDefaultConfiguration();
55424     }
55425     /** @ignore */
55426     get configuration$() {
55427         return this._configuration$;
55428     }
55429     /**
55430      * Get name.
55431      *
55432      * @description The name of the component. Used when interacting with the
55433      * component through the Viewer's API.
55434      */
55435     get name() {
55436         return this._name;
55437     }
55438     /** @ignore */
55439     activate(conf) {
55440         if (this._activated) {
55441             return;
55442         }
55443         if (conf !== undefined) {
55444             this._configurationSubject$.next(conf);
55445         }
55446         this._activated = true;
55447         this._activate();
55448         this._activated$.next(true);
55449     }
55450     /**
55451      * Configure the component.
55452      *
55453      * @param configuration Component configuration.
55454      */
55455     configure(configuration) {
55456         this._configurationSubject$.next(configuration);
55457     }
55458     /** @ignore */
55459     deactivate() {
55460         if (!this._activated) {
55461             return;
55462         }
55463         this._activated = false;
55464         this._deactivate();
55465         this._container.domRenderer.clear(this._name);
55466         this._container.glRenderer.clear(this._name);
55467         this._activated$.next(false);
55468     }
55469     /** @inheritdoc */
55470     fire(type, event) {
55471         super.fire(type, event);
55472     }
55473     /** @inheritdoc */
55474     off(type, handler) {
55475         super.off(type, handler);
55476     }
55477     /** @inheritdoc */
55478     on(type, handler) {
55479         super.on(type, handler);
55480     }
55481     /**
55482      * Detect the viewer's new width and height and resize the component's
55483      * rendered elements accordingly if applicable.
55484      *
55485      * @ignore
55486      */
55487     resize() { return; }
55488 }
55489
55490 var CoverState;
55491 (function (CoverState) {
55492     CoverState[CoverState["Hidden"] = 0] = "Hidden";
55493     CoverState[CoverState["Loading"] = 1] = "Loading";
55494     CoverState[CoverState["Visible"] = 2] = "Visible";
55495 })(CoverState || (CoverState = {}));
55496
55497 class CoverComponent extends Component {
55498     constructor(name, container, navigator) {
55499         super(name, container, navigator);
55500     }
55501     _activate() {
55502         const originalSrc$ = this.configuration$.pipe(first((c) => {
55503             return !!c.id;
55504         }), filter((c) => {
55505             return !c.src;
55506         }), switchMap((c) => {
55507             return this._getImageSrc$(c.id).pipe(catchError((error) => {
55508                 console.error(error);
55509                 return empty();
55510             }));
55511         }), publishReplay(1), refCount());
55512         const subs = this._subscriptions;
55513         subs.push(originalSrc$.pipe(map((src) => {
55514             return { src: src };
55515         }))
55516             .subscribe((c) => {
55517             this._configurationSubject$.next(c);
55518         }));
55519         subs.push(combineLatest(this.configuration$, originalSrc$).pipe(filter(([c, src]) => {
55520             return !!c.src && c.src !== src;
55521         }), first())
55522             .subscribe(([, src]) => {
55523             window.URL.revokeObjectURL(src);
55524         }));
55525         subs.push(this._configuration$.pipe(distinctUntilChanged(undefined, (configuration) => {
55526             return configuration.state;
55527         }), switchMap((configuration) => {
55528             return combineLatest(of(configuration.state), this._navigator.stateService.currentImage$);
55529         }), switchMap(([state, image]) => {
55530             const keySrc$ = combineLatest(of(image.id), image.image$.pipe(filter((imageElement) => {
55531                 return !!imageElement;
55532             }), map((imageElement) => {
55533                 return imageElement.src;
55534             })));
55535             return state === CoverState.Visible ? keySrc$.pipe(first()) : keySrc$;
55536         }), distinctUntilChanged(([k1, s1], [k2, s2]) => {
55537             return k1 === k2 && s1 === s2;
55538         }), map(([key, src]) => {
55539             return { id: key, src: src };
55540         }))
55541             .subscribe(this._configurationSubject$));
55542         subs.push(combineLatest(this._configuration$, this._container.configurationService.exploreUrl$, this._container.renderService.size$).pipe(map(([configuration, exploreUrl, size]) => {
55543             if (!configuration.src) {
55544                 return { name: this._name, vNode: virtualDom.h("div", []) };
55545             }
55546             const compactClass = size.width <= 640 || size.height <= 480 ? ".mapillary-cover-compact" : "";
55547             if (configuration.state === CoverState.Hidden) {
55548                 const doneContainer = virtualDom.h("div.mapillary-cover-container.mapillary-cover-done" + compactClass, [this._getCoverBackgroundVNode(configuration)]);
55549                 return { name: this._name, vNode: doneContainer };
55550             }
55551             const container = virtualDom.h("div.mapillary-cover-container" + compactClass, [this._getCoverButtonVNode(configuration, exploreUrl)]);
55552             return { name: this._name, vNode: container };
55553         }))
55554             .subscribe(this._container.domRenderer.render$));
55555     }
55556     _deactivate() {
55557         this._subscriptions.unsubscribe();
55558     }
55559     _getDefaultConfiguration() {
55560         return { state: CoverState.Visible };
55561     }
55562     _getCoverButtonVNode(configuration, exploreUrl) {
55563         const cover = configuration.state === CoverState.Loading ? "div.mapillary-cover.mapillary-cover-loading" : "div.mapillary-cover";
55564         const coverButton = virtualDom.h("div.mapillary-cover-button", [virtualDom.h("div.mapillary-cover-button-icon", [])]);
55565         const coverLogo = virtualDom.h("a.mapillary-cover-logo", { href: exploreUrl, target: "_blank" }, []);
55566         const coverIndicator = virtualDom.h("div.mapillary-cover-indicator", { onclick: () => { this.configure({ state: CoverState.Loading }); } }, []);
55567         return virtualDom.h(cover, [
55568             this._getCoverBackgroundVNode(configuration),
55569             coverIndicator,
55570             coverButton,
55571             coverLogo,
55572         ]);
55573     }
55574     _getCoverBackgroundVNode(conf) {
55575         const properties = {
55576             style: { backgroundImage: `url(${conf.src})` },
55577         };
55578         const children = [];
55579         if (conf.state === CoverState.Loading) {
55580             children.push(virtualDom.h("div.mapillary-cover-spinner", {}, []));
55581         }
55582         return virtualDom.h("div.mapillary-cover-background", properties, children);
55583     }
55584     _getImageSrc$(id) {
55585         return Observable.create((subscriber) => {
55586             this._navigator.api.getImages$([id])
55587                 .subscribe((items) => {
55588                 for (const item of items) {
55589                     if (item.node_id !== id) {
55590                         continue;
55591                     }
55592                     this._navigator.api.data
55593                         .getImageBuffer(item.node.thumb.url)
55594                         .then((buffer) => {
55595                         const image = new Image();
55596                         image.crossOrigin = "Anonymous";
55597                         image.onload = () => {
55598                             subscriber.next(image.src);
55599                             subscriber.complete();
55600                         };
55601                         image.onerror = () => {
55602                             subscriber.error(new Error(`Failed to load cover ` +
55603                                 `image (${id})`));
55604                         };
55605                         const blob = new Blob([buffer]);
55606                         image.src = window.URL
55607                             .createObjectURL(blob);
55608                     }, (error) => {
55609                         subscriber.error(error);
55610                     });
55611                     return;
55612                 }
55613                 subscriber.error(new MapillaryError(`Non existent cover key: ${id}`));
55614             }, (error) => {
55615                 subscriber.error(error);
55616             });
55617         });
55618     }
55619 }
55620 CoverComponent.componentName = "cover";
55621
55622 class AttributionComponent extends Component {
55623     _activate() {
55624         this._subscriptions.push(combineLatest(this._container.configurationService.exploreUrl$, this._navigator.stateService.currentImage$, this._container.renderService.size$).pipe(map(([exploreUrl, image, size]) => {
55625             const attribution = this._makeAttribution(image.creatorUsername, exploreUrl, image.id, image.capturedAt, size.width);
55626             return {
55627                 name: this._name,
55628                 vNode: attribution,
55629             };
55630         }))
55631             .subscribe(this._container.domRenderer.render$));
55632     }
55633     _deactivate() {
55634         this._subscriptions.unsubscribe();
55635     }
55636     _getDefaultConfiguration() {
55637         return {};
55638     }
55639     makeImageUrl(exploreUrl, id) {
55640         return `${exploreUrl}/app/?pKey=${id}&focus=photo`;
55641     }
55642     _makeAttribution(creatorUsername, exploreUrl, imageId, capturedAt, viewportWidth) {
55643         const compact = viewportWidth <= 640;
55644         const date = this._makeDate(capturedAt, compact);
55645         const by = this._makeBy(creatorUsername, exploreUrl, imageId, compact);
55646         const compactClass = compact ?
55647             ".mapillary-attribution-compact" : "";
55648         return virtualDom.h("div.mapillary-attribution-container" + compactClass, {}, [...by, date]);
55649     }
55650     _makeBy(creatorUsername, exploreUrl, imageId, compact) {
55651         const icon = virtualDom.h("div.mapillary-attribution-logo", []);
55652         return creatorUsername ?
55653             this._makeCreatorBy(icon, creatorUsername, exploreUrl, imageId, compact) :
55654             this._makeGeneralBy(icon, exploreUrl, imageId, compact);
55655     }
55656     _makeCreatorBy(icon, creatorUsername, exploreUrl, imageId, compact) {
55657         const mapillary = virtualDom.h("a.mapillary-attribution-icon-container", { href: exploreUrl, rel: "noreferrer", target: "_blank" }, [icon]);
55658         const content = compact ?
55659             `${creatorUsername}` : `image by ${creatorUsername}`;
55660         const imageBy = virtualDom.h("div.mapillary-attribution-username", { textContent: content }, []);
55661         const image = virtualDom.h("a.mapillary-attribution-image-container", {
55662             href: this.makeImageUrl(exploreUrl, imageId),
55663             rel: "noreferrer",
55664             target: "_blank",
55665         }, [imageBy]);
55666         return [mapillary, image];
55667     }
55668     _makeGeneralBy(icon, exploreUrl, imageId, compact) {
55669         const imagesBy = virtualDom.h("div.mapillary-attribution-username", { textContent: 'images by' }, []);
55670         const mapillary = virtualDom.h("div.mapillary-attribution-icon-container", {}, [icon]);
55671         const contributors = virtualDom.h("div.mapillary-attribution-username", { textContent: 'contributors' }, []);
55672         const children = [mapillary, contributors];
55673         if (!compact) {
55674             children.unshift(imagesBy);
55675         }
55676         const image = virtualDom.h("a.mapillary-attribution-image-container", {
55677             href: this.makeImageUrl(exploreUrl, imageId),
55678             rel: "noreferrer",
55679             target: "_blank",
55680         }, children);
55681         return [image];
55682     }
55683     _makeDate(capturedAt, compact) {
55684         const date = new Date(capturedAt)
55685             .toDateString()
55686             .split(" ");
55687         const formatted = (date.length > 3 ?
55688             compact ?
55689                 [date[3]] :
55690                 [date[1], date[2] + ",", date[3]] :
55691             date).join(" ");
55692         return virtualDom.h("div.mapillary-attribution-date", { textContent: formatted }, []);
55693     }
55694 }
55695 AttributionComponent.componentName = "attribution";
55696
55697 /**
55698  * @class ViewportCoords
55699  *
55700  * @classdesc Provides methods for calculating 2D coordinate conversions
55701  * as well as 3D projection and unprojection.
55702  *
55703  * Basic coordinates are 2D coordinates on the [0, 1] interval and
55704  * have the origin point, (0, 0), at the top left corner and the
55705  * maximum value, (1, 1), at the bottom right corner of the original
55706  * image.
55707  *
55708  * Viewport coordinates are 2D coordinates on the [-1, 1] interval and
55709  * have the origin point in the center. The bottom left corner point is
55710  * (-1, -1) and the top right corner point is (1, 1).
55711  *
55712  * Canvas coordiantes are 2D pixel coordinates on the [0, canvasWidth] and
55713  * [0, canvasHeight] intervals. The origin point (0, 0) is in the top left
55714  * corner and the maximum value is (canvasWidth, canvasHeight) is in the
55715  * bottom right corner.
55716  *
55717  * 3D coordinates are in the topocentric world reference frame.
55718  */
55719 class ViewportCoords {
55720     constructor() {
55721         this._unprojectDepth = 200;
55722     }
55723     /**
55724      * Convert basic coordinates to canvas coordinates.
55725      *
55726      * @description Transform origin and camera position needs to be the
55727      * equal for reliable return value.
55728      *
55729      * @param {number} basicX - Basic X coordinate.
55730      * @param {number} basicY - Basic Y coordinate.
55731      * @param {HTMLElement} container - The viewer container.
55732      * @param {Transform} transform - Transform of the image to unproject from.
55733      * @param {THREE.Camera} camera - Camera used in rendering.
55734      * @returns {Array<number>} 2D canvas coordinates.
55735      */
55736     basicToCanvas(basicX, basicY, container, transform, camera) {
55737         const point3d = transform.unprojectBasic([basicX, basicY], this._unprojectDepth);
55738         const canvas = this.projectToCanvas(point3d, container, camera);
55739         return canvas;
55740     }
55741     /**
55742      * Convert basic coordinates to canvas coordinates safely. If 3D point is
55743      * behind camera null will be returned.
55744      *
55745      * @description Transform origin and camera position needs to be the
55746      * equal for reliable return value.
55747      *
55748      * @param {number} basicX - Basic X coordinate.
55749      * @param {number} basicY - Basic Y coordinate.
55750      * @param {HTMLElement} container - The viewer container.
55751      * @param {Transform} transform - Transform of the image to unproject from.
55752      * @param {THREE.Camera} camera - Camera used in rendering.
55753      * @returns {Array<number>} 2D canvas coordinates if the basic point represents a 3D point
55754      * in front of the camera, otherwise null.
55755      */
55756     basicToCanvasSafe(basicX, basicY, container, transform, camera) {
55757         const viewport = this.basicToViewportSafe(basicX, basicY, transform, camera);
55758         if (viewport === null) {
55759             return null;
55760         }
55761         const canvas = this.viewportToCanvas(viewport[0], viewport[1], container);
55762         return canvas;
55763     }
55764     /**
55765      * Convert basic coordinates to viewport coordinates.
55766      *
55767      * @description Transform origin and camera position needs to be the
55768      * equal for reliable return value.
55769      *
55770      * @param {number} basicX - Basic X coordinate.
55771      * @param {number} basicY - Basic Y coordinate.
55772      * @param {Transform} transform - Transform of the image to unproject from.
55773      * @param {THREE.Camera} camera - Camera used in rendering.
55774      * @returns {Array<number>} 2D viewport coordinates.
55775      */
55776     basicToViewport(basicX, basicY, transform, camera) {
55777         const point3d = transform.unprojectBasic([basicX, basicY], this._unprojectDepth);
55778         const viewport = this.projectToViewport(point3d, camera);
55779         return viewport;
55780     }
55781     /**
55782      * Convert basic coordinates to viewport coordinates safely. If 3D point is
55783      * behind camera null will be returned.
55784      *
55785      * @description Transform origin and camera position needs to be the
55786      * equal for reliable return value.
55787      *
55788      * @param {number} basicX - Basic X coordinate.
55789      * @param {number} basicY - Basic Y coordinate.
55790      * @param {Transform} transform - Transform of the image to unproject from.
55791      * @param {THREE.Camera} camera - Camera used in rendering.
55792      * @returns {Array<number>} 2D viewport coordinates.
55793      */
55794     basicToViewportSafe(basicX, basicY, transform, camera) {
55795         const point3d = transform.unprojectBasic([basicX, basicY], this._unprojectDepth);
55796         const pointCamera = this.worldToCamera(point3d, camera);
55797         if (pointCamera[2] > 0) {
55798             return null;
55799         }
55800         const viewport = this.projectToViewport(point3d, camera);
55801         return viewport;
55802     }
55803     /**
55804      * Convert camera 3D coordinates to viewport coordinates.
55805      *
55806      * @param {number} pointCamera - 3D point in camera coordinate system.
55807      * @param {THREE.Camera} camera - Camera used in rendering.
55808      * @returns {Array<number>} 2D viewport coordinates.
55809      */
55810     cameraToViewport(pointCamera, camera) {
55811         const viewport = new Vector3().fromArray(pointCamera)
55812             .applyMatrix4(camera.projectionMatrix);
55813         return [viewport.x, viewport.y];
55814     }
55815     /**
55816      * Get canvas pixel position from event.
55817      *
55818      * @param {Event} event - Event containing clientX and clientY properties.
55819      * @param {HTMLElement} element - HTML element.
55820      * @returns {Array<number>} 2D canvas coordinates.
55821      */
55822     canvasPosition(event, element) {
55823         const clientRect = element.getBoundingClientRect();
55824         const canvasX = event.clientX - clientRect.left - element.clientLeft;
55825         const canvasY = event.clientY - clientRect.top - element.clientTop;
55826         return [canvasX, canvasY];
55827     }
55828     /**
55829      * Convert canvas coordinates to basic coordinates.
55830      *
55831      * @description Transform origin and camera position needs to be the
55832      * equal for reliable return value.
55833      *
55834      * @param {number} canvasX - Canvas X coordinate.
55835      * @param {number} canvasY - Canvas Y coordinate.
55836      * @param {HTMLElement} container - The viewer container.
55837      * @param {Transform} transform - Transform of the image to unproject from.
55838      * @param {THREE.Camera} camera - Camera used in rendering.
55839      * @returns {Array<number>} 2D basic coordinates.
55840      */
55841     canvasToBasic(canvasX, canvasY, container, transform, camera) {
55842         const point3d = this.unprojectFromCanvas(canvasX, canvasY, container, camera)
55843             .toArray();
55844         const basic = transform.projectBasic(point3d);
55845         return basic;
55846     }
55847     /**
55848      * Convert canvas coordinates to viewport coordinates.
55849      *
55850      * @param {number} canvasX - Canvas X coordinate.
55851      * @param {number} canvasY - Canvas Y coordinate.
55852      * @param {HTMLElement} container - The viewer container.
55853      * @returns {Array<number>} 2D viewport coordinates.
55854      */
55855     canvasToViewport(canvasX, canvasY, container) {
55856         const [canvasWidth, canvasHeight] = this.containerToCanvas(container);
55857         const viewportX = 2 * canvasX / canvasWidth - 1;
55858         const viewportY = 1 - 2 * canvasY / canvasHeight;
55859         return [viewportX, viewportY];
55860     }
55861     /**
55862      * Determines the width and height of the container in canvas coordinates.
55863      *
55864      * @param {HTMLElement} container - The viewer container.
55865      * @returns {Array<number>} 2D canvas coordinates.
55866      */
55867     containerToCanvas(container) {
55868         return [container.offsetWidth, container.offsetHeight];
55869     }
55870     /**
55871      * Determine basic distances from image to canvas corners.
55872      *
55873      * @description Transform origin and camera position needs to be the
55874      * equal for reliable return value.
55875      *
55876      * Determines the smallest basic distance for every side of the canvas.
55877      *
55878      * @param {Transform} transform - Transform of the image to unproject from.
55879      * @param {THREE.Camera} camera - Camera used in rendering.
55880      * @returns {Array<number>} Array of basic distances as [top, right, bottom, left].
55881      */
55882     getBasicDistances(transform, camera) {
55883         const topLeftBasic = this.viewportToBasic(-1, 1, transform, camera);
55884         const topRightBasic = this.viewportToBasic(1, 1, transform, camera);
55885         const bottomRightBasic = this.viewportToBasic(1, -1, transform, camera);
55886         const bottomLeftBasic = this.viewportToBasic(-1, -1, transform, camera);
55887         let topBasicDistance = 0;
55888         let rightBasicDistance = 0;
55889         let bottomBasicDistance = 0;
55890         let leftBasicDistance = 0;
55891         if (topLeftBasic[1] < 0 && topRightBasic[1] < 0) {
55892             topBasicDistance = topLeftBasic[1] > topRightBasic[1] ?
55893                 -topLeftBasic[1] :
55894                 -topRightBasic[1];
55895         }
55896         if (topRightBasic[0] > 1 && bottomRightBasic[0] > 1) {
55897             rightBasicDistance = topRightBasic[0] < bottomRightBasic[0] ?
55898                 topRightBasic[0] - 1 :
55899                 bottomRightBasic[0] - 1;
55900         }
55901         if (bottomRightBasic[1] > 1 && bottomLeftBasic[1] > 1) {
55902             bottomBasicDistance = bottomRightBasic[1] < bottomLeftBasic[1] ?
55903                 bottomRightBasic[1] - 1 :
55904                 bottomLeftBasic[1] - 1;
55905         }
55906         if (bottomLeftBasic[0] < 0 && topLeftBasic[0] < 0) {
55907             leftBasicDistance = bottomLeftBasic[0] > topLeftBasic[0] ?
55908                 -bottomLeftBasic[0] :
55909                 -topLeftBasic[0];
55910         }
55911         return [topBasicDistance, rightBasicDistance, bottomBasicDistance, leftBasicDistance];
55912     }
55913     /**
55914      * Determine pixel distances from image to canvas corners.
55915      *
55916      * @description Transform origin and camera position needs to be the
55917      * equal for reliable return value.
55918      *
55919      * Determines the smallest pixel distance for every side of the canvas.
55920      *
55921      * @param {HTMLElement} container - The viewer container.
55922      * @param {Transform} transform - Transform of the image to unproject from.
55923      * @param {THREE.Camera} camera - Camera used in rendering.
55924      * @returns {Array<number>} Array of pixel distances as [top, right, bottom, left].
55925      */
55926     getPixelDistances(container, transform, camera) {
55927         const topLeftBasic = this.viewportToBasic(-1, 1, transform, camera);
55928         const topRightBasic = this.viewportToBasic(1, 1, transform, camera);
55929         const bottomRightBasic = this.viewportToBasic(1, -1, transform, camera);
55930         const bottomLeftBasic = this.viewportToBasic(-1, -1, transform, camera);
55931         let topPixelDistance = 0;
55932         let rightPixelDistance = 0;
55933         let bottomPixelDistance = 0;
55934         let leftPixelDistance = 0;
55935         const [canvasWidth, canvasHeight] = this.containerToCanvas(container);
55936         if (topLeftBasic[1] < 0 && topRightBasic[1] < 0) {
55937             const basicX = topLeftBasic[1] > topRightBasic[1] ?
55938                 topLeftBasic[0] :
55939                 topRightBasic[0];
55940             const canvas = this.basicToCanvas(basicX, 0, container, transform, camera);
55941             topPixelDistance = canvas[1] > 0 ? canvas[1] : 0;
55942         }
55943         if (topRightBasic[0] > 1 && bottomRightBasic[0] > 1) {
55944             const basicY = topRightBasic[0] < bottomRightBasic[0] ?
55945                 topRightBasic[1] :
55946                 bottomRightBasic[1];
55947             const canvas = this.basicToCanvas(1, basicY, container, transform, camera);
55948             rightPixelDistance = canvas[0] < canvasWidth ? canvasWidth - canvas[0] : 0;
55949         }
55950         if (bottomRightBasic[1] > 1 && bottomLeftBasic[1] > 1) {
55951             const basicX = bottomRightBasic[1] < bottomLeftBasic[1] ?
55952                 bottomRightBasic[0] :
55953                 bottomLeftBasic[0];
55954             const canvas = this.basicToCanvas(basicX, 1, container, transform, camera);
55955             bottomPixelDistance = canvas[1] < canvasHeight ? canvasHeight - canvas[1] : 0;
55956         }
55957         if (bottomLeftBasic[0] < 0 && topLeftBasic[0] < 0) {
55958             const basicY = bottomLeftBasic[0] > topLeftBasic[0] ?
55959                 bottomLeftBasic[1] :
55960                 topLeftBasic[1];
55961             const canvas = this.basicToCanvas(0, basicY, container, transform, camera);
55962             leftPixelDistance = canvas[0] > 0 ? canvas[0] : 0;
55963         }
55964         return [topPixelDistance, rightPixelDistance, bottomPixelDistance, leftPixelDistance];
55965     }
55966     /**
55967      * Determine if an event occured inside an element.
55968      *
55969      * @param {Event} event - Event containing clientX and clientY properties.
55970      * @param {HTMLElement} element - HTML element.
55971      * @returns {boolean} Value indicating if the event occured inside the element or not.
55972      */
55973     insideElement(event, element) {
55974         const clientRect = element.getBoundingClientRect();
55975         const minX = clientRect.left + element.clientLeft;
55976         const maxX = minX + element.clientWidth;
55977         const minY = clientRect.top + element.clientTop;
55978         const maxY = minY + element.clientHeight;
55979         return event.clientX > minX &&
55980             event.clientX < maxX &&
55981             event.clientY > minY &&
55982             event.clientY < maxY;
55983     }
55984     /**
55985      * Project 3D world coordinates to canvas coordinates.
55986      *
55987      * @param {Array<number>} point3D - 3D world coordinates.
55988      * @param {HTMLElement} container - The viewer container.
55989      * @param {THREE.Camera} camera - Camera used in rendering.
55990      * @returns {Array<number>} 2D canvas coordinates.
55991      */
55992     projectToCanvas(point3d, container, camera) {
55993         const viewport = this.projectToViewport(point3d, camera);
55994         const canvas = this.viewportToCanvas(viewport[0], viewport[1], container);
55995         return canvas;
55996     }
55997     /**
55998      * Project 3D world coordinates to canvas coordinates safely. If 3D
55999      * point is behind camera null will be returned.
56000      *
56001      * @param {Array<number>} point3D - 3D world coordinates.
56002      * @param {HTMLElement} container - The viewer container.
56003      * @param {THREE.Camera} camera - Camera used in rendering.
56004      * @returns {Array<number>} 2D canvas coordinates.
56005      */
56006     projectToCanvasSafe(point3d, container, camera) {
56007         const pointCamera = this.worldToCamera(point3d, camera);
56008         if (pointCamera[2] > 0) {
56009             return null;
56010         }
56011         const viewport = this.projectToViewport(point3d, camera);
56012         const canvas = this.viewportToCanvas(viewport[0], viewport[1], container);
56013         return canvas;
56014     }
56015     /**
56016      * Project 3D world coordinates to viewport coordinates.
56017      *
56018      * @param {Array<number>} point3D - 3D world coordinates.
56019      * @param {THREE.Camera} camera - Camera used in rendering.
56020      * @returns {Array<number>} 2D viewport coordinates.
56021      */
56022     projectToViewport(point3d, camera) {
56023         const viewport = new Vector3(point3d[0], point3d[1], point3d[2])
56024             .project(camera);
56025         return [viewport.x, viewport.y];
56026     }
56027     /**
56028      * Uproject canvas coordinates to 3D world coordinates.
56029      *
56030      * @param {number} canvasX - Canvas X coordinate.
56031      * @param {number} canvasY - Canvas Y coordinate.
56032      * @param {HTMLElement} container - The viewer container.
56033      * @param {THREE.Camera} camera - Camera used in rendering.
56034      * @returns {Array<number>} 3D world coordinates.
56035      */
56036     unprojectFromCanvas(canvasX, canvasY, container, camera) {
56037         const viewport = this.canvasToViewport(canvasX, canvasY, container);
56038         const point3d = this.unprojectFromViewport(viewport[0], viewport[1], camera);
56039         return point3d;
56040     }
56041     /**
56042      * Unproject viewport coordinates to 3D world coordinates.
56043      *
56044      * @param {number} viewportX - Viewport X coordinate.
56045      * @param {number} viewportY - Viewport Y coordinate.
56046      * @param {THREE.Camera} camera - Camera used in rendering.
56047      * @returns {Array<number>} 3D world coordinates.
56048      */
56049     unprojectFromViewport(viewportX, viewportY, camera) {
56050         const point3d = new Vector3(viewportX, viewportY, 1)
56051             .unproject(camera);
56052         return point3d;
56053     }
56054     /**
56055      * Convert viewport coordinates to basic coordinates.
56056      *
56057      * @description Transform origin and camera position needs to be the
56058      * equal for reliable return value.
56059      *
56060      * @param {number} viewportX - Viewport X coordinate.
56061      * @param {number} viewportY - Viewport Y coordinate.
56062      * @param {Transform} transform - Transform of the image to unproject from.
56063      * @param {THREE.Camera} camera - Camera used in rendering.
56064      * @returns {Array<number>} 2D basic coordinates.
56065      */
56066     viewportToBasic(viewportX, viewportY, transform, camera) {
56067         const point3d = new Vector3(viewportX, viewportY, 1)
56068             .unproject(camera)
56069             .toArray();
56070         const basic = transform.projectBasic(point3d);
56071         return basic;
56072     }
56073     /**
56074      * Convert viewport coordinates to canvas coordinates.
56075      *
56076      * @param {number} viewportX - Viewport X coordinate.
56077      * @param {number} viewportY - Viewport Y coordinate.
56078      * @param {HTMLElement} container - The viewer container.
56079      * @returns {Array<number>} 2D canvas coordinates.
56080      */
56081     viewportToCanvas(viewportX, viewportY, container) {
56082         const [canvasWidth, canvasHeight] = this.containerToCanvas(container);
56083         const canvasX = canvasWidth * (viewportX + 1) / 2;
56084         const canvasY = -canvasHeight * (viewportY - 1) / 2;
56085         return [canvasX, canvasY];
56086     }
56087     /**
56088      * Convert 3D world coordinates to 3D camera coordinates.
56089      *
56090      * @param {number} point3D - 3D point in world coordinate system.
56091      * @param {THREE.Camera} camera - Camera used in rendering.
56092      * @returns {Array<number>} 3D camera coordinates.
56093      */
56094     worldToCamera(point3d, camera) {
56095         const pointCamera = new Vector3(point3d[0], point3d[1], point3d[2])
56096             .applyMatrix4(camera.matrixWorldInverse);
56097         return pointCamera.toArray();
56098     }
56099 }
56100
56101 /**
56102  * Enumeration for component size.
56103  * @enum {number}
56104  * @readonly
56105  * @description May be used by a component to allow for resizing
56106  * of the UI elements rendered by the component.
56107  */
56108 var ComponentSize;
56109 (function (ComponentSize) {
56110     /**
56111      * Automatic size. The size of the elements will automatically
56112      * change at a predefined threshold.
56113      */
56114     ComponentSize[ComponentSize["Automatic"] = 0] = "Automatic";
56115     /**
56116      * Large size. The size of the elements will be fixed until another
56117      * component size is configured.
56118      */
56119     ComponentSize[ComponentSize["Large"] = 1] = "Large";
56120     /**
56121      * Small size. The size of the elements will be fixed until another
56122      * component size is configured.
56123      */
56124     ComponentSize[ComponentSize["Small"] = 2] = "Small";
56125 })(ComponentSize || (ComponentSize = {}));
56126
56127 /**
56128  * @class BearingComponent
56129  *
56130  * @classdesc Component for indicating bearing and field of view.
56131  *
56132  * @example
56133  * ```js
56134  * var viewer = new Viewer({ ... });
56135  * var bearingComponent = viewer.getComponent("bearing");
56136  * bearingComponent.configure({ size: ComponentSize.Small });
56137  * ```
56138  */
56139 class BearingComponent extends Component {
56140     /** @ignore */
56141     constructor(name, container, navigator) {
56142         super(name, container, navigator);
56143         this._spatial = new Spatial();
56144         this._viewportCoords = new ViewportCoords();
56145         this._svgNamespace = "http://www.w3.org/2000/svg";
56146         this._distinctThreshold = Math.PI / 360;
56147         this._animationSpeed = 0.075;
56148         this._unitBezier = new unitbezier(0.74, 0.67, 0.38, 0.96);
56149     }
56150     _activate() {
56151         const subs = this._subscriptions;
56152         const cameraBearingFov$ = this._container.renderService.renderCamera$.pipe(map((rc) => {
56153             let vFov = this._spatial.degToRad(rc.perspective.fov);
56154             let hFov = rc.perspective.aspect === Number.POSITIVE_INFINITY ?
56155                 Math.PI :
56156                 Math.atan(rc.perspective.aspect * Math.tan(0.5 * vFov)) * 2;
56157             return [this._spatial.azimuthalToBearing(rc.rotation.phi), hFov];
56158         }), distinctUntilChanged((a1, a2) => {
56159             return Math.abs(a2[0] - a1[0]) < this._distinctThreshold &&
56160                 Math.abs(a2[1] - a1[1]) < this._distinctThreshold;
56161         }));
56162         const imageFov$ = combineLatest(this._navigator.stateService.currentState$.pipe(distinctUntilChanged(undefined, (frame) => {
56163             return frame.state.currentImage.id;
56164         })), this._navigator.panService.panImages$).pipe(map(([frame, panImages]) => {
56165             const image = frame.state.currentImage;
56166             const transform = frame.state.currentTransform;
56167             if (isSpherical(image.cameraType)) {
56168                 return [Math.PI, Math.PI];
56169             }
56170             const currentProjectedPoints = this._computeProjectedPoints(transform);
56171             const hFov = this._spatial
56172                 .degToRad(this._computeHorizontalFov(currentProjectedPoints));
56173             let hFovLeft = hFov / 2;
56174             let hFovRight = hFov / 2;
56175             for (const [n, , f] of panImages) {
56176                 const diff = this._spatial.wrap(n.compassAngle - image.compassAngle, -180, 180);
56177                 if (diff < 0) {
56178                     hFovLeft = this._spatial.degToRad(Math.abs(diff)) + f / 2;
56179                 }
56180                 else {
56181                     hFovRight = this._spatial.degToRad(Math.abs(diff)) + f / 2;
56182                 }
56183             }
56184             return [hFovLeft, hFovRight];
56185         }), distinctUntilChanged(([hFovLeft1, hFovRight1], [hFovLeft2, hFovRight2]) => {
56186             return Math.abs(hFovLeft2 - hFovLeft1) < this._distinctThreshold &&
56187                 Math.abs(hFovRight2 - hFovRight1) < this._distinctThreshold;
56188         }));
56189         const offset$ = combineLatest(this._navigator.stateService.currentState$.pipe(distinctUntilChanged(undefined, (frame) => {
56190             return frame.state.currentImage.id;
56191         })), this._container.renderService.bearing$).pipe(map(([frame, bearing]) => {
56192             const offset = this._spatial.degToRad(frame.state.currentImage.compassAngle - bearing);
56193             return offset;
56194         }));
56195         const imageFovOperation$ = new Subject();
56196         const smoothImageFov$ = imageFovOperation$.pipe(scan((state, operation) => {
56197             return operation(state);
56198         }, { alpha: 0, curr: [0, 0, 0], prev: [0, 0, 0] }), map((state) => {
56199             const alpha = this._unitBezier.solve(state.alpha);
56200             const curr = state.curr;
56201             const prev = state.prev;
56202             return [
56203                 this._interpolate(prev[0], curr[0], alpha),
56204                 this._interpolate(prev[1], curr[1], alpha),
56205             ];
56206         }));
56207         subs.push(imageFov$.pipe(map((nbf) => {
56208             return (state) => {
56209                 const a = this._unitBezier.solve(state.alpha);
56210                 const c = state.curr;
56211                 const p = state.prev;
56212                 const prev = [
56213                     this._interpolate(p[0], c[0], a),
56214                     this._interpolate(p[1], c[1], a),
56215                 ];
56216                 const curr = nbf.slice();
56217                 return {
56218                     alpha: 0,
56219                     curr: curr,
56220                     prev: prev,
56221                 };
56222             };
56223         }))
56224             .subscribe(imageFovOperation$));
56225         subs.push(imageFov$.pipe(switchMap(() => {
56226             return this._container.renderService.renderCameraFrame$.pipe(skip(1), scan((alpha) => {
56227                 return alpha + this._animationSpeed;
56228             }, 0), takeWhile((alpha) => {
56229                 return alpha <= 1 + this._animationSpeed;
56230             }), map((alpha) => {
56231                 return Math.min(alpha, 1);
56232             }));
56233         }), map((alpha) => {
56234             return (nbfState) => {
56235                 return {
56236                     alpha: alpha,
56237                     curr: nbfState.curr.slice(),
56238                     prev: nbfState.prev.slice(),
56239                 };
56240             };
56241         }))
56242             .subscribe(imageFovOperation$));
56243         const imageBearingFov$ = combineLatest(offset$, smoothImageFov$).pipe(map(([offset, fov]) => {
56244             return [offset, fov[0], fov[1]];
56245         }));
56246         subs.push(combineLatest(cameraBearingFov$, imageBearingFov$, this._configuration$, this._container.renderService.size$).pipe(map(([[cb, cf], [no, nfl, nfr], configuration, size]) => {
56247             const background = this._createBackground(cb);
56248             const fovIndicator = this._createFovIndicator(nfl, nfr, no);
56249             const north = this._createNorth(cb);
56250             const cameraSector = this._createCircleSectorCompass(this._createCircleSector(Math.max(Math.PI / 20, cf), "#FFF"));
56251             const compact = configuration.size === ComponentSize.Small ||
56252                 configuration.size === ComponentSize.Automatic && size.width < 640 ?
56253                 ".mapillary-bearing-compact" : "";
56254             return {
56255                 name: this._name,
56256                 vNode: virtualDom.h("div.mapillary-bearing-indicator-container" + compact, { oncontextmenu: (event) => { event.preventDefault(); } }, [
56257                     background,
56258                     fovIndicator,
56259                     north,
56260                     cameraSector,
56261                 ]),
56262             };
56263         }))
56264             .subscribe(this._container.domRenderer.render$));
56265     }
56266     _deactivate() {
56267         this._subscriptions.unsubscribe();
56268     }
56269     _getDefaultConfiguration() {
56270         return { size: ComponentSize.Automatic };
56271     }
56272     _createFovIndicator(fovLeft, fovRigth, offset) {
56273         const arc = this._createFovArc(fovLeft, fovRigth);
56274         const group = virtualDom.h("g", {
56275             attributes: { transform: "translate(18,18)" },
56276             namespace: this._svgNamespace,
56277         }, [arc]);
56278         const svg = virtualDom.h("svg", {
56279             attributes: { viewBox: "0 0 36 36" },
56280             namespace: this._svgNamespace,
56281             style: {
56282                 height: "36px",
56283                 left: "2px",
56284                 position: "absolute",
56285                 top: "2px",
56286                 transform: `rotateZ(${this._spatial.radToDeg(offset)}deg)`,
56287                 width: "36px",
56288             },
56289         }, [group]);
56290         return svg;
56291     }
56292     _createFovArc(fovLeft, fovRigth) {
56293         const radius = 16.75;
56294         const strokeWidth = 2.5;
56295         const fov = fovLeft + fovRigth;
56296         if (fov > 2 * Math.PI - Math.PI / 90) {
56297             return virtualDom.h("circle", {
56298                 attributes: {
56299                     cx: "0",
56300                     cy: "0",
56301                     "fill-opacity": "0",
56302                     r: `${radius}`,
56303                     stroke: "#FFF",
56304                     "stroke-width": `${strokeWidth}`,
56305                 },
56306                 namespace: this._svgNamespace,
56307             }, []);
56308         }
56309         let arcStart = -Math.PI / 2 - fovLeft;
56310         let arcEnd = arcStart + fov;
56311         let startX = radius * Math.cos(arcStart);
56312         let startY = radius * Math.sin(arcStart);
56313         let endX = radius * Math.cos(arcEnd);
56314         let endY = radius * Math.sin(arcEnd);
56315         let largeArc = fov >= Math.PI ? 1 : 0;
56316         let description = `M ${startX} ${startY} A ${radius} ${radius} 0 ${largeArc} 1 ${endX} ${endY}`;
56317         return virtualDom.h("path", {
56318             attributes: {
56319                 d: description,
56320                 "fill-opacity": "0",
56321                 stroke: "#FFF",
56322                 "stroke-width": `${strokeWidth}`,
56323             },
56324             namespace: this._svgNamespace,
56325         }, []);
56326     }
56327     _createCircleSectorCompass(cameraSector) {
56328         let group = virtualDom.h("g", {
56329             attributes: { transform: "translate(1,1)" },
56330             namespace: this._svgNamespace,
56331         }, [cameraSector]);
56332         let svg = virtualDom.h("svg", {
56333             attributes: { viewBox: "0 0 2 2" },
56334             namespace: this._svgNamespace,
56335             style: {
56336                 height: "26px",
56337                 left: "7px",
56338                 position: "absolute",
56339                 top: "7px",
56340                 width: "26px",
56341             },
56342         }, [group]);
56343         return svg;
56344     }
56345     _createCircleSector(fov, fill) {
56346         if (fov > 2 * Math.PI - Math.PI / 90) {
56347             return virtualDom.h("circle", {
56348                 attributes: { cx: "0", cy: "0", fill: fill, r: "1" },
56349                 namespace: this._svgNamespace,
56350             }, []);
56351         }
56352         let arcStart = -Math.PI / 2 - fov / 2;
56353         let arcEnd = arcStart + fov;
56354         let startX = Math.cos(arcStart);
56355         let startY = Math.sin(arcStart);
56356         let endX = Math.cos(arcEnd);
56357         let endY = Math.sin(arcEnd);
56358         let largeArc = fov >= Math.PI ? 1 : 0;
56359         let description = `M 0 0 ${startX} ${startY} A 1 1 0 ${largeArc} 1 ${endX} ${endY}`;
56360         return virtualDom.h("path", {
56361             attributes: { d: description, fill: fill },
56362             namespace: this._svgNamespace,
56363         }, []);
56364     }
56365     _createNorth(bearing) {
56366         const north = virtualDom.h("div.mapillary-bearing-north", []);
56367         const container = virtualDom.h("div.mapillary-bearing-north-container", { style: { transform: `rotateZ(${this._spatial.radToDeg(-bearing)}deg)` } }, [north]);
56368         return container;
56369     }
56370     _createBackground(bearing) {
56371         return virtualDom.h("div.mapillary-bearing-indicator-background", { style: { transform: `rotateZ(${this._spatial.radToDeg(-bearing)}deg)` } }, [
56372             virtualDom.h("div.mapillary-bearing-indicator-background-circle", []),
56373             virtualDom.h("div.mapillary-bearing-indicator-background-arrow-container", [
56374                 virtualDom.h("div.mapillary-bearing-indicator-background-arrow", []),
56375             ]),
56376         ]);
56377     }
56378     _computeProjectedPoints(transform) {
56379         const vertices = [[1, 0]];
56380         const directions = [[0, 0.5]];
56381         const pointsPerLine = 12;
56382         return computeProjectedPoints(transform, vertices, directions, pointsPerLine, this._viewportCoords);
56383     }
56384     _computeHorizontalFov(projectedPoints) {
56385         const fovs = projectedPoints
56386             .map((projectedPoint) => {
56387             return this._coordToFov(projectedPoint[0]);
56388         });
56389         const fov = Math.min(...fovs);
56390         return fov;
56391     }
56392     _coordToFov(x) {
56393         return this._spatial.radToDeg(2 * Math.atan(x));
56394     }
56395     _interpolate(x1, x2, alpha) {
56396         return (1 - alpha) * x1 + alpha * x2;
56397     }
56398 }
56399 BearingComponent.componentName = "bearing";
56400
56401 class CacheComponent extends Component {
56402     /** @ignore */
56403     constructor(name, container, navigator) {
56404         super(name, container, navigator);
56405     }
56406     _activate() {
56407         const subs = this._subscriptions;
56408         subs.push(combineLatest(this._navigator.stateService.currentImage$.pipe(switchMap((image) => {
56409             return image.sequenceEdges$;
56410         }), filter((status) => {
56411             return status.cached;
56412         })), this._configuration$).pipe(switchMap((nc) => {
56413             let status = nc[0];
56414             let configuration = nc[1];
56415             let sequenceDepth = Math.max(0, Math.min(4, configuration.depth.sequence));
56416             let next$ = this._cache$(status.edges, NavigationDirection.Next, sequenceDepth);
56417             let prev$ = this._cache$(status.edges, NavigationDirection.Prev, sequenceDepth);
56418             return merge(next$, prev$).pipe(catchError((error) => {
56419                 console.error("Failed to cache sequence edges.", error);
56420                 return empty();
56421             }));
56422         }))
56423             .subscribe(() => { }));
56424         subs.push(combineLatest(this._navigator.stateService.currentImage$.pipe(switchMap((image) => {
56425             return combineLatest(of(image), image.spatialEdges$.pipe(filter((status) => {
56426                 return status.cached;
56427             })));
56428         })), this._configuration$).pipe(switchMap(([[image, edgeStatus], configuration]) => {
56429             let edges = edgeStatus.edges;
56430             let depth = configuration.depth;
56431             let sphericalDepth = Math.max(0, Math.min(2, depth.spherical));
56432             let stepDepth = isSpherical(image.cameraType) ?
56433                 0 : Math.max(0, Math.min(3, depth.step));
56434             let turnDepth = isSpherical(image.cameraType) ?
56435                 0 : Math.max(0, Math.min(1, depth.turn));
56436             let spherical$ = this._cache$(edges, NavigationDirection.Spherical, sphericalDepth);
56437             let forward$ = this._cache$(edges, NavigationDirection.StepForward, stepDepth);
56438             let backward$ = this._cache$(edges, NavigationDirection.StepBackward, stepDepth);
56439             let left$ = this._cache$(edges, NavigationDirection.StepLeft, stepDepth);
56440             let right$ = this._cache$(edges, NavigationDirection.StepRight, stepDepth);
56441             let turnLeft$ = this._cache$(edges, NavigationDirection.TurnLeft, turnDepth);
56442             let turnRight$ = this._cache$(edges, NavigationDirection.TurnRight, turnDepth);
56443             let turnU$ = this._cache$(edges, NavigationDirection.TurnU, turnDepth);
56444             return merge(forward$, backward$, left$, right$, spherical$, turnLeft$, turnRight$, turnU$).pipe(catchError((error) => {
56445                 console.error("Failed to cache spatial edges.", error);
56446                 return empty();
56447             }));
56448         }))
56449             .subscribe(() => { }));
56450     }
56451     _deactivate() {
56452         this._subscriptions.unsubscribe();
56453     }
56454     _getDefaultConfiguration() {
56455         return { depth: { spherical: 1, sequence: 2, step: 1, turn: 0 } };
56456     }
56457     _cache$(edges, direction, depth) {
56458         return zip(of(edges), of(depth)).pipe(expand((ed) => {
56459             let es = ed[0];
56460             let d = ed[1];
56461             let edgesDepths$ = [];
56462             if (d > 0) {
56463                 for (let edge of es) {
56464                     if (edge.data.direction === direction) {
56465                         edgesDepths$.push(zip(this._navigator.graphService.cacheImage$(edge.target).pipe(mergeMap((n) => {
56466                             return this._imageToEdges$(n, direction);
56467                         })), of(d - 1)));
56468                     }
56469                 }
56470             }
56471             return from(edgesDepths$).pipe(mergeAll());
56472         }), skip(1));
56473     }
56474     _imageToEdges$(image, direction) {
56475         return ([NavigationDirection.Next, NavigationDirection.Prev].indexOf(direction) > -1 ?
56476             image.sequenceEdges$ :
56477             image.spatialEdges$).pipe(first((status) => {
56478             return status.cached;
56479         }), map((status) => {
56480             return status.edges;
56481         }));
56482     }
56483 }
56484 CacheComponent.componentName = "cache";
56485
56486 /**
56487  * @class CancelMapillaryError
56488  *
56489  * @classdesc Error thrown when a move to request has been
56490  * cancelled before completing because of a subsequent request.
56491  */
56492 class CancelMapillaryError extends MapillaryError {
56493     constructor(message) {
56494         super(message != null ? message : "The request was cancelled.");
56495         Object.setPrototypeOf(this, CancelMapillaryError.prototype);
56496         this.name = "CancelMapillaryError";
56497     }
56498 }
56499
56500 /**
56501  * @class DirectionDOMCalculator
56502  * @classdesc Helper class for calculating DOM CSS properties.
56503  */
56504 class DirectionDOMCalculator {
56505     constructor(configuration, size) {
56506         this._spatial = new Spatial();
56507         this._minThresholdWidth = 320;
56508         this._maxThresholdWidth = 1480;
56509         this._minThresholdHeight = 240;
56510         this._maxThresholdHeight = 820;
56511         this._configure(configuration);
56512         this._resize(size);
56513         this._reset();
56514     }
56515     get minWidth() {
56516         return this._minWidth;
56517     }
56518     get maxWidth() {
56519         return this._maxWidth;
56520     }
56521     get containerWidth() {
56522         return this._containerWidth;
56523     }
56524     get containerWidthCss() {
56525         return this._containerWidthCss;
56526     }
56527     get containerMarginCss() {
56528         return this._containerMarginCss;
56529     }
56530     get containerLeftCss() {
56531         return this._containerLeftCss;
56532     }
56533     get containerHeight() {
56534         return this._containerHeight;
56535     }
56536     get containerHeightCss() {
56537         return this._containerHeightCss;
56538     }
56539     get containerBottomCss() {
56540         return this._containerBottomCss;
56541     }
56542     get stepCircleSize() {
56543         return this._stepCircleSize;
56544     }
56545     get stepCircleSizeCss() {
56546         return this._stepCircleSizeCss;
56547     }
56548     get stepCircleMarginCss() {
56549         return this._stepCircleMarginCss;
56550     }
56551     get turnCircleSize() {
56552         return this._turnCircleSize;
56553     }
56554     get turnCircleSizeCss() {
56555         return this._turnCircleSizeCss;
56556     }
56557     get outerRadius() {
56558         return this._outerRadius;
56559     }
56560     get innerRadius() {
56561         return this._innerRadius;
56562     }
56563     get shadowOffset() {
56564         return this._shadowOffset;
56565     }
56566     /**
56567      * Configures the min and max width values.
56568      *
56569      * @param {DirectionConfiguration} configuration Configuration
56570      * with min and max width values.
56571      */
56572     configure(configuration) {
56573         this._configure(configuration);
56574         this._reset();
56575     }
56576     /**
56577      * Resizes all properties according to the width and height
56578      * of the size object.
56579      *
56580      * @param {ViewportSize} size The size of the container element.
56581      */
56582     resize(size) {
56583         this._resize(size);
56584         this._reset();
56585     }
56586     /**
56587      * Calculates the coordinates on the unit circle for an angle.
56588      *
56589      * @param {number} angle Angle in radians.
56590      * @returns {Array<number>} The x and y coordinates on the unit circle.
56591      */
56592     angleToCoordinates(angle) {
56593         return [Math.cos(angle), Math.sin(angle)];
56594     }
56595     /**
56596      * Calculates the coordinates on the unit circle for the
56597      * relative angle between the first and second angle.
56598      *
56599      * @param {number} first Angle in radians.
56600      * @param {number} second Angle in radians.
56601      * @returns {Array<number>} The x and y coordinates on the unit circle
56602      * for the relative angle between the first and second angle.
56603      */
56604     relativeAngleToCoordiantes(first, second) {
56605         let relativeAngle = this._spatial.wrapAngle(first - second);
56606         return this.angleToCoordinates(relativeAngle);
56607     }
56608     _configure(configuration) {
56609         this._minWidth = configuration.minWidth;
56610         this._maxWidth = this._getMaxWidth(configuration.minWidth, configuration.maxWidth);
56611     }
56612     _resize(size) {
56613         this._elementWidth = size.width;
56614         this._elementHeight = size.height;
56615     }
56616     _reset() {
56617         this._containerWidth = this._getContainerWidth(this._elementWidth, this._elementHeight);
56618         this._containerHeight = this._getContainerHeight(this.containerWidth);
56619         this._stepCircleSize = this._getStepCircleDiameter(this._containerHeight);
56620         this._turnCircleSize = this._getTurnCircleDiameter(this.containerHeight);
56621         this._outerRadius = this._getOuterRadius(this._containerHeight);
56622         this._innerRadius = this._getInnerRadius(this._containerHeight);
56623         this._shadowOffset = 3;
56624         this._containerWidthCss = this._numberToCssPixels(this._containerWidth);
56625         this._containerMarginCss = this._numberToCssPixels(-0.5 * this._containerWidth);
56626         this._containerLeftCss = this._numberToCssPixels(Math.floor(0.5 * this._elementWidth));
56627         this._containerHeightCss = this._numberToCssPixels(this._containerHeight);
56628         this._containerBottomCss = this._numberToCssPixels(Math.floor(-0.08 * this._containerHeight));
56629         this._stepCircleSizeCss = this._numberToCssPixels(this._stepCircleSize);
56630         this._stepCircleMarginCss = this._numberToCssPixels(-0.5 * this._stepCircleSize);
56631         this._turnCircleSizeCss = this._numberToCssPixels(this._turnCircleSize);
56632     }
56633     _getContainerWidth(elementWidth, elementHeight) {
56634         let relativeWidth = (elementWidth - this._minThresholdWidth) / (this._maxThresholdWidth - this._minThresholdWidth);
56635         let relativeHeight = (elementHeight - this._minThresholdHeight) / (this._maxThresholdHeight - this._minThresholdHeight);
56636         let coeff = Math.max(0, Math.min(1, Math.min(relativeWidth, relativeHeight)));
56637         coeff = 0.04 * Math.round(25 * coeff);
56638         return this._minWidth + coeff * (this._maxWidth - this._minWidth);
56639     }
56640     _getContainerHeight(containerWidth) {
56641         return 0.77 * containerWidth;
56642     }
56643     _getStepCircleDiameter(containerHeight) {
56644         return 0.34 * containerHeight;
56645     }
56646     _getTurnCircleDiameter(containerHeight) {
56647         return 0.3 * containerHeight;
56648     }
56649     _getOuterRadius(containerHeight) {
56650         return 0.31 * containerHeight;
56651     }
56652     _getInnerRadius(containerHeight) {
56653         return 0.125 * containerHeight;
56654     }
56655     _numberToCssPixels(value) {
56656         return value + "px";
56657     }
56658     _getMaxWidth(value, minWidth) {
56659         return value > minWidth ? value : minWidth;
56660     }
56661 }
56662
56663 /**
56664  * @class DirectionDOMRenderer
56665  * @classdesc DOM renderer for direction arrows.
56666  */
56667 class DirectionDOMRenderer {
56668     constructor(configuration, size) {
56669         this._isEdge = false;
56670         this._spatial = new Spatial();
56671         this._calculator = new DirectionDOMCalculator(configuration, size);
56672         this._image = null;
56673         this._rotation = { phi: 0, theta: 0 };
56674         this._epsilon = 0.5 * Math.PI / 180;
56675         this._highlightKey = null;
56676         this._distinguishSequence = false;
56677         this._needsRender = false;
56678         this._stepEdges = [];
56679         this._turnEdges = [];
56680         this._sphericalEdges = [];
56681         this._sequenceEdgeKeys = [];
56682         this._stepDirections = [
56683             NavigationDirection.StepForward,
56684             NavigationDirection.StepBackward,
56685             NavigationDirection.StepLeft,
56686             NavigationDirection.StepRight,
56687         ];
56688         this._turnDirections = [
56689             NavigationDirection.TurnLeft,
56690             NavigationDirection.TurnRight,
56691             NavigationDirection.TurnU,
56692         ];
56693         this._turnNames = {};
56694         this._turnNames[NavigationDirection.TurnLeft] = "mapillary-direction-turn-left";
56695         this._turnNames[NavigationDirection.TurnRight] = "mapillary-direction-turn-right";
56696         this._turnNames[NavigationDirection.TurnU] = "mapillary-direction-turn-around";
56697         // detects IE 8-11, then Edge 20+.
56698         let isIE = !!document.documentMode;
56699         this._isEdge = !isIE && !!window.StyleMedia;
56700     }
56701     /**
56702      * Get needs render.
56703      *
56704      * @returns {boolean} Value indicating whether render should be called.
56705      */
56706     get needsRender() {
56707         return this._needsRender;
56708     }
56709     /**
56710      * Renders virtual DOM elements.
56711      *
56712      * @description Calling render resets the needs render property.
56713      */
56714     render(navigator) {
56715         this._needsRender = false;
56716         let rotation = this._rotation;
56717         let steps = [];
56718         let turns = [];
56719         if (isSpherical(this._image.cameraType)) {
56720             steps = steps.concat(this._createSphericalArrows(navigator, rotation));
56721         }
56722         else {
56723             steps = steps.concat(this._createPerspectiveToSphericalArrows(navigator, rotation));
56724             steps = steps.concat(this._createStepArrows(navigator, rotation));
56725             turns = turns.concat(this._createTurnArrows(navigator));
56726         }
56727         return this._getContainer(steps, turns, rotation);
56728     }
56729     setEdges(edgeStatus, sequence) {
56730         this._setEdges(edgeStatus, sequence);
56731         this._setNeedsRender();
56732     }
56733     /**
56734      * Set image for which to show edges.
56735      *
56736      * @param {Image} image
56737      */
56738     setImage(image) {
56739         this._image = image;
56740         this._clearEdges();
56741         this._setNeedsRender();
56742     }
56743     /**
56744      * Set the render camera to use for calculating rotations.
56745      *
56746      * @param {RenderCamera} renderCamera
56747      */
56748     setRenderCamera(renderCamera) {
56749         let rotation = renderCamera.rotation;
56750         if (Math.abs(rotation.phi - this._rotation.phi) < this._epsilon) {
56751             return;
56752         }
56753         this._rotation = rotation;
56754         this._setNeedsRender();
56755     }
56756     /**
56757      * Set configuration values.
56758      *
56759      * @param {DirectionConfiguration} configuration
56760      */
56761     setConfiguration(configuration) {
56762         let needsRender = false;
56763         if (this._highlightKey !== configuration.highlightId ||
56764             this._distinguishSequence !== configuration.distinguishSequence) {
56765             this._highlightKey = configuration.highlightId;
56766             this._distinguishSequence = configuration.distinguishSequence;
56767             needsRender = true;
56768         }
56769         if (this._calculator.minWidth !== configuration.minWidth ||
56770             this._calculator.maxWidth !== configuration.maxWidth) {
56771             this._calculator.configure(configuration);
56772             needsRender = true;
56773         }
56774         if (needsRender) {
56775             this._setNeedsRender();
56776         }
56777     }
56778     /**
56779      * Detect the element's width and height and resize
56780      * elements accordingly.
56781      *
56782      * @param {ViewportSize} size Size of vßiewer container element.
56783      */
56784     resize(size) {
56785         this._calculator.resize(size);
56786         this._setNeedsRender();
56787     }
56788     _setNeedsRender() {
56789         if (this._image != null) {
56790             this._needsRender = true;
56791         }
56792     }
56793     _clearEdges() {
56794         this._stepEdges = [];
56795         this._turnEdges = [];
56796         this._sphericalEdges = [];
56797         this._sequenceEdgeKeys = [];
56798     }
56799     _setEdges(edgeStatus, sequence) {
56800         this._stepEdges = [];
56801         this._turnEdges = [];
56802         this._sphericalEdges = [];
56803         this._sequenceEdgeKeys = [];
56804         for (let edge of edgeStatus.edges) {
56805             let direction = edge.data.direction;
56806             if (this._stepDirections.indexOf(direction) > -1) {
56807                 this._stepEdges.push(edge);
56808                 continue;
56809             }
56810             if (this._turnDirections.indexOf(direction) > -1) {
56811                 this._turnEdges.push(edge);
56812                 continue;
56813             }
56814             if (edge.data.direction === NavigationDirection.Spherical) {
56815                 this._sphericalEdges.push(edge);
56816             }
56817         }
56818         if (this._distinguishSequence && sequence != null) {
56819             let edges = this._sphericalEdges
56820                 .concat(this._stepEdges)
56821                 .concat(this._turnEdges);
56822             for (let edge of edges) {
56823                 let edgeKey = edge.target;
56824                 for (let sequenceKey of sequence.imageIds) {
56825                     if (sequenceKey === edgeKey) {
56826                         this._sequenceEdgeKeys.push(edgeKey);
56827                         break;
56828                     }
56829                 }
56830             }
56831         }
56832     }
56833     _createSphericalArrows(navigator, rotation) {
56834         let arrows = [];
56835         for (let sphericalEdge of this._sphericalEdges) {
56836             arrows.push(this._createVNodeByKey(navigator, sphericalEdge.target, sphericalEdge.data.worldMotionAzimuth, rotation, this._calculator.outerRadius, "mapillary-direction-arrow-spherical"));
56837         }
56838         for (let stepEdge of this._stepEdges) {
56839             arrows.push(this._createSphericalToPerspectiveArrow(navigator, stepEdge.target, stepEdge.data.worldMotionAzimuth, rotation, stepEdge.data.direction));
56840         }
56841         return arrows;
56842     }
56843     _createSphericalToPerspectiveArrow(navigator, key, azimuth, rotation, direction) {
56844         let threshold = Math.PI / 8;
56845         let relativePhi = rotation.phi;
56846         switch (direction) {
56847             case NavigationDirection.StepBackward:
56848                 relativePhi = rotation.phi - Math.PI;
56849                 break;
56850             case NavigationDirection.StepLeft:
56851                 relativePhi = rotation.phi + Math.PI / 2;
56852                 break;
56853             case NavigationDirection.StepRight:
56854                 relativePhi = rotation.phi - Math.PI / 2;
56855                 break;
56856         }
56857         if (Math.abs(this._spatial.wrapAngle(azimuth - relativePhi)) < threshold) {
56858             return this._createVNodeByKey(navigator, key, azimuth, rotation, this._calculator.outerRadius, "mapillary-direction-arrow-step");
56859         }
56860         return this._createVNodeInactive(key, azimuth, rotation);
56861     }
56862     _createPerspectiveToSphericalArrows(navigator, rotation) {
56863         let arrows = [];
56864         for (let sphericalEdge of this._sphericalEdges) {
56865             arrows.push(this._createVNodeByKey(navigator, sphericalEdge.target, sphericalEdge.data.worldMotionAzimuth, rotation, this._calculator.innerRadius, "mapillary-direction-arrow-spherical", true));
56866         }
56867         return arrows;
56868     }
56869     _createStepArrows(navigator, rotation) {
56870         let arrows = [];
56871         for (let stepEdge of this._stepEdges) {
56872             arrows.push(this._createVNodeByDirection(navigator, stepEdge.target, stepEdge.data.worldMotionAzimuth, rotation, stepEdge.data.direction));
56873         }
56874         return arrows;
56875     }
56876     _createTurnArrows(navigator) {
56877         let turns = [];
56878         for (let turnEdge of this._turnEdges) {
56879             let direction = turnEdge.data.direction;
56880             let name = this._turnNames[direction];
56881             turns.push(this._createVNodeByTurn(navigator, turnEdge.target, name, direction));
56882         }
56883         return turns;
56884     }
56885     _createVNodeByKey(navigator, key, azimuth, rotation, offset, className, shiftVertically) {
56886         let onClick = (e) => {
56887             navigator.moveTo$(key)
56888                 .subscribe(undefined, (error) => {
56889                 if (!(error instanceof CancelMapillaryError)) {
56890                     console.error(error);
56891                 }
56892             });
56893         };
56894         return this._createVNode(key, azimuth, rotation, offset, className, "mapillary-direction-circle", onClick, shiftVertically);
56895     }
56896     _createVNodeByDirection(navigator, key, azimuth, rotation, direction) {
56897         let onClick = (e) => {
56898             navigator.moveDir$(direction)
56899                 .subscribe(undefined, (error) => {
56900                 if (!(error instanceof CancelMapillaryError)) {
56901                     console.error(error);
56902                 }
56903             });
56904         };
56905         return this._createVNode(key, azimuth, rotation, this._calculator.outerRadius, "mapillary-direction-arrow-step", "mapillary-direction-circle", onClick);
56906     }
56907     _createVNodeByTurn(navigator, key, className, direction) {
56908         let onClick = (e) => {
56909             navigator.moveDir$(direction)
56910                 .subscribe(undefined, (error) => {
56911                 if (!(error instanceof CancelMapillaryError)) {
56912                     console.error(error);
56913                 }
56914             });
56915         };
56916         let style = {
56917             height: this._calculator.turnCircleSizeCss,
56918             transform: "rotate(0)",
56919             width: this._calculator.turnCircleSizeCss,
56920         };
56921         switch (direction) {
56922             case NavigationDirection.TurnLeft:
56923                 style.left = "5px";
56924                 style.top = "5px";
56925                 break;
56926             case NavigationDirection.TurnRight:
56927                 style.right = "5px";
56928                 style.top = "5px";
56929                 break;
56930             case NavigationDirection.TurnU:
56931                 style.left = "5px";
56932                 style.bottom = "5px";
56933                 break;
56934         }
56935         let circleProperties = {
56936             attributes: {
56937                 "data-id": key,
56938             },
56939             onclick: onClick,
56940             style: style,
56941         };
56942         let circleClassName = "mapillary-direction-turn-circle";
56943         if (this._sequenceEdgeKeys.indexOf(key) > -1) {
56944             circleClassName += "-sequence";
56945         }
56946         if (this._highlightKey === key) {
56947             circleClassName += "-highlight";
56948         }
56949         let turn = virtualDom.h(`div.${className}`, {}, []);
56950         return virtualDom.h("div." + circleClassName, circleProperties, [turn]);
56951     }
56952     _createVNodeInactive(key, azimuth, rotation) {
56953         return this._createVNode(key, azimuth, rotation, this._calculator.outerRadius, "mapillary-direction-arrow-inactive", "mapillary-direction-circle-inactive");
56954     }
56955     _createVNode(key, azimuth, rotation, radius, className, circleClassName, onClick, shiftVertically) {
56956         let translation = this._calculator.angleToCoordinates(azimuth - rotation.phi);
56957         // rotate 90 degrees clockwise and flip over X-axis
56958         let translationX = Math.round(-radius * translation[1] + 0.5 * this._calculator.containerWidth);
56959         let translationY = Math.round(-radius * translation[0] + 0.5 * this._calculator.containerHeight);
56960         let shadowTranslation = this._calculator.relativeAngleToCoordiantes(azimuth, rotation.phi);
56961         let shadowOffset = this._calculator.shadowOffset;
56962         let shadowTranslationX = -shadowOffset * shadowTranslation[1];
56963         let shadowTranslationY = shadowOffset * shadowTranslation[0];
56964         let filter = `drop-shadow(${shadowTranslationX}px ${shadowTranslationY}px 1px rgba(0,0,0,0.8))`;
56965         let properties = {
56966             style: {
56967                 "-webkit-filter": filter,
56968                 filter: filter,
56969             },
56970         };
56971         let chevron = virtualDom.h("div." + className, properties, []);
56972         let azimuthDeg = -this._spatial.radToDeg(azimuth - rotation.phi);
56973         let circleTransform = shiftVertically ?
56974             `translate(${translationX}px, ${translationY}px) rotate(${azimuthDeg}deg) translateZ(-0.01px)` :
56975             `translate(${translationX}px, ${translationY}px) rotate(${azimuthDeg}deg)`;
56976         let circleProperties = {
56977             attributes: { "data-id": key },
56978             onclick: onClick,
56979             style: {
56980                 height: this._calculator.stepCircleSizeCss,
56981                 marginLeft: this._calculator.stepCircleMarginCss,
56982                 marginTop: this._calculator.stepCircleMarginCss,
56983                 transform: circleTransform,
56984                 width: this._calculator.stepCircleSizeCss,
56985             },
56986         };
56987         if (this._sequenceEdgeKeys.indexOf(key) > -1) {
56988             circleClassName += "-sequence";
56989         }
56990         if (this._highlightKey === key) {
56991             circleClassName += "-highlight";
56992         }
56993         return virtualDom.h("div." + circleClassName, circleProperties, [chevron]);
56994     }
56995     _getContainer(steps, turns, rotation) {
56996         // edge does not handle hover on perspective transforms.
56997         let transform = this._isEdge ?
56998             "rotateX(60deg)" :
56999             `perspective(${this._calculator.containerWidthCss}) rotateX(60deg)`;
57000         let properties = {
57001             oncontextmenu: (event) => { event.preventDefault(); },
57002             style: {
57003                 bottom: this._calculator.containerBottomCss,
57004                 height: this._calculator.containerHeightCss,
57005                 left: this._calculator.containerLeftCss,
57006                 marginLeft: this._calculator.containerMarginCss,
57007                 transform: transform,
57008                 width: this._calculator.containerWidthCss,
57009             },
57010         };
57011         return virtualDom.h("div.mapillary-direction-perspective", properties, turns.concat(steps));
57012     }
57013 }
57014
57015 /**
57016  * @class DirectionComponent
57017  * @classdesc Component showing navigation arrows for steps and turns.
57018  */
57019 class DirectionComponent extends Component {
57020     /** @ignore */
57021     constructor(name, container, navigator, directionDOMRenderer) {
57022         super(name, container, navigator);
57023         this._renderer = !!directionDOMRenderer ?
57024             directionDOMRenderer :
57025             new DirectionDOMRenderer(this.defaultConfiguration, { height: container.container.offsetHeight, width: container.container.offsetWidth });
57026         this._hoveredIdSubject$ = new Subject();
57027         this._hoveredId$ = this._hoveredIdSubject$.pipe(share());
57028     }
57029     fire(type, event) {
57030         super.fire(type, event);
57031     }
57032     off(type, handler) {
57033         super.off(type, handler);
57034     }
57035     on(type, handler) {
57036         super.on(type, handler);
57037     }
57038     _activate() {
57039         const subs = this._subscriptions;
57040         subs.push(this._configuration$
57041             .subscribe((configuration) => {
57042             this._renderer.setConfiguration(configuration);
57043         }));
57044         subs.push(this._container.renderService.size$
57045             .subscribe((size) => {
57046             this._renderer.resize(size);
57047         }));
57048         subs.push(this._navigator.stateService.currentImage$.pipe(tap((image) => {
57049             this._container.domRenderer.render$.next({ name: this._name, vNode: virtualDom.h("div", {}, []) });
57050             this._renderer.setImage(image);
57051         }), withLatestFrom(this._configuration$), switchMap(([image, configuration]) => {
57052             return combineLatest(image.spatialEdges$, configuration.distinguishSequence ?
57053                 this._navigator.graphService
57054                     .cacheSequence$(image.sequenceId).pipe(catchError((error) => {
57055                     console.error(`Failed to cache sequence (${image.sequenceId})`, error);
57056                     return of(null);
57057                 })) :
57058                 of(null));
57059         }))
57060             .subscribe(([edgeStatus, sequence]) => {
57061             this._renderer.setEdges(edgeStatus, sequence);
57062         }));
57063         subs.push(this._container.renderService.renderCameraFrame$.pipe(tap((renderCamera) => {
57064             this._renderer.setRenderCamera(renderCamera);
57065         }), map(() => {
57066             return this._renderer;
57067         }), filter((renderer) => {
57068             return renderer.needsRender;
57069         }), map((renderer) => {
57070             return { name: this._name, vNode: renderer.render(this._navigator) };
57071         }))
57072             .subscribe(this._container.domRenderer.render$));
57073         subs.push(combineLatest(this._container.domRenderer.element$, this._container.renderService.renderCamera$, this._container.mouseService.mouseMove$.pipe(startWith(null)), this._container.mouseService.mouseUp$.pipe(startWith(null))).pipe(map(([element]) => {
57074             let elements = element.getElementsByClassName("mapillary-direction-perspective");
57075             for (let i = 0; i < elements.length; i++) {
57076                 let hovered = elements.item(i).querySelector(":hover");
57077                 if (hovered != null && hovered.hasAttribute("data-id")) {
57078                     return hovered.getAttribute("data-id");
57079                 }
57080             }
57081             return null;
57082         }), distinctUntilChanged())
57083             .subscribe(this._hoveredIdSubject$));
57084         subs.push(this._hoveredId$
57085             .subscribe((id) => {
57086             const type = "hover";
57087             const event = {
57088                 id,
57089                 target: this,
57090                 type,
57091             };
57092             this.fire(type, event);
57093         }));
57094     }
57095     _deactivate() {
57096         this._subscriptions.unsubscribe();
57097     }
57098     _getDefaultConfiguration() {
57099         return {
57100             distinguishSequence: false,
57101             maxWidth: 460,
57102             minWidth: 260,
57103         };
57104     }
57105 }
57106 /** @inheritdoc */
57107 DirectionComponent.componentName = "direction";
57108
57109 const sphericalFrag = `
57110 #ifdef GL_FRAGMENT_PRECISION_HIGH
57111 precision highp float;
57112 #else
57113 precision mediump float;
57114 #endif
57115
57116 #define tau 6.28318530718
57117
57118 uniform sampler2D projectorTex;
57119 uniform float opacity;
57120
57121 varying vec4 vRstq;
57122
57123 void main()
57124 {
57125     vec3 b = normalize(vRstq.xyz);
57126     float lat = -asin(b.y);
57127     float lng = atan(b.x, b.z);
57128     float x = lng / tau + 0.5;
57129     float y = lat / tau * 2.0 + 0.5;
57130     vec4 baseColor = texture2D(projectorTex, vec2(x, y));
57131     baseColor.a = opacity;
57132     gl_FragColor = baseColor;
57133 }
57134 `;
57135
57136 const sphericalVert = `
57137 #ifdef GL_ES
57138 precision highp float;
57139 #endif
57140
57141 uniform mat4 projectorMat;
57142
57143 varying vec4 vRstq;
57144
57145 void main()
57146 {
57147     vRstq = projectorMat * vec4(position, 1.0);
57148     gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
57149 }
57150 `;
57151
57152 const sphericalCurtainFrag = `
57153 #ifdef GL_FRAGMENT_PRECISION_HIGH
57154 precision highp float;
57155 #else
57156 precision mediump float;
57157 #endif
57158
57159 #define tau 6.28318530718
57160
57161 uniform sampler2D projectorTex;
57162 uniform float curtain;
57163 uniform float opacity;
57164
57165 varying vec4 vRstq;
57166
57167 void main()
57168 {
57169     vec3 b = normalize(vRstq.xyz);
57170     float lat = -asin(b.y);
57171     float lng = atan(b.x, b.z);
57172     float x = lng / tau + 0.5;
57173     float y = lat / tau * 2.0 + 0.5;
57174
57175     bool inverted = curtain < 0.5;
57176
57177     float curtainMin = inverted ? curtain + 0.5 : curtain - 0.5;
57178     float curtainMax = curtain;
57179
57180     bool insideCurtain = inverted ?
57181         x > curtainMin || x < curtainMax :
57182         x > curtainMin && x < curtainMax;
57183
57184     vec4 baseColor;
57185     if (insideCurtain) {
57186         baseColor = texture2D(projectorTex, vec2(x, y));
57187         baseColor.a = opacity;
57188     } else {
57189         baseColor = vec4(0.0, 0.0, 0.0, 0.0);
57190     }
57191
57192     gl_FragColor = baseColor;
57193 }
57194 `;
57195
57196 const sphericalCurtainVert = `
57197 #ifdef GL_ES
57198 precision highp float;
57199 #endif
57200
57201 uniform mat4 projectorMat;
57202
57203 varying vec4 vRstq;
57204
57205 void main()
57206 {
57207     vRstq = projectorMat * vec4(position, 1.0);
57208     gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
57209 }
57210 `;
57211
57212 const fisheyeFrag = `
57213 #ifdef GL_FRAGMENT_PRECISION_HIGH
57214 precision highp float;
57215 #else
57216 precision mediump float;
57217 #endif
57218
57219 uniform sampler2D projectorTex;
57220 uniform float opacity;
57221 uniform float focal;
57222 uniform float k1;
57223 uniform float k2;
57224 uniform float scale_x;
57225 uniform float scale_y;
57226 uniform float radial_peak;
57227
57228 varying vec4 vRstq;
57229
57230 void main()
57231 {
57232     float x = vRstq.x;
57233     float y = vRstq.y;
57234     float z = vRstq.z;
57235
57236     float r = sqrt(x * x + y * y);
57237     float theta = atan(r, z);
57238
57239     if (radial_peak > 0. && theta > radial_peak) {
57240         theta = radial_peak;
57241     }
57242
57243     float theta2 = theta * theta;
57244     float theta_d = theta * (1.0 + theta2 * (k1 + theta2 * k2));
57245     float s = focal * theta_d / r;
57246
57247     float u = scale_x * s * x + 0.5;
57248     float v = -scale_y * s * y + 0.5;
57249
57250     vec4 baseColor;
57251     if (u >= 0. && u <= 1. && v >= 0. && v <= 1.) {
57252         baseColor = texture2D(projectorTex, vec2(u, v));
57253         baseColor.a = opacity;
57254     } else {
57255         baseColor = vec4(0.0, 0.0, 0.0, 0.0);
57256     }
57257
57258     gl_FragColor = baseColor;
57259 }
57260 `;
57261
57262 const fisheyeVert = `
57263 #ifdef GL_ES
57264 precision highp float;
57265 #endif
57266
57267 uniform mat4 projectorMat;
57268
57269 varying vec4 vRstq;
57270
57271 void main()
57272 {
57273     vRstq = projectorMat * vec4(position, 1.0);
57274     gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
57275 }
57276 `;
57277
57278 const fisheyeCurtainFrag = `
57279 #ifdef GL_FRAGMENT_PRECISION_HIGH
57280 precision highp float;
57281 #else
57282 precision mediump float;
57283 #endif
57284
57285 uniform sampler2D projectorTex;
57286 uniform float opacity;
57287 uniform float focal;
57288 uniform float k1;
57289 uniform float k2;
57290 uniform float scale_x;
57291 uniform float scale_y;
57292 uniform float radial_peak;
57293 uniform float curtain;
57294
57295 varying vec4 vRstq;
57296
57297 void main()
57298 {
57299     float x = vRstq.x;
57300     float y = vRstq.y;
57301     float z = vRstq.z;
57302
57303     float r2 = sqrt(x * x + y * y);
57304     float theta = atan(r2, z);
57305
57306     if (radial_peak > 0. && theta > radial_peak) {
57307         theta = radial_peak;
57308     }
57309
57310     float theta2 = theta * theta;
57311     float theta_d = theta * (1.0 + theta2 * (k1 + theta2 * k2));
57312     float s = focal * theta_d / r2;
57313
57314     float u = scale_x * s * x + 0.5;
57315     float v = -scale_y * s * y + 0.5;
57316
57317     vec4 baseColor;
57318     if ((u < curtain || curtain >= 1.0) && u >= 0. && u <= 1. && v >= 0. && v <= 1.) {
57319         baseColor = texture2D(projectorTex, vec2(u, v));
57320         baseColor.a = opacity;
57321     } else {
57322         baseColor = vec4(0.0, 0.0, 0.0, 0.0);
57323     }
57324
57325     gl_FragColor = baseColor;
57326 }
57327 `;
57328
57329 const fisheyeCurtainVert = `
57330 #ifdef GL_ES
57331 precision highp float;
57332 #endif
57333
57334 uniform mat4 projectorMat;
57335
57336 varying vec4 vRstq;
57337
57338 void main()
57339 {
57340     vRstq = projectorMat * vec4(position, 1.0);
57341     gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
57342 }
57343 `;
57344
57345 const perspectiveFrag = `
57346 #ifdef GL_FRAGMENT_PRECISION_HIGH
57347 precision highp float;
57348 #else
57349 precision mediump float;
57350 #endif
57351
57352 uniform sampler2D projectorTex;
57353 uniform float opacity;
57354 uniform float focal;
57355 uniform float k1;
57356 uniform float k2;
57357 uniform float scale_x;
57358 uniform float scale_y;
57359 uniform float radial_peak;
57360
57361 varying vec4 vRstq;
57362
57363 void main()
57364 {
57365     float x = vRstq.x / vRstq.z;
57366     float y = vRstq.y / vRstq.z;
57367     float r2 = x * x + y * y;
57368
57369     if (radial_peak > 0. && r2 > radial_peak * sqrt(r2)) {
57370         r2 = radial_peak * radial_peak;
57371     }
57372
57373     float d = 1.0 + k1 * r2 + k2 * r2 * r2;
57374     float u = scale_x * focal * d * x + 0.5;
57375     float v = - scale_y * focal * d * y + 0.5;
57376
57377     vec4 baseColor;
57378     if (u >= 0. && u <= 1. && v >= 0. && v <= 1.) {
57379         baseColor = texture2D(projectorTex, vec2(u, v));
57380         baseColor.a = opacity;
57381     } else {
57382         baseColor = vec4(0.0, 0.0, 0.0, 0.0);
57383     }
57384
57385     gl_FragColor = baseColor;
57386 }
57387 `;
57388
57389 const perspectiveVert = `
57390 #ifdef GL_ES
57391 precision highp float;
57392 #endif
57393
57394 uniform mat4 projectorMat;
57395
57396 varying vec4 vRstq;
57397
57398 void main()
57399 {
57400     vRstq = projectorMat * vec4(position, 1.0);
57401     gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
57402 }
57403 `;
57404
57405 const perspectiveCurtainFrag = `
57406 #ifdef GL_FRAGMENT_PRECISION_HIGH
57407 precision highp float;
57408 #else
57409 precision mediump float;
57410 #endif
57411
57412 uniform sampler2D projectorTex;
57413 uniform float opacity;
57414 uniform float focal;
57415 uniform float k1;
57416 uniform float k2;
57417 uniform float scale_x;
57418 uniform float scale_y;
57419 uniform float radial_peak;
57420 uniform float curtain;
57421
57422 varying vec4 vRstq;
57423
57424 void main()
57425 {
57426     float x = vRstq.x / vRstq.z;
57427     float y = vRstq.y / vRstq.z;
57428     float r2 = x * x + y * y;
57429
57430     if (radial_peak > 0. && r2 > radial_peak * sqrt(r2)) {
57431         r2 = radial_peak * radial_peak;
57432     }
57433
57434     float d = 1.0 + k1 * r2 + k2 * r2 * r2;
57435     float u = scale_x * focal * d * x + 0.5;
57436     float v = - scale_y * focal * d * y + 0.5;
57437
57438     vec4 baseColor;
57439     if ((u < curtain || curtain >= 1.0) && u >= 0. && u <= 1. && v >= 0. && v <= 1.) {
57440         baseColor = texture2D(projectorTex, vec2(u, v));
57441         baseColor.a = opacity;
57442     } else {
57443         baseColor = vec4(0.0, 0.0, 0.0, 0.0);
57444     }
57445
57446     gl_FragColor = baseColor;
57447 }
57448 `;
57449
57450 const perspectiveCurtainVert = `
57451 #ifdef GL_ES
57452 precision highp float;
57453 #endif
57454
57455 uniform mat4 projectorMat;
57456
57457 varying vec4 vRstq;
57458
57459 void main()
57460 {
57461     vRstq = projectorMat * vec4(position, 1.0);
57462     gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
57463 }
57464 `;
57465
57466 const perspectiveDistortedFrag = `
57467 #ifdef GL_FRAGMENT_PRECISION_HIGH
57468 precision highp float;
57469 #else
57470 precision mediump float;
57471 #endif
57472
57473 uniform sampler2D projectorTex;
57474 uniform float opacity;
57475
57476 varying vec4 vRstq;
57477
57478 void main()
57479 {
57480     float u = vRstq.x / vRstq.w;
57481     float v = vRstq.y / vRstq.w;
57482
57483     vec4 baseColor;
57484     if (u >= 0. && u <= 1. && v >= 0. && v <= 1.) {
57485         baseColor = texture2D(projectorTex, vec2(u, v));
57486         baseColor.a = opacity;
57487     } else {
57488         baseColor = vec4(0.0, 0.0, 0.0, 0.0);
57489     }
57490
57491     gl_FragColor = baseColor;
57492 }
57493 `;
57494
57495 const perspectiveDistortedVert = `
57496 #ifdef GL_ES
57497 precision highp float;
57498 #endif
57499
57500 uniform mat4 projectorMat;
57501
57502 varying vec4 vRstq;
57503
57504 void main()
57505 {
57506     vRstq = projectorMat * vec4(position, 1.0);
57507     gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
57508 }
57509 `;
57510
57511 const perspectiveDistortedCurtainFrag = `
57512 #ifdef GL_FRAGMENT_PRECISION_HIGH
57513 precision highp float;
57514 #else
57515 precision mediump float;
57516 #endif
57517
57518 uniform sampler2D projectorTex;
57519 uniform float opacity;
57520 uniform float curtain;
57521
57522 varying vec4 vRstq;
57523
57524 void main()
57525 {
57526     float u = vRstq.x / vRstq.w;
57527     float v = vRstq.y / vRstq.w;
57528
57529     vec4 baseColor;
57530     if ((u < curtain || curtain >= 1.0) && u >= 0. && u <= 1. && v >= 0. && v <= 1.) {
57531         baseColor = texture2D(projectorTex, vec2(u, v));
57532         baseColor.a = opacity;
57533     } else {
57534         baseColor = vec4(0.0, 0.0, 0.0, 0.0);
57535     }
57536
57537     gl_FragColor = baseColor;
57538 }
57539 `;
57540
57541 const perspectiveDistortedCurtainVert = `
57542 #ifdef GL_ES
57543 precision highp float;
57544 #endif
57545
57546 uniform mat4 projectorMat;
57547
57548 varying vec4 vRstq;
57549
57550 void main()
57551 {
57552     vRstq = projectorMat * vec4(position, 1.0);
57553     gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
57554 }
57555 `;
57556
57557 class Shaders {
57558 }
57559 Shaders.fisheye = {
57560     fragment: fisheyeFrag,
57561     vertex: fisheyeVert,
57562 };
57563 Shaders.fisheyeCurtain = {
57564     fragment: fisheyeCurtainFrag,
57565     vertex: fisheyeCurtainVert,
57566 };
57567 Shaders.perspective = {
57568     fragment: perspectiveFrag,
57569     vertex: perspectiveVert,
57570 };
57571 Shaders.perspectiveCurtain = {
57572     fragment: perspectiveCurtainFrag,
57573     vertex: perspectiveCurtainVert,
57574 };
57575 Shaders.perspectiveDistorted = {
57576     fragment: perspectiveDistortedFrag,
57577     vertex: perspectiveDistortedVert,
57578 };
57579 Shaders.perspectiveDistortedCurtain = {
57580     fragment: perspectiveDistortedCurtainFrag,
57581     vertex: perspectiveDistortedCurtainVert,
57582 };
57583 Shaders.spherical = {
57584     fragment: sphericalFrag,
57585     vertex: sphericalVert,
57586 };
57587 Shaders.sphericalCurtain = {
57588     fragment: sphericalCurtainFrag,
57589     vertex: sphericalCurtainVert,
57590 };
57591
57592 class MeshFactory {
57593     constructor(imagePlaneDepth, imageSphereRadius) {
57594         this._imagePlaneDepth = imagePlaneDepth != null ? imagePlaneDepth : 200;
57595         this._imageSphereRadius = imageSphereRadius != null ? imageSphereRadius : 200;
57596     }
57597     createMesh(image, transform) {
57598         if (isSpherical(transform.cameraType)) {
57599             return this._createImageSphere(image, transform);
57600         }
57601         else if (isFisheye(transform.cameraType)) {
57602             return this._createImagePlaneFisheye(image, transform);
57603         }
57604         else {
57605             return this._createImagePlane(image, transform);
57606         }
57607     }
57608     createFlatMesh(image, transform, basicX0, basicX1, basicY0, basicY1) {
57609         let texture = this._createTexture(image.image);
57610         let materialParameters = this._createDistortedPlaneMaterialParameters(transform, texture);
57611         let material = new ShaderMaterial(materialParameters);
57612         let geometry = this._getFlatImagePlaneGeoFromBasic(transform, basicX0, basicX1, basicY0, basicY1);
57613         return new Mesh(geometry, material);
57614     }
57615     createCurtainMesh(image, transform) {
57616         if (isSpherical(transform.cameraType)) {
57617             return this._createSphereCurtainMesh(image, transform);
57618         }
57619         else if (isFisheye(transform.cameraType)) {
57620             return this._createCurtainMeshFisheye(image, transform);
57621         }
57622         else {
57623             return this._createCurtainMesh(image, transform);
57624         }
57625     }
57626     createDistortedCurtainMesh(image, transform) {
57627         return this._createDistortedCurtainMesh(image, transform);
57628     }
57629     _createCurtainMesh(image, transform) {
57630         let texture = this._createTexture(image.image);
57631         let materialParameters = this._createCurtainPlaneMaterialParameters(transform, texture);
57632         let material = new ShaderMaterial(materialParameters);
57633         let geometry = this._useMesh(transform, image) ?
57634             this._getImagePlaneGeo(transform, image) :
57635             this._getRegularFlatImagePlaneGeo(transform);
57636         return new Mesh(geometry, material);
57637     }
57638     _createCurtainMeshFisheye(image, transform) {
57639         let texture = this._createTexture(image.image);
57640         let materialParameters = this._createCurtainPlaneMaterialParametersFisheye(transform, texture);
57641         let material = new ShaderMaterial(materialParameters);
57642         let geometry = this._useMesh(transform, image) ?
57643             this._getImagePlaneGeoFisheye(transform, image) :
57644             this._getRegularFlatImagePlaneGeo(transform);
57645         return new Mesh(geometry, material);
57646     }
57647     _createDistortedCurtainMesh(image, transform) {
57648         let texture = this._createTexture(image.image);
57649         let materialParameters = this._createDistortedCurtainPlaneMaterialParameters(transform, texture);
57650         let material = new ShaderMaterial(materialParameters);
57651         let geometry = this._getRegularFlatImagePlaneGeo(transform);
57652         return new Mesh(geometry, material);
57653     }
57654     _createSphereCurtainMesh(image, transform) {
57655         let texture = this._createTexture(image.image);
57656         let materialParameters = this._createCurtainSphereMaterialParameters(transform, texture);
57657         let material = new ShaderMaterial(materialParameters);
57658         return this._useMesh(transform, image) ?
57659             new Mesh(this._getImageSphereGeo(transform, image), material) :
57660             new Mesh(this._getFlatImageSphereGeo(transform), material);
57661     }
57662     _createImageSphere(image, transform) {
57663         let texture = this._createTexture(image.image);
57664         let materialParameters = this._createSphereMaterialParameters(transform, texture);
57665         let material = new ShaderMaterial(materialParameters);
57666         let mesh = this._useMesh(transform, image) ?
57667             new Mesh(this._getImageSphereGeo(transform, image), material) :
57668             new Mesh(this._getFlatImageSphereGeo(transform), material);
57669         return mesh;
57670     }
57671     _createImagePlane(image, transform) {
57672         let texture = this._createTexture(image.image);
57673         let materialParameters = this._createPlaneMaterialParameters(transform, texture);
57674         let material = new ShaderMaterial(materialParameters);
57675         let geometry = this._useMesh(transform, image) ?
57676             this._getImagePlaneGeo(transform, image) :
57677             this._getRegularFlatImagePlaneGeo(transform);
57678         return new Mesh(geometry, material);
57679     }
57680     _createImagePlaneFisheye(image, transform) {
57681         let texture = this._createTexture(image.image);
57682         let materialParameters = this._createPlaneMaterialParametersFisheye(transform, texture);
57683         let material = new ShaderMaterial(materialParameters);
57684         let geometry = this._useMesh(transform, image) ?
57685             this._getImagePlaneGeoFisheye(transform, image) :
57686             this._getRegularFlatImagePlaneGeoFisheye(transform);
57687         return new Mesh(geometry, material);
57688     }
57689     _createSphereMaterialParameters(transform, texture) {
57690         let materialParameters = {
57691             depthWrite: false,
57692             fragmentShader: Shaders.spherical.fragment,
57693             side: DoubleSide,
57694             transparent: true,
57695             uniforms: {
57696                 opacity: { value: 1.0 },
57697                 projectorMat: { value: transform.rt },
57698                 projectorTex: { value: texture },
57699             },
57700             vertexShader: Shaders.spherical.vertex,
57701         };
57702         return materialParameters;
57703     }
57704     _createCurtainSphereMaterialParameters(transform, texture) {
57705         let materialParameters = {
57706             depthWrite: false,
57707             fragmentShader: Shaders.sphericalCurtain.fragment,
57708             side: DoubleSide,
57709             transparent: true,
57710             uniforms: {
57711                 curtain: { value: 1.0 },
57712                 opacity: { value: 1.0 },
57713                 projectorMat: { value: transform.rt },
57714                 projectorTex: { value: texture },
57715             },
57716             vertexShader: Shaders.sphericalCurtain.vertex,
57717         };
57718         return materialParameters;
57719     }
57720     _createPlaneMaterialParameters(transform, texture) {
57721         let materialParameters = {
57722             depthWrite: false,
57723             fragmentShader: Shaders.perspective.fragment,
57724             side: DoubleSide,
57725             transparent: true,
57726             uniforms: {
57727                 focal: { value: transform.focal },
57728                 k1: { value: transform.ck1 },
57729                 k2: { value: transform.ck2 },
57730                 opacity: { value: 1.0 },
57731                 projectorMat: { value: transform.basicRt },
57732                 projectorTex: { value: texture },
57733                 radial_peak: { value: !!transform.radialPeak ? transform.radialPeak : 0.0 },
57734                 scale_x: { value: Math.max(transform.basicHeight, transform.basicWidth) / transform.basicWidth },
57735                 scale_y: { value: Math.max(transform.basicWidth, transform.basicHeight) / transform.basicHeight },
57736             },
57737             vertexShader: Shaders.perspective.vertex,
57738         };
57739         return materialParameters;
57740     }
57741     _createPlaneMaterialParametersFisheye(transform, texture) {
57742         let materialParameters = {
57743             depthWrite: false,
57744             fragmentShader: Shaders.fisheye.fragment,
57745             side: DoubleSide,
57746             transparent: true,
57747             uniforms: {
57748                 focal: { value: transform.focal },
57749                 k1: { value: transform.ck1 },
57750                 k2: { value: transform.ck2 },
57751                 opacity: { value: 1.0 },
57752                 projectorMat: { value: transform.basicRt },
57753                 projectorTex: { value: texture },
57754                 radial_peak: { value: !!transform.radialPeak ? transform.radialPeak : 0.0 },
57755                 scale_x: { value: Math.max(transform.basicHeight, transform.basicWidth) / transform.basicWidth },
57756                 scale_y: { value: Math.max(transform.basicWidth, transform.basicHeight) / transform.basicHeight },
57757             },
57758             vertexShader: Shaders.fisheye.vertex,
57759         };
57760         return materialParameters;
57761     }
57762     _createCurtainPlaneMaterialParametersFisheye(transform, texture) {
57763         let materialParameters = {
57764             depthWrite: false,
57765             fragmentShader: Shaders.fisheyeCurtain.fragment,
57766             side: DoubleSide,
57767             transparent: true,
57768             uniforms: {
57769                 curtain: { value: 1.0 },
57770                 focal: { value: transform.focal },
57771                 k1: { value: transform.ck1 },
57772                 k2: { value: transform.ck2 },
57773                 opacity: { value: 1.0 },
57774                 projectorMat: { value: transform.basicRt },
57775                 projectorTex: { value: texture },
57776                 radial_peak: { value: !!transform.radialPeak ? transform.radialPeak : 0.0 },
57777                 scale_x: { value: Math.max(transform.basicHeight, transform.basicWidth) / transform.basicWidth },
57778                 scale_y: { value: Math.max(transform.basicWidth, transform.basicHeight) / transform.basicHeight },
57779             },
57780             vertexShader: Shaders.fisheyeCurtain.vertex,
57781         };
57782         return materialParameters;
57783     }
57784     _createCurtainPlaneMaterialParameters(transform, texture) {
57785         let materialParameters = {
57786             depthWrite: false,
57787             fragmentShader: Shaders.perspectiveCurtain.fragment,
57788             side: DoubleSide,
57789             transparent: true,
57790             uniforms: {
57791                 curtain: { value: 1.0 },
57792                 focal: { value: transform.focal },
57793                 k1: { value: transform.ck1 },
57794                 k2: { value: transform.ck2 },
57795                 opacity: { value: 1.0 },
57796                 projectorMat: { value: transform.basicRt },
57797                 projectorTex: { value: texture },
57798                 radial_peak: { value: !!transform.radialPeak ? transform.radialPeak : 0.0 },
57799                 scale_x: { value: Math.max(transform.basicHeight, transform.basicWidth) / transform.basicWidth },
57800                 scale_y: { value: Math.max(transform.basicWidth, transform.basicHeight) / transform.basicHeight },
57801             },
57802             vertexShader: Shaders.perspectiveCurtain.vertex,
57803         };
57804         return materialParameters;
57805     }
57806     _createDistortedCurtainPlaneMaterialParameters(transform, texture) {
57807         let materialParameters = {
57808             depthWrite: false,
57809             fragmentShader: Shaders.perspectiveDistortedCurtain.fragment,
57810             side: DoubleSide,
57811             transparent: true,
57812             uniforms: {
57813                 curtain: { value: 1.0 },
57814                 opacity: { value: 1.0 },
57815                 projectorMat: { value: transform.projectorMatrix() },
57816                 projectorTex: { value: texture },
57817             },
57818             vertexShader: Shaders.perspectiveDistortedCurtain.vertex,
57819         };
57820         return materialParameters;
57821     }
57822     _createDistortedPlaneMaterialParameters(transform, texture) {
57823         let materialParameters = {
57824             depthWrite: false,
57825             fragmentShader: Shaders.perspectiveDistorted.fragment,
57826             side: DoubleSide,
57827             transparent: true,
57828             uniforms: {
57829                 opacity: { value: 1.0 },
57830                 projectorMat: { value: transform.projectorMatrix() },
57831                 projectorTex: { value: texture },
57832             },
57833             vertexShader: Shaders.perspectiveDistorted.vertex,
57834         };
57835         return materialParameters;
57836     }
57837     _createTexture(image) {
57838         let texture = new Texture(image);
57839         texture.minFilter = LinearFilter;
57840         texture.needsUpdate = true;
57841         return texture;
57842     }
57843     _useMesh(transform, image) {
57844         return image.mesh.vertices.length && transform.hasValidScale;
57845     }
57846     _getImageSphereGeo(transform, image) {
57847         const t = transform.srtInverse;
57848         // push everything at least 5 meters in front of the camera
57849         let minZ = 5.0 * transform.scale;
57850         let maxZ = this._imageSphereRadius * transform.scale;
57851         let vertices = image.mesh.vertices;
57852         let numVertices = vertices.length / 3;
57853         let positions = new Float32Array(vertices.length);
57854         for (let i = 0; i < numVertices; ++i) {
57855             let index = 3 * i;
57856             let x = vertices[index + 0];
57857             let y = vertices[index + 1];
57858             let z = vertices[index + 2];
57859             let l = Math.sqrt(x * x + y * y + z * z);
57860             let boundedL = Math.max(minZ, Math.min(l, maxZ));
57861             let factor = boundedL / l;
57862             let p = new Vector3(x * factor, y * factor, z * factor);
57863             p.applyMatrix4(t);
57864             positions[index + 0] = p.x;
57865             positions[index + 1] = p.y;
57866             positions[index + 2] = p.z;
57867         }
57868         let faces = image.mesh.faces;
57869         let indices = new Uint16Array(faces.length);
57870         for (let i = 0; i < faces.length; ++i) {
57871             indices[i] = faces[i];
57872         }
57873         let geometry = new BufferGeometry();
57874         geometry.setAttribute("position", new BufferAttribute(positions, 3));
57875         geometry.setIndex(new BufferAttribute(indices, 1));
57876         return geometry;
57877     }
57878     _getImagePlaneGeo(transform, image) {
57879         const undistortionMarginFactor = 3;
57880         const t = transform.srtInverse;
57881         // push everything at least 5 meters in front of the camera
57882         let minZ = 5.0 * transform.scale;
57883         let maxZ = this._imagePlaneDepth * transform.scale;
57884         let vertices = image.mesh.vertices;
57885         let numVertices = vertices.length / 3;
57886         let positions = new Float32Array(vertices.length);
57887         for (let i = 0; i < numVertices; ++i) {
57888             let index = 3 * i;
57889             let x = vertices[index + 0];
57890             let y = vertices[index + 1];
57891             let z = vertices[index + 2];
57892             if (i < 4) {
57893                 x *= undistortionMarginFactor;
57894                 y *= undistortionMarginFactor;
57895             }
57896             let boundedZ = Math.max(minZ, Math.min(z, maxZ));
57897             let factor = boundedZ / z;
57898             let p = new Vector3(x * factor, y * factor, boundedZ);
57899             p.applyMatrix4(t);
57900             positions[index + 0] = p.x;
57901             positions[index + 1] = p.y;
57902             positions[index + 2] = p.z;
57903         }
57904         let faces = image.mesh.faces;
57905         let indices = new Uint16Array(faces.length);
57906         for (let i = 0; i < faces.length; ++i) {
57907             indices[i] = faces[i];
57908         }
57909         let geometry = new BufferGeometry();
57910         geometry.setAttribute("position", new BufferAttribute(positions, 3));
57911         geometry.setIndex(new BufferAttribute(indices, 1));
57912         return geometry;
57913     }
57914     _getImagePlaneGeoFisheye(transform, image) {
57915         const t = transform.srtInverse;
57916         // push everything at least 5 meters in front of the camera
57917         let minZ = 5.0 * transform.scale;
57918         let maxZ = this._imagePlaneDepth * transform.scale;
57919         let vertices = image.mesh.vertices;
57920         let numVertices = vertices.length / 3;
57921         let positions = new Float32Array(vertices.length);
57922         for (let i = 0; i < numVertices; ++i) {
57923             let index = 3 * i;
57924             let x = vertices[index + 0];
57925             let y = vertices[index + 1];
57926             let z = vertices[index + 2];
57927             let l = Math.sqrt(x * x + y * y + z * z);
57928             let boundedL = Math.max(minZ, Math.min(l, maxZ));
57929             let factor = boundedL / l;
57930             let p = new Vector3(x * factor, y * factor, z * factor);
57931             p.applyMatrix4(t);
57932             positions[index + 0] = p.x;
57933             positions[index + 1] = p.y;
57934             positions[index + 2] = p.z;
57935         }
57936         let faces = image.mesh.faces;
57937         let indices = new Uint16Array(faces.length);
57938         for (let i = 0; i < faces.length; ++i) {
57939             indices[i] = faces[i];
57940         }
57941         let geometry = new BufferGeometry();
57942         geometry.setAttribute("position", new BufferAttribute(positions, 3));
57943         geometry.setIndex(new BufferAttribute(indices, 1));
57944         return geometry;
57945     }
57946     _getFlatImageSphereGeo(transform) {
57947         const geometry = new SphereGeometry(this._imageSphereRadius, 20, 40);
57948         const t = transform.rt
57949             .clone()
57950             .invert();
57951         geometry.applyMatrix4(t);
57952         return geometry;
57953     }
57954     _getRegularFlatImagePlaneGeo(transform) {
57955         let width = transform.width;
57956         let height = transform.height;
57957         let size = Math.max(width, height);
57958         let dx = width / 2.0 / size;
57959         let dy = height / 2.0 / size;
57960         return this._getFlatImagePlaneGeo(transform, dx, dy);
57961     }
57962     _getFlatImagePlaneGeo(transform, dx, dy) {
57963         let vertices = [];
57964         vertices.push(transform.unprojectSfM([-dx, -dy], this._imagePlaneDepth));
57965         vertices.push(transform.unprojectSfM([dx, -dy], this._imagePlaneDepth));
57966         vertices.push(transform.unprojectSfM([dx, dy], this._imagePlaneDepth));
57967         vertices.push(transform.unprojectSfM([-dx, dy], this._imagePlaneDepth));
57968         return this._createFlatGeometry(vertices);
57969     }
57970     _getRegularFlatImagePlaneGeoFisheye(transform) {
57971         let width = transform.width;
57972         let height = transform.height;
57973         let size = Math.max(width, height);
57974         let dx = width / 2.0 / size;
57975         let dy = height / 2.0 / size;
57976         return this._getFlatImagePlaneGeoFisheye(transform, dx, dy);
57977     }
57978     _getFlatImagePlaneGeoFisheye(transform, dx, dy) {
57979         let vertices = [];
57980         vertices.push(transform.unprojectSfM([-dx, -dy], this._imagePlaneDepth));
57981         vertices.push(transform.unprojectSfM([dx, -dy], this._imagePlaneDepth));
57982         vertices.push(transform.unprojectSfM([dx, dy], this._imagePlaneDepth));
57983         vertices.push(transform.unprojectSfM([-dx, dy], this._imagePlaneDepth));
57984         return this._createFlatGeometry(vertices);
57985     }
57986     _getFlatImagePlaneGeoFromBasic(transform, basicX0, basicX1, basicY0, basicY1) {
57987         let vertices = [];
57988         vertices.push(transform.unprojectBasic([basicX0, basicY0], this._imagePlaneDepth));
57989         vertices.push(transform.unprojectBasic([basicX1, basicY0], this._imagePlaneDepth));
57990         vertices.push(transform.unprojectBasic([basicX1, basicY1], this._imagePlaneDepth));
57991         vertices.push(transform.unprojectBasic([basicX0, basicY1], this._imagePlaneDepth));
57992         return this._createFlatGeometry(vertices);
57993     }
57994     _createFlatGeometry(vertices) {
57995         let positions = new Float32Array(12);
57996         for (let i = 0; i < vertices.length; i++) {
57997             let index = 3 * i;
57998             positions[index + 0] = vertices[i][0];
57999             positions[index + 1] = vertices[i][1];
58000             positions[index + 2] = vertices[i][2];
58001         }
58002         let indices = new Uint16Array(6);
58003         indices[0] = 0;
58004         indices[1] = 1;
58005         indices[2] = 3;
58006         indices[3] = 1;
58007         indices[4] = 2;
58008         indices[5] = 3;
58009         let geometry = new BufferGeometry();
58010         geometry.setAttribute("position", new BufferAttribute(positions, 3));
58011         geometry.setIndex(new BufferAttribute(indices, 1));
58012         return geometry;
58013     }
58014 }
58015
58016 class MeshScene {
58017     constructor() {
58018         this._planes = {};
58019         this._planesOld = {};
58020         this._planesPeriphery = {};
58021         this._scene = new Scene();
58022         this._sceneOld = new Scene();
58023         this._scenePeriphery = new Scene();
58024     }
58025     get planes() {
58026         return this._planes;
58027     }
58028     get planesOld() {
58029         return this._planesOld;
58030     }
58031     get planesPeriphery() {
58032         return this._planesPeriphery;
58033     }
58034     get scene() {
58035         return this._scene;
58036     }
58037     get sceneOld() {
58038         return this._sceneOld;
58039     }
58040     get scenePeriphery() {
58041         return this._scenePeriphery;
58042     }
58043     updateImagePlanes(planes) {
58044         this._dispose(this._planesOld, this.sceneOld);
58045         for (const key in this._planes) {
58046             if (!this._planes.hasOwnProperty(key)) {
58047                 continue;
58048             }
58049             const plane = this._planes[key];
58050             this._scene.remove(plane);
58051             this._sceneOld.add(plane);
58052         }
58053         for (const key in planes) {
58054             if (!planes.hasOwnProperty(key)) {
58055                 continue;
58056             }
58057             this._scene.add(planes[key]);
58058         }
58059         this._planesOld = this._planes;
58060         this._planes = planes;
58061     }
58062     addImagePlanes(planes) {
58063         for (const key in planes) {
58064             if (!planes.hasOwnProperty(key)) {
58065                 continue;
58066             }
58067             const plane = planes[key];
58068             this._scene.add(plane);
58069             this._planes[key] = plane;
58070         }
58071     }
58072     addImagePlanesOld(planes) {
58073         for (const key in planes) {
58074             if (!planes.hasOwnProperty(key)) {
58075                 continue;
58076             }
58077             const plane = planes[key];
58078             this._sceneOld.add(plane);
58079             this._planesOld[key] = plane;
58080         }
58081     }
58082     setImagePlanes(planes) {
58083         this._clear();
58084         this.addImagePlanes(planes);
58085     }
58086     addPeripheryPlanes(planes) {
58087         for (const key in planes) {
58088             if (!planes.hasOwnProperty(key)) {
58089                 continue;
58090             }
58091             const plane = planes[key];
58092             this._scenePeriphery.add(plane);
58093             this._planesPeriphery[key] = plane;
58094         }
58095     }
58096     setPeripheryPlanes(planes) {
58097         this._clearPeriphery();
58098         this.addPeripheryPlanes(planes);
58099     }
58100     setImagePlanesOld(planes) {
58101         this._clearOld();
58102         this.addImagePlanesOld(planes);
58103     }
58104     clear() {
58105         this._clear();
58106         this._clearOld();
58107     }
58108     _clear() {
58109         this._dispose(this._planes, this._scene);
58110         this._planes = {};
58111     }
58112     _clearOld() {
58113         this._dispose(this._planesOld, this._sceneOld);
58114         this._planesOld = {};
58115     }
58116     _clearPeriphery() {
58117         this._dispose(this._planesPeriphery, this._scenePeriphery);
58118         this._planesPeriphery = {};
58119     }
58120     _dispose(planes, scene) {
58121         for (const key in planes) {
58122             if (!planes.hasOwnProperty(key)) {
58123                 continue;
58124             }
58125             const plane = planes[key];
58126             scene.remove(plane);
58127             plane.geometry.dispose();
58128             plane.material.dispose();
58129             let texture = plane.material.uniforms.projectorTex.value;
58130             if (texture != null) {
58131                 texture.dispose();
58132             }
58133         }
58134     }
58135 }
58136
58137 class ImageGLRenderer {
58138     constructor() {
58139         this._factory = new MeshFactory();
58140         this._scene = new MeshScene();
58141         this._alpha = 0;
58142         this._alphaOld = 0;
58143         this._fadeOutSpeed = 0.05;
58144         this._currentKey = null;
58145         this._previousKey = null;
58146         this._providerDisposers = {};
58147         this._frameId = 0;
58148         this._needsRender = false;
58149     }
58150     get frameId() {
58151         return this._frameId;
58152     }
58153     get needsRender() {
58154         return this._needsRender;
58155     }
58156     indicateNeedsRender() {
58157         this._needsRender = true;
58158     }
58159     addPeripheryPlane(image, transform) {
58160         const mesh = this._factory.createMesh(image, transform);
58161         const planes = {};
58162         planes[image.id] = mesh;
58163         this._scene.addPeripheryPlanes(planes);
58164         this._needsRender = true;
58165     }
58166     clearPeripheryPlanes() {
58167         this._scene.setPeripheryPlanes({});
58168         this._needsRender = true;
58169     }
58170     updateFrame(frame) {
58171         this._updateFrameId(frame.id);
58172         this._needsRender = this._updateAlpha(frame.state.alpha) || this._needsRender;
58173         this._needsRender = this._updateAlphaOld(frame.state.alpha) || this._needsRender;
58174         this._needsRender = this._updateImagePlanes(frame.state) || this._needsRender;
58175     }
58176     setTextureProvider(key, provider) {
58177         if (key !== this._currentKey) {
58178             return;
58179         }
58180         let createdSubscription = provider.textureCreated$
58181             .subscribe((texture) => {
58182             this._updateTexture(texture);
58183         });
58184         let updatedSubscription = provider.textureUpdated$
58185             .subscribe((updated) => {
58186             this._needsRender = true;
58187         });
58188         let dispose = () => {
58189             createdSubscription.unsubscribe();
58190             updatedSubscription.unsubscribe();
58191             provider.dispose();
58192         };
58193         if (key in this._providerDisposers) {
58194             let disposeProvider = this._providerDisposers[key];
58195             disposeProvider();
58196             delete this._providerDisposers[key];
58197         }
58198         this._providerDisposers[key] = dispose;
58199     }
58200     updateTextureImage(imageElement, image) {
58201         this._needsRender = true;
58202         const planes = this._extend({}, this._scene.planes, this._scene.planesOld, this._scene.planesPeriphery);
58203         for (const key in planes) {
58204             if (!planes.hasOwnProperty(key)) {
58205                 continue;
58206             }
58207             if (key !== image.id) {
58208                 continue;
58209             }
58210             const plane = planes[key];
58211             let material = plane.material;
58212             let texture = material.uniforms.projectorTex.value;
58213             texture.image = imageElement;
58214             texture.needsUpdate = true;
58215         }
58216     }
58217     render(perspectiveCamera, renderer) {
58218         const planes = this._scene.planes;
58219         const planesOld = this._scene.planesOld;
58220         const planesPeriphery = this._scene.planesPeriphery;
58221         const planeAlpha = Object.keys(planesOld).length ? 1 : this._alpha;
58222         const peripheryAlpha = Object.keys(planesOld).length ? 1 : Math.floor(this._alpha);
58223         for (const key in planes) {
58224             if (!planes.hasOwnProperty(key)) {
58225                 continue;
58226             }
58227             const plane = planes[key];
58228             plane.material.uniforms.opacity.value = planeAlpha;
58229         }
58230         for (const key in planesOld) {
58231             if (!planesOld.hasOwnProperty(key)) {
58232                 continue;
58233             }
58234             const plane = planesOld[key];
58235             plane.material.uniforms.opacity.value = this._alphaOld;
58236         }
58237         for (const key in planesPeriphery) {
58238             if (!planesPeriphery.hasOwnProperty(key)) {
58239                 continue;
58240             }
58241             const plane = planesPeriphery[key];
58242             plane.material.uniforms.opacity.value = peripheryAlpha;
58243         }
58244         renderer.render(this._scene.scenePeriphery, perspectiveCamera);
58245         renderer.render(this._scene.scene, perspectiveCamera);
58246         renderer.render(this._scene.sceneOld, perspectiveCamera);
58247         for (const key in planes) {
58248             if (!planes.hasOwnProperty(key)) {
58249                 continue;
58250             }
58251             const plane = planes[key];
58252             plane.material.uniforms.opacity.value = this._alpha;
58253         }
58254         renderer.render(this._scene.scene, perspectiveCamera);
58255     }
58256     clearNeedsRender() {
58257         this._needsRender = false;
58258     }
58259     dispose() {
58260         this._scene.clear();
58261     }
58262     _updateFrameId(frameId) {
58263         this._frameId = frameId;
58264     }
58265     _updateAlpha(alpha) {
58266         if (alpha === this._alpha) {
58267             return false;
58268         }
58269         this._alpha = alpha;
58270         return true;
58271     }
58272     _updateAlphaOld(alpha) {
58273         if (alpha < 1 || this._alphaOld === 0) {
58274             return false;
58275         }
58276         this._alphaOld = Math.max(0, this._alphaOld - this._fadeOutSpeed);
58277         return true;
58278     }
58279     _updateImagePlanes(state) {
58280         if (state.currentImage == null ||
58281             state.currentImage.id === this._currentKey) {
58282             return false;
58283         }
58284         let previousKey = state.previousImage != null ? state.previousImage.id : null;
58285         let currentKey = state.currentImage.id;
58286         if (this._previousKey !== previousKey &&
58287             this._previousKey !== currentKey &&
58288             this._previousKey in this._providerDisposers) {
58289             let disposeProvider = this._providerDisposers[this._previousKey];
58290             disposeProvider();
58291             delete this._providerDisposers[this._previousKey];
58292         }
58293         if (previousKey != null) {
58294             if (previousKey !== this._currentKey && previousKey !== this._previousKey) {
58295                 let previousMesh = this._factory.createMesh(state.previousImage, state.previousTransform);
58296                 const previousPlanes = {};
58297                 previousPlanes[previousKey] = previousMesh;
58298                 this._scene.updateImagePlanes(previousPlanes);
58299             }
58300             this._previousKey = previousKey;
58301         }
58302         this._currentKey = currentKey;
58303         let currentMesh = this._factory.createMesh(state.currentImage, state.currentTransform);
58304         const planes = {};
58305         planes[currentKey] = currentMesh;
58306         this._scene.updateImagePlanes(planes);
58307         this._alphaOld = 1;
58308         return true;
58309     }
58310     _updateTexture(texture) {
58311         this._needsRender = true;
58312         const planes = this._scene.planes;
58313         for (const key in planes) {
58314             if (!planes.hasOwnProperty(key)) {
58315                 continue;
58316             }
58317             const plane = planes[key];
58318             let material = plane.material;
58319             let oldTexture = material.uniforms.projectorTex.value;
58320             material.uniforms.projectorTex.value = null;
58321             oldTexture.dispose();
58322             material.uniforms.projectorTex.value = texture;
58323         }
58324     }
58325     _extend(dest, ...sources) {
58326         for (const src of sources) {
58327             for (const k in src) {
58328                 if (!src.hasOwnProperty(k)) {
58329                     continue;
58330                 }
58331                 dest[k] = src[k];
58332             }
58333         }
58334         return dest;
58335     }
58336 }
58337
58338 var RenderPass$1;
58339 (function (RenderPass) {
58340     RenderPass[RenderPass["Background"] = 0] = "Background";
58341     RenderPass[RenderPass["Opaque"] = 1] = "Opaque";
58342 })(RenderPass$1 || (RenderPass$1 = {}));
58343
58344 /**
58345  * @class ImageTileLoader
58346  *
58347  * @classdesc Represents a loader of image tiles.
58348  */
58349 class TileLoader {
58350     /**
58351      * Create a new image image tile loader instance.
58352      *
58353      * @param {APIWrapper} _api - API wrapper.
58354      */
58355     constructor(_api) {
58356         this._api = _api;
58357         this._urls$ = new Map();
58358     }
58359     /**
58360      * Retrieve an image tile.
58361      *
58362      * @param {string} url - URL to the image tile resource
58363      */
58364     getImage$(url) {
58365         let aborter;
58366         const abort = new Promise((_, reject) => {
58367             aborter = reject;
58368         });
58369         return [Observable.create((subscriber) => {
58370                 this._api.data
58371                     .getImageBuffer(url, abort)
58372                     .then((buffer) => {
58373                     aborter = null;
58374                     const image = new Image();
58375                     image.crossOrigin = "Anonymous";
58376                     image.onload = () => {
58377                         window.URL.revokeObjectURL(image.src);
58378                         subscriber.next(image);
58379                         subscriber.complete();
58380                     };
58381                     image.onerror = () => {
58382                         aborter = null;
58383                         window.URL.revokeObjectURL(image.src);
58384                         subscriber.error(new Error(`Failed to load image tile`));
58385                     };
58386                     const blob = new Blob([buffer]);
58387                     image.src = window.URL.createObjectURL(blob);
58388                 }, (error) => {
58389                     aborter = null;
58390                     subscriber.error(error);
58391                 });
58392             }),
58393             () => {
58394                 if (!!aborter) {
58395                     aborter();
58396                 }
58397             }];
58398     }
58399     getURLs$(imageId, level) {
58400         const uniqueId = this._inventId(imageId, level);
58401         if (this._urls$.has(uniqueId)) {
58402             return this._urls$.get(uniqueId);
58403         }
58404         const request = { imageId, z: level };
58405         const urls$ = this._api
58406             .getImageTiles$(request)
58407             .pipe(map(contract => contract.node), finalize(() => {
58408             this._urls$.delete(uniqueId);
58409         }), publish(), refCount());
58410         this._urls$.set(uniqueId, urls$);
58411         return urls$;
58412     }
58413     _inventId(imageId, level) {
58414         return `${imageId}-${level}`;
58415     }
58416 }
58417
58418 /**
58419  * @class ImageTileStore
58420  *
58421  * @classdesc Represents a store for image tiles.
58422  */
58423 class TileStore {
58424     /**
58425      * Create a new image image tile store instance.
58426      */
58427     constructor() {
58428         this._tiles = new Map();
58429         this._urlLevels = new Set();
58430         this._urls = new Map();
58431     }
58432     /**
58433      * Add an image tile to the store.
58434      *
58435      * @param {string} id - The identifier for the image tile.
58436      * @param {HTMLImageElement} image - The image tile.
58437      */
58438     add(id, image) {
58439         if (this._tiles.has(id)) {
58440             throw new Error(`Image tile already stored (${id})`);
58441         }
58442         this._tiles.set(id, image);
58443     }
58444     addURLs(level, ents) {
58445         const urls = this._urls;
58446         for (const ent of ents) {
58447             const id = this.inventId(ent);
58448             if (this._urls.has(id)) {
58449                 throw new Error(`URL already stored (${id})`);
58450             }
58451             urls.set(id, ent.url);
58452         }
58453         this._urlLevels.add(level);
58454     }
58455     /**
58456      * Dispose the store.
58457      *
58458      * @description Disposes all cached assets.
58459      */
58460     dispose() {
58461         this._tiles
58462             .forEach(image => window.URL.revokeObjectURL(image.src));
58463         this._tiles.clear();
58464         this._urls.clear();
58465         this._urlLevels.clear();
58466     }
58467     /**
58468      * Get an image tile from the store.
58469      *
58470      * @param {string} id - The identifier for the tile.
58471      * @param {number} level - The level of the tile.
58472      */
58473     get(id) {
58474         return this._tiles.get(id);
58475     }
58476     getURL(id) {
58477         return this._urls.get(id);
58478     }
58479     /**
58480      * Check if an image tile exist in the store.
58481      *
58482      * @param {string} id - The identifier for the tile.
58483      * @param {number} level - The level of the tile.
58484      */
58485     has(id) {
58486         return this._tiles.has(id);
58487     }
58488     hasURL(id) {
58489         return this._urls.has(id);
58490     }
58491     hasURLLevel(level) {
58492         return this._urlLevels.has(level);
58493     }
58494     /**
58495      * Create a unique tile id from a tile.
58496      *
58497      * @description Tile ids are used as a hash for
58498      * storing the tile in a dictionary.
58499      *
58500      * @param {ImageTileEnt} tile - The tile.
58501      * @returns {string} Unique id.
58502      */
58503     inventId(tile) {
58504         return `${tile.z}-${tile.x}-${tile.y}`;
58505     }
58506 }
58507
58508 /**
58509  * @class RegionOfInterestCalculator
58510  *
58511  * @classdesc Represents a calculator for regions of interest.
58512  */
58513 class RegionOfInterestCalculator {
58514     constructor() {
58515         this._viewportCoords = new ViewportCoords();
58516     }
58517     /**
58518      * Compute a region of interest based on the current render camera
58519      * and the viewport size.
58520      *
58521      * @param {RenderCamera} renderCamera - Render camera used for unprojections.
58522      * @param {ViewportSize} size - Viewport size in pixels.
58523      * @param {Transform} transform - Transform used for projections.
58524      *
58525      * @returns {TileRegionOfInterest} A region of interest.
58526      */
58527     computeRegionOfInterest(renderCamera, size, transform) {
58528         const viewportBoundaryPoints = this._viewportBoundaryPoints(4);
58529         const bbox = this._viewportPointsBoundingBox(viewportBoundaryPoints, renderCamera, transform);
58530         this._clipBoundingBox(bbox);
58531         const viewportPixelWidth = 2 / size.width;
58532         const viewportPixelHeight = 2 / size.height;
58533         const centralViewportPixel = [
58534             [-0.5 * viewportPixelWidth, 0.5 * viewportPixelHeight],
58535             [0.5 * viewportPixelWidth, 0.5 * viewportPixelHeight],
58536             [0.5 * viewportPixelWidth, -0.5 * viewportPixelHeight],
58537             [-0.5 * viewportPixelWidth, -0.5 * viewportPixelHeight],
58538         ];
58539         const cpbox = this._viewportPointsBoundingBox(centralViewportPixel, renderCamera, transform);
58540         const inverted = cpbox.minX < cpbox.maxX;
58541         return {
58542             bbox: bbox,
58543             pixelHeight: cpbox.maxY - cpbox.minY,
58544             pixelWidth: cpbox.maxX - cpbox.minX + (inverted ? 0 : 1),
58545         };
58546     }
58547     _viewportBoundaryPoints(pointsPerSide) {
58548         const points = [];
58549         const os = [[-1, 1], [1, 1], [1, -1], [-1, -1]];
58550         const ds = [[2, 0], [0, -2], [-2, 0], [0, 2]];
58551         for (let side = 0; side < 4; ++side) {
58552             const o = os[side];
58553             const d = ds[side];
58554             for (let i = 0; i < pointsPerSide; ++i) {
58555                 points.push([o[0] + d[0] * i / pointsPerSide,
58556                     o[1] + d[1] * i / pointsPerSide]);
58557             }
58558         }
58559         return points;
58560     }
58561     _viewportPointsBoundingBox(viewportPoints, renderCamera, transform) {
58562         const basicPoints = viewportPoints
58563             .map((point) => {
58564             return this._viewportCoords
58565                 .viewportToBasic(point[0], point[1], transform, renderCamera.perspective);
58566         });
58567         if (isSpherical(transform.cameraType)) {
58568             return this._boundingBoxSpherical(basicPoints);
58569         }
58570         else {
58571             return this._boundingBox(basicPoints);
58572         }
58573     }
58574     _boundingBox(points) {
58575         const bbox = {
58576             maxX: Number.NEGATIVE_INFINITY,
58577             maxY: Number.NEGATIVE_INFINITY,
58578             minX: Number.POSITIVE_INFINITY,
58579             minY: Number.POSITIVE_INFINITY,
58580         };
58581         for (let i = 0; i < points.length; ++i) {
58582             bbox.minX = Math.min(bbox.minX, points[i][0]);
58583             bbox.maxX = Math.max(bbox.maxX, points[i][0]);
58584             bbox.minY = Math.min(bbox.minY, points[i][1]);
58585             bbox.maxY = Math.max(bbox.maxY, points[i][1]);
58586         }
58587         return bbox;
58588     }
58589     _boundingBoxSpherical(points) {
58590         const xs = [];
58591         const ys = [];
58592         for (let i = 0; i < points.length; ++i) {
58593             xs.push(points[i][0]);
58594             ys.push(points[i][1]);
58595         }
58596         xs.sort((a, b) => { return this._sign(a - b); });
58597         ys.sort((a, b) => { return this._sign(a - b); });
58598         const intervalX = this._intervalSpherical(xs);
58599         return {
58600             maxX: intervalX[1],
58601             maxY: ys[ys.length - 1],
58602             minX: intervalX[0],
58603             minY: ys[0],
58604         };
58605     }
58606     /**
58607      * Find the max interval between consecutive numbers.
58608      * Assumes numbers are between 0 and 1, sorted and that
58609      * x is equivalent to x + 1.
58610      */
58611     _intervalSpherical(xs) {
58612         let maxdx = 0;
58613         let maxi = -1;
58614         for (let i = 0; i < xs.length - 1; ++i) {
58615             const dx = xs[i + 1] - xs[i];
58616             if (dx > maxdx) {
58617                 maxdx = dx;
58618                 maxi = i;
58619             }
58620         }
58621         const loopdx = xs[0] + 1 - xs[xs.length - 1];
58622         if (loopdx > maxdx) {
58623             return [xs[0], xs[xs.length - 1]];
58624         }
58625         else {
58626             return [xs[maxi + 1], xs[maxi]];
58627         }
58628     }
58629     _clipBoundingBox(bbox) {
58630         bbox.minX = Math.max(0, Math.min(1, bbox.minX));
58631         bbox.maxX = Math.max(0, Math.min(1, bbox.maxX));
58632         bbox.minY = Math.max(0, Math.min(1, bbox.minY));
58633         bbox.maxY = Math.max(0, Math.min(1, bbox.maxY));
58634     }
58635     _sign(n) {
58636         return n > 0 ? 1 : n < 0 ? -1 : 0;
58637     }
58638 }
58639
58640 const TILE_MIN_REQUEST_LEVEL = 11;
58641 const TILE_SIZE = 1024;
58642
58643 function clamp(value, min, max) {
58644     return Math.max(min, Math.min(max, value));
58645 }
58646 function levelTilePixelSize(level) {
58647     return TILE_SIZE / levelScale(level);
58648 }
58649 function levelScale(level) {
58650     return Math.pow(2, level.z - level.max);
58651 }
58652 function rawImageLevel(size) {
58653     const s = Math.max(size.w, size.h);
58654     return Math.log(s) / Math.log(2);
58655 }
58656 function baseImageLevel(size) {
58657     return Math.ceil(rawImageLevel(size));
58658 }
58659 function clampedImageLevel(size, min, max) {
58660     return Math.max(min, Math.min(max, baseImageLevel(size)));
58661 }
58662 function basicToTileCoords2D(basic, size, level) {
58663     const tilePixelSize = levelTilePixelSize(level);
58664     const w = size.w;
58665     const h = size.h;
58666     const maxX = Math.ceil(w / tilePixelSize) - 1;
58667     const maxY = Math.ceil(h / tilePixelSize) - 1;
58668     const x = clamp(Math.floor(w * basic[0] / tilePixelSize), 0, maxX);
58669     const y = clamp(Math.floor(h * basic[1] / tilePixelSize), 0, maxY);
58670     return { x, y };
58671 }
58672 function tileToPixelCoords2D(tile, size, level) {
58673     const scale = 1 / levelScale(level);
58674     const scaledTS = scale * TILE_SIZE;
58675     const x = scaledTS * tile.x;
58676     const y = scaledTS * tile.y;
58677     const w = Math.min(scaledTS, size.w - x);
58678     const h = Math.min(scaledTS, size.h - y);
58679     return { h, x, y, w };
58680 }
58681 function hasOverlap1D(low, base, scale) {
58682     return (scale * low <= base &&
58683         base < scale * (low + 1));
58684 }
58685 function hasOverlap2D(tile1, tile2) {
58686     if (tile1.z === tile2.z) {
58687         return tile1.x === tile2.x && tile1.y === tile2.y;
58688     }
58689     const low = tile1.z < tile2.z ? tile1 : tile2;
58690     const base = tile1.z < tile2.z ? tile2 : tile1;
58691     const scale = 1 / levelScale({ max: base.z, z: low.z });
58692     const overlapX = hasOverlap1D(low.x, base.x, scale);
58693     const overlapY = hasOverlap1D(low.y, base.y, scale);
58694     return overlapX && overlapY;
58695 }
58696 function cornersToTilesCoords2D(topLeft, bottomRight, size, level) {
58697     const xs = [];
58698     if (topLeft.x > bottomRight.x) {
58699         const tilePixelSize = levelTilePixelSize(level);
58700         const maxX = Math.ceil(size.w / tilePixelSize) - 1;
58701         for (let x = topLeft.x; x <= maxX; x++) {
58702             xs.push(x);
58703         }
58704         for (let x = 0; x <= bottomRight.x; x++) {
58705             xs.push(x);
58706         }
58707     }
58708     else {
58709         for (let x = topLeft.x; x <= bottomRight.x; x++) {
58710             xs.push(x);
58711         }
58712     }
58713     const tiles = [];
58714     for (const x of xs) {
58715         for (let y = topLeft.y; y <= bottomRight.y; y++) {
58716             tiles.push({ x, y });
58717         }
58718     }
58719     return tiles;
58720 }
58721 function verifySize(size) {
58722     return size.w > 0 && size.h > 0;
58723 }
58724
58725 /**
58726  * @class TextureProvider
58727  *
58728  * @classdesc Represents a provider of textures.
58729  */
58730 class TextureProvider {
58731     /**
58732      * Create a new image texture provider instance.
58733      *
58734      * @param {string} imageId - The identifier of the image for which to request tiles.
58735      * @param {number} width - The full width of the original image.
58736      * @param {number} height - The full height of the original image.
58737      * @param {HTMLImageElement} background - Image to use as background.
58738      * @param {TileLoader} loader - Loader for retrieving tiles.
58739      * @param {TileStore} store - Store for saving tiles.
58740      * @param {THREE.WebGLRenderer} renderer - Renderer used for rendering tiles to texture.
58741      */
58742     constructor(imageId, width, height, background, loader, store, renderer) {
58743         const size = { h: height, w: width };
58744         if (!verifySize(size)) {
58745             console.warn(`Original image size (${width}, ${height}) ` +
58746                 `is invalid (${imageId}). Tiles will not be loaded.`);
58747         }
58748         this._imageId = imageId;
58749         this._size = size;
58750         this._level = {
58751             max: baseImageLevel(this._size),
58752             z: -1,
58753         };
58754         this._holder = new SubscriptionHolder();
58755         this._updated$ = new Subject();
58756         this._createdSubject$ = new Subject();
58757         this._created$ = this._createdSubject$
58758             .pipe(publishReplay(1), refCount());
58759         this._holder.push(this._created$.subscribe(() => { }));
58760         this._hasSubject$ = new Subject();
58761         this._has$ = this._hasSubject$
58762             .pipe(startWith(false), publishReplay(1), refCount());
58763         this._holder.push(this._has$.subscribe(() => { }));
58764         this._renderedLevel = new Set();
58765         this._rendered = new Map();
58766         this._subscriptions = new Map();
58767         this._urlSubscriptions = new Map();
58768         this._loader = loader;
58769         this._store = store;
58770         this._background = background;
58771         this._renderer = renderer;
58772         this._aborts = [];
58773         this._render = null;
58774         this._disposed = false;
58775     }
58776     /**
58777      * Get disposed.
58778      *
58779      * @returns {boolean} Value indicating whether provider has
58780      * been disposed.
58781      */
58782     get disposed() {
58783         return this._disposed;
58784     }
58785     /**
58786      * Get hasTexture$.
58787      *
58788      * @returns {Observable<boolean>} Observable emitting
58789      * values indicating when the existance of a texture
58790      * changes.
58791      */
58792     get hasTexture$() {
58793         return this._has$;
58794     }
58795     /**
58796      * Get id.
58797      *
58798      * @returns {boolean} The identifier of the image for
58799      * which to render textures.
58800      */
58801     get id() {
58802         return this._imageId;
58803     }
58804     /**
58805      * Get textureUpdated$.
58806      *
58807      * @returns {Observable<boolean>} Observable emitting
58808      * values when an existing texture has been updated.
58809      */
58810     get textureUpdated$() {
58811         return this._updated$;
58812     }
58813     /**
58814      * Get textureCreated$.
58815      *
58816      * @returns {Observable<boolean>} Observable emitting
58817      * values when a new texture has been created.
58818      */
58819     get textureCreated$() {
58820         return this._created$;
58821     }
58822     /**
58823      * Abort all outstanding image tile requests.
58824      */
58825     abort() {
58826         this._subscriptions.forEach(sub => sub.unsubscribe());
58827         this._subscriptions.clear();
58828         for (const abort of this._aborts) {
58829             abort();
58830         }
58831         this._aborts = [];
58832     }
58833     /**
58834      * Dispose the provider.
58835      *
58836      * @description Disposes all cached assets and
58837      * aborts all outstanding image tile requests.
58838      */
58839     dispose() {
58840         if (this._disposed) {
58841             console.warn(`Texture already disposed (${this._imageId})`);
58842             return;
58843         }
58844         this._urlSubscriptions.forEach(sub => sub.unsubscribe());
58845         this._urlSubscriptions.clear();
58846         this.abort();
58847         if (this._render != null) {
58848             this._render.target.dispose();
58849             this._render.target = null;
58850             this._render.camera = null;
58851             this._render = null;
58852         }
58853         this._store.dispose();
58854         this._holder.unsubscribe();
58855         this._renderedLevel.clear();
58856         this._background = null;
58857         this._renderer = null;
58858         this._disposed = true;
58859     }
58860     /**
58861      * Set the region of interest.
58862      *
58863      * @description When the region of interest is set the
58864      * the tile level is determined and tiles for the region
58865      * are fetched from the store or the loader and renderedLevel
58866      * to the texture.
58867      *
58868      * @param {TileRegionOfInterest} roi - Spatial edges to cache.
58869      */
58870     setRegionOfInterest(roi) {
58871         if (!verifySize(this._size)) {
58872             return;
58873         }
58874         const virtualWidth = 1 / roi.pixelWidth;
58875         const virtualHeight = 1 / roi.pixelHeight;
58876         const level = clampedImageLevel({ h: virtualHeight, w: virtualWidth }, TILE_MIN_REQUEST_LEVEL, this._level.max);
58877         if (level !== this._level.z) {
58878             this.abort();
58879             this._level.z = level;
58880             this._renderedLevel.clear();
58881             this._rendered
58882                 .forEach((tile, id) => {
58883                 if (tile.z !== level) {
58884                     return;
58885                 }
58886                 this._renderedLevel.add(id);
58887             });
58888         }
58889         if (this._render == null) {
58890             this._initRender();
58891         }
58892         const topLeft = basicToTileCoords2D([roi.bbox.minX, roi.bbox.minY], this._size, this._level);
58893         const bottomRight = basicToTileCoords2D([roi.bbox.maxX, roi.bbox.maxY], this._size, this._level);
58894         const tiles = cornersToTilesCoords2D(topLeft, bottomRight, this._size, this._level);
58895         this._fetchTiles(level, tiles);
58896     }
58897     /**
58898      * Retrieve an image tile.
58899      *
58900      * @description Retrieve an image tile and render it to the
58901      * texture. Add the tile to the store and emit to the updated
58902      * observable.
58903      *
58904      * @param {ImageTileEnt} tile - The tile ent.
58905      */
58906     _fetchTile(tile) {
58907         const getTile = this._loader.getImage$(tile.url);
58908         const tile$ = getTile[0];
58909         const abort = getTile[1];
58910         this._aborts.push(abort);
58911         const tileId = this._store.inventId(tile);
58912         const subscription = tile$.subscribe((image) => {
58913             const pixels = tileToPixelCoords2D(tile, this._size, this._level);
58914             this._renderToTarget(pixels, image);
58915             this._subscriptions.delete(tileId);
58916             this._removeFromArray(abort, this._aborts);
58917             this._markRendered(tile);
58918             this._store.add(tileId, image);
58919             this._updated$.next(true);
58920         }, (error) => {
58921             this._subscriptions.delete(tileId);
58922             this._removeFromArray(abort, this._aborts);
58923             console.error(error);
58924         });
58925         if (!subscription.closed) {
58926             this._subscriptions.set(tileId, subscription);
58927         }
58928     }
58929     /**
58930      * Fetch image tiles.
58931      *
58932      * @description Retrieve a image tiles and render them to the
58933      * texture. Retrieve from store if it exists, otherwise retrieve
58934      * from loader.
58935      *
58936      * @param {Array<TileCoords2D>} tiles - Array of tile coordinates to
58937      * retrieve.
58938      */
58939     _fetchTiles(level, tiles) {
58940         const urls$ = this._store.hasURLLevel(level) ?
58941             of(undefined) :
58942             this._loader
58943                 .getURLs$(this._imageId, level)
58944                 .pipe(tap(ents => {
58945                 if (!this._store.hasURLLevel(level)) {
58946                     this._store.addURLs(level, ents);
58947                 }
58948             }));
58949         const subscription = urls$.subscribe(() => {
58950             if (level !== this._level.z) {
58951                 return;
58952             }
58953             for (const tile of tiles) {
58954                 const ent = {
58955                     x: tile.x,
58956                     y: tile.y,
58957                     z: level,
58958                     url: null,
58959                 };
58960                 const id = this._store.inventId(ent);
58961                 if (this._renderedLevel.has(id) ||
58962                     this._subscriptions.has(id)) {
58963                     continue;
58964                 }
58965                 if (this._store.has(id)) {
58966                     const pixels = tileToPixelCoords2D(tile, this._size, this._level);
58967                     this._renderToTarget(pixels, this._store.get(id));
58968                     this._markRendered(ent);
58969                     this._updated$.next(true);
58970                     continue;
58971                 }
58972                 ent.url = this._store.getURL(id);
58973                 this._fetchTile(ent);
58974             }
58975             this._urlSubscriptions.delete(level);
58976         }, (error) => {
58977             this._urlSubscriptions.delete(level);
58978             console.error(error);
58979         });
58980         if (!subscription.closed) {
58981             this._urlSubscriptions.set(level, subscription);
58982         }
58983     }
58984     _initRender() {
58985         const dx = this._size.w / 2;
58986         const dy = this._size.h / 2;
58987         const near = -1;
58988         const far = 1;
58989         const camera = new OrthographicCamera(-dx, dx, dy, -dy, near, far);
58990         camera.position.z = 1;
58991         const gl = this._renderer.getContext();
58992         const maxTextureSize = gl.getParameter(gl.MAX_TEXTURE_SIZE);
58993         const backgroundSize = Math.max(this._size.w, this._size.h);
58994         const scale = maxTextureSize > backgroundSize ?
58995             1 : maxTextureSize / backgroundSize;
58996         const targetWidth = Math.floor(scale * this._size.w);
58997         const targetHeight = Math.floor(scale * this._size.h);
58998         const target = new WebGLRenderTarget(targetWidth, targetHeight, {
58999             depthBuffer: false,
59000             format: RGBFormat,
59001             magFilter: LinearFilter,
59002             minFilter: LinearFilter,
59003             stencilBuffer: false,
59004         });
59005         this._render = { camera, target };
59006         const pixels = tileToPixelCoords2D({ x: 0, y: 0 }, this._size, { max: this._level.max, z: 0 });
59007         this._renderToTarget(pixels, this._background);
59008         this._createdSubject$.next(target.texture);
59009         this._hasSubject$.next(true);
59010     }
59011     /**
59012      * Mark a tile as rendered.
59013      *
59014      * @description Clears tiles marked as rendered in other
59015      * levels of the tile pyramid if they overlap the
59016      * newly rendered tile.
59017      *
59018      * @param {Arrary<number>} tile - The tile ent.
59019      */
59020     _markRendered(tile) {
59021         const others = Array.from(this._rendered.entries())
59022             .filter(([_, t]) => {
59023             return t.z !== tile.z;
59024         });
59025         for (const [otherId, other] of others) {
59026             if (hasOverlap2D(tile, other)) {
59027                 this._rendered.delete(otherId);
59028             }
59029         }
59030         const id = this._store.inventId(tile);
59031         this._rendered.set(id, tile);
59032         this._renderedLevel.add(id);
59033     }
59034     /**
59035      * Remove an item from an array if it exists in array.
59036      *
59037      * @param {T} item - Item to remove.
59038      * @param {Array<T>} array - Array from which item should be removed.
59039      */
59040     _removeFromArray(item, array) {
59041         const index = array.indexOf(item);
59042         if (index !== -1) {
59043             array.splice(index, 1);
59044         }
59045     }
59046     /**
59047      * Render an image tile to the target texture.
59048      *
59049      * @param {ImageTileEnt} tile - Tile ent.
59050      * @param {HTMLImageElement} image - The image tile to render.
59051      */
59052     _renderToTarget(pixel, image) {
59053         const texture = new Texture(image);
59054         texture.minFilter = LinearFilter;
59055         texture.needsUpdate = true;
59056         const geometry = new PlaneGeometry(pixel.w, pixel.h);
59057         const material = new MeshBasicMaterial({
59058             map: texture,
59059             side: FrontSide,
59060         });
59061         const mesh = new Mesh(geometry, material);
59062         mesh.position.x = -this._size.w / 2 + pixel.x + pixel.w / 2;
59063         mesh.position.y = this._size.h / 2 - pixel.y - pixel.h / 2;
59064         const scene = new Scene();
59065         scene.add(mesh);
59066         const target = this._renderer.getRenderTarget();
59067         this._renderer.resetState();
59068         this._renderer.setRenderTarget(this._render.target);
59069         this._renderer.render(scene, this._render.camera);
59070         this._renderer.setRenderTarget(target);
59071         scene.remove(mesh);
59072         geometry.dispose();
59073         material.dispose();
59074         texture.dispose();
59075     }
59076 }
59077
59078 var State;
59079 (function (State) {
59080     State[State["Custom"] = 0] = "Custom";
59081     State[State["Earth"] = 1] = "Earth";
59082     State[State["Traversing"] = 2] = "Traversing";
59083     State[State["Waiting"] = 3] = "Waiting";
59084     State[State["WaitingInteractively"] = 4] = "WaitingInteractively";
59085 })(State || (State = {}));
59086
59087 class ImageComponent extends Component {
59088     constructor(name, container, navigator) {
59089         super(name, container, navigator);
59090         this._imageTileLoader = new TileLoader(navigator.api);
59091         this._roiCalculator = new RegionOfInterestCalculator();
59092         this._rendererOperation$ = new Subject();
59093         this._rendererCreator$ = new Subject();
59094         this._rendererDisposer$ = new Subject();
59095         this._renderer$ = this._rendererOperation$.pipe(scan((renderer, operation) => {
59096             return operation(renderer);
59097         }, null), filter((renderer) => {
59098             return renderer != null;
59099         }), distinctUntilChanged(undefined, (renderer) => {
59100             return renderer.frameId;
59101         }));
59102         this._rendererCreator$.pipe(map(() => {
59103             return (renderer) => {
59104                 if (renderer != null) {
59105                     throw new Error("Multiple image plane states can not be created at the same time");
59106                 }
59107                 return new ImageGLRenderer();
59108             };
59109         }))
59110             .subscribe(this._rendererOperation$);
59111         this._rendererDisposer$.pipe(map(() => {
59112             return (renderer) => {
59113                 renderer.dispose();
59114                 return null;
59115             };
59116         }))
59117             .subscribe(this._rendererOperation$);
59118     }
59119     _activate() {
59120         const subs = this._subscriptions;
59121         subs.push(this._renderer$.pipe(map((renderer) => {
59122             const renderHash = {
59123                 name: this._name,
59124                 renderer: {
59125                     frameId: renderer.frameId,
59126                     needsRender: renderer.needsRender,
59127                     render: renderer.render.bind(renderer),
59128                     pass: RenderPass$1.Background,
59129                 },
59130             };
59131             renderer.clearNeedsRender();
59132             return renderHash;
59133         }))
59134             .subscribe(this._container.glRenderer.render$));
59135         this._rendererCreator$.next(null);
59136         subs.push(this._navigator.stateService.currentState$.pipe(map((frame) => {
59137             return (renderer) => {
59138                 renderer.updateFrame(frame);
59139                 return renderer;
59140             };
59141         }))
59142             .subscribe(this._rendererOperation$));
59143         const textureProvider$ = this._container.configurationService.imageTiling$.pipe(switchMap((active) => {
59144             return active ?
59145                 this._navigator.stateService.currentState$ :
59146                 new Subject();
59147         }), distinctUntilChanged(undefined, (frame) => {
59148             return frame.state.currentImage.id;
59149         }), withLatestFrom(this._container.glRenderer.webGLRenderer$), map(([frame, renderer]) => {
59150             const state = frame.state;
59151             const currentNode = state.currentImage;
59152             const currentTransform = state.currentTransform;
59153             return new TextureProvider(currentNode.id, currentTransform.basicWidth, currentTransform.basicHeight, currentNode.image, this._imageTileLoader, new TileStore(), renderer);
59154         }), publishReplay(1), refCount());
59155         subs.push(textureProvider$.subscribe(() => { }));
59156         subs.push(textureProvider$.pipe(map((provider) => {
59157             return (renderer) => {
59158                 renderer.setTextureProvider(provider.id, provider);
59159                 return renderer;
59160             };
59161         }))
59162             .subscribe(this._rendererOperation$));
59163         subs.push(textureProvider$.pipe(pairwise())
59164             .subscribe((pair) => {
59165             const previous = pair[0];
59166             previous.abort();
59167         }));
59168         const roiTrigger$ = this._container.configurationService.imageTiling$.pipe(switchMap((active) => {
59169             return active ?
59170                 combineLatest(this._navigator.stateService.state$, this._navigator.stateService.inTranslation$) :
59171                 new Subject();
59172         }), switchMap(([state, inTranslation]) => {
59173             const streetState = state === State.Traversing ||
59174                 state === State.Waiting ||
59175                 state === State.WaitingInteractively;
59176             const active = streetState && !inTranslation;
59177             return active ?
59178                 this._container.renderService.renderCameraFrame$ :
59179                 empty();
59180         }), map((camera) => {
59181             return {
59182                 camera,
59183                 height: camera.size.height.valueOf(),
59184                 lookat: camera.camera.lookat.clone(),
59185                 width: camera.size.width.valueOf(),
59186                 zoom: camera.zoom.valueOf(),
59187             };
59188         }), pairwise(), map(([pl0, pl1]) => {
59189             const stalled = pl0.width === pl1.width &&
59190                 pl0.height === pl1.height &&
59191                 pl0.zoom === pl1.zoom &&
59192                 pl0.lookat.equals(pl1.lookat);
59193             return { camera: pl1.camera, stalled };
59194         }), distinctUntilChanged((x, y) => {
59195             return x.stalled === y.stalled;
59196         }), filter((camera) => {
59197             return camera.stalled;
59198         }), withLatestFrom(this._container.renderService.size$, this._navigator.stateService.currentTransform$));
59199         subs.push(textureProvider$.pipe(switchMap((provider) => {
59200             return roiTrigger$.pipe(map(([stalled, size, transform]) => {
59201                 const camera = stalled.camera;
59202                 const basic = new ViewportCoords()
59203                     .viewportToBasic(0, 0, transform, camera.perspective);
59204                 if (basic[0] < 0 ||
59205                     basic[1] < 0 ||
59206                     basic[0] > 1 ||
59207                     basic[1] > 1) {
59208                     return undefined;
59209                 }
59210                 return [
59211                     this._roiCalculator
59212                         .computeRegionOfInterest(camera, size, transform),
59213                     provider,
59214                 ];
59215             }), filter((args) => {
59216                 return !!args;
59217             }));
59218         }), filter((args) => {
59219             return !args[1].disposed;
59220         }))
59221             .subscribe(([roi, provider]) => {
59222             provider.setRegionOfInterest(roi);
59223         }));
59224         const hasTexture$ = textureProvider$
59225             .pipe(switchMap((provider) => {
59226             return provider.hasTexture$;
59227         }), startWith(false), publishReplay(1), refCount());
59228         subs.push(hasTexture$.subscribe(() => { }));
59229         subs.push(this._navigator.panService.panImages$.pipe(filter((panNodes) => {
59230             return panNodes.length === 0;
59231         }), map(() => {
59232             return (renderer) => {
59233                 renderer.clearPeripheryPlanes();
59234                 return renderer;
59235             };
59236         }))
59237             .subscribe(this._rendererOperation$));
59238         const cachedPanNodes$ = this._navigator.panService.panImages$.pipe(switchMap((nts) => {
59239             return from(nts).pipe(mergeMap(([n, t]) => {
59240                 return combineLatest(this._navigator.graphService.cacheImage$(n.id).pipe(catchError((error) => {
59241                     console.error(`Failed to cache periphery image (${n.id})`, error);
59242                     return empty();
59243                 })), of(t));
59244             }));
59245         }), share());
59246         subs.push(cachedPanNodes$.pipe(map(([n, t]) => {
59247             return (renderer) => {
59248                 renderer.addPeripheryPlane(n, t);
59249                 return renderer;
59250             };
59251         }))
59252             .subscribe(this._rendererOperation$));
59253         subs.push(cachedPanNodes$.pipe(mergeMap(([n]) => {
59254             return n.cacheImage$().pipe(catchError(() => {
59255                 return empty();
59256             }));
59257         }), map((n) => {
59258             return (renderer) => {
59259                 renderer.updateTextureImage(n.image, n);
59260                 return renderer;
59261             };
59262         }))
59263             .subscribe(this._rendererOperation$));
59264         const inTransition$ = this._navigator.stateService.currentState$.pipe(map((frame) => {
59265             return frame.state.alpha < 1;
59266         }), distinctUntilChanged());
59267         const panTrigger$ = combineLatest(this._container.mouseService.active$, this._container.touchService.active$, this._navigator.stateService.inMotion$, inTransition$).pipe(map(([mouseActive, touchActive, inMotion, inTransition]) => {
59268             return !(mouseActive || touchActive || inMotion || inTransition);
59269         }), filter((trigger) => {
59270             return trigger;
59271         }));
59272         subs.push(this._navigator.stateService.state$
59273             .pipe(switchMap(state => {
59274             return state === State.Traversing ?
59275                 this._navigator.panService.panImages$ :
59276                 empty();
59277         }), switchMap((nts) => {
59278             return panTrigger$.pipe(withLatestFrom(this._container.renderService.renderCamera$, this._navigator.stateService.currentImage$, this._navigator.stateService.currentTransform$), mergeMap(([, renderCamera, currentNode, currentTransform]) => {
59279                 return of([
59280                     renderCamera,
59281                     currentNode,
59282                     currentTransform,
59283                     nts,
59284                 ]);
59285             }));
59286         }), switchMap(([camera, cn, ct, nts]) => {
59287             const direction = camera.camera.lookat.clone().sub(camera.camera.position);
59288             const cd = new Spatial().viewingDirection(cn.rotation);
59289             const ca = cd.angleTo(direction);
59290             const closest = [ca, undefined];
59291             const basic = new ViewportCoords().viewportToBasic(0, 0, ct, camera.perspective);
59292             if (basic[0] >= 0 && basic[0] <= 1 && basic[1] >= 0 && basic[1] <= 1) {
59293                 closest[0] = Number.NEGATIVE_INFINITY;
59294             }
59295             for (const [n] of nts) {
59296                 const d = new Spatial().viewingDirection(n.rotation);
59297                 const a = d.angleTo(direction);
59298                 if (a < closest[0]) {
59299                     closest[0] = a;
59300                     closest[1] = n.id;
59301                 }
59302             }
59303             if (!closest[1]) {
59304                 return empty();
59305             }
59306             return this._navigator.moveTo$(closest[1]).pipe(catchError(() => {
59307                 return empty();
59308             }));
59309         }))
59310             .subscribe());
59311     }
59312     _deactivate() {
59313         this._rendererDisposer$.next(null);
59314         this._subscriptions.unsubscribe();
59315     }
59316     _getDefaultConfiguration() {
59317         return {};
59318     }
59319 }
59320 ImageComponent.componentName = "image";
59321
59322 class HandlerBase {
59323     /** @ignore */
59324     constructor(component, container, navigator) {
59325         this._component = component;
59326         this._container = container;
59327         this._navigator = navigator;
59328         this._enabled = false;
59329     }
59330     /**
59331      * Returns a Boolean indicating whether the interaction is enabled.
59332      *
59333      * @returns {boolean} `true` if the interaction is enabled.
59334      */
59335     get isEnabled() {
59336         return this._enabled;
59337     }
59338     /**
59339      * Enables the interaction.
59340      *
59341      * @example
59342      * ```js
59343      * <component-name>.<handler-name>.enable();
59344      * ```
59345      */
59346     enable() {
59347         if (this._enabled || !this._component.activated) {
59348             return;
59349         }
59350         this._enable();
59351         this._enabled = true;
59352         this._component.configure(this._getConfiguration(true));
59353     }
59354     /**
59355      * Disables the interaction.
59356      *
59357      * @example
59358      * ```js
59359      * <component-name>.<handler-name>.disable();
59360      * ```
59361      */
59362     disable() {
59363         if (!this._enabled) {
59364             return;
59365         }
59366         this._disable();
59367         this._enabled = false;
59368         if (this._component.activated) {
59369             this._component.configure(this._getConfiguration(false));
59370         }
59371     }
59372 }
59373
59374 /**
59375  * The `KeySequenceNavigationHandler` allows the user to navigate through a sequence using the
59376  * following key commands:
59377  *
59378  * `ALT` + `Up Arrow`: Navigate to next image in the sequence.
59379  * `ALT` + `Down Arrow`: Navigate to previous image in sequence.
59380  *
59381  * @example
59382  * ```js
59383  * var keyboardComponent = viewer.getComponent("keyboard");
59384  *
59385  * keyboardComponent.keySequenceNavigation.disable();
59386  * keyboardComponent.keySequenceNavigation.enable();
59387  *
59388  * var isEnabled = keyboardComponent.keySequenceNavigation.isEnabled;
59389  * ```
59390  */
59391 class KeySequenceNavigationHandler extends HandlerBase {
59392     _enable() {
59393         const sequenceEdges$ = this._navigator.stateService.currentImage$.pipe(switchMap((image) => {
59394             return image.sequenceEdges$;
59395         }));
59396         this._keyDownSubscription = this._container.keyboardService.keyDown$.pipe(withLatestFrom(sequenceEdges$))
59397             .subscribe(([event, edgeStatus]) => {
59398             let direction = null;
59399             switch (event.keyCode) {
59400                 case 38: // up
59401                     direction = NavigationDirection.Next;
59402                     break;
59403                 case 40: // down
59404                     direction = NavigationDirection.Prev;
59405                     break;
59406                 default:
59407                     return;
59408             }
59409             event.preventDefault();
59410             if (!event.altKey || event.shiftKey || !edgeStatus.cached) {
59411                 return;
59412             }
59413             for (const edge of edgeStatus.edges) {
59414                 if (edge.data.direction === direction) {
59415                     this._navigator.moveTo$(edge.target)
59416                         .subscribe(undefined, (error) => {
59417                         if (!(error instanceof CancelMapillaryError)) {
59418                             console.error(error);
59419                         }
59420                     });
59421                     return;
59422                 }
59423             }
59424         });
59425     }
59426     _disable() {
59427         this._keyDownSubscription.unsubscribe();
59428     }
59429     _getConfiguration(enable) {
59430         return { keySequenceNavigation: enable };
59431     }
59432 }
59433
59434 /**
59435  * The `KeySpatialNavigationHandler` allows the user to navigate through a sequence using the
59436  * following key commands:
59437  *
59438  * `Up Arrow`: Step forward.
59439  * `Down Arrow`: Step backward.
59440  * `Left Arrow`: Step to the left.
59441  * `Rigth Arrow`: Step to the right.
59442  * `SHIFT` + `Down Arrow`: Turn around.
59443  * `SHIFT` + `Left Arrow`: Turn to the left.
59444  * `SHIFT` + `Rigth Arrow`: Turn to the right.
59445  *
59446  * @example
59447  * ```js
59448  * var keyboardComponent = viewer.getComponent("keyboard");
59449  *
59450  * keyboardComponent.keySpatialNavigation.disable();
59451  * keyboardComponent.keySpatialNavigation.enable();
59452  *
59453  * var isEnabled = keyboardComponent.keySpatialNavigation.isEnabled;
59454  * ```
59455  */
59456 class KeySpatialNavigationHandler extends HandlerBase {
59457     /** @ignore */
59458     constructor(component, container, navigator, spatial) {
59459         super(component, container, navigator);
59460         this._spatial = spatial;
59461     }
59462     _enable() {
59463         const spatialEdges$ = this._navigator.stateService.currentImage$.pipe(switchMap((image) => {
59464             return image.spatialEdges$;
59465         }));
59466         this._keyDownSubscription = this._container.keyboardService.keyDown$.pipe(withLatestFrom(spatialEdges$, this._navigator.stateService.currentState$))
59467             .subscribe(([event, edgeStatus, frame]) => {
59468             let spherical = isSpherical(frame.state.currentImage.cameraType);
59469             let direction = null;
59470             switch (event.keyCode) {
59471                 case 37: // left
59472                     direction = event.shiftKey && !spherical ? NavigationDirection.TurnLeft : NavigationDirection.StepLeft;
59473                     break;
59474                 case 38: // up
59475                     direction = event.shiftKey && !spherical ? NavigationDirection.Spherical : NavigationDirection.StepForward;
59476                     break;
59477                 case 39: // right
59478                     direction = event.shiftKey && !spherical ? NavigationDirection.TurnRight : NavigationDirection.StepRight;
59479                     break;
59480                 case 40: // down
59481                     direction = event.shiftKey && !spherical ? NavigationDirection.TurnU : NavigationDirection.StepBackward;
59482                     break;
59483                 default:
59484                     return;
59485             }
59486             event.preventDefault();
59487             if (event.altKey || !edgeStatus.cached ||
59488                 (event.shiftKey && spherical)) {
59489                 return;
59490             }
59491             if (!spherical) {
59492                 this._moveDir(direction, edgeStatus);
59493             }
59494             else {
59495                 const shifts = {};
59496                 shifts[NavigationDirection.StepBackward] = Math.PI;
59497                 shifts[NavigationDirection.StepForward] = 0;
59498                 shifts[NavigationDirection.StepLeft] = Math.PI / 2;
59499                 shifts[NavigationDirection.StepRight] = -Math.PI / 2;
59500                 const phi = this._rotationFromCamera(frame.state.camera).phi;
59501                 const navigationAngle = this._spatial.wrapAngle(phi + shifts[direction]);
59502                 const threshold = Math.PI / 4;
59503                 const edges = edgeStatus.edges.filter((e) => {
59504                     return e.data.direction === NavigationDirection.Spherical || e.data.direction === direction;
59505                 });
59506                 let smallestAngle = Number.MAX_VALUE;
59507                 let toKey = null;
59508                 for (const edge of edges) {
59509                     const angle = Math.abs(this._spatial.wrapAngle(edge.data.worldMotionAzimuth - navigationAngle));
59510                     if (angle < Math.min(smallestAngle, threshold)) {
59511                         smallestAngle = angle;
59512                         toKey = edge.target;
59513                     }
59514                 }
59515                 if (toKey == null) {
59516                     return;
59517                 }
59518                 this._moveTo(toKey);
59519             }
59520         });
59521     }
59522     _disable() {
59523         this._keyDownSubscription.unsubscribe();
59524     }
59525     _getConfiguration(enable) {
59526         return { keySpatialNavigation: enable };
59527     }
59528     _moveDir(direction, edgeStatus) {
59529         for (const edge of edgeStatus.edges) {
59530             if (edge.data.direction === direction) {
59531                 this._moveTo(edge.target);
59532                 return;
59533             }
59534         }
59535     }
59536     _moveTo(id) {
59537         this._navigator.moveTo$(id)
59538             .subscribe(undefined, (error) => {
59539             if (!(error instanceof CancelMapillaryError)) {
59540                 console.error(error);
59541             }
59542         });
59543     }
59544     _rotationFromCamera(camera) {
59545         let direction = camera.lookat.clone().sub(camera.position);
59546         let upProjection = direction.clone().dot(camera.up);
59547         let planeProjection = direction.clone().sub(camera.up.clone().multiplyScalar(upProjection));
59548         let phi = Math.atan2(planeProjection.y, planeProjection.x);
59549         let theta = Math.PI / 2 - this._spatial.angleToPlane(direction.toArray(), [0, 0, 1]);
59550         return { phi: phi, theta: theta };
59551     }
59552 }
59553
59554 /**
59555  * The `KeyZoomHandler` allows the user to zoom in and out using the
59556  * following key commands:
59557  *
59558  * `+`: Zoom in.
59559  * `-`: Zoom out.
59560  *
59561  * @example
59562  * ```js
59563  * var keyboardComponent = viewer.getComponent("keyboard");
59564  *
59565  * keyboardComponent.keyZoom.disable();
59566  * keyboardComponent.keyZoom.enable();
59567  *
59568  * var isEnabled = keyboardComponent.keyZoom.isEnabled;
59569  * ```
59570  */
59571 class KeyZoomHandler extends HandlerBase {
59572     /** @ignore */
59573     constructor(component, container, navigator, viewportCoords) {
59574         super(component, container, navigator);
59575         this._viewportCoords = viewportCoords;
59576     }
59577     _enable() {
59578         this._keyDownSubscription = this._container.keyboardService.keyDown$.pipe(withLatestFrom(this._container.renderService.renderCamera$, this._navigator.stateService.currentTransform$))
59579             .subscribe(([event, render, transform]) => {
59580             if (event.altKey || event.ctrlKey || event.metaKey) {
59581                 return;
59582             }
59583             let delta = 0;
59584             switch (event.key) {
59585                 case "+":
59586                     delta = 1;
59587                     break;
59588                 case "-":
59589                     delta = -1;
59590                     break;
59591                 default:
59592                     return;
59593             }
59594             event.preventDefault();
59595             const unprojected = this._viewportCoords.unprojectFromViewport(0, 0, render.perspective);
59596             const reference = transform.projectBasic(unprojected.toArray());
59597             this._navigator.stateService.zoomIn(delta, reference);
59598         });
59599     }
59600     _disable() {
59601         this._keyDownSubscription.unsubscribe();
59602     }
59603     _getConfiguration(enable) {
59604         return { keyZoom: enable };
59605     }
59606 }
59607
59608 /**
59609  * The `KeyPlayHandler` allows the user to control the play behavior
59610  * using the following key commands:
59611  *
59612  * `Spacebar`: Start or stop playing.
59613  * `SHIFT` + `D`: Switch direction.
59614  * `<`: Decrease speed.
59615  * `>`: Increase speed.
59616  *
59617  * @example
59618  * ```js
59619  * var keyboardComponent = viewer.getComponent("keyboard");
59620  *
59621  * keyboardComponent.keyPlay.disable();
59622  * keyboardComponent.keyPlay.enable();
59623  *
59624  * var isEnabled = keyboardComponent.keyPlay.isEnabled;
59625  * ```
59626  */
59627 class KeyPlayHandler extends HandlerBase {
59628     _enable() {
59629         this._keyDownSubscription = this._container.keyboardService.keyDown$.pipe(withLatestFrom(this._navigator.playService.playing$, this._navigator.playService.direction$, this._navigator.playService.speed$, this._navigator.stateService.currentImage$.pipe(switchMap((image) => {
59630             return image.sequenceEdges$;
59631         })), this._navigator.stateService.state$.pipe(map((state) => {
59632             return state === State.Earth;
59633         }), distinctUntilChanged())))
59634             .subscribe(([event, playing, direction, speed, status, earth]) => {
59635             if (event.altKey || event.ctrlKey || event.metaKey) {
59636                 return;
59637             }
59638             switch (event.key) {
59639                 case "D":
59640                     if (!event.shiftKey) {
59641                         return;
59642                     }
59643                     const newDirection = playing ?
59644                         null : direction === NavigationDirection.Next ?
59645                         NavigationDirection.Prev : direction === NavigationDirection.Prev ?
59646                         NavigationDirection.Next : null;
59647                     if (newDirection != null) {
59648                         this._navigator.playService.setDirection(newDirection);
59649                     }
59650                     break;
59651                 case " ":
59652                     if (event.shiftKey) {
59653                         return;
59654                     }
59655                     if (!earth) {
59656                         if (playing) {
59657                             this._navigator.playService.stop();
59658                         }
59659                         else {
59660                             for (let edge of status.edges) {
59661                                 if (edge.data.direction === direction) {
59662                                     this._navigator.playService.play();
59663                                 }
59664                             }
59665                         }
59666                     }
59667                     break;
59668                 case "<":
59669                     this._navigator.playService.setSpeed(speed - 0.05);
59670                     break;
59671                 case ">":
59672                     this._navigator.playService.setSpeed(speed + 0.05);
59673                     break;
59674                 default:
59675                     return;
59676             }
59677             event.preventDefault();
59678         });
59679     }
59680     _disable() {
59681         this._keyDownSubscription.unsubscribe();
59682     }
59683     _getConfiguration(enable) {
59684         return { keyPlay: enable };
59685     }
59686 }
59687
59688 /**
59689  * @class KeyboardComponent
59690  *
59691  * @classdesc Component for keyboard event handling.
59692  *
59693  * To retrive and use the keyboard component
59694  *
59695  * @example
59696  * ```js
59697  * var viewer = new Viewer({ ... });
59698  *
59699  * var keyboardComponent = viewer.getComponent("keyboard");
59700  * ```
59701  */
59702 class KeyboardComponent extends Component {
59703     /** @ignore */
59704     constructor(name, container, navigator) {
59705         super(name, container, navigator);
59706         this._keyPlayHandler =
59707             new KeyPlayHandler(this, container, navigator);
59708         this._keySequenceNavigationHandler =
59709             new KeySequenceNavigationHandler(this, container, navigator);
59710         this._keySpatialNavigationHandler =
59711             new KeySpatialNavigationHandler(this, container, navigator, new Spatial());
59712         this._keyZoomHandler =
59713             new KeyZoomHandler(this, container, navigator, new ViewportCoords());
59714     }
59715     /**
59716      * Get key play.
59717      *
59718      * @returns {KeyPlayHandler} The key play handler.
59719      */
59720     get keyPlay() {
59721         return this._keyPlayHandler;
59722     }
59723     /**
59724      * Get key sequence navigation.
59725      *
59726      * @returns {KeySequenceNavigationHandler} The key sequence navigation handler.
59727      */
59728     get keySequenceNavigation() {
59729         return this._keySequenceNavigationHandler;
59730     }
59731     /**
59732      * Get spatial.
59733      *
59734      * @returns {KeySpatialNavigationHandler} The spatial handler.
59735      */
59736     get keySpatialNavigation() {
59737         return this._keySpatialNavigationHandler;
59738     }
59739     /**
59740      * Get key zoom.
59741      *
59742      * @returns {KeyZoomHandler} The key zoom handler.
59743      */
59744     get keyZoom() {
59745         return this._keyZoomHandler;
59746     }
59747     _activate() {
59748         this._subscriptions.push(this._configuration$
59749             .subscribe((configuration) => {
59750             if (configuration.keyPlay) {
59751                 this._keyPlayHandler.enable();
59752             }
59753             else {
59754                 this._keyPlayHandler.disable();
59755             }
59756             if (configuration.keySequenceNavigation) {
59757                 this._keySequenceNavigationHandler.enable();
59758             }
59759             else {
59760                 this._keySequenceNavigationHandler.disable();
59761             }
59762             if (configuration.keySpatialNavigation) {
59763                 this._keySpatialNavigationHandler.enable();
59764             }
59765             else {
59766                 this._keySpatialNavigationHandler.disable();
59767             }
59768             if (configuration.keyZoom) {
59769                 this._keyZoomHandler.enable();
59770             }
59771             else {
59772                 this._keyZoomHandler.disable();
59773             }
59774         }));
59775     }
59776     _deactivate() {
59777         this._subscriptions.unsubscribe();
59778         this._keyPlayHandler.disable();
59779         this._keySequenceNavigationHandler.disable();
59780         this._keySpatialNavigationHandler.disable();
59781         this._keyZoomHandler.disable();
59782     }
59783     _getDefaultConfiguration() {
59784         return { keyPlay: true, keySequenceNavigation: true, keySpatialNavigation: true, keyZoom: true };
59785     }
59786 }
59787 KeyboardComponent.componentName = "keyboard";
59788
59789 class MarkerScene {
59790     constructor(scene, raycaster) {
59791         this._needsRender = false;
59792         this._interactiveObjects = [];
59793         this._markers = {};
59794         this._objectMarkers = {};
59795         this._raycaster = !!raycaster ? raycaster : new Raycaster();
59796         this._scene = !!scene ? scene : new Scene();
59797     }
59798     get markers() {
59799         return this._markers;
59800     }
59801     get needsRender() {
59802         return this._needsRender;
59803     }
59804     add(marker, position) {
59805         if (marker.id in this._markers) {
59806             this._dispose(marker.id);
59807         }
59808         marker.createGeometry(position);
59809         this._scene.add(marker.geometry);
59810         this._markers[marker.id] = marker;
59811         for (let interactiveObject of marker.getInteractiveObjects()) {
59812             this._interactiveObjects.push(interactiveObject);
59813             this._objectMarkers[interactiveObject.uuid] = marker.id;
59814         }
59815         this._needsRender = true;
59816     }
59817     clear() {
59818         for (const id in this._markers) {
59819             if (!this._markers.hasOwnProperty) {
59820                 continue;
59821             }
59822             this._dispose(id);
59823         }
59824         this._needsRender = true;
59825     }
59826     get(id) {
59827         return this._markers[id];
59828     }
59829     getAll() {
59830         return Object
59831             .keys(this._markers)
59832             .map((id) => { return this._markers[id]; });
59833     }
59834     has(id) {
59835         return id in this._markers;
59836     }
59837     intersectObjects([viewportX, viewportY], camera) {
59838         this._raycaster.setFromCamera(new Vector2(viewportX, viewportY), camera);
59839         const intersects = this._raycaster.intersectObjects(this._interactiveObjects);
59840         for (const intersect of intersects) {
59841             if (intersect.object.uuid in this._objectMarkers) {
59842                 return this._objectMarkers[intersect.object.uuid];
59843             }
59844         }
59845         return null;
59846     }
59847     lerpAltitude(id, alt, alpha) {
59848         if (!(id in this._markers)) {
59849             return;
59850         }
59851         this._markers[id].lerpAltitude(alt, alpha);
59852         this._needsRender = true;
59853     }
59854     remove(id) {
59855         if (!(id in this._markers)) {
59856             return;
59857         }
59858         this._dispose(id);
59859         this._needsRender = true;
59860     }
59861     render(perspectiveCamera, renderer) {
59862         renderer.render(this._scene, perspectiveCamera);
59863         this._needsRender = false;
59864     }
59865     update(id, position, lngLat) {
59866         if (!(id in this._markers)) {
59867             return;
59868         }
59869         const marker = this._markers[id];
59870         marker.updatePosition(position, lngLat);
59871         this._needsRender = true;
59872     }
59873     _dispose(id) {
59874         const marker = this._markers[id];
59875         this._scene.remove(marker.geometry);
59876         for (let interactiveObject of marker.getInteractiveObjects()) {
59877             const index = this._interactiveObjects.indexOf(interactiveObject);
59878             if (index !== -1) {
59879                 this._interactiveObjects.splice(index, 1);
59880             }
59881             else {
59882                 console.warn(`Object does not exist (${interactiveObject.id}) for ${id}`);
59883             }
59884             delete this._objectMarkers[interactiveObject.uuid];
59885         }
59886         marker.disposeGeometry();
59887         delete this._markers[id];
59888     }
59889 }
59890
59891 /**
59892  * @class MarkerComponent
59893  *
59894  * @classdesc Component for showing and editing 3D marker objects.
59895  *
59896  * The `add` method is used for adding new markers or replacing
59897  * markers already in the set.
59898  *
59899  * If a marker already in the set has the same
59900  * id as one of the markers added, the old marker will be removed and
59901  * the added marker will take its place.
59902  *
59903  * It is not possible to update markers in the set by updating any properties
59904  * directly on the marker object. Markers need to be replaced by
59905  * re-adding them for updates to geographic position or configuration
59906  * to be reflected.
59907  *
59908  * Markers added to the marker component can be either interactive
59909  * or non-interactive. Different marker types define their behavior.
59910  * Markers with interaction support can be configured with options
59911  * to respond to dragging inside the viewer and be detected when
59912  * retrieving markers from pixel points with the `getMarkerIdAt` method.
59913  *
59914  * To retrive and use the marker component
59915  *
59916  * @example
59917  * ```js
59918  * var viewer = new Viewer({ component: { marker: true }, ... });
59919  *
59920  * var markerComponent = viewer.getComponent("marker");
59921  * ```
59922  */
59923 class MarkerComponent extends Component {
59924     /** @ignore */
59925     constructor(name, container, navigator) {
59926         super(name, container, navigator);
59927         this._graphCalculator = new GraphCalculator();
59928         this._markerScene = new MarkerScene();
59929         this._markerSet = new MarkerSet();
59930         this._viewportCoords = new ViewportCoords();
59931         this._relativeGroundAltitude = -2;
59932     }
59933     /**
59934      * Add markers to the marker set or replace markers in the marker set.
59935      *
59936      * @description If a marker already in the set has the same
59937      * id as one of the markers added, the old marker will be removed
59938      * the added marker will take its place.
59939      *
59940      * Any marker inside the visible bounding bbox
59941      * will be initialized and placed in the viewer.
59942      *
59943      * @param {Array<Marker>} markers - Markers to add.
59944      *
59945      * @example
59946      * ```js
59947      * markerComponent.add([marker1, marker2]);
59948      * ```
59949      */
59950     add(markers) {
59951         this._markerSet.add(markers);
59952     }
59953     fire(type, event) {
59954         super.fire(type, event);
59955     }
59956     /**
59957      * Returns the marker in the marker set with the specified id, or
59958      * undefined if the id matches no marker.
59959      *
59960      * @param {string} markerId - Id of the marker.
59961      *
59962      * @example
59963      * ```js
59964      * var marker = markerComponent.get("markerId");
59965      * ```
59966      *
59967      */
59968     get(markerId) {
59969         return this._markerSet.get(markerId);
59970     }
59971     /**
59972      * Returns an array of all markers.
59973      *
59974      * @example
59975      * ```js
59976      * var markers = markerComponent.getAll();
59977      * ```
59978      */
59979     getAll() {
59980         return this._markerSet.getAll();
59981     }
59982     /**
59983      * Returns the id of the interactive marker closest to the current camera
59984      * position at the specified point.
59985      *
59986      * @description Notice that the pixelPoint argument requires x, y
59987      * coordinates from pixel space.
59988      *
59989      * With this function, you can use the coordinates provided by mouse
59990      * events to get information out of the marker component.
59991      *
59992      * If no interactive geometry of an interactive marker exist at the pixel
59993      * point, `null` will be returned.
59994      *
59995      * @param {Array<number>} pixelPoint - Pixel coordinates on the viewer element.
59996      * @returns {string} Id of the interactive marker closest to the camera. If no
59997      * interactive marker exist at the pixel point, `null` will be returned.
59998      *
59999      * @example
60000      * ```js
60001      * markerComponent.getMarkerIdAt([100, 100])
60002      *     .then((markerId) => { console.log(markerId); });
60003      * ```
60004      */
60005     getMarkerIdAt(pixelPoint) {
60006         return new Promise((resolve, reject) => {
60007             this._container.renderService.renderCamera$.pipe(first(), map((render) => {
60008                 const viewport = this._viewportCoords
60009                     .canvasToViewport(pixelPoint[0], pixelPoint[1], this._container.container);
60010                 const id = this._markerScene.intersectObjects(viewport, render.perspective);
60011                 return id;
60012             }))
60013                 .subscribe((id) => {
60014                 resolve(id);
60015             }, (error) => {
60016                 reject(error);
60017             });
60018         });
60019     }
60020     /**
60021      * Check if a marker exist in the marker set.
60022      *
60023      * @param {string} markerId - Id of the marker.
60024      *
60025      * @example
60026      * ```js
60027      * var markerExists = markerComponent.has("markerId");
60028      * ```
60029      */
60030     has(markerId) {
60031         return this._markerSet.has(markerId);
60032     }
60033     off(type, handler) {
60034         super.off(type, handler);
60035     }
60036     on(type, handler) {
60037         super.on(type, handler);
60038     }
60039     /**
60040      * Remove markers with the specified ids from the marker set.
60041      *
60042      * @param {Array<string>} markerIds - Ids for markers to remove.
60043      *
60044      * @example
60045      * ```js
60046      * markerComponent.remove(["id-1", "id-2"]);
60047      * ```
60048      */
60049     remove(markerIds) {
60050         this._markerSet.remove(markerIds);
60051     }
60052     /**
60053      * Remove all markers from the marker set.
60054      *
60055      * @example
60056      * ```js
60057      * markerComponent.removeAll();
60058      * ```
60059      */
60060     removeAll() {
60061         this._markerSet.removeAll();
60062     }
60063     _activate() {
60064         const groundAltitude$ = this._navigator.stateService.currentState$.pipe(map((frame) => {
60065             return frame.state.camera.position.z + this._relativeGroundAltitude;
60066         }), distinctUntilChanged((a1, a2) => {
60067             return Math.abs(a1 - a2) < 0.01;
60068         }), publishReplay(1), refCount());
60069         const geoInitiated$ = combineLatest(groundAltitude$, this._navigator.stateService.reference$).pipe(first(), map(() => { }), publishReplay(1), refCount());
60070         const clampedConfiguration$ = this._configuration$.pipe(map((configuration) => {
60071             return { visibleBBoxSize: Math.max(1, Math.min(200, configuration.visibleBBoxSize)) };
60072         }));
60073         const currentLngLat$ = this._navigator.stateService.currentImage$.pipe(map((image) => { return image.lngLat; }), publishReplay(1), refCount());
60074         const visibleBBox$ = combineLatest(clampedConfiguration$, currentLngLat$).pipe(map(([configuration, lngLat]) => {
60075             return this._graphCalculator
60076                 .boundingBoxCorners(lngLat, configuration.visibleBBoxSize / 2);
60077         }), publishReplay(1), refCount());
60078         const visibleMarkers$ = combineLatest(concat(of(this._markerSet), this._markerSet.changed$), visibleBBox$).pipe(map(([set, bbox]) => {
60079             return set.search(bbox);
60080         }));
60081         const subs = this._subscriptions;
60082         subs.push(geoInitiated$.pipe(switchMap(() => {
60083             return visibleMarkers$.pipe(withLatestFrom(this._navigator.stateService.reference$, groundAltitude$));
60084         }))
60085             .subscribe(([markers, reference, alt]) => {
60086             const markerScene = this._markerScene;
60087             const sceneMarkers = markerScene.markers;
60088             const markersToRemove = Object.assign({}, sceneMarkers);
60089             for (const marker of markers) {
60090                 if (marker.id in sceneMarkers) {
60091                     delete markersToRemove[marker.id];
60092                 }
60093                 else {
60094                     const point3d = geodeticToEnu(marker.lngLat.lng, marker.lngLat.lat, reference.alt + alt, reference.lng, reference.lat, reference.alt);
60095                     markerScene.add(marker, point3d);
60096                 }
60097             }
60098             for (const id in markersToRemove) {
60099                 if (!markersToRemove.hasOwnProperty(id)) {
60100                     continue;
60101                 }
60102                 markerScene.remove(id);
60103             }
60104         }));
60105         subs.push(geoInitiated$.pipe(switchMap(() => {
60106             return this._markerSet.updated$.pipe(withLatestFrom(visibleBBox$, this._navigator.stateService.reference$, groundAltitude$));
60107         }))
60108             .subscribe(([markers, [sw, ne], reference, alt]) => {
60109             const markerScene = this._markerScene;
60110             for (const marker of markers) {
60111                 const exists = markerScene.has(marker.id);
60112                 const visible = marker.lngLat.lat > sw.lat &&
60113                     marker.lngLat.lat < ne.lat &&
60114                     marker.lngLat.lng > sw.lng &&
60115                     marker.lngLat.lng < ne.lng;
60116                 if (visible) {
60117                     const point3d = geodeticToEnu(marker.lngLat.lng, marker.lngLat.lat, reference.alt + alt, reference.lng, reference.lat, reference.alt);
60118                     markerScene.add(marker, point3d);
60119                 }
60120                 else if (!visible && exists) {
60121                     markerScene.remove(marker.id);
60122                 }
60123             }
60124         }));
60125         subs.push(this._navigator.stateService.reference$.pipe(skip(1), withLatestFrom(groundAltitude$))
60126             .subscribe(([reference, alt]) => {
60127             const markerScene = this._markerScene;
60128             for (const marker of markerScene.getAll()) {
60129                 const point3d = geodeticToEnu(marker.lngLat.lng, marker.lngLat.lat, reference.alt + alt, reference.lng, reference.lat, reference.alt);
60130                 markerScene.update(marker.id, point3d);
60131             }
60132         }));
60133         subs.push(groundAltitude$.pipe(skip(1), withLatestFrom(this._navigator.stateService.reference$, currentLngLat$))
60134             .subscribe(([alt, reference, lngLat]) => {
60135             const markerScene = this._markerScene;
60136             const position = geodeticToEnu(lngLat.lng, lngLat.lat, reference.alt + alt, reference.lng, reference.lat, reference.alt);
60137             for (const marker of markerScene.getAll()) {
60138                 const point3d = geodeticToEnu(marker.lngLat.lng, marker.lngLat.lat, reference.alt + alt, reference.lng, reference.lat, reference.alt);
60139                 const distanceX = point3d[0] - position[0];
60140                 const distanceY = point3d[1] - position[1];
60141                 const groundDistance = Math
60142                     .sqrt(distanceX * distanceX + distanceY * distanceY);
60143                 if (groundDistance > 50) {
60144                     continue;
60145                 }
60146                 markerScene.lerpAltitude(marker.id, alt, Math.min(1, Math.max(0, 1.2 - 1.2 * groundDistance / 50)));
60147             }
60148         }));
60149         subs.push(this._navigator.stateService.currentState$
60150             .pipe(map((frame) => {
60151             const scene = this._markerScene;
60152             return {
60153                 name: this._name,
60154                 renderer: {
60155                     frameId: frame.id,
60156                     needsRender: scene.needsRender,
60157                     render: scene.render.bind(scene),
60158                     pass: RenderPass$1.Opaque,
60159                 },
60160             };
60161         }))
60162             .subscribe(this._container.glRenderer.render$));
60163         const hoveredMarkerId$ = combineLatest(this._container.renderService.renderCamera$, this._container.mouseService.mouseMove$)
60164             .pipe(map(([render, event]) => {
60165             const element = this._container.container;
60166             const [canvasX, canvasY] = this._viewportCoords.canvasPosition(event, element);
60167             const viewport = this._viewportCoords
60168                 .canvasToViewport(canvasX, canvasY, element);
60169             const markerId = this._markerScene.intersectObjects(viewport, render.perspective);
60170             return markerId;
60171         }), publishReplay(1), refCount());
60172         const draggingStarted$ = this._container.mouseService
60173             .filtered$(this._name, this._container.mouseService.mouseDragStart$).pipe(map(() => {
60174             return true;
60175         }));
60176         const draggingStopped$ = this._container.mouseService
60177             .filtered$(this._name, this._container.mouseService.mouseDragEnd$).pipe(map(() => {
60178             return false;
60179         }));
60180         const filteredDragging$ = merge(draggingStarted$, draggingStopped$)
60181             .pipe(startWith(false));
60182         subs.push(merge(draggingStarted$.pipe(withLatestFrom(hoveredMarkerId$)), combineLatest(draggingStopped$, of(null))).pipe(startWith([false, null]), pairwise())
60183             .subscribe(([previous, current]) => {
60184             const dragging = current[0];
60185             const type = dragging ?
60186                 "markerdragstart" :
60187                 "markerdragend";
60188             const id = dragging ? current[1] : previous[1];
60189             const marker = this._markerScene.get(id);
60190             const event = {
60191                 marker,
60192                 target: this,
60193                 type,
60194             };
60195             this.fire(type, event);
60196         }));
60197         const mouseDown$ = merge(this._container.mouseService.mouseDown$.pipe(map(() => { return true; })), this._container.mouseService.documentMouseUp$.pipe(map(() => { return false; }))).pipe(startWith(false));
60198         subs.push(combineLatest(this._container.mouseService.active$, hoveredMarkerId$.pipe(distinctUntilChanged()), mouseDown$, filteredDragging$)
60199             .pipe(map(([active, markerId, mouseDown, filteredDragging]) => {
60200             return (!active && markerId != null && mouseDown) ||
60201                 filteredDragging;
60202         }), distinctUntilChanged())
60203             .subscribe((claim) => {
60204             if (claim) {
60205                 this._container.mouseService.claimMouse(this._name, 1);
60206                 this._container.mouseService.claimWheel(this._name, 1);
60207             }
60208             else {
60209                 this._container.mouseService.unclaimMouse(this._name);
60210                 this._container.mouseService.unclaimWheel(this._name);
60211             }
60212         }));
60213         const offset$ = this._container.mouseService
60214             .filtered$(this._name, this._container.mouseService.mouseDragStart$).pipe(withLatestFrom(hoveredMarkerId$, this._container.renderService.renderCamera$), map(([e, id, r]) => {
60215             const marker = this._markerScene.get(id);
60216             const element = this._container.container;
60217             const [groundCanvasX, groundCanvasY] = this._viewportCoords
60218                 .projectToCanvas(marker.geometry.position
60219                 .toArray(), element, r.perspective);
60220             const [canvasX, canvasY] = this._viewportCoords
60221                 .canvasPosition(e, element);
60222             const offset = [canvasX - groundCanvasX, canvasY - groundCanvasY];
60223             return [marker, offset, r];
60224         }), publishReplay(1), refCount());
60225         subs.push(this._container.mouseService
60226             .filtered$(this._name, this._container.mouseService.mouseDrag$)
60227             .pipe(withLatestFrom(offset$, this._navigator.stateService.reference$, clampedConfiguration$))
60228             .subscribe(([event, [marker, offset, render], reference, configuration]) => {
60229             if (!this._markerScene.has(marker.id)) {
60230                 return;
60231             }
60232             const element = this._container.container;
60233             const [canvasX, canvasY] = this._viewportCoords
60234                 .canvasPosition(event, element);
60235             const groundX = canvasX - offset[0];
60236             const groundY = canvasY - offset[1];
60237             const [viewportX, viewportY] = this._viewportCoords
60238                 .canvasToViewport(groundX, groundY, element);
60239             const direction = new Vector3(viewportX, viewportY, 1)
60240                 .unproject(render.perspective)
60241                 .sub(render.perspective.position)
60242                 .normalize();
60243             const distance = Math.min(this._relativeGroundAltitude / direction.z, configuration.visibleBBoxSize / 2 - 0.1);
60244             if (distance < 0) {
60245                 return;
60246             }
60247             const intersection = direction
60248                 .clone()
60249                 .multiplyScalar(distance)
60250                 .add(render.perspective.position);
60251             intersection.z =
60252                 render.perspective.position.z
60253                     + this._relativeGroundAltitude;
60254             const [lng, lat] = enuToGeodetic(intersection.x, intersection.y, intersection.z, reference.lng, reference.lat, reference.alt);
60255             this._markerScene
60256                 .update(marker.id, intersection.toArray(), { lat, lng });
60257             this._markerSet.update(marker);
60258             const type = "markerposition";
60259             const markerEvent = {
60260                 marker,
60261                 target: this,
60262                 type,
60263             };
60264             this.fire(type, markerEvent);
60265         }));
60266     }
60267     _deactivate() {
60268         this._subscriptions.unsubscribe();
60269         this._markerScene.clear();
60270     }
60271     _getDefaultConfiguration() {
60272         return { visibleBBoxSize: 100 };
60273     }
60274 }
60275 MarkerComponent.componentName = "marker";
60276
60277 function sign$1(n) {
60278     return n > 0 ? 1 : n < 0 ? -1 : 0;
60279 }
60280 function colinearPointOnSegment(p, s) {
60281     return p.x <= Math.max(s.p1.x, s.p2.x) &&
60282         p.x >= Math.min(s.p1.x, s.p2.x) &&
60283         p.y >= Math.max(s.p1.y, s.p2.y) &&
60284         p.y >= Math.min(s.p1.y, s.p2.y);
60285 }
60286 function parallel(s1, s2) {
60287     const ux = s1.p2.x - s1.p1.x;
60288     const uy = s1.p2.y - s1.p1.y;
60289     const vx = s2.p2.x - s2.p1.x;
60290     const vy = s2.p2.y - s2.p1.y;
60291     const cross = ux * vy - uy * vx;
60292     const u2 = ux * ux + uy * uy;
60293     const v2 = vx * vx + vy * vy;
60294     const epsilon2 = 1e-10;
60295     return cross * cross < epsilon2 * u2 * v2;
60296 }
60297 function tripletOrientation(p1, p2, p3) {
60298     const orientation = (p2.y - p1.y) * (p3.x - p2.x) -
60299         (p3.y - p2.y) * (p2.x - p1.x);
60300     return sign$1(orientation);
60301 }
60302 function segmentsIntersect(s1, s2) {
60303     if (parallel(s1, s2)) {
60304         return false;
60305     }
60306     const o1 = tripletOrientation(s1.p1, s1.p2, s2.p1);
60307     const o2 = tripletOrientation(s1.p1, s1.p2, s2.p2);
60308     const o3 = tripletOrientation(s2.p1, s2.p2, s1.p1);
60309     const o4 = tripletOrientation(s2.p1, s2.p2, s1.p2);
60310     if (o1 !== o2 && o3 !== o4) {
60311         return true;
60312     }
60313     if (o1 === 0 && colinearPointOnSegment(s2.p1, s1)) {
60314         return true;
60315     }
60316     if (o2 === 0 && colinearPointOnSegment(s2.p2, s1)) {
60317         return true;
60318     }
60319     if (o3 === 0 && colinearPointOnSegment(s1.p1, s2)) {
60320         return true;
60321     }
60322     if (o4 === 0 && colinearPointOnSegment(s1.p2, s2)) {
60323         return true;
60324     }
60325     return false;
60326 }
60327 function segmentIntersection(s1, s2) {
60328     if (parallel(s1, s2)) {
60329         return undefined;
60330     }
60331     const x1 = s1.p1.x;
60332     const x2 = s1.p2.x;
60333     const y1 = s1.p1.y;
60334     const y2 = s1.p2.y;
60335     const x3 = s2.p1.x;
60336     const x4 = s2.p2.x;
60337     const y3 = s2.p1.y;
60338     const y4 = s2.p2.y;
60339     const den = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4);
60340     const xNum = (x1 * y2 - y1 * x2) * (x3 - x4) - (x1 - x2) * (x3 * y4 - y3 * x4);
60341     const yNum = (x1 * y2 - y1 * x2) * (y3 - y4) - (y1 - y2) * (x3 * y4 - y3 * x4);
60342     return { x: xNum / den, y: yNum / den };
60343 }
60344
60345 function basicBoundaryPoints(pointsPerSide) {
60346     let points = [];
60347     let os = [[0, 0], [1, 0], [1, 1], [0, 1]];
60348     let ds = [[1, 0], [0, 1], [-1, 0], [0, -1]];
60349     for (let side = 0; side < 4; ++side) {
60350         let o = os[side];
60351         let d = ds[side];
60352         for (let i = 0; i < pointsPerSide; ++i) {
60353             points.push([o[0] + d[0] * i / pointsPerSide,
60354                 o[1] + d[1] * i / pointsPerSide]);
60355         }
60356     }
60357     return points;
60358 }
60359 function insideViewport(x, y) {
60360     return x >= -1 && x <= 1 && y >= -1 && y <= 1;
60361 }
60362 function insideBasic(x, y) {
60363     return x >= 0 && x <= 1 && y >= 0 && y <= 1;
60364 }
60365 function viewportDistances(transform, perspective, viewportCoords) {
60366     const boundaryPointsBasic = basicBoundaryPoints(100);
60367     const boundaryPointsViewport = boundaryPointsBasic
60368         .map((basic) => {
60369         return viewportCoords.basicToViewportSafe(basic[0], basic[1], transform, perspective);
60370     });
60371     const visibleBoundaryPoints = [];
60372     const viewportSides = [
60373         { x: -1, y: 1 },
60374         { x: 1, y: 1 },
60375         { x: 1, y: -1 },
60376         { x: -1, y: -1 }
60377     ];
60378     const intersections = [false, false, false, false];
60379     for (let i = 0; i < boundaryPointsViewport.length; i++) {
60380         const p1 = boundaryPointsViewport[i];
60381         const p2 = boundaryPointsViewport[(i + 1) % boundaryPointsViewport.length];
60382         if (p1 === null) {
60383             continue;
60384         }
60385         if (p2 === null) {
60386             if (insideViewport(p1[0], p1[1])) {
60387                 visibleBoundaryPoints.push(p1);
60388             }
60389             continue;
60390         }
60391         const [x1, y1] = p1;
60392         const [x2, y2] = p2;
60393         if (insideViewport(x1, y1)) {
60394             if (insideViewport(x2, y2)) {
60395                 visibleBoundaryPoints.push(p1);
60396             }
60397             else {
60398                 for (let side = 0; side < 4; side++) {
60399                     const s1 = { p1: { x: x1, y: y1 }, p2: { x: x2, y: y2 } };
60400                     const s2 = { p1: viewportSides[side], p2: viewportSides[(side + 1) % 4] };
60401                     const intersecting = segmentsIntersect(s1, s2);
60402                     if (intersecting) {
60403                         const intersection = segmentIntersection(s1, s2);
60404                         visibleBoundaryPoints.push(p1, [intersection.x, intersection.y]);
60405                         intersections[side] = true;
60406                     }
60407                 }
60408             }
60409         }
60410     }
60411     const [topLeftBasicX, topLeftBasicY] = viewportCoords.viewportToBasic(-1, 1, transform, perspective);
60412     const [topRightBasicX, topRightBasicY] = viewportCoords.viewportToBasic(1, 1, transform, perspective);
60413     const [bottomRightBasicX, bottomRightBasicY] = viewportCoords.viewportToBasic(1, -1, transform, perspective);
60414     const [bottomLeftBasicX, bottomLeftBasicY] = viewportCoords.viewportToBasic(-1, -1, transform, perspective);
60415     if (insideBasic(topLeftBasicX, topLeftBasicY)) {
60416         intersections[3] = intersections[0] = true;
60417     }
60418     if (insideBasic(topRightBasicX, topRightBasicY)) {
60419         intersections[0] = intersections[1] = true;
60420     }
60421     if (insideBasic(bottomRightBasicX, bottomRightBasicY)) {
60422         intersections[1] = intersections[2] = true;
60423     }
60424     if (insideBasic(bottomLeftBasicX, bottomLeftBasicY)) {
60425         intersections[2] = intersections[3] = true;
60426     }
60427     const maximums = [-1, -1, 1, 1];
60428     for (let visibleBoundaryPoint of visibleBoundaryPoints) {
60429         const x = visibleBoundaryPoint[0];
60430         const y = visibleBoundaryPoint[1];
60431         if (x > maximums[1]) {
60432             maximums[1] = x;
60433         }
60434         if (x < maximums[3]) {
60435             maximums[3] = x;
60436         }
60437         if (y > maximums[0]) {
60438             maximums[0] = y;
60439         }
60440         if (y < maximums[2]) {
60441             maximums[2] = y;
60442         }
60443     }
60444     const boundary = [1, 1, -1, -1];
60445     const distances = [];
60446     for (let side = 0; side < 4; side++) {
60447         if (intersections[side]) {
60448             distances.push(0);
60449             continue;
60450         }
60451         distances.push(Math.abs(boundary[side] - maximums[side]));
60452     }
60453     return distances;
60454 }
60455
60456 /**
60457  * The `BounceHandler` ensures that the viewer bounces back to the image
60458  * when drag panning outside of the image edge.
60459  */
60460 class BounceHandler extends HandlerBase {
60461     constructor(component, container, navigator, viewportCoords, spatial) {
60462         super(component, container, navigator);
60463         this._spatial = spatial;
60464         this._viewportCoords = viewportCoords;
60465     }
60466     _enable() {
60467         const inTransition$ = this._navigator.stateService.currentState$.pipe(map((frame) => {
60468             return frame.state.alpha < 1;
60469         }), distinctUntilChanged());
60470         this._bounceSubscription = combineLatest(inTransition$, this._navigator.stateService.inTranslation$, this._container.mouseService.active$, this._container.touchService.active$).pipe(map((noForce) => {
60471             return noForce[0] || noForce[1] || noForce[2] || noForce[3];
60472         }), distinctUntilChanged(), switchMap((noForce) => {
60473             return noForce ?
60474                 empty() :
60475                 combineLatest(this._container.renderService.renderCamera$, this._navigator.stateService.currentTransform$.pipe(first()));
60476         }), withLatestFrom(this._navigator.panService.panImages$))
60477             .subscribe(([[render, transform], nts]) => {
60478             if (!transform.hasValidScale && render.camera.focal < 0.1) {
60479                 return;
60480             }
60481             if (render.perspective.aspect === 0 || render.perspective.aspect === Number.POSITIVE_INFINITY) {
60482                 return;
60483             }
60484             const distances = viewportDistances(transform, render.perspective, this._viewportCoords);
60485             const basic = this._viewportCoords.viewportToBasic(0, 0, transform, render.perspective);
60486             if ((basic[0] < 0 || basic[0] > 1) && nts.length > 0) {
60487                 distances[0] = distances[2] = 0;
60488             }
60489             for (const [, t] of nts) {
60490                 const d = viewportDistances(t, render.perspective, this._viewportCoords);
60491                 for (let i = 1; i < distances.length; i += 2) {
60492                     if (d[i] < distances[i]) {
60493                         distances[i] = d[i];
60494                     }
60495                 }
60496             }
60497             if (Math.max(...distances) < 0.01) {
60498                 return;
60499             }
60500             const horizontalDistance = distances[1] - distances[3];
60501             const verticalDistance = distances[0] - distances[2];
60502             const currentDirection = this._viewportCoords
60503                 .unprojectFromViewport(0, 0, render.perspective)
60504                 .sub(render.perspective.position);
60505             const directionPhi = this._viewportCoords
60506                 .unprojectFromViewport(horizontalDistance, 0, render.perspective)
60507                 .sub(render.perspective.position);
60508             const directionTheta = this._viewportCoords
60509                 .unprojectFromViewport(0, verticalDistance, render.perspective)
60510                 .sub(render.perspective.position);
60511             let phi = (horizontalDistance > 0 ? 1 : -1) * directionPhi.angleTo(currentDirection);
60512             let theta = (verticalDistance > 0 ? 1 : -1) * directionTheta.angleTo(currentDirection);
60513             const threshold = Math.PI / 60;
60514             const coeff = 1e-1;
60515             phi = this._spatial.clamp(coeff * phi, -threshold, threshold);
60516             theta = this._spatial.clamp(coeff * theta, -threshold, threshold);
60517             this._navigator.stateService.rotateUnbounded({ phi: phi, theta: theta });
60518         });
60519     }
60520     _disable() {
60521         this._bounceSubscription.unsubscribe();
60522     }
60523     _getConfiguration() {
60524         return {};
60525     }
60526 }
60527
60528 class MouseOperator {
60529     static filteredPairwiseMouseDrag$(name, mouseService) {
60530         return this._filteredPairwiseMouseDrag$(name, mouseService, mouseService.mouseDragStart$, mouseService.mouseDrag$, mouseService.mouseDragEnd$);
60531     }
60532     static filteredPairwiseMouseRightDrag$(name, mouseService) {
60533         return this._filteredPairwiseMouseDrag$(name, mouseService, mouseService.mouseRightDragStart$, mouseService.mouseRightDrag$, mouseService.mouseRightDragEnd$);
60534     }
60535     static _filteredPairwiseMouseDrag$(name, mouseService, mouseDragStart$, mouseDrag$, mouseDragEnd$) {
60536         return mouseService
60537             .filtered$(name, mouseDragStart$).pipe(switchMap((mouseDragStart) => {
60538             const dragging$ = concat(of(mouseDragStart), mouseService
60539                 .filtered$(name, mouseDrag$));
60540             const dragEnd$ = mouseService
60541                 .filtered$(name, mouseDragEnd$).pipe(map(() => {
60542                 return null;
60543             }));
60544             return merge(dragging$, dragEnd$).pipe(takeWhile((e) => {
60545                 return !!e;
60546             }), startWith(null));
60547         }), pairwise(), filter((pair) => {
60548             return pair[0] != null && pair[1] != null;
60549         }));
60550     }
60551 }
60552
60553 /**
60554  * The `DragPanHandler` allows the user to pan the viewer image by clicking and dragging the cursor.
60555  *
60556  * @example
60557  * ```js
60558  * var pointerComponent = viewer.getComponent("pointer");
60559  *
60560  * pointerComponent.dragPan.disable();
60561  * pointerComponent.dragPan.enable();
60562  *
60563  * var isEnabled = pointerComponent.dragPan.isEnabled;
60564  * ```
60565  */
60566 class DragPanHandler extends HandlerBase {
60567     /** @ignore */
60568     constructor(component, container, navigator, viewportCoords, spatial) {
60569         super(component, container, navigator);
60570         this._spatial = spatial;
60571         this._viewportCoords = viewportCoords;
60572     }
60573     _enable() {
60574         let draggingStarted$ = this._container.mouseService
60575             .filtered$(this._component.name, this._container.mouseService.mouseDragStart$).pipe(map(() => {
60576             return true;
60577         }), share());
60578         let draggingStopped$ = this._container.mouseService
60579             .filtered$(this._component.name, this._container.mouseService.mouseDragEnd$).pipe(map(() => {
60580             return false;
60581         }), share());
60582         this._activeMouseSubscription = merge(draggingStarted$, draggingStopped$)
60583             .subscribe(this._container.mouseService.activate$);
60584         const documentMouseMove$ = merge(draggingStarted$, draggingStopped$).pipe(switchMap((dragging) => {
60585             return dragging ?
60586                 this._container.mouseService.documentMouseMove$ :
60587                 empty();
60588         }));
60589         this._preventDefaultSubscription = merge(documentMouseMove$, this._container.touchService.touchMove$)
60590             .subscribe((event) => {
60591             event.preventDefault(); // prevent selection of content outside the viewer
60592         });
60593         let touchMovingStarted$ = this._container.touchService.singleTouchDragStart$.pipe(map(() => {
60594             return true;
60595         }));
60596         let touchMovingStopped$ = this._container.touchService.singleTouchDragEnd$.pipe(map(() => {
60597             return false;
60598         }));
60599         this._activeTouchSubscription = merge(touchMovingStarted$, touchMovingStopped$)
60600             .subscribe(this._container.touchService.activate$);
60601         const rotation$ = this._navigator.stateService.currentState$.pipe(map((frame) => {
60602             return isSpherical(frame.state.currentImage.cameraType) ||
60603                 frame.state.imagesAhead < 1;
60604         }), distinctUntilChanged(), switchMap((enable) => {
60605             if (!enable) {
60606                 return empty();
60607             }
60608             const mouseDrag$ = MouseOperator.filteredPairwiseMouseDrag$(this._component.name, this._container.mouseService);
60609             const singleTouchDrag$ = merge(this._container.touchService.singleTouchDragStart$, this._container.touchService.singleTouchDrag$, this._container.touchService.singleTouchDragEnd$.pipe(map(() => { return null; }))).pipe(map((event) => {
60610                 return event != null && event.touches.length > 0 ?
60611                     event.touches[0] : null;
60612             }), pairwise(), filter((pair) => {
60613                 return pair[0] != null && pair[1] != null;
60614             }));
60615             return merge(mouseDrag$, singleTouchDrag$);
60616         }), withLatestFrom(this._container.renderService.renderCamera$, this._navigator.stateService.currentTransform$, this._navigator.panService.panImages$), map(([events, render, transform, nts]) => {
60617             let previousEvent = events[0];
60618             let event = events[1];
60619             let movementX = event.clientX - previousEvent.clientX;
60620             let movementY = event.clientY - previousEvent.clientY;
60621             let element = this._container.container;
60622             let [canvasX, canvasY] = this._viewportCoords.canvasPosition(event, element);
60623             let currentDirection = this._viewportCoords.unprojectFromCanvas(canvasX, canvasY, element, render.perspective)
60624                 .sub(render.perspective.position);
60625             let directionX = this._viewportCoords.unprojectFromCanvas(canvasX - movementX, canvasY, element, render.perspective)
60626                 .sub(render.perspective.position);
60627             let directionY = this._viewportCoords.unprojectFromCanvas(canvasX, canvasY - movementY, element, render.perspective)
60628                 .sub(render.perspective.position);
60629             let phi = (movementX > 0 ? 1 : -1) * directionX.angleTo(currentDirection);
60630             let theta = (movementY > 0 ? -1 : 1) * directionY.angleTo(currentDirection);
60631             const distances = viewportDistances(transform, render.perspective, this._viewportCoords);
60632             for (const [, t] of nts) {
60633                 const d = viewportDistances(t, render.perspective, this._viewportCoords);
60634                 for (let i = 0; i < distances.length; i++) {
60635                     if (d[i] < distances[i]) {
60636                         distances[i] = d[i];
60637                     }
60638                 }
60639             }
60640             if (distances[0] > 0 && theta < 0) {
60641                 theta /= Math.max(1, 2e2 * distances[0]);
60642             }
60643             if (distances[2] > 0 && theta > 0) {
60644                 theta /= Math.max(1, 2e2 * distances[2]);
60645             }
60646             if (distances[1] > 0 && phi < 0) {
60647                 phi /= Math.max(1, 2e2 * distances[1]);
60648             }
60649             if (distances[3] > 0 && phi > 0) {
60650                 phi /= Math.max(1, 2e2 * distances[3]);
60651             }
60652             return { phi: phi, theta: theta };
60653         }), share());
60654         this._rotateWithoutInertiaSubscription = rotation$
60655             .subscribe((rotation) => {
60656             this._navigator.stateService.rotateWithoutInertia(rotation);
60657         });
60658         this._rotateSubscription = rotation$.pipe(scan((rotationBuffer, rotation) => {
60659             this._drainBuffer(rotationBuffer);
60660             rotationBuffer.push([Date.now(), rotation]);
60661             return rotationBuffer;
60662         }, []), sample(merge(this._container.mouseService.filtered$(this._component.name, this._container.mouseService.mouseDragEnd$), this._container.touchService.singleTouchDragEnd$)), map((rotationBuffer) => {
60663             const drainedBuffer = this._drainBuffer(rotationBuffer.slice());
60664             const rotation = { phi: 0, theta: 0 };
60665             for (const bufferedRotation of drainedBuffer) {
60666                 rotation.phi += bufferedRotation[1].phi;
60667                 rotation.theta += bufferedRotation[1].theta;
60668             }
60669             const count = drainedBuffer.length;
60670             if (count > 0) {
60671                 rotation.phi /= count;
60672                 rotation.theta /= count;
60673             }
60674             const threshold = Math.PI / 18;
60675             rotation.phi = this._spatial.clamp(rotation.phi, -threshold, threshold);
60676             rotation.theta = this._spatial.clamp(rotation.theta, -threshold, threshold);
60677             return rotation;
60678         }))
60679             .subscribe((rotation) => {
60680             this._navigator.stateService.rotate(rotation);
60681         });
60682     }
60683     _disable() {
60684         this._activeMouseSubscription.unsubscribe();
60685         this._activeTouchSubscription.unsubscribe();
60686         this._preventDefaultSubscription.unsubscribe();
60687         this._rotateSubscription.unsubscribe();
60688         this._rotateWithoutInertiaSubscription.unsubscribe();
60689         this._activeMouseSubscription = null;
60690         this._activeTouchSubscription = null;
60691         this._preventDefaultSubscription = null;
60692         this._rotateSubscription = null;
60693     }
60694     _getConfiguration(enable) {
60695         return { dragPan: enable };
60696     }
60697     _drainBuffer(buffer) {
60698         const cutoff = 50;
60699         const now = Date.now();
60700         while (buffer.length > 0 && now - buffer[0][0] > cutoff) {
60701             buffer.shift();
60702         }
60703         return buffer;
60704     }
60705 }
60706
60707 class EarthControlHandler extends HandlerBase {
60708     /** @ignore */
60709     constructor(component, container, navigator, viewportCoords, spatial) {
60710         super(component, container, navigator);
60711         this._spatial = spatial;
60712         this._viewportCoords = viewportCoords;
60713         this._subscriptions = new SubscriptionHolder();
60714     }
60715     _enable() {
60716         const earth$ = this._navigator.stateService.state$.pipe(map((state) => {
60717             return state === State.Earth;
60718         }), publishReplay(1), refCount());
60719         const subs = this._subscriptions;
60720         subs.push(earth$.pipe(switchMap((earth) => {
60721             return earth ?
60722                 this._container.mouseService.mouseWheel$ :
60723                 empty();
60724         }))
60725             .subscribe((event) => {
60726             event.preventDefault();
60727         }));
60728         subs.push(earth$.pipe(switchMap((earth) => {
60729             if (!earth) {
60730                 return empty();
60731             }
60732             return MouseOperator.filteredPairwiseMouseDrag$(this._component.name, this._container.mouseService).pipe(filter(([e1, e2]) => {
60733                 return !(e1.ctrlKey && e2.ctrlKey);
60734             }));
60735         }), withLatestFrom(this._container.renderService.renderCamera$, this._navigator.stateService.currentTransform$), map(([[previous, current], render, transform]) => {
60736             const planeNormal = [0, 0, 1];
60737             const planePoint = [0, 0, -2];
60738             const currentIntersection = this._planeIntersection(current, planeNormal, planePoint, render.perspective, this._container.container);
60739             const previousIntersection = this._planeIntersection(previous, planeNormal, planePoint, render.perspective, this._container.container);
60740             if (!currentIntersection || !previousIntersection) {
60741                 return null;
60742             }
60743             const direction = new Vector3()
60744                 .subVectors(currentIntersection, previousIntersection)
60745                 .multiplyScalar(-1)
60746                 .toArray();
60747             return direction;
60748         }), filter((direction) => {
60749             return !!direction;
60750         }))
60751             .subscribe((direction) => {
60752             this._navigator.stateService.truck(direction);
60753         }));
60754         subs.push(earth$.pipe(switchMap((earth) => {
60755             if (!earth) {
60756                 return empty();
60757             }
60758             return MouseOperator.filteredPairwiseMouseDrag$(this._component.name, this._container.mouseService).pipe(filter(([e1, e2]) => {
60759                 return e1.ctrlKey && e2.ctrlKey;
60760             }));
60761         }), map(([previous, current]) => {
60762             return this._mousePairToRotation(previous, current);
60763         }))
60764             .subscribe((rotation) => {
60765             this._navigator.stateService.orbit(rotation);
60766         }));
60767         subs.push(earth$.pipe(switchMap((earth) => {
60768             if (!earth) {
60769                 return empty();
60770             }
60771             return MouseOperator.filteredPairwiseMouseRightDrag$(this._component.name, this._container.mouseService).pipe(filter(([e1, e2]) => {
60772                 return !e1.ctrlKey && !e2.ctrlKey;
60773             }));
60774         }), map(([previous, current]) => {
60775             return this._mousePairToRotation(previous, current);
60776         }))
60777             .subscribe((rotation) => {
60778             this._navigator.stateService.orbit(rotation);
60779         }));
60780         subs.push(earth$.pipe(switchMap((earth) => {
60781             if (!earth) {
60782                 return empty();
60783             }
60784             return this._container.mouseService
60785                 .filteredWheel$(this._component.name, this._container.mouseService.mouseWheel$);
60786         }), map((event) => {
60787             let delta = event.deltaY;
60788             if (event.deltaMode === 1) {
60789                 delta = 40 * delta;
60790             }
60791             else if (event.deltaMode === 2) {
60792                 delta = 800 * delta;
60793             }
60794             const canvasSize = this._viewportCoords.containerToCanvas(this._container.container);
60795             return -delta / canvasSize[1];
60796         }))
60797             .subscribe((delta) => {
60798             this._navigator.stateService.dolly(delta);
60799         }));
60800     }
60801     _disable() {
60802         this._subscriptions.unsubscribe();
60803     }
60804     _getConfiguration() {
60805         return {};
60806     }
60807     _eventToViewport(event, element) {
60808         const previousCanvas = this._viewportCoords.canvasPosition(event, element);
60809         return this._viewportCoords.canvasToViewport(previousCanvas[0], previousCanvas[1], element);
60810     }
60811     _mousePairToRotation(previous, current) {
60812         const [currentX, currentY] = this._eventToViewport(current, this._container.container);
60813         const [previousX, previousY] = this._eventToViewport(previous, this._container.container);
60814         const phi = (previousX - currentX) * Math.PI;
60815         const theta = (currentY - previousY) * Math.PI / 2;
60816         return { phi: phi, theta: theta };
60817     }
60818     _planeIntersection(event, planeNormal, planePoint, camera, element) {
60819         const [canvasX, canvasY] = this._viewportCoords.canvasPosition(event, element);
60820         const direction = this._viewportCoords
60821             .unprojectFromCanvas(canvasX, canvasY, element, camera)
60822             .sub(camera.position)
60823             .normalize();
60824         if (Math.abs(this._spatial.angleToPlane(direction.toArray(), planeNormal)) < Math.PI / 90) {
60825             return null;
60826         }
60827         const l0 = camera.position.clone();
60828         const n = new Vector3().fromArray(planeNormal);
60829         const p0 = new Vector3().fromArray(planePoint);
60830         const d = new Vector3().subVectors(p0, l0).dot(n) / direction.clone().dot(n);
60831         const intersection = new Vector3().addVectors(l0, direction.multiplyScalar(d));
60832         if (this._viewportCoords.worldToCamera(intersection.toArray(), camera)[2] > 0) {
60833             return null;
60834         }
60835         return intersection;
60836     }
60837 }
60838
60839 /**
60840  * The `ScrollZoomHandler` allows the user to zoom the viewer image by scrolling.
60841  *
60842  * @example
60843  * ```js
60844  * var pointerComponent = viewer.getComponent("pointer");
60845  *
60846  * pointerComponent.scrollZoom.disable();
60847  * pointerComponent.scrollZoom.enable();
60848  *
60849  * var isEnabled = pointerComponent.scrollZoom.isEnabled;
60850  * ```
60851  */
60852 class ScrollZoomHandler extends HandlerBase {
60853     /** @ignore */
60854     constructor(component, container, navigator, viewportCoords) {
60855         super(component, container, navigator);
60856         this._viewportCoords = viewportCoords;
60857     }
60858     _enable() {
60859         this._container.mouseService.claimWheel(this._component.name, 0);
60860         this._preventDefaultSubscription = this._container.mouseService.mouseWheel$
60861             .subscribe((event) => {
60862             event.preventDefault();
60863         });
60864         this._zoomSubscription = this._container.mouseService
60865             .filteredWheel$(this._component.name, this._container.mouseService.mouseWheel$).pipe(withLatestFrom(this._navigator.stateService.currentState$, (w, f) => {
60866             return [w, f];
60867         }), filter((args) => {
60868             let state = args[1].state;
60869             return isSpherical(state.currentImage.cameraType) ||
60870                 state.imagesAhead < 1;
60871         }), map((args) => {
60872             return args[0];
60873         }), withLatestFrom(this._container.renderService.renderCamera$, this._navigator.stateService.currentTransform$, (w, r, t) => {
60874             return [w, r, t];
60875         }))
60876             .subscribe((args) => {
60877             let event = args[0];
60878             let render = args[1];
60879             let transform = args[2];
60880             let element = this._container.container;
60881             let [canvasX, canvasY] = this._viewportCoords.canvasPosition(event, element);
60882             let unprojected = this._viewportCoords.unprojectFromCanvas(canvasX, canvasY, element, render.perspective);
60883             let reference = transform.projectBasic(unprojected.toArray());
60884             let deltaY = event.deltaY;
60885             if (event.deltaMode === 1) {
60886                 deltaY = 40 * deltaY;
60887             }
60888             else if (event.deltaMode === 2) {
60889                 deltaY = 800 * deltaY;
60890             }
60891             const canvasSize = this._viewportCoords.containerToCanvas(element);
60892             let zoom = -3 * deltaY / canvasSize[1];
60893             this._navigator.stateService.zoomIn(zoom, reference);
60894         });
60895     }
60896     _disable() {
60897         this._container.mouseService.unclaimWheel(this._component.name);
60898         this._preventDefaultSubscription.unsubscribe();
60899         this._zoomSubscription.unsubscribe();
60900         this._preventDefaultSubscription = null;
60901         this._zoomSubscription = null;
60902     }
60903     _getConfiguration(enable) {
60904         return { scrollZoom: enable };
60905     }
60906 }
60907
60908 /**
60909  * The `TouchZoomHandler` allows the user to zoom the viewer image by pinching on a touchscreen.
60910  *
60911  * @example
60912  * ```js
60913  * var pointerComponent = viewer.getComponent("pointer");
60914  *
60915  * pointerComponent.touchZoom.disable();
60916  * pointerComponent.touchZoom.enable();
60917  *
60918  * var isEnabled = pointerComponent.touchZoom.isEnabled;
60919  * ```
60920  */
60921 class TouchZoomHandler extends HandlerBase {
60922     /** @ignore */
60923     constructor(component, container, navigator, viewportCoords) {
60924         super(component, container, navigator);
60925         this._viewportCoords = viewportCoords;
60926     }
60927     _enable() {
60928         this._preventDefaultSubscription = this._container.touchService.pinch$
60929             .subscribe((pinch) => {
60930             pinch.originalEvent.preventDefault();
60931         });
60932         let pinchStarted$ = this._container.touchService.pinchStart$.pipe(map((event) => {
60933             return true;
60934         }));
60935         let pinchStopped$ = this._container.touchService.pinchEnd$.pipe(map((event) => {
60936             return false;
60937         }));
60938         this._activeSubscription = merge(pinchStarted$, pinchStopped$)
60939             .subscribe(this._container.touchService.activate$);
60940         this._zoomSubscription = this._container.touchService.pinch$.pipe(withLatestFrom(this._navigator.stateService.currentState$), filter((args) => {
60941             let state = args[1].state;
60942             return isSpherical(state.currentImage.cameraType) ||
60943                 state.imagesAhead < 1;
60944         }), map((args) => {
60945             return args[0];
60946         }), withLatestFrom(this._container.renderService.renderCamera$, this._navigator.stateService.currentTransform$))
60947             .subscribe(([pinch, render, transform]) => {
60948             let element = this._container.container;
60949             let [canvasX, canvasY] = this._viewportCoords.canvasPosition(pinch, element);
60950             let unprojected = this._viewportCoords.unprojectFromCanvas(canvasX, canvasY, element, render.perspective);
60951             let reference = transform.projectBasic(unprojected.toArray());
60952             const [canvasWidth, canvasHeight] = this._viewportCoords.containerToCanvas(element);
60953             let zoom = 3 * pinch.distanceChange / Math.min(canvasWidth, canvasHeight);
60954             this._navigator.stateService.zoomIn(zoom, reference);
60955         });
60956     }
60957     _disable() {
60958         this._activeSubscription.unsubscribe();
60959         this._preventDefaultSubscription.unsubscribe();
60960         this._zoomSubscription.unsubscribe();
60961         this._preventDefaultSubscription = null;
60962         this._zoomSubscription = null;
60963     }
60964     _getConfiguration(enable) {
60965         return { touchZoom: enable };
60966     }
60967 }
60968
60969 /**
60970  * @class PointerComponent
60971  *
60972  * @classdesc Component handling mouse, pen, and touch events for camera movement.
60973  *
60974  * To retrive and use the mouse component
60975  *
60976  * @example
60977  * ```js
60978  * var viewer = new Viewer({ ... });
60979  *
60980  * var pointerComponent = viewer.getComponent("pointer");
60981  * ```
60982  */
60983 class PointerComponent extends Component {
60984     /** @ignore */
60985     constructor(name, container, navigator) {
60986         super(name, container, navigator);
60987         const spatial = new Spatial();
60988         const viewportCoords = new ViewportCoords();
60989         this._bounceHandler =
60990             new BounceHandler(this, container, navigator, viewportCoords, spatial);
60991         this._dragPanHandler =
60992             new DragPanHandler(this, container, navigator, viewportCoords, spatial);
60993         this._earthControlHandler =
60994             new EarthControlHandler(this, container, navigator, viewportCoords, spatial);
60995         this._scrollZoomHandler =
60996             new ScrollZoomHandler(this, container, navigator, viewportCoords);
60997         this._touchZoomHandler =
60998             new TouchZoomHandler(this, container, navigator, viewportCoords);
60999     }
61000     /**
61001      * Get drag pan.
61002      *
61003      * @returns {DragPanHandler} The drag pan handler.
61004      */
61005     get dragPan() {
61006         return this._dragPanHandler;
61007     }
61008     /**
61009      * Get earth control.
61010      *
61011      * @returns {EarthControlHandler} The earth control handler.
61012      */
61013     get earthControl() {
61014         return this._earthControlHandler;
61015     }
61016     /**
61017      * Get scroll zoom.
61018      *
61019      * @returns {ScrollZoomHandler} The scroll zoom handler.
61020      */
61021     get scrollZoom() {
61022         return this._scrollZoomHandler;
61023     }
61024     /**
61025      * Get touch zoom.
61026      *
61027      * @returns {TouchZoomHandler} The touch zoom handler.
61028      */
61029     get touchZoom() {
61030         return this._touchZoomHandler;
61031     }
61032     _activate() {
61033         this._bounceHandler.enable();
61034         this._subscriptions.push(this._configuration$
61035             .subscribe((configuration) => {
61036             if (configuration.dragPan) {
61037                 this._dragPanHandler.enable();
61038             }
61039             else {
61040                 this._dragPanHandler.disable();
61041             }
61042             if (configuration.earthControl) {
61043                 this._earthControlHandler.enable();
61044             }
61045             else {
61046                 this._earthControlHandler.disable();
61047             }
61048             if (configuration.scrollZoom) {
61049                 this._scrollZoomHandler.enable();
61050             }
61051             else {
61052                 this._scrollZoomHandler.disable();
61053             }
61054             if (configuration.touchZoom) {
61055                 this._touchZoomHandler.enable();
61056             }
61057             else {
61058                 this._touchZoomHandler.disable();
61059             }
61060         }));
61061         this._container.mouseService.claimMouse(this._name, 0);
61062     }
61063     _deactivate() {
61064         this._container.mouseService.unclaimMouse(this._name);
61065         this._subscriptions.unsubscribe();
61066         this._bounceHandler.disable();
61067         this._dragPanHandler.disable();
61068         this._earthControlHandler.disable();
61069         this._scrollZoomHandler.disable();
61070         this._touchZoomHandler.disable();
61071     }
61072     _getDefaultConfiguration() {
61073         return {
61074             dragPan: true,
61075             earthControl: true,
61076             scrollZoom: true,
61077             touchZoom: true,
61078         };
61079     }
61080 }
61081 /** @inheritdoc */
61082 PointerComponent.componentName = "pointer";
61083
61084 class DOM {
61085     constructor(doc) {
61086         this._document = !!doc ? doc : document;
61087     }
61088     get document() {
61089         return this._document;
61090     }
61091     createElement(tagName, className, container) {
61092         const element = this._document.createElement(tagName);
61093         if (!!className) {
61094             element.className = className;
61095         }
61096         if (!!container) {
61097             container.appendChild(element);
61098         }
61099         return element;
61100     }
61101 }
61102
61103 /**
61104  * @class PopupComponent
61105  *
61106  * @classdesc Component for showing HTML popup objects.
61107  *
61108  * The `add` method is used for adding new popups. Popups are removed by reference.
61109  *
61110  * It is not possible to update popups in the set by updating any properties
61111  * directly on the popup object. Popups need to be replaced by
61112  * removing them and creating new ones with relevant changed properties and
61113  * adding those instead.
61114  *
61115  * Popups are only relevant to a single image because they are based on
61116  * 2D basic image coordinates. Popups related to a certain image should
61117  * be removed when the viewer is moved to another image.
61118  *
61119  * To retrive and use the popup component
61120  *
61121  * @example
61122  * ```js
61123  * var viewer = new Viewer({ component: { popup: true }, ... });
61124  *
61125  * var popupComponent = viewer.getComponent("popup");
61126  * ```
61127  */
61128 class PopupComponent extends Component {
61129     /** @ignore */
61130     constructor(name, container, navigator, dom) {
61131         super(name, container, navigator);
61132         this._dom = !!dom ? dom : new DOM();
61133         this._popups = [];
61134         this._added$ = new Subject();
61135         this._popups$ = new Subject();
61136     }
61137     /**
61138      * Add popups to the popups set.
61139      *
61140      * @description Adding a new popup never replaces an old one
61141      * because they are stored by reference. Adding an already
61142      * existing popup has no effect.
61143      *
61144      * @param {Array<Popup>} popups - Popups to add.
61145      *
61146      * @example
61147      * ```js
61148      * popupComponent.add([popup1, popup2]);
61149      * ```
61150      */
61151     add(popups) {
61152         for (const popup of popups) {
61153             if (this._popups.indexOf(popup) !== -1) {
61154                 continue;
61155             }
61156             this._popups.push(popup);
61157             if (this._activated) {
61158                 popup.setParentContainer(this._popupContainer);
61159             }
61160         }
61161         this._added$.next(popups);
61162         this._popups$.next(this._popups);
61163     }
61164     /**
61165      * Returns an array of all popups.
61166      *
61167      * @example
61168      * ```js
61169      * var popups = popupComponent.getAll();
61170      * ```
61171      */
61172     getAll() {
61173         return this._popups.slice();
61174     }
61175     /**
61176      * Remove popups based on reference from the popup set.
61177      *
61178      * @param {Array<Popup>} popups - Popups to remove.
61179      *
61180      * @example
61181      * ```js
61182      * popupComponent.remove([popup1, popup2]);
61183      * ```
61184      */
61185     remove(popups) {
61186         for (const popup of popups) {
61187             this._remove(popup);
61188         }
61189         this._popups$.next(this._popups);
61190     }
61191     /**
61192      * Remove all popups from the popup set.
61193      *
61194      * @example
61195      * ```js
61196      * popupComponent.removeAll();
61197      * ```
61198      */
61199     removeAll() {
61200         for (const popup of this._popups.slice()) {
61201             this._remove(popup);
61202         }
61203         this._popups$.next(this._popups);
61204     }
61205     _activate() {
61206         this._popupContainer = this._dom.createElement("div", "mapillary-popup-container", this._container.container);
61207         for (const popup of this._popups) {
61208             popup.setParentContainer(this._popupContainer);
61209         }
61210         const subs = this._subscriptions;
61211         subs.push(combineLatest(this._container.renderService.renderCamera$, this._container.renderService.size$, this._navigator.stateService.currentTransform$)
61212             .subscribe(([renderCamera, size, transform]) => {
61213             for (const popup of this._popups) {
61214                 popup.update(renderCamera, size, transform);
61215             }
61216         }));
61217         const changed$ = this._popups$.pipe(startWith(this._popups), switchMap((popups) => {
61218             return from(popups).pipe(mergeMap((popup) => {
61219                 return popup.changed$;
61220             }));
61221         }), map((popup) => {
61222             return [popup];
61223         }));
61224         subs.push(merge(this._added$, changed$).pipe(withLatestFrom(this._container.renderService.renderCamera$, this._container.renderService.size$, this._navigator.stateService.currentTransform$))
61225             .subscribe(([popups, renderCamera, size, transform]) => {
61226             for (const popup of popups) {
61227                 popup.update(renderCamera, size, transform);
61228             }
61229         }));
61230     }
61231     _deactivate() {
61232         this._subscriptions.unsubscribe();
61233         for (const popup of this._popups) {
61234             popup.remove();
61235         }
61236         this._container.container.removeChild(this._popupContainer);
61237         delete this._popupContainer;
61238     }
61239     _getDefaultConfiguration() {
61240         return {};
61241     }
61242     _remove(popup) {
61243         const index = this._popups.indexOf(popup);
61244         if (index === -1) {
61245             return;
61246         }
61247         const removed = this._popups.splice(index, 1)[0];
61248         if (this._activated) {
61249             removed.remove();
61250         }
61251     }
61252 }
61253 PopupComponent.componentName = "popup";
61254
61255 /**
61256  * Enumeration for graph modes.
61257  * @enum {number}
61258  * @readonly
61259  * @description Modes for the retrieval and caching performed
61260  * by the graph service on the graph.
61261  */
61262 var GraphMode;
61263 (function (GraphMode) {
61264     /**
61265      * Caching is performed on sequences only and sequence edges are
61266      * calculated. Spatial tiles
61267      * are not retrieved and spatial edges are not calculated when
61268      * caching nodes. Complete sequences are being cached for requested
61269      * nodes within the graph.
61270      */
61271     GraphMode[GraphMode["Sequence"] = 0] = "Sequence";
61272     /**
61273      * Caching is performed with emphasis on spatial data. Sequence edges
61274      * as well as spatial edges are cached. Sequence data
61275      * is still requested but complete sequences are not being cached
61276      * for requested nodes.
61277      *
61278      * This is the initial mode of the graph service.
61279      */
61280     GraphMode[GraphMode["Spatial"] = 1] = "Spatial";
61281 })(GraphMode || (GraphMode = {}));
61282
61283 var SequenceMode;
61284 (function (SequenceMode) {
61285     SequenceMode[SequenceMode["Default"] = 0] = "Default";
61286     SequenceMode[SequenceMode["Playback"] = 1] = "Playback";
61287     SequenceMode[SequenceMode["Timeline"] = 2] = "Timeline";
61288 })(SequenceMode || (SequenceMode = {}));
61289
61290 class SequenceDOMRenderer {
61291     constructor(container) {
61292         this._container = container;
61293         this._minThresholdWidth = 320;
61294         this._maxThresholdWidth = 1480;
61295         this._minThresholdHeight = 240;
61296         this._maxThresholdHeight = 820;
61297         this._stepperDefaultWidth = 108;
61298         this._controlsDefaultWidth = 88;
61299         this._defaultHeight = 30;
61300         this._expandControls = false;
61301         this._mode = SequenceMode.Default;
61302         this._speed = 0.5;
61303         this._changingSpeed = false;
61304         this._index = null;
61305         this._changingPosition = false;
61306         this._mouseEnterDirection$ = new Subject();
61307         this._mouseLeaveDirection$ = new Subject();
61308         this._notifyChanged$ = new Subject();
61309         this._notifyChangingPositionChanged$ = new Subject();
61310         this._notifySpeedChanged$ = new Subject();
61311         this._notifyIndexChanged$ = new Subject();
61312     }
61313     get changed$() {
61314         return this._notifyChanged$;
61315     }
61316     get changingPositionChanged$() {
61317         return this._notifyChangingPositionChanged$;
61318     }
61319     get speed$() {
61320         return this._notifySpeedChanged$;
61321     }
61322     get index$() {
61323         return this._notifyIndexChanged$;
61324     }
61325     get mouseEnterDirection$() {
61326         return this._mouseEnterDirection$;
61327     }
61328     get mouseLeaveDirection$() {
61329         return this._mouseLeaveDirection$;
61330     }
61331     activate() {
61332         if (!!this._changingSubscription) {
61333             return;
61334         }
61335         this._changingSubscription = merge(this._container.mouseService.documentMouseUp$, this._container.touchService.touchEnd$.pipe(filter((touchEvent) => {
61336             return touchEvent.touches.length === 0;
61337         })))
61338             .subscribe(() => {
61339             if (this._changingSpeed) {
61340                 this._changingSpeed = false;
61341             }
61342             if (this._changingPosition) {
61343                 this._setChangingPosition(false);
61344             }
61345         });
61346     }
61347     deactivate() {
61348         if (!this._changingSubscription) {
61349             return;
61350         }
61351         this._changingSpeed = false;
61352         this._changingPosition = false;
61353         this._expandControls = false;
61354         this._mode = SequenceMode.Default;
61355         this._changingSubscription.unsubscribe();
61356         this._changingSubscription = null;
61357     }
61358     render(edgeStatus, configuration, containerWidth, speed, index, max, playEnabled, component, navigator) {
61359         if (configuration.visible === false) {
61360             return virtualDom.h("div.mapillary-sequence-container", {}, []);
61361         }
61362         const stepper = this._createStepper(edgeStatus, configuration, playEnabled, containerWidth, component, navigator);
61363         const controls = this._createSequenceControls(containerWidth);
61364         const playback = this._createPlaybackControls(containerWidth, speed, component, configuration);
61365         const timeline = this._createTimelineControls(containerWidth, index, max);
61366         return virtualDom.h("div.mapillary-sequence-container", [stepper, controls, playback, timeline]);
61367     }
61368     getContainerWidth(size, configuration) {
61369         let minWidth = configuration.minWidth;
61370         let maxWidth = configuration.maxWidth;
61371         if (maxWidth < minWidth) {
61372             maxWidth = minWidth;
61373         }
61374         let relativeWidth = (size.width - this._minThresholdWidth) / (this._maxThresholdWidth - this._minThresholdWidth);
61375         let relativeHeight = (size.height - this._minThresholdHeight) / (this._maxThresholdHeight - this._minThresholdHeight);
61376         let coeff = Math.max(0, Math.min(1, Math.min(relativeWidth, relativeHeight)));
61377         return minWidth + coeff * (maxWidth - minWidth);
61378     }
61379     _createPositionInput(index, max) {
61380         this._index = index;
61381         const onPosition = (e) => {
61382             this._index = Number(e.target.value);
61383             this._notifyIndexChanged$.next(this._index);
61384         };
61385         const boundingRect = this._container.domContainer.getBoundingClientRect();
61386         const width = Math.max(276, Math.min(410, 5 + 0.8 * boundingRect.width)) - 65;
61387         const onStart = (e) => {
61388             e.stopPropagation();
61389             this._setChangingPosition(true);
61390         };
61391         const onMove = (e) => {
61392             if (this._changingPosition === true) {
61393                 e.stopPropagation();
61394             }
61395         };
61396         const onKeyDown = (e) => {
61397             if (e.key === "ArrowDown" || e.key === "ArrowLeft" ||
61398                 e.key === "ArrowRight" || e.key === "ArrowUp") {
61399                 e.preventDefault();
61400             }
61401         };
61402         const positionInputProperties = {
61403             max: max != null ? max : 1,
61404             min: 0,
61405             onchange: onPosition,
61406             oninput: onPosition,
61407             onkeydown: onKeyDown,
61408             onpointerdown: onStart,
61409             onpointermove: onMove,
61410             ontouchmove: onMove,
61411             ontouchstart: onStart,
61412             style: {
61413                 width: `${width}px`,
61414             },
61415             type: "range",
61416             value: index != null ? index : 0,
61417         };
61418         const disabled = index == null || max == null || max <= 1;
61419         if (disabled) {
61420             positionInputProperties.disabled = "true";
61421         }
61422         const positionInput = virtualDom.h("input.mapillary-sequence-position", positionInputProperties, []);
61423         const positionContainerClass = disabled ? ".mapillary-sequence-position-container-inactive" : ".mapillary-sequence-position-container";
61424         return virtualDom.h("div" + positionContainerClass, [positionInput]);
61425     }
61426     _createSpeedInput(speed) {
61427         this._speed = speed;
61428         const onSpeed = (e) => {
61429             this._speed = Number(e.target.value) / 1000;
61430             this._notifySpeedChanged$.next(this._speed);
61431         };
61432         const boundingRect = this._container.domContainer.getBoundingClientRect();
61433         const width = Math.max(276, Math.min(410, 5 + 0.8 * boundingRect.width)) - 160;
61434         const onStart = (e) => {
61435             this._changingSpeed = true;
61436             e.stopPropagation();
61437         };
61438         const onMove = (e) => {
61439             if (this._changingSpeed === true) {
61440                 e.stopPropagation();
61441             }
61442         };
61443         const onKeyDown = (e) => {
61444             if (e.key === "ArrowDown" || e.key === "ArrowLeft" ||
61445                 e.key === "ArrowRight" || e.key === "ArrowUp") {
61446                 e.preventDefault();
61447             }
61448         };
61449         const speedInput = virtualDom.h("input.mapillary-sequence-speed", {
61450             max: 1000,
61451             min: 0,
61452             onchange: onSpeed,
61453             oninput: onSpeed,
61454             onkeydown: onKeyDown,
61455             onpointerdown: onStart,
61456             onpointermove: onMove,
61457             ontouchmove: onMove,
61458             ontouchstart: onStart,
61459             style: {
61460                 width: `${width}px`,
61461             },
61462             type: "range",
61463             value: 1000 * speed,
61464         }, []);
61465         return virtualDom.h("div.mapillary-sequence-speed-container", [speedInput]);
61466     }
61467     _createPlaybackControls(containerWidth, speed, component, configuration) {
61468         if (this._mode !== SequenceMode.Playback) {
61469             return virtualDom.h("div.mapillary-sequence-playback", []);
61470         }
61471         const switchIcon = virtualDom.h("div.mapillary-sequence-switch-icon.mapillary-sequence-icon-visible", []);
61472         const direction = configuration.direction === NavigationDirection.Next ?
61473             NavigationDirection.Prev : NavigationDirection.Next;
61474         const playing = configuration.playing;
61475         const switchButtonProperties = {
61476             onclick: () => {
61477                 if (!playing) {
61478                     component.configure({ direction });
61479                 }
61480             },
61481         };
61482         const switchButtonClassName = configuration.playing ? ".mapillary-sequence-switch-button-inactive" : ".mapillary-sequence-switch-button";
61483         const switchButton = virtualDom.h("div" + switchButtonClassName, switchButtonProperties, [switchIcon]);
61484         const slowIcon = virtualDom.h("div.mapillary-sequence-slow-icon.mapillary-sequence-icon-visible", []);
61485         const slowContainer = virtualDom.h("div.mapillary-sequence-slow-container", [slowIcon]);
61486         const fastIcon = virtualDom.h("div.mapillary-sequence-fast-icon.mapillary-sequence-icon-visible", []);
61487         const fastContainer = virtualDom.h("div.mapillary-sequence-fast-container", [fastIcon]);
61488         const closeIcon = virtualDom.h("div.mapillary-sequence-close-icon.mapillary-sequence-icon-visible", []);
61489         const closeButtonProperties = {
61490             onclick: () => {
61491                 this._mode = SequenceMode.Default;
61492                 this._notifyChanged$.next(this);
61493             },
61494         };
61495         const closeButton = virtualDom.h("div.mapillary-sequence-close-button", closeButtonProperties, [closeIcon]);
61496         const speedInput = this._createSpeedInput(speed);
61497         const playbackChildren = [switchButton, slowContainer, speedInput, fastContainer, closeButton];
61498         const top = Math.round(containerWidth / this._stepperDefaultWidth * this._defaultHeight + 10);
61499         const playbackProperties = { style: { top: `${top}px` } };
61500         return virtualDom.h("div.mapillary-sequence-playback", playbackProperties, playbackChildren);
61501     }
61502     _createPlayingButton(nextId, prevId, playEnabled, configuration, component) {
61503         let canPlay = (configuration.direction === NavigationDirection.Next && nextId != null) ||
61504             (configuration.direction === NavigationDirection.Prev && prevId != null);
61505         canPlay = canPlay && playEnabled;
61506         let onclick = configuration.playing ?
61507             () => { component.stop(); } :
61508             canPlay ? () => { component.play(); } : null;
61509         let buttonProperties = { onclick: onclick };
61510         let iconProperties = {};
61511         if (configuration.direction === NavigationDirection.Prev) {
61512             iconProperties.style = {
61513                 transform: "rotate(180deg) translate(50%, 50%)",
61514             };
61515         }
61516         let icon = virtualDom.h("div.mapillary-sequence-icon", iconProperties, []);
61517         let buttonClass = configuration.playing ?
61518             "mapillary-sequence-stop" :
61519             canPlay ?
61520                 "mapillary-sequence-play" :
61521                 "mapillary-sequence-play-inactive";
61522         return virtualDom.h("div." + buttonClass, buttonProperties, [icon]);
61523     }
61524     _createSequenceControls(containerWidth) {
61525         const borderRadius = Math.round(8 / this._stepperDefaultWidth * containerWidth);
61526         const expanderProperties = {
61527             onclick: () => {
61528                 this._expandControls = !this._expandControls;
61529                 this._mode = SequenceMode.Default;
61530                 this._notifyChanged$.next(this);
61531             },
61532             style: {
61533                 "border-bottom-right-radius": `${borderRadius}px`,
61534                 "border-top-right-radius": `${borderRadius}px`,
61535             },
61536         };
61537         const expanderBar = virtualDom.h("div.mapillary-sequence-expander-bar", []);
61538         const expander = virtualDom.h("div.mapillary-sequence-expander-button", expanderProperties, [expanderBar]);
61539         const fastIconClassName = this._mode === SequenceMode.Playback ?
61540             ".mapillary-sequence-fast-icon-gray.mapillary-sequence-icon-visible" : ".mapillary-sequence-fast-icon";
61541         const fastIcon = virtualDom.h("div" + fastIconClassName, []);
61542         const playbackProperties = {
61543             onclick: () => {
61544                 this._mode = this._mode === SequenceMode.Playback ?
61545                     SequenceMode.Default :
61546                     SequenceMode.Playback;
61547                 this._notifyChanged$.next(this);
61548             },
61549         };
61550         const playback = virtualDom.h("div.mapillary-sequence-playback-button", playbackProperties, [fastIcon]);
61551         const timelineIconClassName = this._mode === SequenceMode.Timeline ?
61552             ".mapillary-sequence-timeline-icon-gray.mapillary-sequence-icon-visible" : ".mapillary-sequence-timeline-icon";
61553         const timelineIcon = virtualDom.h("div" + timelineIconClassName, []);
61554         const timelineProperties = {
61555             onclick: () => {
61556                 this._mode = this._mode === SequenceMode.Timeline ?
61557                     SequenceMode.Default :
61558                     SequenceMode.Timeline;
61559                 this._notifyChanged$.next(this);
61560             },
61561         };
61562         const timeline = virtualDom.h("div.mapillary-sequence-timeline-button", timelineProperties, [timelineIcon]);
61563         const properties = {
61564             style: {
61565                 height: (this._defaultHeight / this._stepperDefaultWidth * containerWidth) + "px",
61566                 transform: `translate(${containerWidth / 2 + 2}px, 0)`,
61567                 width: (this._controlsDefaultWidth / this._stepperDefaultWidth * containerWidth) + "px",
61568             },
61569         };
61570         const className = ".mapillary-sequence-controls" +
61571             (this._expandControls ? ".mapillary-sequence-controls-expanded" : "");
61572         return virtualDom.h("div" + className, properties, [playback, timeline, expander]);
61573     }
61574     _createSequenceArrows(nextId, prevId, containerWidth, configuration, navigator) {
61575         let nextProperties = {
61576             onclick: nextId != null ?
61577                 () => {
61578                     navigator.moveDir$(NavigationDirection.Next)
61579                         .subscribe(undefined, (error) => {
61580                         if (!(error instanceof CancelMapillaryError)) {
61581                             console.error(error);
61582                         }
61583                     });
61584                 } :
61585                 null,
61586             onpointerenter: () => { this._mouseEnterDirection$.next(NavigationDirection.Next); },
61587             onpointerleave: () => { this._mouseLeaveDirection$.next(NavigationDirection.Next); },
61588         };
61589         const borderRadius = Math.round(8 / this._stepperDefaultWidth * containerWidth);
61590         let prevProperties = {
61591             onclick: prevId != null ?
61592                 () => {
61593                     navigator.moveDir$(NavigationDirection.Prev)
61594                         .subscribe(undefined, (error) => {
61595                         if (!(error instanceof CancelMapillaryError)) {
61596                             console.error(error);
61597                         }
61598                     });
61599                 } :
61600                 null,
61601             onpointerenter: () => { this._mouseEnterDirection$.next(NavigationDirection.Prev); },
61602             onpointerleave: () => { this._mouseLeaveDirection$.next(NavigationDirection.Prev); },
61603             style: {
61604                 "border-bottom-left-radius": `${borderRadius}px`,
61605                 "border-top-left-radius": `${borderRadius}px`,
61606             },
61607         };
61608         let nextClass = this._getStepClassName(NavigationDirection.Next, nextId, configuration.highlightId);
61609         let prevClass = this._getStepClassName(NavigationDirection.Prev, prevId, configuration.highlightId);
61610         let nextIcon = virtualDom.h("div.mapillary-sequence-icon", []);
61611         let prevIcon = virtualDom.h("div.mapillary-sequence-icon", []);
61612         return [
61613             virtualDom.h("div." + prevClass, prevProperties, [prevIcon]),
61614             virtualDom.h("div." + nextClass, nextProperties, [nextIcon]),
61615         ];
61616     }
61617     _createStepper(edgeStatus, configuration, playEnabled, containerWidth, component, navigator) {
61618         let nextId = null;
61619         let prevId = null;
61620         for (let edge of edgeStatus.edges) {
61621             if (edge.data.direction === NavigationDirection.Next) {
61622                 nextId = edge.target;
61623             }
61624             if (edge.data.direction === NavigationDirection.Prev) {
61625                 prevId = edge.target;
61626             }
61627         }
61628         const playingButton = this._createPlayingButton(nextId, prevId, playEnabled, configuration, component);
61629         const buttons = this._createSequenceArrows(nextId, prevId, containerWidth, configuration, navigator);
61630         buttons.splice(1, 0, playingButton);
61631         const containerProperties = {
61632             oncontextmenu: (event) => { event.preventDefault(); },
61633             style: {
61634                 height: (this._defaultHeight / this._stepperDefaultWidth * containerWidth) + "px",
61635                 width: containerWidth + "px",
61636             },
61637         };
61638         return virtualDom.h("div.mapillary-sequence-stepper", containerProperties, buttons);
61639     }
61640     _createTimelineControls(containerWidth, index, max) {
61641         if (this._mode !== SequenceMode.Timeline) {
61642             return virtualDom.h("div.mapillary-sequence-timeline", []);
61643         }
61644         const positionInput = this._createPositionInput(index, max);
61645         const closeIcon = virtualDom.h("div.mapillary-sequence-close-icon.mapillary-sequence-icon-visible", []);
61646         const closeButtonProperties = {
61647             onclick: () => {
61648                 this._mode = SequenceMode.Default;
61649                 this._notifyChanged$.next(this);
61650             },
61651         };
61652         const closeButton = virtualDom.h("div.mapillary-sequence-close-button", closeButtonProperties, [closeIcon]);
61653         const top = Math.round(containerWidth / this._stepperDefaultWidth * this._defaultHeight + 10);
61654         const playbackProperties = { style: { top: `${top}px` } };
61655         return virtualDom.h("div.mapillary-sequence-timeline", playbackProperties, [positionInput, closeButton]);
61656     }
61657     _getStepClassName(direction, imageId, highlightId) {
61658         let className = direction === NavigationDirection.Next ?
61659             "mapillary-sequence-step-next" :
61660             "mapillary-sequence-step-prev";
61661         if (imageId == null) {
61662             className += "-inactive";
61663         }
61664         else {
61665             if (highlightId === imageId) {
61666                 className += "-highlight";
61667             }
61668         }
61669         return className;
61670     }
61671     _setChangingPosition(value) {
61672         this._changingPosition = value;
61673         this._notifyChangingPositionChanged$.next(value);
61674     }
61675 }
61676
61677 /**
61678  * @class SequenceComponent
61679  * @classdesc Component showing navigation arrows for sequence directions
61680  * as well as playing button. Exposes an API to start and stop play.
61681  */
61682 class SequenceComponent extends Component {
61683     constructor(name, container, navigator, renderer, scheduler) {
61684         super(name, container, navigator);
61685         this._sequenceDOMRenderer = !!renderer ? renderer : new SequenceDOMRenderer(container);
61686         this._scheduler = scheduler;
61687         this._containerWidth$ = new Subject();
61688         this._hoveredIdSubject$ = new Subject();
61689         this._hoveredId$ = this._hoveredIdSubject$.pipe(share());
61690         this._navigator.playService.playing$.pipe(skip(1), withLatestFrom(this._configuration$))
61691             .subscribe(([playing, configuration]) => {
61692             const type = "playing";
61693             const event = {
61694                 playing,
61695                 target: this,
61696                 type,
61697             };
61698             this.fire(type, event);
61699             if (playing === configuration.playing) {
61700                 return;
61701             }
61702             if (playing) {
61703                 this.play();
61704             }
61705             else {
61706                 this.stop();
61707             }
61708         });
61709         this._navigator.playService.direction$.pipe(skip(1), withLatestFrom(this._configuration$))
61710             .subscribe(([direction, configuration]) => {
61711             if (direction !== configuration.direction) {
61712                 this.configure({ direction });
61713             }
61714         });
61715     }
61716     fire(type, event) {
61717         super.fire(type, event);
61718     }
61719     off(type, handler) {
61720         super.off(type, handler);
61721     }
61722     on(type, handler) {
61723         super.on(type, handler);
61724     }
61725     /**
61726      * Start playing.
61727      *
61728      * @fires playing
61729      */
61730     play() { this.configure({ playing: true }); }
61731     /**
61732      * Stop playing.
61733      *
61734      * @fires playing
61735      */
61736     stop() { this.configure({ playing: false }); }
61737     _activate() {
61738         this._sequenceDOMRenderer.activate();
61739         const edgeStatus$ = this._navigator.stateService.currentImage$.pipe(switchMap((image) => {
61740             return image.sequenceEdges$;
61741         }), publishReplay(1), refCount());
61742         const sequence$ = this._navigator.stateService.currentImage$.pipe(distinctUntilChanged(undefined, (image) => {
61743             return image.sequenceId;
61744         }), switchMap((image) => {
61745             return concat(of(null), this._navigator.graphService.cacheSequence$(image.sequenceId).pipe(retry(3), catchError((e) => {
61746                 console.error("Failed to cache sequence", e);
61747                 return of(null);
61748             })));
61749         }), startWith(null), publishReplay(1), refCount());
61750         const subs = this._subscriptions;
61751         subs.push(sequence$.subscribe());
61752         const rendererId$ = this._sequenceDOMRenderer.index$.pipe(withLatestFrom(sequence$), map(([index, sequence]) => {
61753             return sequence != null ? sequence.imageIds[index] : null;
61754         }), filter((id) => {
61755             return !!id;
61756         }), distinctUntilChanged(), publish(), refCount());
61757         subs.push(merge(rendererId$.pipe(debounceTime(100, this._scheduler)), rendererId$.pipe(auditTime(400, this._scheduler))).pipe(distinctUntilChanged(), switchMap((id) => {
61758             return this._navigator.moveTo$(id).pipe(catchError(() => {
61759                 return empty();
61760             }));
61761         }))
61762             .subscribe());
61763         subs.push(this._sequenceDOMRenderer.changingPositionChanged$.pipe(filter((changing) => {
61764             return changing;
61765         }))
61766             .subscribe(() => {
61767             this._navigator.graphService.setGraphMode(GraphMode.Sequence);
61768         }));
61769         subs.push(this._sequenceDOMRenderer.changingPositionChanged$.pipe(filter((changing) => {
61770             return !changing;
61771         }))
61772             .subscribe(() => {
61773             this._navigator.graphService.setGraphMode(GraphMode.Spatial);
61774         }));
61775         this._navigator.graphService.graphMode$.pipe(switchMap((mode) => {
61776             return mode === GraphMode.Spatial ?
61777                 this._navigator.stateService.currentImage$.pipe(take(2)) :
61778                 empty();
61779         }), filter((image) => {
61780             return !image.spatialEdges.cached;
61781         }), switchMap((image) => {
61782             return this._navigator.graphService.cacheImage$(image.id).pipe(catchError(() => {
61783                 return empty();
61784             }));
61785         }))
61786             .subscribe();
61787         subs.push(this._sequenceDOMRenderer.changingPositionChanged$.pipe(filter((changing) => {
61788             return changing;
61789         }))
61790             .subscribe(() => {
61791             this._navigator.playService.stop();
61792         }));
61793         subs.push(combineLatest(this._navigator.graphService.graphMode$, this._sequenceDOMRenderer.changingPositionChanged$.pipe(startWith(false), distinctUntilChanged())).pipe(withLatestFrom(this._navigator.stateService.currentImage$), switchMap(([[mode, changing], image]) => {
61794             return changing && mode === GraphMode.Sequence ?
61795                 this._navigator.graphService.cacheSequenceImages$(image.sequenceId, image.id).pipe(retry(3), catchError((error) => {
61796                     console.error("Failed to cache sequence images.", error);
61797                     return empty();
61798                 })) :
61799                 empty();
61800         }))
61801             .subscribe());
61802         const position$ = sequence$.pipe(switchMap((sequence) => {
61803             if (!sequence) {
61804                 return of({ index: null, max: null });
61805             }
61806             let firstCurrentId = true;
61807             return this._sequenceDOMRenderer.changingPositionChanged$.pipe(startWith(false), distinctUntilChanged(), switchMap((changingPosition) => {
61808                 const skipCount = !changingPosition &&
61809                     firstCurrentId ?
61810                     0 : 1;
61811                 firstCurrentId = false;
61812                 return changingPosition ?
61813                     rendererId$ :
61814                     this._navigator.stateService.currentImage$.pipe(map((image) => {
61815                         return image.id;
61816                     }), distinctUntilChanged(), skip(skipCount));
61817             }), map((imageId) => {
61818                 const index = sequence.imageIds.indexOf(imageId);
61819                 if (index === -1) {
61820                     return { index: null, max: null };
61821                 }
61822                 return { index: index, max: sequence.imageIds.length - 1 };
61823             }));
61824         }));
61825         const earth$ = this._navigator.stateService.state$.pipe(map((state) => {
61826             return state === State.Earth;
61827         }), distinctUntilChanged());
61828         subs.push(combineLatest(edgeStatus$, this._configuration$, this._containerWidth$, this._sequenceDOMRenderer.changed$.pipe(startWith(this._sequenceDOMRenderer)), this._navigator.playService.speed$, position$, earth$).pipe(map(([edgeStatus, configuration, containerWidth, , speed, position, earth]) => {
61829             const vNode = this._sequenceDOMRenderer
61830                 .render(edgeStatus, configuration, containerWidth, speed, position.index, position.max, !earth, this, this._navigator);
61831             return { name: this._name, vNode: vNode };
61832         }))
61833             .subscribe(this._container.domRenderer.render$));
61834         subs.push(this._sequenceDOMRenderer.speed$
61835             .subscribe((speed) => {
61836             this._navigator.playService.setSpeed(speed);
61837         }));
61838         subs.push(this._configuration$.pipe(map((configuration) => {
61839             return configuration.direction;
61840         }), distinctUntilChanged())
61841             .subscribe((direction) => {
61842             this._navigator.playService.setDirection(direction);
61843         }));
61844         subs.push(combineLatest(this._container.renderService.size$, this._configuration$.pipe(distinctUntilChanged((value1, value2) => {
61845             return value1[0] === value2[0] && value1[1] === value2[1];
61846         }, (configuration) => {
61847             return [configuration.minWidth, configuration.maxWidth];
61848         }))).pipe(map(([size, configuration]) => {
61849             return this._sequenceDOMRenderer.getContainerWidth(size, configuration);
61850         }))
61851             .subscribe(this._containerWidth$));
61852         subs.push(this._configuration$.pipe(map((configuration) => {
61853             return configuration.playing;
61854         }), distinctUntilChanged())
61855             .subscribe((playing) => {
61856             if (playing) {
61857                 this._navigator.playService.play();
61858             }
61859             else {
61860                 this._navigator.playService.stop();
61861             }
61862         }));
61863         subs.push(this._sequenceDOMRenderer.mouseEnterDirection$.pipe(switchMap((direction) => {
61864             const edgeTo$ = edgeStatus$.pipe(map((edgeStatus) => {
61865                 for (let edge of edgeStatus.edges) {
61866                     if (edge.data.direction === direction) {
61867                         return edge.target;
61868                     }
61869                 }
61870                 return null;
61871             }), takeUntil(this._sequenceDOMRenderer.mouseLeaveDirection$));
61872             return concat(edgeTo$, of(null));
61873         }), distinctUntilChanged())
61874             .subscribe(this._hoveredIdSubject$));
61875         subs.push(this._hoveredId$
61876             .subscribe((id) => {
61877             const type = "hover";
61878             const event = {
61879                 id,
61880                 target: this,
61881                 type,
61882             };
61883             this.fire(type, event);
61884         }));
61885     }
61886     _deactivate() {
61887         this._subscriptions.unsubscribe();
61888         this._sequenceDOMRenderer.deactivate();
61889     }
61890     _getDefaultConfiguration() {
61891         return {
61892             direction: NavigationDirection.Next,
61893             maxWidth: 108,
61894             minWidth: 70,
61895             playing: false,
61896             visible: true,
61897         };
61898     }
61899 }
61900 /** @inheritdoc */
61901 SequenceComponent.componentName = "sequence";
61902
61903 /**
61904  * Enumeration for slider mode.
61905  *
61906  * @enum {number}
61907  * @readonly
61908  *
61909  * @description Modes for specifying how transitions
61910  * between images are performed in slider mode. Only
61911  * applicable when the slider component determines
61912  * that transitions with motion is possilble. When it
61913  * is not, the stationary mode will be applied.
61914  */
61915 var SliderConfigurationMode;
61916 (function (SliderConfigurationMode) {
61917     /**
61918      * Transitions with motion.
61919      *
61920      * @description The slider component moves the
61921      * camera between the image origins.
61922      *
61923      * In this mode it is not possible to zoom or pan.
61924      *
61925      * The slider component falls back to stationary
61926      * mode when it determines that the pair of images
61927      * does not have a strong enough relation.
61928      */
61929     SliderConfigurationMode[SliderConfigurationMode["Motion"] = 0] = "Motion";
61930     /**
61931      * Stationary transitions.
61932      *
61933      * @description The camera is stationary.
61934      *
61935      * In this mode it is possible to zoom and pan.
61936      */
61937     SliderConfigurationMode[SliderConfigurationMode["Stationary"] = 1] = "Stationary";
61938 })(SliderConfigurationMode || (SliderConfigurationMode = {}));
61939
61940 class SliderGLRenderer {
61941     constructor() {
61942         this._factory = new MeshFactory();
61943         this._scene = new MeshScene();
61944         this._spatial = new Spatial();
61945         this._currentKey = null;
61946         this._previousKey = null;
61947         this._disabled = false;
61948         this._curtain = 1;
61949         this._frameId = 0;
61950         this._needsRender = false;
61951         this._mode = null;
61952         this._currentProviderDisposers = {};
61953         this._previousProviderDisposers = {};
61954     }
61955     get disabled() {
61956         return this._disabled;
61957     }
61958     get frameId() {
61959         return this._frameId;
61960     }
61961     get needsRender() {
61962         return this._needsRender;
61963     }
61964     setTextureProvider(key, provider) {
61965         this._setTextureProvider(key, this._currentKey, provider, this._currentProviderDisposers, this._updateTexture.bind(this));
61966     }
61967     setTextureProviderPrev(key, provider) {
61968         this._setTextureProvider(key, this._previousKey, provider, this._previousProviderDisposers, this._updateTexturePrev.bind(this));
61969     }
61970     update(frame, mode) {
61971         this._updateFrameId(frame.id);
61972         this._updateImagePlanes(frame.state, mode);
61973     }
61974     updateCurtain(curtain) {
61975         if (this._curtain === curtain) {
61976             return;
61977         }
61978         this._curtain = curtain;
61979         this._updateCurtain();
61980         this._needsRender = true;
61981     }
61982     updateTexture(imageElement, image) {
61983         const planes = image.id === this._currentKey ?
61984             this._scene.planes :
61985             image.id === this._previousKey ?
61986                 this._scene.planesOld :
61987                 {};
61988         if (Object.keys(planes).length === 0) {
61989             return;
61990         }
61991         this._needsRender = true;
61992         for (const key in planes) {
61993             if (!planes.hasOwnProperty(key)) {
61994                 continue;
61995             }
61996             const plane = planes[key];
61997             let material = plane.material;
61998             let texture = material.uniforms.projectorTex.value;
61999             texture.image = imageElement;
62000             texture.needsUpdate = true;
62001         }
62002     }
62003     updateTextureImage(imageElement, image) {
62004         if (this._currentKey !== image.id) {
62005             return;
62006         }
62007         this._needsRender = true;
62008         const planes = this._scene.planes;
62009         for (const key in planes) {
62010             if (!planes.hasOwnProperty(key)) {
62011                 continue;
62012             }
62013             const plane = planes[key];
62014             let material = plane.material;
62015             let texture = material.uniforms.projectorTex.value;
62016             texture.image = imageElement;
62017             texture.needsUpdate = true;
62018         }
62019     }
62020     render(perspectiveCamera, renderer) {
62021         if (!this.disabled) {
62022             renderer.render(this._scene.sceneOld, perspectiveCamera);
62023         }
62024         renderer.render(this._scene.scene, perspectiveCamera);
62025         this._needsRender = false;
62026     }
62027     dispose() {
62028         this._scene.clear();
62029         for (const key in this._currentProviderDisposers) {
62030             if (!this._currentProviderDisposers.hasOwnProperty(key)) {
62031                 continue;
62032             }
62033             this._currentProviderDisposers[key]();
62034         }
62035         for (const key in this._previousProviderDisposers) {
62036             if (!this._previousProviderDisposers.hasOwnProperty(key)) {
62037                 continue;
62038             }
62039             this._previousProviderDisposers[key]();
62040         }
62041         this._currentProviderDisposers = {};
62042         this._previousProviderDisposers = {};
62043     }
62044     _getBasicCorners(currentAspect, previousAspect) {
62045         let offsetX;
62046         let offsetY;
62047         if (currentAspect > previousAspect) {
62048             offsetX = 0.5;
62049             offsetY = 0.5 * currentAspect / previousAspect;
62050         }
62051         else {
62052             offsetX = 0.5 * previousAspect / currentAspect;
62053             offsetY = 0.5;
62054         }
62055         return [[0.5 - offsetX, 0.5 - offsetY], [0.5 + offsetX, 0.5 + offsetY]];
62056     }
62057     _setDisabled(state) {
62058         this._disabled = state.currentImage == null ||
62059             state.previousImage == null ||
62060             (isSpherical(state.currentImage.cameraType) &&
62061                 !isSpherical(state.previousImage.cameraType));
62062     }
62063     _setTextureProvider(key, originalKey, provider, providerDisposers, updateTexture) {
62064         if (key !== originalKey) {
62065             return;
62066         }
62067         let createdSubscription = provider.textureCreated$
62068             .subscribe(updateTexture);
62069         let updatedSubscription = provider.textureUpdated$
62070             .subscribe((updated) => {
62071             this._needsRender = true;
62072         });
62073         let dispose = () => {
62074             createdSubscription.unsubscribe();
62075             updatedSubscription.unsubscribe();
62076             provider.dispose();
62077         };
62078         if (key in providerDisposers) {
62079             let disposeProvider = providerDisposers[key];
62080             disposeProvider();
62081             delete providerDisposers[key];
62082         }
62083         providerDisposers[key] = dispose;
62084     }
62085     _updateCurtain() {
62086         const planes = this._scene.planes;
62087         for (const key in planes) {
62088             if (!planes.hasOwnProperty(key)) {
62089                 continue;
62090             }
62091             const plane = planes[key];
62092             let shaderMaterial = plane.material;
62093             if (!!shaderMaterial.uniforms.curtain) {
62094                 shaderMaterial.uniforms.curtain.value = this._curtain;
62095             }
62096         }
62097     }
62098     _updateFrameId(frameId) {
62099         this._frameId = frameId;
62100     }
62101     _updateImagePlanes(state, mode) {
62102         const currentChanged = state.currentImage != null && this._currentKey !== state.currentImage.id;
62103         const previousChanged = state.previousImage != null && this._previousKey !== state.previousImage.id;
62104         const modeChanged = this._mode !== mode;
62105         if (!(currentChanged || previousChanged || modeChanged)) {
62106             return;
62107         }
62108         this._setDisabled(state);
62109         this._needsRender = true;
62110         this._mode = mode;
62111         const motionless = state.motionless ||
62112             mode === SliderConfigurationMode.Stationary ||
62113             isSpherical(state.currentImage.cameraType);
62114         if (this.disabled || previousChanged) {
62115             if (this._previousKey in this._previousProviderDisposers) {
62116                 this._previousProviderDisposers[this._previousKey]();
62117                 delete this._previousProviderDisposers[this._previousKey];
62118             }
62119         }
62120         if (this.disabled) {
62121             this._scene.setImagePlanesOld({});
62122         }
62123         else {
62124             if (previousChanged || modeChanged) {
62125                 const previousNode = state.previousImage;
62126                 this._previousKey = previousNode.id;
62127                 const elements = state.currentTransform.rt.elements;
62128                 let translation = [elements[12], elements[13], elements[14]];
62129                 const currentAspect = state.currentTransform.basicAspect;
62130                 const previousAspect = state.previousTransform.basicAspect;
62131                 const textureScale = currentAspect > previousAspect ?
62132                     [1, previousAspect / currentAspect] :
62133                     [currentAspect / previousAspect, 1];
62134                 let rotation = state.currentImage.rotation;
62135                 let width = state.currentImage.width;
62136                 let height = state.currentImage.height;
62137                 if (isSpherical(previousNode.cameraType)) {
62138                     rotation = state.previousImage.rotation;
62139                     translation = this._spatial
62140                         .rotate(this._spatial
62141                         .opticalCenter(state.currentImage.rotation, translation)
62142                         .toArray(), rotation)
62143                         .multiplyScalar(-1)
62144                         .toArray();
62145                     width = state.previousImage.width;
62146                     height = state.previousImage.height;
62147                 }
62148                 const transform = new Transform(state.currentImage.exifOrientation, width, height, state.currentImage.scale, rotation, translation, previousNode.image, textureScale, state.currentImage.cameraParameters, state.currentImage.cameraType);
62149                 let mesh = undefined;
62150                 if (isSpherical(previousNode.cameraType)) {
62151                     mesh = this._factory.createMesh(previousNode, motionless ||
62152                         isSpherical(state.currentImage.cameraType) ?
62153                         transform : state.previousTransform);
62154                 }
62155                 else {
62156                     if (motionless) {
62157                         const [[basicX0, basicY0], [basicX1, basicY1]] = this._getBasicCorners(currentAspect, previousAspect);
62158                         mesh = this._factory.createFlatMesh(state.previousImage, transform, basicX0, basicX1, basicY0, basicY1);
62159                     }
62160                     else {
62161                         mesh = this._factory.createMesh(state.previousImage, state.previousTransform);
62162                     }
62163                 }
62164                 const previousPlanes = {};
62165                 previousPlanes[previousNode.id] = mesh;
62166                 this._scene.setImagePlanesOld(previousPlanes);
62167             }
62168         }
62169         if (currentChanged || modeChanged) {
62170             if (this._currentKey in this._currentProviderDisposers) {
62171                 this._currentProviderDisposers[this._currentKey]();
62172                 delete this._currentProviderDisposers[this._currentKey];
62173             }
62174             this._currentKey = state.currentImage.id;
62175             const planes = {};
62176             if (isSpherical(state.currentImage.cameraType)) {
62177                 planes[state.currentImage.id] =
62178                     this._factory.createCurtainMesh(state.currentImage, state.currentTransform);
62179             }
62180             else {
62181                 if (motionless) {
62182                     planes[state.currentImage.id] = this._factory.createDistortedCurtainMesh(state.currentImage, state.currentTransform);
62183                 }
62184                 else {
62185                     planes[state.currentImage.id] = this._factory.createCurtainMesh(state.currentImage, state.currentTransform);
62186                 }
62187             }
62188             this._scene.setImagePlanes(planes);
62189             this._updateCurtain();
62190         }
62191     }
62192     _updateTexture(texture) {
62193         this._needsRender = true;
62194         const planes = this._scene.planes;
62195         for (const key in planes) {
62196             if (!planes.hasOwnProperty(key)) {
62197                 continue;
62198             }
62199             const plane = planes[key];
62200             let material = plane.material;
62201             let oldTexture = material.uniforms.projectorTex.value;
62202             material.uniforms.projectorTex.value = null;
62203             oldTexture.dispose();
62204             material.uniforms.projectorTex.value = texture;
62205         }
62206     }
62207     _updateTexturePrev(texture) {
62208         this._needsRender = true;
62209         const planes = this._scene.planesOld;
62210         for (const key in planes) {
62211             if (!planes.hasOwnProperty(key)) {
62212                 continue;
62213             }
62214             const plane = planes[key];
62215             let material = plane.material;
62216             let oldTexture = material.uniforms.projectorTex.value;
62217             material.uniforms.projectorTex.value = null;
62218             oldTexture.dispose();
62219             material.uniforms.projectorTex.value = texture;
62220         }
62221     }
62222 }
62223
62224 class SliderDOMRenderer {
62225     constructor(container) {
62226         this._container = container;
62227         this._interacting = false;
62228         this._notifyModeChanged$ = new Subject();
62229         this._notifyPositionChanged$ = new Subject();
62230         this._stopInteractionSubscription = null;
62231     }
62232     get mode$() {
62233         return this._notifyModeChanged$;
62234     }
62235     get position$() {
62236         return this._notifyPositionChanged$;
62237     }
62238     activate() {
62239         if (!!this._stopInteractionSubscription) {
62240             return;
62241         }
62242         this._stopInteractionSubscription = merge(this._container.mouseService.documentMouseUp$, this._container.touchService.touchEnd$.pipe(filter((touchEvent) => {
62243             return touchEvent.touches.length === 0;
62244         })))
62245             .subscribe((event) => {
62246             if (this._interacting) {
62247                 this._interacting = false;
62248             }
62249         });
62250     }
62251     deactivate() {
62252         if (!this._stopInteractionSubscription) {
62253             return;
62254         }
62255         this._interacting = false;
62256         this._stopInteractionSubscription.unsubscribe();
62257         this._stopInteractionSubscription = null;
62258     }
62259     render(position, mode, motionless, spherical, visible) {
62260         const children = [];
62261         if (visible) {
62262             children.push(virtualDom.h("div.mapillary-slider-border", []));
62263             const modeVisible = !(motionless || spherical);
62264             if (modeVisible) {
62265                 children.push(this._createModeButton(mode));
62266                 children.push(this._createModeButton2d(mode));
62267             }
62268             children.push(this._createPositionInput(position, modeVisible));
62269         }
62270         const boundingRect = this._container.domContainer.getBoundingClientRect();
62271         const width = Math.max(215, Math.min(400, boundingRect.width - 100));
62272         return virtualDom.h("div.mapillary-slider-container", { style: { width: `${width}px` } }, children);
62273     }
62274     _createModeButton(mode) {
62275         const properties = {
62276             onclick: () => {
62277                 if (mode === SliderConfigurationMode.Motion) {
62278                     return;
62279                 }
62280                 this._notifyModeChanged$.next(SliderConfigurationMode.Motion);
62281             },
62282         };
62283         const className = mode === SliderConfigurationMode.Stationary ?
62284             "mapillary-slider-mode-button-inactive" :
62285             "mapillary-slider-mode-button";
62286         return virtualDom.h("div." + className, properties, [virtualDom.h("div.mapillary-slider-mode-icon", [])]);
62287     }
62288     _createModeButton2d(mode) {
62289         const properties = {
62290             onclick: () => {
62291                 if (mode === SliderConfigurationMode.Stationary) {
62292                     return;
62293                 }
62294                 this._notifyModeChanged$.next(SliderConfigurationMode.Stationary);
62295             },
62296         };
62297         const className = mode === SliderConfigurationMode.Motion ?
62298             "mapillary-slider-mode-button-2d-inactive" :
62299             "mapillary-slider-mode-button-2d";
62300         return virtualDom.h("div." + className, properties, [virtualDom.h("div.mapillary-slider-mode-icon-2d", [])]);
62301     }
62302     _createPositionInput(position, modeVisible) {
62303         const onChange = (e) => {
62304             this._notifyPositionChanged$.next(Number(e.target.value) / 1000);
62305         };
62306         const onStart = (e) => {
62307             this._interacting = true;
62308             e.stopPropagation();
62309         };
62310         const onMove = (e) => {
62311             if (this._interacting) {
62312                 e.stopPropagation();
62313             }
62314         };
62315         const onKeyDown = (e) => {
62316             if (e.key === "ArrowDown" || e.key === "ArrowLeft" ||
62317                 e.key === "ArrowRight" || e.key === "ArrowUp") {
62318                 e.preventDefault();
62319             }
62320         };
62321         const boundingRect = this._container.domContainer.getBoundingClientRect();
62322         const width = Math.max(215, Math.min(400, boundingRect.width - 105)) - 84 + (modeVisible ? 0 : 52);
62323         const positionInput = virtualDom.h("input.mapillary-slider-position", {
62324             max: 1000,
62325             min: 0,
62326             onchange: onChange,
62327             oninput: onChange,
62328             onkeydown: onKeyDown,
62329             onpointerdown: onStart,
62330             onpointermove: onMove,
62331             ontouchmove: onMove,
62332             ontouchstart: onStart,
62333             style: {
62334                 width: `${width}px`,
62335             },
62336             type: "range",
62337             value: 1000 * position,
62338         }, []);
62339         return virtualDom.h("div.mapillary-slider-position-container", [positionInput]);
62340     }
62341 }
62342
62343 /**
62344  * @class SliderComponent
62345  *
62346  * @classdesc Component for comparing pairs of images. Renders
62347  * a slider for adjusting the curtain of the first image.
62348  *
62349  * Deactivate the sequence, direction and image plane
62350  * components when activating the slider component to avoid
62351  * interfering UI elements.
62352  *
62353  * To retrive and use the slider component
62354  *
62355  * @example
62356  * ```js
62357  * var viewer = new Viewer({ ... });
62358  *
62359  * viewer.deactivateComponent("image");
62360  * viewer.deactivateComponent("direction");
62361  * viewer.deactivateComponent("sequence");
62362  *
62363  * viewer.activateComponent("slider");
62364  *
62365  * var sliderComponent = viewer.getComponent("slider");
62366  * ```
62367  */
62368 class SliderComponent extends Component {
62369     /** @ignore */
62370     constructor(name, container, navigator, viewportCoords) {
62371         super(name, container, navigator);
62372         this._viewportCoords = !!viewportCoords ? viewportCoords : new ViewportCoords();
62373         this._domRenderer = new SliderDOMRenderer(container);
62374         this._imageTileLoader = new TileLoader(navigator.api);
62375         this._roiCalculator = new RegionOfInterestCalculator();
62376         this._spatial = new Spatial();
62377         this._glRendererOperation$ = new Subject();
62378         this._glRendererCreator$ = new Subject();
62379         this._glRendererDisposer$ = new Subject();
62380         this._glRenderer$ = this._glRendererOperation$.pipe(scan((glRenderer, operation) => {
62381             return operation(glRenderer);
62382         }, null), filter((glRenderer) => {
62383             return glRenderer != null;
62384         }), distinctUntilChanged(undefined, (glRenderer) => {
62385             return glRenderer.frameId;
62386         }));
62387         this._glRendererCreator$.pipe(map(() => {
62388             return (glRenderer) => {
62389                 if (glRenderer != null) {
62390                     throw new Error("Multiple slider states can not be created at the same time");
62391                 }
62392                 return new SliderGLRenderer();
62393             };
62394         }))
62395             .subscribe(this._glRendererOperation$);
62396         this._glRendererDisposer$.pipe(map(() => {
62397             return (glRenderer) => {
62398                 glRenderer.dispose();
62399                 return null;
62400             };
62401         }))
62402             .subscribe(this._glRendererOperation$);
62403     }
62404     _activate() {
62405         const subs = this._subscriptions;
62406         subs.push(this._domRenderer.mode$
62407             .subscribe((mode) => {
62408             this.configure({ mode });
62409         }));
62410         subs.push(this._glRenderer$.pipe(map((glRenderer) => {
62411             let renderHash = {
62412                 name: this._name,
62413                 renderer: {
62414                     frameId: glRenderer.frameId,
62415                     needsRender: glRenderer.needsRender,
62416                     render: glRenderer.render.bind(glRenderer),
62417                     pass: RenderPass$1.Background,
62418                 },
62419             };
62420             return renderHash;
62421         }))
62422             .subscribe(this._container.glRenderer.render$));
62423         const position$ = concat(this.configuration$.pipe(map((configuration) => {
62424             return configuration.initialPosition != null ?
62425                 configuration.initialPosition : 1;
62426         }), first()), this._domRenderer.position$);
62427         const mode$ = this.configuration$.pipe(map((configuration) => {
62428             return configuration.mode;
62429         }), distinctUntilChanged());
62430         const motionless$ = this._navigator.stateService.currentState$.pipe(map((frame) => {
62431             return frame.state.motionless;
62432         }), distinctUntilChanged());
62433         const spherical$ = this._navigator.stateService.currentState$.pipe(map((frame) => {
62434             return isSpherical(frame.state.currentImage.cameraType);
62435         }), distinctUntilChanged());
62436         const sliderVisible$ = combineLatest(this._configuration$.pipe(map((configuration) => {
62437             return configuration.sliderVisible;
62438         })), this._navigator.stateService.currentState$.pipe(map((frame) => {
62439             return !(frame.state.currentImage == null ||
62440                 frame.state.previousImage == null ||
62441                 (isSpherical(frame.state.currentImage.cameraType) &&
62442                     !isSpherical(frame.state.previousImage.cameraType)));
62443         }), distinctUntilChanged())).pipe(map(([sliderVisible, enabledState]) => {
62444             return sliderVisible && enabledState;
62445         }), distinctUntilChanged());
62446         this._waitSubscription = combineLatest(mode$, motionless$, spherical$, sliderVisible$).pipe(withLatestFrom(this._navigator.stateService.state$))
62447             .subscribe(([[mode, motionless, spherical, sliderVisible], state]) => {
62448             const interactive = sliderVisible &&
62449                 (motionless ||
62450                     mode === SliderConfigurationMode.Stationary ||
62451                     spherical);
62452             if (interactive && state !== State.WaitingInteractively) {
62453                 this._navigator.stateService.waitInteractively();
62454             }
62455             else if (!interactive && state !== State.Waiting) {
62456                 this._navigator.stateService.wait();
62457             }
62458         });
62459         subs.push(combineLatest(position$, mode$, motionless$, spherical$, sliderVisible$)
62460             .subscribe(([position, mode, motionless, spherical]) => {
62461             if (motionless || mode === SliderConfigurationMode.Stationary || spherical) {
62462                 this._navigator.stateService.moveTo(1);
62463             }
62464             else {
62465                 this._navigator.stateService.moveTo(position);
62466             }
62467         }));
62468         subs.push(combineLatest(position$, mode$, motionless$, spherical$, sliderVisible$, this._container.renderService.size$).pipe(map(([position, mode, motionless, spherical, sliderVisible]) => {
62469             return {
62470                 name: this._name,
62471                 vNode: this._domRenderer.render(position, mode, motionless, spherical, sliderVisible),
62472             };
62473         }))
62474             .subscribe(this._container.domRenderer.render$));
62475         this._glRendererCreator$.next(null);
62476         subs.push(combineLatest(position$, spherical$, sliderVisible$, this._container.renderService.renderCamera$, this._navigator.stateService.currentTransform$).pipe(map(([position, spherical, visible, render, transform]) => {
62477             if (!spherical) {
62478                 return visible ? position : 1;
62479             }
62480             const basicMin = this._viewportCoords.viewportToBasic(-1.15, 0, transform, render.perspective);
62481             const basicMax = this._viewportCoords.viewportToBasic(1.15, 0, transform, render.perspective);
62482             const shiftedMax = basicMax[0] < basicMin[0] ? basicMax[0] + 1 : basicMax[0];
62483             const basicPosition = basicMin[0] + position * (shiftedMax - basicMin[0]);
62484             return basicPosition > 1 ? basicPosition - 1 : basicPosition;
62485         }), map((position) => {
62486             return (glRenderer) => {
62487                 glRenderer.updateCurtain(position);
62488                 return glRenderer;
62489             };
62490         }))
62491             .subscribe(this._glRendererOperation$));
62492         subs.push(combineLatest(this._navigator.stateService.currentState$, mode$).pipe(map(([frame, mode]) => {
62493             return (glRenderer) => {
62494                 glRenderer.update(frame, mode);
62495                 return glRenderer;
62496             };
62497         }))
62498             .subscribe(this._glRendererOperation$));
62499         subs.push(this._configuration$.pipe(filter((configuration) => {
62500             return configuration.ids != null;
62501         }), switchMap((configuration) => {
62502             return zip(zip(this._catchCacheImage$(configuration.ids.background), this._catchCacheImage$(configuration.ids.foreground)).pipe(map((images) => {
62503                 return { background: images[0], foreground: images[1] };
62504             })), this._navigator.stateService.currentState$.pipe(first())).pipe(map((nf) => {
62505                 return { images: nf[0], state: nf[1].state };
62506             }));
62507         }))
62508             .subscribe((co) => {
62509             if (co.state.currentImage != null &&
62510                 co.state.previousImage != null &&
62511                 co.state.currentImage.id === co.images.foreground.id &&
62512                 co.state.previousImage.id === co.images.background.id) {
62513                 return;
62514             }
62515             if (co.state.currentImage.id === co.images.background.id) {
62516                 this._navigator.stateService.setImages([co.images.foreground]);
62517                 return;
62518             }
62519             if (co.state.currentImage.id === co.images.foreground.id &&
62520                 co.state.trajectory.length === 1) {
62521                 this._navigator.stateService.prependImages([co.images.background]);
62522                 return;
62523             }
62524             this._navigator.stateService.setImages([co.images.background]);
62525             this._navigator.stateService.setImages([co.images.foreground]);
62526         }, (e) => {
62527             console.error(e);
62528         }));
62529         const textureProvider$ = this._container.configurationService.imageTiling$.pipe(switchMap((active) => {
62530             return active ?
62531                 this._navigator.stateService.currentState$ :
62532                 new Subject();
62533         }), distinctUntilChanged(undefined, (frame) => {
62534             return frame.state.currentImage.id;
62535         }), withLatestFrom(this._container.glRenderer.webGLRenderer$, this._container.renderService.size$), map(([frame, renderer, size]) => {
62536             const state = frame.state;
62537             Math.max(size.width, size.height);
62538             const currentImage = state.currentImage;
62539             const currentTransform = state.currentTransform;
62540             return new TextureProvider(currentImage.id, currentTransform.basicWidth, currentTransform.basicHeight, currentImage.image, this._imageTileLoader, new TileStore(), renderer);
62541         }), publishReplay(1), refCount());
62542         subs.push(textureProvider$.subscribe(() => { }));
62543         subs.push(textureProvider$.pipe(map((provider) => {
62544             return (renderer) => {
62545                 renderer.setTextureProvider(provider.id, provider);
62546                 return renderer;
62547             };
62548         }))
62549             .subscribe(this._glRendererOperation$));
62550         subs.push(textureProvider$.pipe(pairwise())
62551             .subscribe((pair) => {
62552             let previous = pair[0];
62553             previous.abort();
62554         }));
62555         const roiTrigger$ = this._container.configurationService.imageTiling$.pipe(switchMap((active) => {
62556             return active ?
62557                 combineLatest(this._container.renderService.renderCameraFrame$, this._container.renderService.size$.pipe(debounceTime(250))) :
62558                 new Subject();
62559         }), map(([camera, size]) => {
62560             return [
62561                 camera.camera.position.clone(),
62562                 camera.camera.lookat.clone(),
62563                 camera.zoom.valueOf(),
62564                 size.height.valueOf(),
62565                 size.width.valueOf()
62566             ];
62567         }), pairwise(), skipWhile((pls) => {
62568             return pls[1][2] - pls[0][2] < 0 || pls[1][2] === 0;
62569         }), map((pls) => {
62570             let samePosition = pls[0][0].equals(pls[1][0]);
62571             let sameLookat = pls[0][1].equals(pls[1][1]);
62572             let sameZoom = pls[0][2] === pls[1][2];
62573             let sameHeight = pls[0][3] === pls[1][3];
62574             let sameWidth = pls[0][4] === pls[1][4];
62575             return samePosition && sameLookat && sameZoom && sameHeight && sameWidth;
62576         }), distinctUntilChanged(), filter((stalled) => {
62577             return stalled;
62578         }), switchMap(() => {
62579             return this._container.renderService.renderCameraFrame$.pipe(first());
62580         }), withLatestFrom(this._container.renderService.size$, this._navigator.stateService.currentTransform$));
62581         subs.push(textureProvider$.pipe(switchMap((provider) => {
62582             return roiTrigger$.pipe(map(([camera, size, transform]) => {
62583                 return [
62584                     this._roiCalculator.computeRegionOfInterest(camera, size, transform),
62585                     provider,
62586                 ];
62587             }));
62588         }), filter((args) => {
62589             return !args[1].disposed;
62590         }))
62591             .subscribe((args) => {
62592             let roi = args[0];
62593             let provider = args[1];
62594             provider.setRegionOfInterest(roi);
62595         }));
62596         const hasTexture$ = textureProvider$.pipe(switchMap((provider) => {
62597             return provider.hasTexture$;
62598         }), startWith(false), publishReplay(1), refCount());
62599         subs.push(hasTexture$.subscribe(() => { }));
62600         const textureProviderPrev$ = this._container.configurationService.imageTiling$.pipe(switchMap((active) => {
62601             return active ?
62602                 this._navigator.stateService.currentState$ :
62603                 new Subject();
62604         }), filter((frame) => {
62605             return !!frame.state.previousImage;
62606         }), distinctUntilChanged(undefined, (frame) => {
62607             return frame.state.previousImage.id;
62608         }), withLatestFrom(this._container.glRenderer.webGLRenderer$, this._container.renderService.size$), map(([frame, renderer, size]) => {
62609             const state = frame.state;
62610             const previousImage = state.previousImage;
62611             const previousTransform = state.previousTransform;
62612             return new TextureProvider(previousImage.id, previousTransform.basicWidth, previousTransform.basicHeight, previousImage.image, this._imageTileLoader, new TileStore(), renderer);
62613         }), publishReplay(1), refCount());
62614         subs.push(textureProviderPrev$.subscribe(() => { }));
62615         subs.push(textureProviderPrev$.pipe(map((provider) => {
62616             return (renderer) => {
62617                 renderer.setTextureProviderPrev(provider.id, provider);
62618                 return renderer;
62619             };
62620         }))
62621             .subscribe(this._glRendererOperation$));
62622         subs.push(textureProviderPrev$.pipe(pairwise())
62623             .subscribe((pair) => {
62624             let previous = pair[0];
62625             previous.abort();
62626         }));
62627         const roiTriggerPrev$ = this._container.configurationService.imageTiling$.pipe(switchMap((active) => {
62628             return active ?
62629                 combineLatest(this._container.renderService.renderCameraFrame$, this._container.renderService.size$.pipe(debounceTime(250))) :
62630                 new Subject();
62631         }), map(([camera, size]) => {
62632             return [
62633                 camera.camera.position.clone(),
62634                 camera.camera.lookat.clone(),
62635                 camera.zoom.valueOf(),
62636                 size.height.valueOf(),
62637                 size.width.valueOf()
62638             ];
62639         }), pairwise(), skipWhile((pls) => {
62640             return pls[1][2] - pls[0][2] < 0 || pls[1][2] === 0;
62641         }), map((pls) => {
62642             let samePosition = pls[0][0].equals(pls[1][0]);
62643             let sameLookat = pls[0][1].equals(pls[1][1]);
62644             let sameZoom = pls[0][2] === pls[1][2];
62645             let sameHeight = pls[0][3] === pls[1][3];
62646             let sameWidth = pls[0][4] === pls[1][4];
62647             return samePosition && sameLookat && sameZoom && sameHeight && sameWidth;
62648         }), distinctUntilChanged(), filter((stalled) => {
62649             return stalled;
62650         }), switchMap(() => {
62651             return this._container.renderService.renderCameraFrame$.pipe(first());
62652         }), withLatestFrom(this._container.renderService.size$, this._navigator.stateService.currentTransform$));
62653         subs.push(textureProviderPrev$.pipe(switchMap((provider) => {
62654             return roiTriggerPrev$.pipe(map(([camera, size, transform]) => {
62655                 return [
62656                     this._roiCalculator.computeRegionOfInterest(camera, size, transform),
62657                     provider,
62658                 ];
62659             }));
62660         }), filter((args) => {
62661             return !args[1].disposed;
62662         }), withLatestFrom(this._navigator.stateService.currentState$))
62663             .subscribe(([[roi, provider], frame]) => {
62664             let shiftedRoi = null;
62665             if (isSpherical(frame.state.previousImage.cameraType)) {
62666                 if (isSpherical(frame.state.currentImage.cameraType)) {
62667                     const currentViewingDirection = this._spatial.viewingDirection(frame.state.currentImage.rotation);
62668                     const previousViewingDirection = this._spatial.viewingDirection(frame.state.previousImage.rotation);
62669                     const directionDiff = this._spatial.angleBetweenVector2(currentViewingDirection.x, currentViewingDirection.y, previousViewingDirection.x, previousViewingDirection.y);
62670                     const shift = directionDiff / (2 * Math.PI);
62671                     const bbox = {
62672                         maxX: this._spatial.wrap(roi.bbox.maxX + shift, 0, 1),
62673                         maxY: roi.bbox.maxY,
62674                         minX: this._spatial.wrap(roi.bbox.minX + shift, 0, 1),
62675                         minY: roi.bbox.minY,
62676                     };
62677                     shiftedRoi = {
62678                         bbox: bbox,
62679                         pixelHeight: roi.pixelHeight,
62680                         pixelWidth: roi.pixelWidth,
62681                     };
62682                 }
62683                 else {
62684                     const currentViewingDirection = this._spatial.viewingDirection(frame.state.currentImage.rotation);
62685                     const previousViewingDirection = this._spatial.viewingDirection(frame.state.previousImage.rotation);
62686                     const directionDiff = this._spatial.angleBetweenVector2(currentViewingDirection.x, currentViewingDirection.y, previousViewingDirection.x, previousViewingDirection.y);
62687                     const shiftX = directionDiff / (2 * Math.PI);
62688                     const a1 = this._spatial.angleToPlane(currentViewingDirection.toArray(), [0, 0, 1]);
62689                     const a2 = this._spatial.angleToPlane(previousViewingDirection.toArray(), [0, 0, 1]);
62690                     const shiftY = (a2 - a1) / (2 * Math.PI);
62691                     const currentTransform = frame.state.currentTransform;
62692                     const size = Math.max(currentTransform.basicWidth, currentTransform.basicHeight);
62693                     const hFov = size > 0 ?
62694                         2 * Math.atan(0.5 * currentTransform.basicWidth / (size * currentTransform.focal)) :
62695                         Math.PI / 3;
62696                     const vFov = size > 0 ?
62697                         2 * Math.atan(0.5 * currentTransform.basicHeight / (size * currentTransform.focal)) :
62698                         Math.PI / 3;
62699                     const spanningWidth = hFov / (2 * Math.PI);
62700                     const spanningHeight = vFov / Math.PI;
62701                     const basicWidth = (roi.bbox.maxX - roi.bbox.minX) * spanningWidth;
62702                     const basicHeight = (roi.bbox.maxY - roi.bbox.minY) * spanningHeight;
62703                     const pixelWidth = roi.pixelWidth * spanningWidth;
62704                     const pixelHeight = roi.pixelHeight * spanningHeight;
62705                     const zoomShiftX = (roi.bbox.minX + roi.bbox.maxX) / 2 - 0.5;
62706                     const zoomShiftY = (roi.bbox.minY + roi.bbox.maxY) / 2 - 0.5;
62707                     const minX = 0.5 + shiftX + spanningWidth * zoomShiftX - basicWidth / 2;
62708                     const maxX = 0.5 + shiftX + spanningWidth * zoomShiftX + basicWidth / 2;
62709                     const minY = 0.5 + shiftY + spanningHeight * zoomShiftY - basicHeight / 2;
62710                     const maxY = 0.5 + shiftY + spanningHeight * zoomShiftY + basicHeight / 2;
62711                     const bbox = {
62712                         maxX: this._spatial.wrap(maxX, 0, 1),
62713                         maxY: maxY,
62714                         minX: this._spatial.wrap(minX, 0, 1),
62715                         minY: minY,
62716                     };
62717                     shiftedRoi = {
62718                         bbox: bbox,
62719                         pixelHeight: pixelHeight,
62720                         pixelWidth: pixelWidth,
62721                     };
62722                 }
62723             }
62724             else {
62725                 const currentBasicAspect = frame.state.currentTransform.basicAspect;
62726                 const previousBasicAspect = frame.state.previousTransform.basicAspect;
62727                 const [[cornerMinX, cornerMinY], [cornerMaxX, cornerMaxY]] = this._getBasicCorners(currentBasicAspect, previousBasicAspect);
62728                 const basicWidth = cornerMaxX - cornerMinX;
62729                 const basicHeight = cornerMaxY - cornerMinY;
62730                 const pixelWidth = roi.pixelWidth / basicWidth;
62731                 const pixelHeight = roi.pixelHeight / basicHeight;
62732                 const minX = (basicWidth - 1) / (2 * basicWidth) + roi.bbox.minX / basicWidth;
62733                 const maxX = (basicWidth - 1) / (2 * basicWidth) + roi.bbox.maxX / basicWidth;
62734                 const minY = (basicHeight - 1) / (2 * basicHeight) + roi.bbox.minY / basicHeight;
62735                 const maxY = (basicHeight - 1) / (2 * basicHeight) + roi.bbox.maxY / basicHeight;
62736                 const bbox = {
62737                     maxX: maxX,
62738                     maxY: maxY,
62739                     minX: minX,
62740                     minY: minY,
62741                 };
62742                 this._clipBoundingBox(bbox);
62743                 shiftedRoi = {
62744                     bbox: bbox,
62745                     pixelHeight: pixelHeight,
62746                     pixelWidth: pixelWidth,
62747                 };
62748             }
62749             provider.setRegionOfInterest(shiftedRoi);
62750         }));
62751         const hasTexturePrev$ = textureProviderPrev$.pipe(switchMap((provider) => {
62752             return provider.hasTexture$;
62753         }), startWith(false), publishReplay(1), refCount());
62754         subs.push(hasTexturePrev$.subscribe(() => { }));
62755     }
62756     _deactivate() {
62757         this._waitSubscription.unsubscribe();
62758         this._navigator.stateService.state$.pipe(first())
62759             .subscribe((state) => {
62760             if (state !== State.Traversing) {
62761                 this._navigator.stateService.traverse();
62762             }
62763         });
62764         this._glRendererDisposer$.next(null);
62765         this._domRenderer.deactivate();
62766         this._subscriptions.unsubscribe();
62767         this.configure({ ids: null });
62768     }
62769     _getDefaultConfiguration() {
62770         return {
62771             initialPosition: 1,
62772             mode: SliderConfigurationMode.Motion,
62773             sliderVisible: true,
62774         };
62775     }
62776     _catchCacheImage$(imageId) {
62777         return this._navigator.graphService.cacheImage$(imageId).pipe(catchError((error) => {
62778             console.error(`Failed to cache slider image (${imageId})`, error);
62779             return empty();
62780         }));
62781     }
62782     _getBasicCorners(currentAspect, previousAspect) {
62783         let offsetX;
62784         let offsetY;
62785         if (currentAspect > previousAspect) {
62786             offsetX = 0.5;
62787             offsetY = 0.5 * currentAspect / previousAspect;
62788         }
62789         else {
62790             offsetX = 0.5 * previousAspect / currentAspect;
62791             offsetY = 0.5;
62792         }
62793         return [[0.5 - offsetX, 0.5 - offsetY], [0.5 + offsetX, 0.5 + offsetY]];
62794     }
62795     _clipBoundingBox(bbox) {
62796         bbox.minX = Math.max(0, Math.min(1, bbox.minX));
62797         bbox.maxX = Math.max(0, Math.min(1, bbox.maxX));
62798         bbox.minY = Math.max(0, Math.min(1, bbox.minY));
62799         bbox.maxY = Math.max(0, Math.min(1, bbox.maxY));
62800     }
62801 }
62802 SliderComponent.componentName = "slider";
62803
62804 class PlayService {
62805     constructor(graphService, stateService) {
62806         this._subscriptions = new SubscriptionHolder();
62807         this._graphService = graphService;
62808         this._stateService = stateService;
62809         const subs = this._subscriptions;
62810         this._directionSubject$ = new Subject();
62811         this._direction$ = this._directionSubject$.pipe(startWith(NavigationDirection.Next), publishReplay(1), refCount());
62812         subs.push(this._direction$.subscribe());
62813         this._playing = false;
62814         this._playingSubject$ = new Subject();
62815         this._playing$ = this._playingSubject$.pipe(startWith(this._playing), publishReplay(1), refCount());
62816         subs.push(this._playing$.subscribe());
62817         this._speed = 0.5;
62818         this._speedSubject$ = new Subject();
62819         this._speed$ = this._speedSubject$.pipe(startWith(this._speed), publishReplay(1), refCount());
62820         subs.push(this._speed$.subscribe());
62821         this._imagesAhead = this._mapImagesAhead(this._mapSpeed(this._speed));
62822         this._bridging$ = null;
62823     }
62824     get playing() {
62825         return this._playing;
62826     }
62827     get direction$() {
62828         return this._direction$;
62829     }
62830     get playing$() {
62831         return this._playing$;
62832     }
62833     get speed$() {
62834         return this._speed$;
62835     }
62836     play() {
62837         if (this._playing) {
62838             return;
62839         }
62840         this._stateService.cutImages();
62841         const stateSpeed = this._setSpeed(this._speed);
62842         this._stateService.setSpeed(stateSpeed);
62843         this._graphModeSubscription = this._speed$.pipe(map((speed) => {
62844             return speed > PlayService.sequenceSpeed ? GraphMode.Sequence : GraphMode.Spatial;
62845         }), distinctUntilChanged())
62846             .subscribe((mode) => {
62847             this._graphService.setGraphMode(mode);
62848         });
62849         this._cacheSubscription = combineLatest(this._stateService.currentImage$.pipe(map((image) => {
62850             return [image.sequenceId, image.id];
62851         }), distinctUntilChanged(undefined, ([sequenceId]) => {
62852             return sequenceId;
62853         })), this._graphService.graphMode$, this._direction$).pipe(switchMap(([[sequenceId, imageId], mode, direction]) => {
62854             if (direction !== NavigationDirection.Next && direction !== NavigationDirection.Prev) {
62855                 return of([undefined, direction]);
62856             }
62857             const sequence$ = (mode === GraphMode.Sequence ?
62858                 this._graphService.cacheSequenceImages$(sequenceId, imageId) :
62859                 this._graphService.cacheSequence$(sequenceId)).pipe(retry(3), catchError((error) => {
62860                 console.error(error);
62861                 return of(undefined);
62862             }));
62863             return combineLatest(sequence$, of(direction));
62864         }), switchMap(([sequence, direction]) => {
62865             if (sequence === undefined) {
62866                 return empty();
62867             }
62868             const imageIds = sequence.imageIds.slice();
62869             if (direction === NavigationDirection.Prev) {
62870                 imageIds.reverse();
62871             }
62872             return this._stateService.currentState$.pipe(map((frame) => {
62873                 return [frame.state.trajectory[frame.state.trajectory.length - 1].id, frame.state.imagesAhead];
62874             }), scan(([lastRequestKey, previousRequestKeys], [lastTrajectoryKey, imagesAhead]) => {
62875                 if (lastRequestKey === undefined) {
62876                     lastRequestKey = lastTrajectoryKey;
62877                 }
62878                 const lastIndex = imageIds.length - 1;
62879                 if (imagesAhead >= this._imagesAhead || imageIds[lastIndex] === lastRequestKey) {
62880                     return [lastRequestKey, []];
62881                 }
62882                 const current = imageIds.indexOf(lastTrajectoryKey);
62883                 const start = imageIds.indexOf(lastRequestKey) + 1;
62884                 const end = Math.min(lastIndex, current + this._imagesAhead - imagesAhead) + 1;
62885                 if (end <= start) {
62886                     return [lastRequestKey, []];
62887                 }
62888                 return [imageIds[end - 1], imageIds.slice(start, end)];
62889             }, [undefined, []]), mergeMap(([lastRequestKey, newRequestKeys]) => {
62890                 return from(newRequestKeys);
62891             }));
62892         }), mergeMap((key) => {
62893             return this._graphService.cacheImage$(key).pipe(catchError(() => {
62894                 return empty();
62895             }));
62896         }, 6))
62897             .subscribe();
62898         this._playingSubscription = this._stateService.currentState$.pipe(filter((frame) => {
62899             return frame.state.imagesAhead < this._imagesAhead;
62900         }), distinctUntilChanged(undefined, (frame) => {
62901             return frame.state.lastImage.id;
62902         }), map((frame) => {
62903             const lastImage = frame.state.lastImage;
62904             const trajectory = frame.state.trajectory;
62905             let increasingTime = undefined;
62906             for (let i = trajectory.length - 2; i >= 0; i--) {
62907                 const image = trajectory[i];
62908                 if (image.sequenceId !== lastImage.sequenceId) {
62909                     break;
62910                 }
62911                 if (image.capturedAt !== lastImage.capturedAt) {
62912                     increasingTime = image.capturedAt < lastImage.capturedAt;
62913                     break;
62914                 }
62915             }
62916             return [frame.state.lastImage, increasingTime];
62917         }), withLatestFrom(this._direction$), switchMap(([[image, increasingTime], direction]) => {
62918             return zip(([NavigationDirection.Next, NavigationDirection.Prev].indexOf(direction) > -1 ?
62919                 image.sequenceEdges$ :
62920                 image.spatialEdges$).pipe(first((status) => {
62921                 return status.cached;
62922             }), timeout(15000)), of(direction)).pipe(map(([s, d]) => {
62923                 for (let edge of s.edges) {
62924                     if (edge.data.direction === d) {
62925                         return edge.target;
62926                     }
62927                 }
62928                 return null;
62929             }), switchMap((key) => {
62930                 return key != null ?
62931                     this._graphService.cacheImage$(key) :
62932                     empty();
62933             }));
62934         }))
62935             .subscribe((image) => {
62936             this._stateService.appendImagess([image]);
62937         }, (error) => {
62938             console.error(error);
62939             this.stop();
62940         });
62941         this._clearSubscription = this._stateService.currentImage$.pipe(bufferCount(1, 10))
62942             .subscribe((images) => {
62943             this._stateService.clearPriorImages();
62944         });
62945         this._setPlaying(true);
62946         const currentLastImages$ = this._stateService.currentState$.pipe(map((frame) => {
62947             return frame.state;
62948         }), distinctUntilChanged(([kc1, kl1], [kc2, kl2]) => {
62949             return kc1 === kc2 && kl1 === kl2;
62950         }, (state) => {
62951             return [state.currentImage.id, state.lastImage.id];
62952         }), filter((state) => {
62953             return state.currentImage.id === state.lastImage.id &&
62954                 state.currentIndex === state.trajectory.length - 1;
62955         }), map((state) => {
62956             return state.currentImage;
62957         }));
62958         this._stopSubscription = combineLatest(currentLastImages$, this._direction$).pipe(switchMap(([image, direction]) => {
62959             const edgeStatus$ = ([NavigationDirection.Next, NavigationDirection.Prev].indexOf(direction) > -1 ?
62960                 image.sequenceEdges$ :
62961                 image.spatialEdges$).pipe(first((status) => {
62962                 return status.cached;
62963             }), timeout(15000), catchError((error) => {
62964                 console.error(error);
62965                 return of({ cached: false, edges: [] });
62966             }));
62967             return combineLatest(of(direction), edgeStatus$).pipe(map(([d, es]) => {
62968                 for (const edge of es.edges) {
62969                     if (edge.data.direction === d) {
62970                         return true;
62971                     }
62972                 }
62973                 return false;
62974             }));
62975         }), mergeMap((hasEdge) => {
62976             if (hasEdge || !this._bridging$) {
62977                 return of(hasEdge);
62978             }
62979             return this._bridging$.pipe(map((image) => {
62980                 return image != null;
62981             }), catchError((error) => {
62982                 console.error(error);
62983                 return of(false);
62984             }));
62985         }), first((hasEdge) => {
62986             return !hasEdge;
62987         }))
62988             .subscribe(undefined, undefined, () => { this.stop(); });
62989         if (this._stopSubscription.closed) {
62990             this._stopSubscription = null;
62991         }
62992         this._earthSubscription = this._stateService.state$
62993             .pipe(map((state) => {
62994             return state === State.Earth;
62995         }), distinctUntilChanged(), first((earth) => {
62996             return earth;
62997         }))
62998             .subscribe(undefined, undefined, () => { this.stop(); });
62999         if (this._earthSubscription.closed) {
63000             this._earthSubscription = null;
63001         }
63002     }
63003     dispose() {
63004         this.stop();
63005         this._subscriptions.unsubscribe();
63006     }
63007     setDirection(direction) {
63008         this._directionSubject$.next(direction);
63009     }
63010     setSpeed(speed) {
63011         speed = Math.max(0, Math.min(1, speed));
63012         if (speed === this._speed) {
63013             return;
63014         }
63015         const stateSpeed = this._setSpeed(speed);
63016         if (this._playing) {
63017             this._stateService.setSpeed(stateSpeed);
63018         }
63019         this._speedSubject$.next(this._speed);
63020     }
63021     stop() {
63022         if (!this._playing) {
63023             return;
63024         }
63025         if (!!this._stopSubscription) {
63026             if (!this._stopSubscription.closed) {
63027                 this._stopSubscription.unsubscribe();
63028             }
63029             this._stopSubscription = null;
63030         }
63031         if (!!this._earthSubscription) {
63032             if (!this._earthSubscription.closed) {
63033                 this._earthSubscription.unsubscribe();
63034             }
63035             this._earthSubscription = null;
63036         }
63037         this._graphModeSubscription.unsubscribe();
63038         this._graphModeSubscription = null;
63039         this._cacheSubscription.unsubscribe();
63040         this._cacheSubscription = null;
63041         this._playingSubscription.unsubscribe();
63042         this._playingSubscription = null;
63043         this._clearSubscription.unsubscribe();
63044         this._clearSubscription = null;
63045         this._stateService.setSpeed(1);
63046         this._stateService.cutImages();
63047         this._graphService.setGraphMode(GraphMode.Spatial);
63048         this._setPlaying(false);
63049     }
63050     _mapSpeed(speed) {
63051         const x = 2 * speed - 1;
63052         return Math.pow(10, x) - 0.2 * x;
63053     }
63054     _mapImagesAhead(stateSpeed) {
63055         return Math.round(Math.max(10, Math.min(50, 8 + 6 * stateSpeed)));
63056     }
63057     _setPlaying(playing) {
63058         this._playing = playing;
63059         this._playingSubject$.next(playing);
63060     }
63061     _setSpeed(speed) {
63062         this._speed = speed;
63063         const stateSpeed = this._mapSpeed(this._speed);
63064         this._imagesAhead = this._mapImagesAhead(stateSpeed);
63065         return stateSpeed;
63066     }
63067 }
63068 PlayService.sequenceSpeed = 0.54;
63069
63070 var CameraVisualizationMode;
63071 (function (CameraVisualizationMode) {
63072     /**
63073      * Cameras are hidden.
63074      */
63075     CameraVisualizationMode[CameraVisualizationMode["Hidden"] = 0] = "Hidden";
63076     /**
63077      * Cameras are shown, all with the same color.
63078      */
63079     CameraVisualizationMode[CameraVisualizationMode["Homogeneous"] = 1] = "Homogeneous";
63080     /**
63081      * Cameras are shown with colors based on the
63082      * their clusters.
63083      */
63084     CameraVisualizationMode[CameraVisualizationMode["Cluster"] = 2] = "Cluster";
63085     /**
63086      * Cameras are shown with colors based on the
63087      * their connected components.
63088      */
63089     CameraVisualizationMode[CameraVisualizationMode["ConnectedComponent"] = 3] = "ConnectedComponent";
63090     /**
63091      * Cameras are shown, with colors based on the
63092      * their sequence.
63093      */
63094     CameraVisualizationMode[CameraVisualizationMode["Sequence"] = 4] = "Sequence";
63095 })(CameraVisualizationMode || (CameraVisualizationMode = {}));
63096
63097 var OriginalPositionMode;
63098 (function (OriginalPositionMode) {
63099     /**
63100      * Original positions are hidden.
63101      */
63102     OriginalPositionMode[OriginalPositionMode["Hidden"] = 0] = "Hidden";
63103     /**
63104      * Visualize original positions with altitude change.
63105      */
63106     OriginalPositionMode[OriginalPositionMode["Altitude"] = 1] = "Altitude";
63107     /**
63108      * Visualize original positions without altitude change,
63109      * i.e. as flat lines from the camera origin.
63110      */
63111     OriginalPositionMode[OriginalPositionMode["Flat"] = 2] = "Flat";
63112 })(OriginalPositionMode || (OriginalPositionMode = {}));
63113
63114 class ClusterPoints extends Points {
63115     constructor(parameters) {
63116         super();
63117         this._originalSize = parameters.originalSize;
63118         const cluster = parameters.cluster;
63119         const scale = parameters.scale;
63120         const translation = parameters.translation;
63121         this._makeAttributes(cluster);
63122         this.material.size = scale * this._originalSize;
63123         this.material.vertexColors = true;
63124         this.material.needsUpdate = true;
63125         this.matrixAutoUpdate = false;
63126         this.position.fromArray(translation);
63127         this.updateMatrix();
63128         this.updateMatrixWorld(false);
63129     }
63130     dispose() {
63131         this.geometry.dispose();
63132         this.material.dispose();
63133     }
63134     resize(scale) {
63135         this.material.size = scale * this._originalSize;
63136         this.material.needsUpdate = true;
63137     }
63138     _makeAttributes(cluster) {
63139         const positions = [];
63140         const colors = [];
63141         const points = cluster.points;
63142         for (const pointId in points) {
63143             if (!points.hasOwnProperty(pointId)) {
63144                 continue;
63145             }
63146             const point = points[pointId];
63147             positions.push(...point.coordinates);
63148             const color = point.color;
63149             colors.push(color[0]);
63150             colors.push(color[1]);
63151             colors.push(color[2]);
63152         }
63153         const geometry = this.geometry;
63154         geometry.setAttribute("position", new BufferAttribute(new Float32Array(positions), 3));
63155         geometry.setAttribute("color", new BufferAttribute(new Float32Array(colors), 3));
63156     }
63157 }
63158
63159 class CellLine extends Line {
63160     constructor(vertices) {
63161         super();
63162         this._makeAttributes(vertices);
63163         this.matrixAutoUpdate = false;
63164         this.updateMatrix();
63165         this.updateMatrixWorld(false);
63166     }
63167     dispose() {
63168         this.geometry.dispose();
63169         this.material.dispose();
63170     }
63171     _makeAttributes(vertices) {
63172         const closedPolygon = vertices.slice();
63173         closedPolygon.push(vertices[0]);
63174         let index = 0;
63175         const positions = new Float32Array(3 * (vertices.length + 1));
63176         for (const vertex of closedPolygon) {
63177             positions[index++] = vertex[0];
63178             positions[index++] = vertex[1];
63179             positions[index++] = vertex[2];
63180         }
63181         this.geometry.setAttribute("position", new BufferAttribute(positions, 3));
63182     }
63183 }
63184
63185 // Level 0: 1 x 1 x 1 meter cubes
63186 const OCTREE_ROOT_LEVEL = 14; // 16384 meters
63187 const OCTREE_LEAF_LEVEL = 6; // 64 meters
63188 function isLeafLevel(level, leafLevel) {
63189     return level === leafLevel;
63190 }
63191 function levelToSize(level) {
63192     return Math.pow(2, level);
63193 }
63194 function levelToRootBoundingBox(level) {
63195     const size = levelToSize(level);
63196     const half = size / 2;
63197     const min = [-half, -half, -half];
63198     const max = [half, half, half];
63199     return { min, max };
63200 }
63201
63202 class SpatialOctreeNode {
63203     constructor(level, leafLevel, boundingBox, parent) {
63204         this.level = level;
63205         this.leafLevel = leafLevel;
63206         this.boundingBox = boundingBox;
63207         this.parent = parent;
63208         this.children = [];
63209         this.items = [];
63210         if (parent) {
63211             parent.children.push(this);
63212         }
63213     }
63214     get isEmpty() {
63215         return !(this.children.length || this.items.length);
63216     }
63217     add(object) {
63218         const self = this;
63219         if (!self.boundingBox.containsPoint(object.position)) {
63220             throw new Error(`Item not contained in node`);
63221         }
63222         if (isLeafLevel(self.level, self.leafLevel)) {
63223             self.items.push(object);
63224             return this;
63225         }
63226         for (const child of self.children) {
63227             if (child.boundingBox.containsPoint(object.position)) {
63228                 return child.add(object);
63229             }
63230         }
63231         for (const boundingBox of self._generateBoundingBoxes()) {
63232             if (boundingBox.containsPoint(object.position)) {
63233                 const child = new SpatialOctreeNode(self.level - 1, self.leafLevel, boundingBox, self);
63234                 return child.add(object);
63235             }
63236         }
63237         throw new Error(`Item not contained in children`);
63238     }
63239     intersect(ray, target, nodes) {
63240         if (!ray.intersectBox(this.boundingBox, target)) {
63241             return;
63242         }
63243         if (isLeafLevel(this.level, this.leafLevel)) {
63244             nodes.push(this);
63245             return;
63246         }
63247         for (const child of this.children) {
63248             child.intersect(ray, target, nodes);
63249         }
63250     }
63251     remove(object) {
63252         const index = this.items.indexOf(object);
63253         if (index < 0) {
63254             throw new Error(`Item does not exist ${object.uuid}`);
63255         }
63256         this.items.splice(index, 1);
63257     }
63258     traverse() {
63259         const self = this;
63260         if (!self.isEmpty) {
63261             return;
63262         }
63263         const parent = self.parent;
63264         if (!parent) {
63265             return;
63266         }
63267         const index = parent.children.indexOf(self);
63268         if (index < 0) {
63269             throw new Error(`Corrupt octree`);
63270         }
63271         parent.children.splice(index, 1);
63272         this.parent = null;
63273         parent.traverse();
63274     }
63275     _generateBoundingBoxes() {
63276         const self = this;
63277         const min = self.boundingBox.min;
63278         const max = self.boundingBox.max;
63279         const size = (max.x - min.x) / 2;
63280         const mins = [
63281             [min.x, min.y + size, min.z + size],
63282             [min.x + size, min.y + size, min.z + size],
63283             [min.x, min.y, min.z + size],
63284             [min.x + size, min.y, min.z + size],
63285             [min.x, min.y + size, min.z],
63286             [min.x + size, min.y + size, min.z],
63287             [min.x, min.y, min.z],
63288             [min.x + size, min.y, min.z],
63289         ];
63290         const boundingBoxes = [];
63291         for (const [minX, minY, minZ] of mins) {
63292             boundingBoxes.push(new Box3(new Vector3(minX, minY, minZ), new Vector3(minX + size, minY + size, minZ + size)));
63293         }
63294         return boundingBoxes;
63295     }
63296 }
63297
63298 class SpatialOctree {
63299     constructor(rootLevel, leafLevel) {
63300         this.rootLevel = rootLevel;
63301         this.leafLevel = leafLevel;
63302         if (leafLevel > rootLevel) {
63303             throw new Error();
63304         }
63305         this._index = new Map();
63306         this._root = this._makeRoot();
63307     }
63308     get root() {
63309         return this._root;
63310     }
63311     add(object) {
63312         if (!this.root.boundingBox.containsPoint(object.position)) {
63313             console.warn(`Object outside bounding box ${object.uuid}`);
63314             return;
63315         }
63316         const leaf = this._root.add(object);
63317         this._index.set(object.uuid, leaf);
63318     }
63319     has(object) {
63320         return this._index.has(object.uuid);
63321     }
63322     intersect(ray) {
63323         const leaves = [];
63324         const target = new Vector3();
63325         this._root.intersect(ray, target, leaves);
63326         return leaves
63327             .map(leaf => leaf.items)
63328             .reduce((acc, items) => {
63329             acc.push(...items);
63330             return acc;
63331         }, []);
63332     }
63333     reset() {
63334         this._root = this._makeRoot();
63335         this._index.clear();
63336     }
63337     remove(object) {
63338         if (!this.has(object)) {
63339             throw new Error(`Frame does not exist ${object.uuid}`);
63340         }
63341         const leaf = this._index.get(object.uuid);
63342         leaf.remove(object);
63343         leaf.traverse();
63344         this._index.delete(object.uuid);
63345     }
63346     _makeRoot() {
63347         const level = this.rootLevel;
63348         const bbox = levelToRootBoundingBox(level);
63349         const box = new Box3(new Vector3().fromArray(bbox.min), new Vector3().fromArray(bbox.max));
63350         return new SpatialOctreeNode(level, this.leafLevel, box);
63351     }
63352 }
63353
63354 class SpatialIntersection {
63355     constructor(octree, raycaster) {
63356         this._objects = [];
63357         this._objectImageMap = new Map();
63358         this._octree = octree !== null && octree !== void 0 ? octree : new SpatialOctree(OCTREE_ROOT_LEVEL, OCTREE_LEAF_LEVEL);
63359         this._raycaster = raycaster !== null && raycaster !== void 0 ? raycaster : new Raycaster();
63360         this._interactiveLayer = 1;
63361         this._raycaster = !!raycaster ?
63362             raycaster :
63363             new Raycaster(undefined, undefined, 1, 10000);
63364         this._lineThreshold = 0.2;
63365         this._largeLineThreshold = 0.4;
63366         this._raycaster.params.Line.threshold = this._lineThreshold;
63367         this._raycaster.layers.set(this._interactiveLayer);
63368     }
63369     get interactiveLayer() { return this._interactiveLayer; }
63370     get octree() { return this._octree; }
63371     get raycaster() { return this._raycaster; }
63372     add(object, imageId) {
63373         const uuid = object.uuid;
63374         this._objectImageMap.set(uuid, imageId);
63375         this._objects.push(object);
63376         this._octree.add(object);
63377     }
63378     intersectObjects(viewport, camera) {
63379         this._raycaster.setFromCamera(new Vector2().fromArray(viewport), camera);
63380         const objects = this._octree.intersect(this.raycaster.ray);
63381         const intersects = this._raycaster.intersectObjects(objects);
63382         const onMap = this._objectImageMap;
63383         for (const intersect of intersects) {
63384             const uuid = intersect.object.uuid;
63385             if (!onMap.has(uuid)) {
63386                 continue;
63387             }
63388             return onMap.get(uuid);
63389         }
63390         return null;
63391     }
63392     remove(object) {
63393         const objects = this._objects;
63394         const index = objects.indexOf(object);
63395         if (index !== -1) {
63396             const deleted = objects.splice(index, 1);
63397             for (const d of deleted) {
63398                 this._objectImageMap.delete(d.uuid);
63399             }
63400             this._octree.remove(object);
63401         }
63402         else {
63403             console.warn(`Object does not exist`);
63404         }
63405     }
63406     resetIntersectionThreshold(useLarge) {
63407         this._raycaster.params.Line.threshold = useLarge ?
63408             this._largeLineThreshold :
63409             this._lineThreshold;
63410     }
63411 }
63412
63413 class PositionLine extends Line {
63414     constructor(parameters) {
63415         super(parameters.geometry, parameters.material);
63416         const mode = parameters.mode;
63417         const originalOrigin = parameters.originalOrigin;
63418         const transform = parameters.transform;
63419         const origin = transform.unprojectBasic([0, 0], 0);
63420         this._relativeAltitude = originalOrigin[2] - origin[2];
63421         this._makeAttributes(origin, originalOrigin, mode);
63422         this.matrixAutoUpdate = false;
63423         this.position.fromArray(origin);
63424         this.updateMatrix();
63425         this.updateMatrixWorld(false);
63426     }
63427     dispose() {
63428         this.geometry.dispose();
63429         this.material.dispose();
63430     }
63431     setMode(mode) {
63432         const positionAttribute = this.geometry.attributes.position;
63433         const positions = positionAttribute.array;
63434         positions[5] = this._modeToAltitude(mode);
63435         positionAttribute.needsUpdate = true;
63436         this.geometry.computeBoundingSphere();
63437     }
63438     _makeAttributes(origin, originalOrigin, mode) {
63439         const positions = new Float32Array(6);
63440         positions[0] = 0;
63441         positions[1] = 0;
63442         positions[2] = 0;
63443         positions[3] = originalOrigin[0] - origin[0];
63444         positions[4] = originalOrigin[1] - origin[1];
63445         positions[5] = this._modeToAltitude(mode);
63446         const attribute = new BufferAttribute(positions, 3);
63447         this.geometry.setAttribute("position", attribute);
63448         attribute.needsUpdate = true;
63449         this.geometry.computeBoundingSphere();
63450     }
63451     _modeToAltitude(mode) {
63452         return mode === OriginalPositionMode.Altitude ?
63453             this._relativeAltitude : 0;
63454     }
63455 }
63456
63457 class CameraFrameBase extends LineSegments {
63458     constructor(parameters) {
63459         super(parameters.geometry, parameters.material);
63460         const color = parameters.color;
63461         const size = parameters.size;
63462         const scale = parameters.scale;
63463         const transform = parameters.transform;
63464         const origin = transform.unprojectBasic([0, 0], 0);
63465         const positions = this._makePositions(size, transform, origin);
63466         this._makeAttributes(positions, color);
63467         this.geometry.computeBoundingSphere();
63468         this.geometry.computeBoundingBox();
63469         this.matrixAutoUpdate = false;
63470         this.position.fromArray(origin);
63471         this.scale.set(scale, scale, scale);
63472         this.updateMatrix();
63473         this.updateMatrixWorld(false);
63474     }
63475     dispose() {
63476         this.geometry.dispose();
63477         this.material.dispose();
63478     }
63479     setColor(color) {
63480         this._updateColorAttribute(color);
63481         return this;
63482     }
63483     resize(scale) {
63484         this.scale.set(scale, scale, scale);
63485         this.updateMatrix();
63486         this.updateMatrixWorld(false);
63487         return this;
63488     }
63489     _makeAttributes(positions, color) {
63490         const geometry = this.geometry;
63491         const positionAttribute = new BufferAttribute(new Float32Array(positions), 3);
63492         geometry.setAttribute("position", positionAttribute);
63493         positionAttribute.needsUpdate = true;
63494         const colorAttribute = new BufferAttribute(new Float32Array(positions.length), 3);
63495         geometry.setAttribute("color", colorAttribute);
63496         this._updateColorAttribute(color);
63497     }
63498     _updateColorAttribute(color) {
63499         const [r, g, b] = new Color(color).toArray();
63500         const colorAttribute = this.geometry.attributes.color;
63501         const colors = colorAttribute.array;
63502         const length = colors.length;
63503         let index = 0;
63504         for (let i = 0; i < length; i++) {
63505             colors[index++] = r;
63506             colors[index++] = g;
63507             colors[index++] = b;
63508         }
63509         colorAttribute.needsUpdate = true;
63510     }
63511 }
63512
63513 class SphericalCameraFrame extends CameraFrameBase {
63514     _makePositions(size, transform, origin) {
63515         const vs = 10;
63516         const positions = [];
63517         positions.push(...this._makeAxis(size, transform, origin));
63518         positions.push(...this._makeLat(0.5, vs, size, transform, origin));
63519         for (const lat of [0, 0.25, 0.5, 0.75]) {
63520             positions
63521                 .push(...this._makeLng(lat, vs, size, transform, origin));
63522         }
63523         return positions;
63524     }
63525     _makeAxis(size, transform, origin) {
63526         const south = transform.unprojectBasic([0.5, 1], 0.8 * size);
63527         const north = transform.unprojectBasic([0.5, 0], 1.2 * size);
63528         return [
63529             south[0] - origin[0],
63530             south[1] - origin[1],
63531             south[2] - origin[2],
63532             north[0] - origin[0],
63533             north[1] - origin[1],
63534             north[2] - origin[2],
63535         ];
63536     }
63537     _makeLat(basicY, numVertices, size, transform, origin) {
63538         const dist = 0.8 * size;
63539         const [originX, originY, originZ] = origin;
63540         const positions = [];
63541         const first = transform.unprojectBasic([0, basicY], dist);
63542         first[0] -= originX;
63543         first[1] -= originY;
63544         first[2] -= originZ;
63545         positions.push(...first);
63546         for (let i = 1; i <= numVertices; i++) {
63547             const position = transform.unprojectBasic([i / numVertices, basicY], dist);
63548             position[0] -= originX;
63549             position[1] -= originY;
63550             position[2] -= originZ;
63551             positions.push(...position, ...position);
63552         }
63553         positions.push(...first);
63554         return positions;
63555     }
63556     _makeLng(basicX, numVertices, size, transform, origin) {
63557         const dist = 0.8 * size;
63558         const [originX, originY, originZ] = origin;
63559         const positions = [];
63560         const first = transform.unprojectBasic([basicX, 0], dist);
63561         first[0] -= originX;
63562         first[1] -= originY;
63563         first[2] -= originZ;
63564         positions.push(...first);
63565         for (let i = 0; i <= numVertices; i++) {
63566             const position = transform.unprojectBasic([basicX, i / numVertices], dist);
63567             position[0] -= originX;
63568             position[1] -= originY;
63569             position[2] -= originZ;
63570             positions.push(...position, ...position);
63571         }
63572         positions.push(...first);
63573         return positions;
63574     }
63575 }
63576
63577 class PerspectiveCameraFrame extends CameraFrameBase {
63578     _makePositions(size, transform, origin) {
63579         const samples = 8;
63580         const positions = [];
63581         positions.push(...this._makeDiags(size, transform, origin));
63582         positions.push(...this._makeFrame(size, samples, transform, origin));
63583         return positions;
63584     }
63585     _makeDiags(size, transform, origin) {
63586         const depth = size;
63587         const [originX, originY, originZ] = origin;
63588         const cameraCenter = [0, 0, 0];
63589         const positions = [];
63590         for (const vertex2d of [[0, 0], [1, 0], [1, 1], [0, 1]]) {
63591             const corner = transform.unprojectBasic(vertex2d, depth, true);
63592             corner[0] -= originX;
63593             corner[1] -= originY;
63594             corner[2] -= originZ;
63595             positions.push(...cameraCenter, ...corner);
63596         }
63597         return positions;
63598     }
63599     _makeFrame(size, samples, transform, origin) {
63600         const vertices2d = [];
63601         vertices2d.push(...this._subsample([0, 1], [0, 0], samples));
63602         vertices2d.push(...this._subsample([0, 0], [1, 0], samples));
63603         vertices2d.push(...this._subsample([1, 0], [1, 1], samples));
63604         const depth = size;
63605         const [originX, originY, originZ] = origin;
63606         const positions = [];
63607         for (const vertex2d of vertices2d) {
63608             const position = transform.unprojectBasic(vertex2d, depth, true);
63609             position[0] -= originX;
63610             position[1] -= originY;
63611             position[2] -= originZ;
63612             positions.push(...position);
63613         }
63614         return positions;
63615     }
63616     _interpolate(a, b, alpha) {
63617         return a + alpha * (b - a);
63618     }
63619     _subsample(p1, p2, subsamples) {
63620         if (subsamples < 1) {
63621             return [p1, p2];
63622         }
63623         const samples = [];
63624         samples.push(p1);
63625         for (let i = 0; i <= subsamples; i++) {
63626             const p = [];
63627             for (let j = 0; j < 3; j++) {
63628                 p.push(this._interpolate(p1[j], p2[j], i / (subsamples + 1)));
63629             }
63630             samples.push(p);
63631             samples.push(p);
63632         }
63633         samples.push(p2);
63634         return samples;
63635     }
63636 }
63637
63638 class SpatialCell {
63639     constructor(id, _scene, _intersection) {
63640         this.id = id;
63641         this._scene = _scene;
63642         this._intersection = _intersection;
63643         this.cameras = new Object3D();
63644         this.keys = [];
63645         this._positionLines = {};
63646         this._positions = new Object3D();
63647         this._cameraFrames = {};
63648         this._clusters = new Map();
63649         this._connectedComponents = new Map();
63650         this._sequences = new Map();
63651         this._props = {};
63652         this.clusterVisibles = {};
63653         this._frameMaterial = new LineBasicMaterial({
63654             fog: false,
63655             vertexColors: true,
63656         });
63657         this._positionMaterial = new LineBasicMaterial({
63658             fog: false,
63659             color: 0xff0000,
63660         });
63661         this._scene.add(this.cameras, this._positions);
63662     }
63663     addImage(props) {
63664         const image = props.image;
63665         const id = image.id;
63666         if (this.hasImage(id)) {
63667             throw new Error(`Image exists ${id}`);
63668         }
63669         const ccId = props.idMap.ccId;
63670         if (!(this._connectedComponents.has(ccId))) {
63671             this._connectedComponents.set(ccId, []);
63672         }
63673         const cId = props.idMap.clusterId;
63674         if (!this._clusters.has(cId)) {
63675             this._clusters.set(cId, []);
63676         }
63677         const sId = props.idMap.sequenceId;
63678         if (!this._sequences.has(sId)) {
63679             this._sequences.set(sId, []);
63680         }
63681         this._props[id] = {
63682             image: image,
63683             ids: { ccId, clusterId: cId, sequenceId: sId },
63684         };
63685         this.keys.push(id);
63686     }
63687     applyCameraColor(imageId, color) {
63688         this._cameraFrames[imageId].setColor(color);
63689     }
63690     applyCameraSize(size) {
63691         for (const camera of this.cameras.children) {
63692             camera.resize(size);
63693         }
63694     }
63695     applyFilter(filter) {
63696         var _a;
63697         const clusterVisibles = this.clusterVisibles;
63698         for (const clusterId in clusterVisibles) {
63699             if (!clusterVisibles.hasOwnProperty(clusterId)) {
63700                 continue;
63701             }
63702             clusterVisibles[clusterId] = false;
63703         }
63704         const cameraFrames = this._cameraFrames;
63705         const positionLines = this._positionLines;
63706         const interactiveLayer = this._intersection.interactiveLayer;
63707         for (const props of Object.values(this._props)) {
63708             const image = props.image;
63709             const visible = filter(image);
63710             const key = image.id;
63711             positionLines[key].visible = visible;
63712             const camera = cameraFrames[key];
63713             this._setCameraVisibility(camera, visible, interactiveLayer);
63714             clusterVisibles[_a = props.ids.clusterId] || (clusterVisibles[_a] = visible);
63715         }
63716     }
63717     applyPositionMode(mode) {
63718         this._positions.visible =
63719             mode !== OriginalPositionMode.Hidden;
63720         for (const position of this._positions.children) {
63721             position.setMode(mode);
63722         }
63723     }
63724     dispose() {
63725         this._disposeCameras();
63726         this._disposePositions();
63727         this._scene = null;
63728         this._intersection = null;
63729     }
63730     getCamerasByMode(mode) {
63731         if (mode === CameraVisualizationMode.Cluster) {
63732             return this._clusters;
63733         }
63734         else if (mode === CameraVisualizationMode.ConnectedComponent) {
63735             return this._connectedComponents;
63736         }
63737         else if (mode === CameraVisualizationMode.Sequence) {
63738             return this._sequences;
63739         }
63740         const cvm = CameraVisualizationMode;
63741         const defaultId = cvm[cvm.Homogeneous];
63742         const cameras = new Map();
63743         cameras.set(defaultId, this.cameras.children);
63744         return cameras;
63745     }
63746     getColorId(imageId, mode) {
63747         const props = this._props[imageId];
63748         const cvm = CameraVisualizationMode;
63749         switch (mode) {
63750             case cvm.Cluster:
63751                 return props.ids.clusterId;
63752             case cvm.ConnectedComponent:
63753                 return props.ids.ccId;
63754             case cvm.Sequence:
63755                 return props.ids.sequenceId;
63756             default:
63757                 return cvm[cvm.Homogeneous];
63758         }
63759     }
63760     hasImage(key) {
63761         return this.keys.indexOf(key) !== -1;
63762     }
63763     visualize(props) {
63764         var _a, _b;
63765         const id = props.id;
63766         const visible = props.visible;
63767         const transform = props.transform;
63768         const cameraParameters = {
63769             color: props.color,
63770             material: this._frameMaterial,
63771             scale: props.scale,
63772             size: props.maxSize,
63773             transform,
63774         };
63775         const camera = isSpherical(transform.cameraType) ?
63776             new SphericalCameraFrame(cameraParameters) :
63777             new PerspectiveCameraFrame(cameraParameters);
63778         const interactiveLayer = this._intersection.interactiveLayer;
63779         this._setCameraVisibility(camera, visible, interactiveLayer);
63780         this.cameras.add(camera);
63781         this._cameraFrames[id] = camera;
63782         const intersection = this._intersection;
63783         intersection.add(camera, id);
63784         const ids = this._props[id].ids;
63785         (_a = this.clusterVisibles)[_b = ids.clusterId] || (_a[_b] = visible);
63786         this._connectedComponents.get(ids.ccId).push(camera);
63787         this._clusters.get(ids.clusterId).push(camera);
63788         this._sequences.get(ids.sequenceId).push(camera);
63789         const positionParameters = {
63790             material: this._positionMaterial,
63791             mode: props.positionMode,
63792             originalOrigin: props.originalPosition,
63793             transform,
63794         };
63795         const position = new PositionLine(positionParameters);
63796         position.visible = visible;
63797         this._positions.add(position);
63798         this._positionLines[id] = position;
63799     }
63800     _disposeCameras() {
63801         const intersection = this._intersection;
63802         const cameras = this.cameras;
63803         for (const camera of cameras.children.slice()) {
63804             camera.dispose();
63805             intersection.remove(camera);
63806             cameras.remove(camera);
63807         }
63808         this._scene.remove(this.cameras);
63809     }
63810     _disposePositions() {
63811         const positions = this._positions;
63812         for (const position of positions.children.slice()) {
63813             position.dispose();
63814             positions.remove(position);
63815         }
63816         this._scene.remove(this._positions);
63817     }
63818     _setCameraVisibility(camera, visible, layer) {
63819         camera.visible = visible;
63820         if (visible) {
63821             camera.layers.enable(layer);
63822         }
63823         else {
63824             camera.layers.disable(layer);
63825         }
63826     }
63827 }
63828
63829 class SpatialAssets {
63830     constructor() {
63831         this._colors = new Map();
63832         const cvm = CameraVisualizationMode;
63833         this._colors.set(cvm[cvm.Homogeneous], "#FFFFFF");
63834     }
63835     getColor(id) {
63836         const colors = this._colors;
63837         if (!colors.has(id)) {
63838             colors.set(id, this._randomColor());
63839         }
63840         return colors.get(id);
63841     }
63842     _randomColor() {
63843         return `hsl(${Math.floor(360 * Math.random())}, 100%, 50%)`;
63844     }
63845 }
63846
63847 function isModeVisible(mode) {
63848     return mode !== CameraVisualizationMode.Hidden;
63849 }
63850 function isOverviewState(state) {
63851     return state === State.Custom || state === State.Earth;
63852 }
63853
63854 const NO_CLUSTER_ID = "NO_CLUSTER_ID";
63855 const NO_MERGE_ID = "NO_MERGE_ID";
63856 const NO_SEQUENCE_ID = "NO_SEQUENCE_ID";
63857 class SpatialScene {
63858     constructor(configuration, scene) {
63859         this._rayNearScale = 1.1;
63860         this._originalPointSize = 2;
63861         this._originalCameraSize = 2;
63862         this._imageCellMap = new Map();
63863         this._scene = !!scene ? scene : new Scene();
63864         this._scene.autoUpdate = false;
63865         this._intersection = new SpatialIntersection();
63866         this._assets = new SpatialAssets();
63867         this._needsRender = false;
63868         this._images = {};
63869         this._cells = {};
63870         this._cellClusters = {};
63871         this._clusters = {};
63872         this._cameraVisualizationMode =
63873             !!configuration.cameraVisualizationMode ?
63874                 configuration.cameraVisualizationMode :
63875                 CameraVisualizationMode.Homogeneous;
63876         this._cameraSize = configuration.cameraSize;
63877         this._pointSize = configuration.pointSize;
63878         this._pointsVisible = configuration.pointsVisible;
63879         this._positionMode = configuration.originalPositionMode;
63880         this._cellsVisible = configuration.cellsVisible;
63881         this._hoveredId = null;
63882         this._selectedId = null;
63883         this._colors = { hover: "#FF0000", select: "#FF8000" };
63884         this._filter = () => true;
63885     }
63886     get needsRender() { return this._needsRender; }
63887     get intersection() {
63888         return this._intersection;
63889     }
63890     addCluster(reconstruction, translation, cellId) {
63891         if (this.hasCluster(reconstruction.id, cellId)) {
63892             return;
63893         }
63894         const clusterId = reconstruction.id;
63895         if (!(clusterId in this._clusters)) {
63896             this._clusters[clusterId] = {
63897                 points: new Object3D(),
63898                 cellIds: [],
63899             };
63900             const visible = this._getClusterVisible(clusterId);
63901             this._clusters[clusterId].points.visible = visible;
63902             this._clusters[clusterId].points.add(new ClusterPoints({
63903                 cluster: reconstruction,
63904                 originalSize: this._originalPointSize,
63905                 scale: this._pointSize,
63906                 translation,
63907             }));
63908             this._scene.add(this._clusters[clusterId].points);
63909         }
63910         if (this._clusters[clusterId].cellIds.indexOf(cellId) === -1) {
63911             this._clusters[clusterId].cellIds.push(cellId);
63912         }
63913         if (!(cellId in this._cellClusters)) {
63914             this._cellClusters[cellId] = { keys: [] };
63915         }
63916         if (this._cellClusters[cellId].keys.indexOf(clusterId) === -1) {
63917             this._cellClusters[cellId].keys.push(clusterId);
63918         }
63919         this._needsRender = true;
63920     }
63921     addImage(image, transform, originalPosition, cellId) {
63922         var _a, _b, _c;
63923         const imageId = image.id;
63924         const idMap = {
63925             clusterId: (_a = image.clusterId) !== null && _a !== void 0 ? _a : NO_CLUSTER_ID,
63926             sequenceId: (_b = image.sequenceId) !== null && _b !== void 0 ? _b : NO_SEQUENCE_ID,
63927             ccId: (_c = image.mergeId) !== null && _c !== void 0 ? _c : NO_MERGE_ID,
63928         };
63929         if (!(cellId in this._images)) {
63930             const created = new SpatialCell(cellId, this._scene, this._intersection);
63931             created.cameras.visible =
63932                 isModeVisible(this._cameraVisualizationMode);
63933             created.applyPositionMode(this._positionMode);
63934             this._images[cellId] = created;
63935         }
63936         const cell = this._images[cellId];
63937         if (cell.hasImage(imageId)) {
63938             return;
63939         }
63940         cell.addImage({ idMap, image: image });
63941         const colorId = cell.getColorId(imageId, this._cameraVisualizationMode);
63942         const color = this._assets.getColor(colorId);
63943         const visible = this._filter(image);
63944         cell.visualize({
63945             id: imageId,
63946             color,
63947             positionMode: this._positionMode,
63948             scale: this._cameraSize,
63949             transform,
63950             visible,
63951             maxSize: this._originalCameraSize,
63952             originalPosition
63953         });
63954         this._imageCellMap.set(imageId, cellId);
63955         if (imageId === this._selectedId) {
63956             this._highlight(imageId, this._colors.select, this._cameraVisualizationMode);
63957         }
63958         if (idMap.clusterId in this._clusters) {
63959             const clusterVisible = this._getClusterVisible(idMap.clusterId);
63960             this._clusters[idMap.clusterId].points.visible = clusterVisible;
63961         }
63962         this._needsRender = true;
63963     }
63964     addCell(vertices, cellId) {
63965         if (this.hasCell(cellId)) {
63966             return;
63967         }
63968         const cell = new CellLine(vertices);
63969         this._cells[cellId] = new Object3D();
63970         this._cells[cellId].visible = this._cellsVisible;
63971         this._cells[cellId].add(cell);
63972         this._scene.add(this._cells[cellId]);
63973         this._needsRender = true;
63974     }
63975     deactivate() {
63976         this._filter = () => true;
63977         this._selectedId = null;
63978         this._hoveredId = null;
63979         this.uncache();
63980     }
63981     hasCluster(clusterId, cellId) {
63982         return clusterId in this._clusters &&
63983             this._clusters[clusterId].cellIds.indexOf(cellId) !== -1;
63984     }
63985     hasCell(cellId) {
63986         return cellId in this._cells;
63987     }
63988     hasImage(imageId, cellId) {
63989         return cellId in this._images &&
63990             this._images[cellId].hasImage(imageId);
63991     }
63992     setCameraSize(cameraSize) {
63993         if (Math.abs(cameraSize - this._cameraSize) < 1e-3) {
63994             return;
63995         }
63996         const imageCells = this._images;
63997         for (const cellId of Object.keys(imageCells)) {
63998             imageCells[cellId].applyCameraSize(cameraSize);
63999         }
64000         this._intersection.raycaster.near = this._getNear(cameraSize);
64001         this._cameraSize = cameraSize;
64002         this._needsRender = true;
64003     }
64004     setFilter(filter) {
64005         this._filter = filter;
64006         const clusterVisibles = {};
64007         for (const imageCell of Object.values(this._images)) {
64008             imageCell.applyFilter(filter);
64009             const imageCV = imageCell.clusterVisibles;
64010             for (const clusterId in imageCV) {
64011                 if (!imageCV.hasOwnProperty(clusterId)) {
64012                     continue;
64013                 }
64014                 if (!(clusterId in clusterVisibles)) {
64015                     clusterVisibles[clusterId] = false;
64016                 }
64017                 clusterVisibles[clusterId] || (clusterVisibles[clusterId] = imageCV[clusterId]);
64018             }
64019         }
64020         const pointsVisible = this._pointsVisible;
64021         for (const clusterId in clusterVisibles) {
64022             if (!clusterVisibles.hasOwnProperty(clusterId)) {
64023                 continue;
64024             }
64025             clusterVisibles[clusterId] && (clusterVisibles[clusterId] = pointsVisible);
64026             const visible = clusterVisibles[clusterId];
64027             if (clusterId in this._clusters) {
64028                 this._clusters[clusterId].points.visible = visible;
64029             }
64030         }
64031         this._needsRender = true;
64032     }
64033     setHoveredImage(imageId) {
64034         if (imageId != null && !this._imageCellMap.has(imageId)) {
64035             throw new MapillaryError(`Image does not exist: ${imageId}`);
64036         }
64037         if (this._hoveredId === imageId) {
64038             return;
64039         }
64040         this._needsRender = true;
64041         if (this._hoveredId != null) {
64042             if (this._hoveredId === this._selectedId) {
64043                 this._highlight(this._hoveredId, this._colors.select, this._cameraVisualizationMode);
64044             }
64045             else {
64046                 this._resetCameraColor(this._hoveredId);
64047             }
64048         }
64049         this._highlight(imageId, this._colors.hover, this._cameraVisualizationMode);
64050         this._hoveredId = imageId;
64051     }
64052     setNavigationState(isOverview) {
64053         this._intersection.resetIntersectionThreshold(isOverview);
64054     }
64055     setPointSize(pointSize) {
64056         if (Math.abs(pointSize - this._pointSize) < 1e-3) {
64057             return;
64058         }
64059         const clusters = this._clusters;
64060         for (const key in clusters) {
64061             if (!clusters.hasOwnProperty(key)) {
64062                 continue;
64063             }
64064             for (const points of clusters[key].points.children) {
64065                 points.resize(pointSize);
64066             }
64067         }
64068         this._pointSize = pointSize;
64069         this._needsRender = true;
64070     }
64071     setPointVisibility(visible) {
64072         if (visible === this._pointsVisible) {
64073             return;
64074         }
64075         for (const clusterId in this._clusters) {
64076             if (!this._clusters.hasOwnProperty(clusterId)) {
64077                 continue;
64078             }
64079             this._clusters[clusterId].points.visible = visible;
64080         }
64081         this._pointsVisible = visible;
64082         this._needsRender = true;
64083     }
64084     setPositionMode(mode) {
64085         if (mode === this._positionMode) {
64086             return;
64087         }
64088         for (const cell of Object.values(this._images)) {
64089             cell.applyPositionMode(mode);
64090         }
64091         this._positionMode = mode;
64092         this._needsRender = true;
64093     }
64094     setSelectedImage(id) {
64095         if (this._selectedId === id) {
64096             return;
64097         }
64098         this._needsRender = true;
64099         if (this._selectedId != null) {
64100             this._resetCameraColor(this._selectedId);
64101         }
64102         this._highlight(id, this._colors.select, this._cameraVisualizationMode);
64103         this._selectedId = id;
64104     }
64105     setCellVisibility(visible) {
64106         if (visible === this._cellsVisible) {
64107             return;
64108         }
64109         for (const cellId in this._cells) {
64110             if (!this._cells.hasOwnProperty(cellId)) {
64111                 continue;
64112             }
64113             this._cells[cellId].visible = visible;
64114         }
64115         this._cellsVisible = visible;
64116         this._needsRender = true;
64117     }
64118     setCameraVisualizationMode(mode) {
64119         if (mode === this._cameraVisualizationMode) {
64120             return;
64121         }
64122         const visible = isModeVisible(mode);
64123         const assets = this._assets;
64124         for (const cell of Object.values(this._images)) {
64125             cell.cameras.visible = visible;
64126             const cameraMap = cell.getCamerasByMode(mode);
64127             cameraMap.forEach((cameras, colorId) => {
64128                 const color = assets.getColor(colorId);
64129                 for (const camera of cameras) {
64130                     camera.setColor(color);
64131                 }
64132             });
64133         }
64134         this._highlight(this._hoveredId, this._colors.hover, mode);
64135         this._highlight(this._selectedId, this._colors.select, mode);
64136         this._cameraVisualizationMode = mode;
64137         this._needsRender = true;
64138     }
64139     render(camera, renderer) {
64140         renderer.render(this._scene, camera);
64141         this._needsRender = false;
64142     }
64143     uncache(keepCellIds) {
64144         for (const cellId of Object.keys(this._cellClusters)) {
64145             if (!!keepCellIds && keepCellIds.indexOf(cellId) !== -1) {
64146                 continue;
64147             }
64148             this._disposeReconstruction(cellId);
64149         }
64150         for (const cellId of Object.keys(this._images)) {
64151             if (!!keepCellIds && keepCellIds.indexOf(cellId) !== -1) {
64152                 continue;
64153             }
64154             const nceMap = this._imageCellMap;
64155             const keys = this._images[cellId].keys;
64156             for (const key of keys) {
64157                 nceMap.delete(key);
64158             }
64159             this._images[cellId].dispose();
64160             delete this._images[cellId];
64161         }
64162         for (const cellId of Object.keys(this._cells)) {
64163             if (!!keepCellIds && keepCellIds.indexOf(cellId) !== -1) {
64164                 continue;
64165             }
64166             this._disposeCell(cellId);
64167         }
64168         this._needsRender = true;
64169     }
64170     _getClusterVisible(clusterId) {
64171         if (!this._pointsVisible) {
64172             return false;
64173         }
64174         let visible = false;
64175         for (const imageCell of Object.values(this._images)) {
64176             const imageCV = imageCell.clusterVisibles;
64177             if (!(clusterId in imageCV)) {
64178                 continue;
64179             }
64180             visible || (visible = imageCV[clusterId]);
64181         }
64182         return visible;
64183     }
64184     _disposePoints(cellId) {
64185         for (const clusterId of this._cellClusters[cellId].keys) {
64186             if (!(clusterId in this._clusters)) {
64187                 continue;
64188             }
64189             const index = this._clusters[clusterId].cellIds.indexOf(cellId);
64190             if (index === -1) {
64191                 continue;
64192             }
64193             this._clusters[clusterId].cellIds.splice(index, 1);
64194             if (this._clusters[clusterId].cellIds.length > 0) {
64195                 continue;
64196             }
64197             for (const points of this._clusters[clusterId].points.children.slice()) {
64198                 points.dispose();
64199             }
64200             this._scene.remove(this._clusters[clusterId].points);
64201             delete this._clusters[clusterId];
64202         }
64203     }
64204     _disposeReconstruction(cellId) {
64205         this._disposePoints(cellId);
64206         delete this._cellClusters[cellId];
64207     }
64208     _disposeCell(cellId) {
64209         const cell = this._cells[cellId];
64210         for (const line of cell.children.slice()) {
64211             line.dispose();
64212             cell.remove(line);
64213         }
64214         this._scene.remove(cell);
64215         delete this._cells[cellId];
64216     }
64217     _getNear(cameraSize) {
64218         const near = this._rayNearScale *
64219             this._originalCameraSize *
64220             cameraSize;
64221         return Math.max(1, near);
64222     }
64223     _resetCameraColor(imageId) {
64224         const nceMap = this._imageCellMap;
64225         if (imageId == null || !nceMap.has(imageId)) {
64226             return;
64227         }
64228         const cellId = nceMap.get(imageId);
64229         const cell = this._images[cellId];
64230         const colorId = cell.getColorId(imageId, this._cameraVisualizationMode);
64231         const color = this._assets.getColor(colorId);
64232         cell.applyCameraColor(imageId, color);
64233     }
64234     _highlight(imageId, color, mode) {
64235         const nceMap = this._imageCellMap;
64236         if (imageId == null || !nceMap.has(imageId)) {
64237             return;
64238         }
64239         const cellId = nceMap.get(imageId);
64240         color = mode === CameraVisualizationMode.Homogeneous ?
64241             color : "#FFFFFF";
64242         this._images[cellId].applyCameraColor(imageId, color);
64243     }
64244 }
64245
64246 class SpatialCache {
64247     constructor(graphService, provider) {
64248         this._graphService = graphService;
64249         this._data = provider;
64250         this._cells = {};
64251         this._cacheRequests = {};
64252         this._clusters = {};
64253         this._clusterCells = {};
64254         this._cellClusters = {};
64255         this._cachingCells$ = {};
64256         this._cachingClusters$ = {};
64257     }
64258     cacheClusters$(cellId) {
64259         if (!this.hasCell(cellId)) {
64260             throw new Error("Cannot cache reconstructions of a non-existing cell.");
64261         }
64262         if (this.hasClusters(cellId)) {
64263             throw new Error("Cannot cache reconstructions that already exists.");
64264         }
64265         if (this.isCachingClusters(cellId)) {
64266             return this._cachingClusters$[cellId];
64267         }
64268         const duplicatedClusters = this.getCell(cellId)
64269             .filter((n) => {
64270             return !!n.clusterId && !!n.clusterUrl;
64271         })
64272             .map((n) => {
64273             return { key: n.clusterId, url: n.clusterUrl };
64274         });
64275         const clusters = Array
64276             .from(new Map(duplicatedClusters.map((cd) => {
64277             return [cd.key, cd];
64278         }))
64279             .values());
64280         this._cellClusters[cellId] = clusters;
64281         this._cacheRequests[cellId] = [];
64282         let aborter;
64283         const abort = new Promise((_, reject) => {
64284             aborter = reject;
64285         });
64286         this._cacheRequests[cellId].push(aborter);
64287         this._cachingClusters$[cellId] =
64288             this._cacheClusters$(clusters, cellId, abort).pipe(finalize(() => {
64289                 if (cellId in this._cachingClusters$) {
64290                     delete this._cachingClusters$[cellId];
64291                 }
64292                 if (cellId in this._cacheRequests) {
64293                     delete this._cacheRequests[cellId];
64294                 }
64295             }), publish(), refCount());
64296         return this._cachingClusters$[cellId];
64297     }
64298     cacheCell$(cellId) {
64299         if (this.hasCell(cellId)) {
64300             throw new Error("Cannot cache cell that already exists.");
64301         }
64302         if (this.isCachingCell(cellId)) {
64303             return this._cachingCells$[cellId];
64304         }
64305         this._cachingCells$[cellId] = this._graphService.cacheCell$(cellId).pipe(catchError((error) => {
64306             console.error(error);
64307             return empty();
64308         }), filter(() => {
64309             return !(cellId in this._cells);
64310         }), tap((images) => {
64311             this._cells[cellId] = [];
64312             this._cells[cellId].push(...images);
64313             delete this._cachingCells$[cellId];
64314         }), finalize(() => {
64315             if (cellId in this._cachingCells$) {
64316                 delete this._cachingCells$[cellId];
64317             }
64318         }), publish(), refCount());
64319         return this._cachingCells$[cellId];
64320     }
64321     isCachingClusters(cellId) {
64322         return cellId in this._cachingClusters$;
64323     }
64324     isCachingCell(cellId) {
64325         return cellId in this._cachingCells$;
64326     }
64327     hasClusters(cellId) {
64328         if (cellId in this._cachingClusters$ ||
64329             !(cellId in this._cellClusters)) {
64330             return false;
64331         }
64332         for (const cd of this._cellClusters[cellId]) {
64333             if (!(cd.key in this._clusters)) {
64334                 return false;
64335             }
64336         }
64337         return true;
64338     }
64339     hasCell(cellId) {
64340         return !(cellId in this._cachingCells$) && cellId in this._cells;
64341     }
64342     getClusters(cellId) {
64343         return cellId in this._cellClusters ?
64344             this._cellClusters[cellId]
64345                 .map((cd) => {
64346                 return this._clusters[cd.key];
64347             })
64348                 .filter((reconstruction) => {
64349                 return !!reconstruction;
64350             }) :
64351             [];
64352     }
64353     getCell(cellId) {
64354         return cellId in this._cells ? this._cells[cellId] : [];
64355     }
64356     uncache(keepCellIds) {
64357         for (let cellId of Object.keys(this._cacheRequests)) {
64358             if (!!keepCellIds && keepCellIds.indexOf(cellId) !== -1) {
64359                 continue;
64360             }
64361             for (const aborter of this._cacheRequests[cellId]) {
64362                 aborter();
64363             }
64364             delete this._cacheRequests[cellId];
64365         }
64366         for (let cellId of Object.keys(this._cellClusters)) {
64367             if (!!keepCellIds && keepCellIds.indexOf(cellId) !== -1) {
64368                 continue;
64369             }
64370             for (const cd of this._cellClusters[cellId]) {
64371                 if (!(cd.key in this._clusterCells)) {
64372                     continue;
64373                 }
64374                 const index = this._clusterCells[cd.key].indexOf(cellId);
64375                 if (index === -1) {
64376                     continue;
64377                 }
64378                 this._clusterCells[cd.key].splice(index, 1);
64379                 if (this._clusterCells[cd.key].length > 0) {
64380                     continue;
64381                 }
64382                 delete this._clusterCells[cd.key];
64383                 delete this._clusters[cd.key];
64384             }
64385             delete this._cellClusters[cellId];
64386         }
64387         for (let cellId of Object.keys(this._cells)) {
64388             if (!!keepCellIds && keepCellIds.indexOf(cellId) !== -1) {
64389                 continue;
64390             }
64391             delete this._cells[cellId];
64392         }
64393     }
64394     updateCell$(cellId) {
64395         if (!this.hasCell(cellId)) {
64396             throw new Error("Cannot update cell that does not exists.");
64397         }
64398         return this._graphService.cacheCell$(cellId).pipe(catchError((error) => {
64399             console.error(error);
64400             return empty();
64401         }), filter(() => {
64402             return cellId in this._cells;
64403         }), tap((images) => {
64404             this._cells[cellId] = [];
64405             this._cells[cellId].push(...images);
64406         }), publish(), refCount());
64407     }
64408     updateClusters$(cellId) {
64409         if (!this.hasCell(cellId)) {
64410             throw new Error("Cannot update reconstructions of a non-existing cell.");
64411         }
64412         if (!this.hasClusters(cellId)) {
64413             throw new Error("Cannot update reconstructions for cell that is not cached.");
64414         }
64415         const duplicatedClusters = this.getCell(cellId)
64416             .filter((n) => {
64417             return !!n.clusterId && !!n.clusterUrl;
64418         })
64419             .map((n) => {
64420             return { key: n.clusterId, url: n.clusterUrl };
64421         });
64422         const clusters = Array
64423             .from(new Map(duplicatedClusters.map((cd) => {
64424             return [cd.key, cd];
64425         }))
64426             .values())
64427             .filter(cd => {
64428             return !(cd.key in this._clusters);
64429         });
64430         this._cellClusters[cellId].push(...clusters);
64431         return this._cacheClusters$(clusters, cellId, null);
64432     }
64433     _cacheClusters$(clusters, cellId, cancellation) {
64434         return from(clusters).pipe(mergeMap((cd) => {
64435             if (this._hasCluster(cd.key)) {
64436                 return of(this._getCluster(cd.key));
64437             }
64438             return this._getCluster$(cd.url, cd.key, cancellation)
64439                 .pipe(catchError((error) => {
64440                 if (error instanceof CancelMapillaryError) {
64441                     return empty();
64442                 }
64443                 console.error(error);
64444                 return empty();
64445             }));
64446         }, 6), filter(() => {
64447             return cellId in this._cellClusters;
64448         }), tap((reconstruction) => {
64449             if (!this._hasCluster(reconstruction.id)) {
64450                 this._clusters[reconstruction.id] = reconstruction;
64451             }
64452             if (!(reconstruction.id in this._clusterCells)) {
64453                 this._clusterCells[reconstruction.id] = [];
64454             }
64455             if (this._clusterCells[reconstruction.id].indexOf(cellId) === -1) {
64456                 this._clusterCells[reconstruction.id].push(cellId);
64457             }
64458         }));
64459     }
64460     _getCluster(id) {
64461         return this._clusters[id];
64462     }
64463     _getCluster$(url, clusterId, abort) {
64464         return Observable.create((subscriber) => {
64465             this._data.getCluster(url, abort)
64466                 .then((reconstruction) => {
64467                 reconstruction.id = clusterId;
64468                 subscriber.next(reconstruction);
64469                 subscriber.complete();
64470             }, (error) => {
64471                 subscriber.error(error);
64472             });
64473         });
64474     }
64475     _hasCluster(id) {
64476         return id in this._clusters;
64477     }
64478 }
64479
64480 function connectedComponent(cellId, depth, geometry) {
64481     const cells = new Set();
64482     cells.add(cellId);
64483     connectedComponentRecursive(cells, [cellId], 0, depth, geometry);
64484     return Array.from(cells);
64485 }
64486 function connectedComponentRecursive(cells, current, currentDepth, maxDepth, geometry) {
64487     if (currentDepth >= maxDepth) {
64488         return;
64489     }
64490     const adjacent = [];
64491     for (const cellId of current) {
64492         const aCells = geometry.getAdjacent(cellId);
64493         adjacent.push(...aCells);
64494     }
64495     const newCells = [];
64496     for (const a of adjacent) {
64497         if (cells.has(a)) {
64498             continue;
64499         }
64500         cells.add(a);
64501         newCells.push(a);
64502     }
64503     connectedComponentRecursive(cells, newCells, currentDepth + 1, maxDepth, geometry);
64504 }
64505
64506 class SpatialComponent extends Component {
64507     /** @ignore */
64508     constructor(name, container, navigator) {
64509         super(name, container, navigator);
64510         this._cache = new SpatialCache(navigator.graphService, navigator.api.data);
64511         this._scene = new SpatialScene(this._getDefaultConfiguration());
64512         this._viewportCoords = new ViewportCoords();
64513         this._spatial = new Spatial();
64514     }
64515     /**
64516      * Returns the image id of the camera frame closest to the current
64517      * render camera position at the specified point.
64518      *
64519      * @description Notice that the pixelPoint argument requires x, y
64520      * coordinates from pixel space.
64521      *
64522      * With this function, you can use the coordinates provided by mouse
64523      * events to get information out of the spatial component.
64524      *
64525      * If no camera frame exist at the pixel
64526      * point, `null` will be returned.
64527      *
64528      * @param {Array<number>} pixelPoint - Pixel coordinates on
64529      * the viewer element.
64530      * @returns {string} Image id of the camera frame closest to
64531      * the camera. If no camera frame is intersected at the
64532      * pixel point, `null` will be returned.
64533      *
64534      * @example
64535      * ```js
64536      * spatialComponent.getFrameIdAt([100, 125])
64537      *     .then((imageId) => { console.log(imageId); });
64538      * ```
64539      */
64540     getFrameIdAt(pixelPoint) {
64541         return new Promise((resolve, reject) => {
64542             this._container.renderService.renderCamera$.pipe(first(), map((render) => {
64543                 const viewport = this._viewportCoords
64544                     .canvasToViewport(pixelPoint[0], pixelPoint[1], this._container.container);
64545                 const id = this._scene.intersection
64546                     .intersectObjects(viewport, render.perspective);
64547                 return id;
64548             }))
64549                 .subscribe((id) => {
64550                 resolve(id);
64551             }, (error) => {
64552                 reject(error);
64553             });
64554         });
64555     }
64556     _activate() {
64557         this._navigator.cacheService.configure({ cellDepth: 3 });
64558         const subs = this._subscriptions;
64559         subs.push(this._navigator.stateService.reference$
64560             .subscribe(() => {
64561             this._scene.uncache();
64562         }));
64563         subs.push(this._navigator.graphService.filter$
64564             .subscribe(imageFilter => { this._scene.setFilter(imageFilter); }));
64565         const bearing$ = this._container.renderService.bearing$.pipe(map((bearing) => {
64566             const interval = 6;
64567             const discrete = interval * Math.floor(bearing / interval);
64568             return discrete;
64569         }), distinctUntilChanged(), publishReplay(1), refCount());
64570         const cellId$ = this._navigator.stateService.currentImage$
64571             .pipe(map((image) => {
64572             return this._navigator.api.data.geometry
64573                 .lngLatToCellId(image.originalLngLat);
64574         }), distinctUntilChanged(), publishReplay(1), refCount());
64575         const cellGridDepth$ = this._configuration$
64576             .pipe(map((c) => {
64577             return this._spatial.clamp(c.cellGridDepth, 1, 3);
64578         }), distinctUntilChanged(), publishReplay(1), refCount());
64579         const sequencePlay$ = combineLatest(this._navigator.playService.playing$, this._navigator.playService.speed$).pipe(map(([playing, speed]) => {
64580             return playing && speed > PlayService.sequenceSpeed;
64581         }), distinctUntilChanged(), publishReplay(1), refCount());
64582         const isOverview$ = this._navigator.stateService.state$.pipe(map((state) => {
64583             return isOverviewState(state);
64584         }), distinctUntilChanged(), publishReplay(1), refCount());
64585         subs.push(isOverview$.subscribe((isOverview) => {
64586             this._scene.setNavigationState(isOverview);
64587         }));
64588         const cell$ = combineLatest(isOverview$, sequencePlay$, bearing$, cellGridDepth$, this._navigator.stateService.currentImage$)
64589             .pipe(distinctUntilChanged(([o1, s1, b1, d1, i1], [o2, s2, b2, d2, i2]) => {
64590             if (o1 !== o2) {
64591                 return false;
64592             }
64593             const isd = i1.id === i2.id && s1 === s2 && d1 === d2;
64594             if (o1) {
64595                 return isd;
64596             }
64597             return isd && b1 === b2;
64598         }), concatMap(([isOverview, sequencePlay, bearing, depth, image]) => {
64599             if (isOverview) {
64600                 const geometry = this._navigator.api.data.geometry;
64601                 const cellId = geometry
64602                     .lngLatToCellId(image.originalLngLat);
64603                 const cells = sequencePlay ?
64604                     [cellId] :
64605                     connectedComponent(cellId, depth, geometry);
64606                 return of(cells);
64607             }
64608             const fov = sequencePlay ? 30 : 90;
64609             return of(this._cellsInFov(image, bearing, fov));
64610         }), switchMap((cellIds) => {
64611             return from(cellIds).pipe(mergeMap((cellId) => {
64612                 const t$ = this._cache.hasCell(cellId) ?
64613                     of(this._cache.getCell(cellId)) :
64614                     this._cache.cacheCell$(cellId);
64615                 return t$.pipe(map((images) => ({ id: cellId, images })));
64616             }, 6));
64617         }));
64618         subs.push(cell$.pipe(withLatestFrom(this._navigator.stateService.reference$))
64619             .subscribe(([cell, reference]) => {
64620             if (this._scene.hasCell(cell.id)) {
64621                 return;
64622             }
64623             this._scene.addCell(this._cellToTopocentric(cell.id, reference), cell.id);
64624         }));
64625         subs.push(cell$.pipe(withLatestFrom(this._navigator.stateService.reference$))
64626             .subscribe(([cell, reference]) => {
64627             this._addSceneImages(cell, reference);
64628         }));
64629         subs.push(cell$.pipe(concatMap((cell) => {
64630             const cellId = cell.id;
64631             let reconstructions$;
64632             if (this._cache.hasClusters(cellId)) {
64633                 reconstructions$ = from(this._cache.getClusters(cellId));
64634             }
64635             else if (this._cache.isCachingClusters(cellId)) {
64636                 reconstructions$ = this._cache.cacheClusters$(cellId).pipe(last(null, {}), switchMap(() => {
64637                     return from(this._cache.getClusters(cellId));
64638                 }));
64639             }
64640             else if (this._cache.hasCell(cellId)) {
64641                 reconstructions$ = this._cache.cacheClusters$(cellId);
64642             }
64643             else {
64644                 reconstructions$ = empty();
64645             }
64646             return combineLatest(of(cellId), reconstructions$);
64647         }), withLatestFrom(this._navigator.stateService.reference$))
64648             .subscribe(([[cellId, reconstruction], reference]) => {
64649             if (this._scene
64650                 .hasCluster(reconstruction.id, cellId)) {
64651                 return;
64652             }
64653             this._scene.addCluster(reconstruction, this._computeTranslation(reconstruction, reference), cellId);
64654         }));
64655         subs.push(this._configuration$.pipe(map((c) => {
64656             c.cameraSize = this._spatial.clamp(c.cameraSize, 0.01, 1);
64657             c.pointSize = this._spatial.clamp(c.pointSize, 0.01, 1);
64658             return {
64659                 cameraSize: c.cameraSize,
64660                 cameraVisualizationMode: c.cameraVisualizationMode,
64661                 cellsVisible: c.cellsVisible,
64662                 originalPositionMode: c.originalPositionMode,
64663                 pointSize: c.pointSize,
64664                 pointsVisible: c.pointsVisible,
64665             };
64666         }), distinctUntilChanged((c1, c2) => {
64667             return c1.cameraSize === c2.cameraSize &&
64668                 c1.cameraVisualizationMode === c2.cameraVisualizationMode &&
64669                 c1.cellsVisible === c2.cellsVisible &&
64670                 c1.originalPositionMode === c2.originalPositionMode &&
64671                 c1.pointSize === c2.pointSize &&
64672                 c1.pointsVisible === c2.pointsVisible;
64673         }))
64674             .subscribe((c) => {
64675             this._scene.setCameraSize(c.cameraSize);
64676             this._scene.setPointSize(c.pointSize);
64677             this._scene.setPointVisibility(c.pointsVisible);
64678             this._scene.setCellVisibility(c.cellsVisible);
64679             const cvm = c.cameraVisualizationMode;
64680             this._scene.setCameraVisualizationMode(cvm);
64681             const opm = c.originalPositionMode;
64682             this._scene.setPositionMode(opm);
64683         }));
64684         subs.push(combineLatest(cellId$, cellGridDepth$)
64685             .subscribe(([cellId, depth]) => {
64686             const keepCells = connectedComponent(cellId, depth, this._navigator.api.data.geometry);
64687             this._scene.uncache(keepCells);
64688             this._cache.uncache(keepCells);
64689         }));
64690         subs.push(this._navigator.playService.playing$.pipe(switchMap((playing) => {
64691             return playing ?
64692                 empty() :
64693                 this._container.mouseService.dblClick$;
64694         }), withLatestFrom(this._container.renderService.renderCamera$), switchMap(([event, render]) => {
64695             const element = this._container.container;
64696             const [canvasX, canvasY] = this._viewportCoords
64697                 .canvasPosition(event, element);
64698             const viewport = this._viewportCoords.canvasToViewport(canvasX, canvasY, element);
64699             const id = this._scene.intersection
64700                 .intersectObjects(viewport, render.perspective);
64701             return !!id ?
64702                 this._navigator.moveTo$(id).pipe(catchError(() => {
64703                     return empty();
64704                 })) :
64705                 empty();
64706         }))
64707             .subscribe());
64708         const intersectChange$ = combineLatest(this._configuration$, this._navigator.stateService.state$).pipe(map(([c, state]) => {
64709             c.cameraSize = this._spatial.clamp(c.cameraSize, 0.01, 1);
64710             return {
64711                 size: c.cameraSize,
64712                 visible: isModeVisible(c.cameraVisualizationMode),
64713                 state,
64714             };
64715         }), distinctUntilChanged((c1, c2) => {
64716             return c1.size === c2.size &&
64717                 c1.visible === c2.visible &&
64718                 c1.state === c2.state;
64719         }));
64720         const mouseMove$ = this._container.mouseService.mouseMove$.pipe(publishReplay(1), refCount());
64721         subs.push(mouseMove$.subscribe());
64722         const mouseHover$ = merge(this._container.mouseService.mouseEnter$, this._container.mouseService.mouseLeave$, this._container.mouseService.windowBlur$);
64723         subs.push(combineLatest(this._navigator.playService.playing$, mouseHover$, isOverview$, this._navigator.graphService.filter$)
64724             .pipe(switchMap(([playing, mouseHover]) => {
64725             return !playing && mouseHover.type === "pointerenter" ?
64726                 combineLatest(concat(mouseMove$.pipe(take(1)), this._container.mouseService.mouseMove$), this._container.renderService.renderCamera$, intersectChange$) :
64727                 combineLatest(of(mouseHover), of(null), of(null));
64728         }))
64729             .subscribe(([event, render]) => {
64730             if (event.type !== "pointermove") {
64731                 this._scene.setHoveredImage(null);
64732                 return;
64733             }
64734             const element = this._container.container;
64735             const [canvasX, canvasY] = this._viewportCoords.canvasPosition(event, element);
64736             const viewport = this._viewportCoords.canvasToViewport(canvasX, canvasY, element);
64737             const key = this._scene.intersection
64738                 .intersectObjects(viewport, render.perspective);
64739             this._scene.setHoveredImage(key);
64740         }));
64741         subs.push(this._navigator.stateService.currentId$
64742             .subscribe((id) => {
64743             this._scene.setSelectedImage(id);
64744         }));
64745         subs.push(this._navigator.stateService.currentState$
64746             .pipe(map((frame) => {
64747             const scene = this._scene;
64748             return {
64749                 name: this._name,
64750                 renderer: {
64751                     frameId: frame.id,
64752                     needsRender: scene.needsRender,
64753                     render: scene.render.bind(scene),
64754                     pass: RenderPass$1.Opaque,
64755                 },
64756             };
64757         }))
64758             .subscribe(this._container.glRenderer.render$));
64759         const updatedCell$ = this._navigator.graphService.dataAdded$
64760             .pipe(filter((cellId) => {
64761             return this._cache.hasCell(cellId);
64762         }), mergeMap((cellId) => {
64763             return this._cache.updateCell$(cellId).pipe(map((images) => ({ id: cellId, images })), withLatestFrom(this._navigator.stateService.reference$));
64764         }), publish(), refCount());
64765         subs.push(updatedCell$
64766             .subscribe(([cell, reference]) => {
64767             this._addSceneImages(cell, reference);
64768         }));
64769         subs.push(updatedCell$
64770             .pipe(concatMap(([cell]) => {
64771             const cellId = cell.id;
64772             const cache = this._cache;
64773             let reconstructions$;
64774             if (cache.hasClusters(cellId)) {
64775                 reconstructions$ =
64776                     cache.updateClusters$(cellId);
64777             }
64778             else if (cache.isCachingClusters(cellId)) {
64779                 reconstructions$ = this._cache.cacheClusters$(cellId).pipe(last(null, {}), switchMap(() => {
64780                     return from(cache.updateClusters$(cellId));
64781                 }));
64782             }
64783             else {
64784                 reconstructions$ = empty();
64785             }
64786             return combineLatest(of(cellId), reconstructions$);
64787         }), withLatestFrom(this._navigator.stateService.reference$))
64788             .subscribe(([[cellId, reconstruction], reference]) => {
64789             if (this._scene.hasCluster(reconstruction.id, cellId)) {
64790                 return;
64791             }
64792             this._scene.addCluster(reconstruction, this._computeTranslation(reconstruction, reference), cellId);
64793         }));
64794     }
64795     _deactivate() {
64796         this._subscriptions.unsubscribe();
64797         this._cache.uncache();
64798         this._scene.deactivate();
64799         this._navigator.cacheService.configure();
64800     }
64801     _getDefaultConfiguration() {
64802         return {
64803             cameraSize: 0.1,
64804             cameraVisualizationMode: CameraVisualizationMode.Homogeneous,
64805             cellGridDepth: 1,
64806             originalPositionMode: OriginalPositionMode.Hidden,
64807             pointSize: 0.1,
64808             pointsVisible: true,
64809             cellsVisible: false,
64810         };
64811     }
64812     _addSceneImages(cell, reference) {
64813         const cellId = cell.id;
64814         const images = cell.images;
64815         for (const image of images) {
64816             if (this._scene.hasImage(image.id, cellId)) {
64817                 continue;
64818             }
64819             this._scene.addImage(image, this._createTransform(image, reference), this._computeOriginalPosition(image, reference), cellId);
64820         }
64821     }
64822     _cellsInFov(image, bearing, fov) {
64823         const spatial = this._spatial;
64824         const geometry = this._navigator.api.data.geometry;
64825         const cell = geometry.lngLatToCellId(image.originalLngLat);
64826         const cells = [cell];
64827         const threshold = fov / 2;
64828         const adjacent = geometry.getAdjacent(cell);
64829         for (const a of adjacent) {
64830             const vertices = geometry.getVertices(a);
64831             for (const vertex of vertices) {
64832                 const [x, y] = geodeticToEnu(vertex.lng, vertex.lat, 0, image.lngLat.lng, image.lngLat.lat, 0);
64833                 const azimuthal = Math.atan2(y, x);
64834                 const vertexBearing = spatial.radToDeg(spatial.azimuthalToBearing(azimuthal));
64835                 if (Math.abs(vertexBearing - bearing) < threshold) {
64836                     cells.push(a);
64837                 }
64838             }
64839         }
64840         return cells;
64841     }
64842     _computeOriginalPosition(image, reference) {
64843         return geodeticToEnu(image.originalLngLat.lng, image.originalLngLat.lat, image.originalAltitude != null ? image.originalAltitude : image.computedAltitude, reference.lng, reference.lat, reference.alt);
64844     }
64845     _cellToTopocentric(cellId, reference) {
64846         const vertices = this._navigator.api.data.geometry
64847             .getVertices(cellId)
64848             .map((vertex) => {
64849             return geodeticToEnu(vertex.lng, vertex.lat, -2, reference.lng, reference.lat, reference.alt);
64850         });
64851         return vertices;
64852     }
64853     _computeTranslation(reconstruction, reference) {
64854         return geodeticToEnu(reconstruction.reference.lng, reconstruction.reference.lat, reconstruction.reference.alt, reference.lng, reference.lat, reference.alt);
64855     }
64856     _createTransform(image, reference) {
64857         const translation = computeTranslation({ alt: image.computedAltitude, lat: image.lngLat.lat, lng: image.lngLat.lng }, image.rotation, reference);
64858         const transform = new Transform(image.exifOrientation, image.width, image.height, image.scale, image.rotation, translation, undefined, undefined, image.cameraParameters, image.cameraType);
64859         return transform;
64860     }
64861 }
64862 SpatialComponent.componentName = "spatial";
64863
64864 /**
64865  * @class Geometry
64866  * @abstract
64867  * @classdesc Represents a geometry.
64868  */
64869 class Geometry {
64870     /**
64871      * Create a geometry.
64872      *
64873      * @constructor
64874      * @ignore
64875      */
64876     constructor() {
64877         this._notifyChanged$ = new Subject();
64878     }
64879     /**
64880      * Get changed observable.
64881      *
64882      * @description Emits the geometry itself every time the geometry
64883      * has changed.
64884      *
64885      * @returns {Observable<Geometry>} Observable emitting the geometry instance.
64886      * @ignore
64887      */
64888     get changed$() {
64889         return this._notifyChanged$;
64890     }
64891 }
64892
64893 class GeometryTagError extends MapillaryError {
64894     constructor(message) {
64895         super(message != null ? message : "The provided geometry value is incorrect");
64896         Object.setPrototypeOf(this, GeometryTagError.prototype);
64897         this.name = "GeometryTagError";
64898     }
64899 }
64900
64901 /**
64902  * @class PointsGeometry
64903  *
64904  * @classdesc Represents a point set in the 2D basic image coordinate system.
64905  *
64906  * @example
64907  * ```js
64908  * var points = [[0.5, 0.3], [0.7, 0.3], [0.6, 0.5]];
64909  * var pointsGeometry = new PointsGeometry(points);
64910  * ```
64911  */
64912 class PointsGeometry extends Geometry {
64913     /**
64914      * Create a points geometry.
64915      *
64916      * @constructor
64917      * @param {Array<Array<number>>} points - Array of 2D points on the basic coordinate
64918      * system. The number of points must be greater than or equal to two.
64919      *
64920      * @throws {GeometryTagError} Point coordinates must be valid basic coordinates.
64921      */
64922     constructor(points) {
64923         super();
64924         const pointsLength = points.length;
64925         if (pointsLength < 2) {
64926             throw new GeometryTagError("A points geometry must have two or more positions.");
64927         }
64928         this._points = [];
64929         for (const point of points) {
64930             if (point[0] < 0 || point[0] > 1 ||
64931                 point[1] < 0 || point[1] > 1) {
64932                 throw new GeometryTagError("Basic coordinates of points must be on the interval [0, 1].");
64933             }
64934             this._points.push(point.slice());
64935         }
64936     }
64937     /**
64938      * Get points property.
64939      * @returns {Array<Array<number>>} Array of 2d points.
64940      */
64941     get points() {
64942         return this._points;
64943     }
64944     /**
64945      * Add a point to the point set.
64946      *
64947      * @param {Array<number>} point - Point to add.
64948      * @ignore
64949      */
64950     addPoint2d(point) {
64951         const clamped = [
64952             Math.max(0, Math.min(1, point[0])),
64953             Math.max(0, Math.min(1, point[1])),
64954         ];
64955         this._points.push(clamped);
64956         this._notifyChanged$.next(this);
64957     }
64958     /**
64959      * Get the coordinates of a point from the point set representation of the geometry.
64960      *
64961      * @param {number} index - Point index.
64962      * @returns {Array<number>} Array representing the 2D basic coordinates of the point.
64963      * @ignore
64964      */
64965     getPoint2d(index) {
64966         return this._points[index].slice();
64967     }
64968     /**
64969      * Remove a point from the point set.
64970      *
64971      * @param {number} index - The index of the point to remove.
64972      * @ignore
64973      */
64974     removePoint2d(index) {
64975         if (index < 0 ||
64976             index >= this._points.length ||
64977             this._points.length < 3) {
64978             throw new GeometryTagError("Index for removed point must be valid.");
64979         }
64980         this._points.splice(index, 1);
64981         this._notifyChanged$.next(this);
64982     }
64983     /** @ignore */
64984     setVertex2d(index, value, transform) {
64985         this.setPoint2d(index, value, transform);
64986     }
64987     /** @ignore */
64988     setPoint2d(index, value, transform) {
64989         const changed = [
64990             Math.max(0, Math.min(1, value[0])),
64991             Math.max(0, Math.min(1, value[1])),
64992         ];
64993         this._points[index] = changed;
64994         this._notifyChanged$.next(this);
64995     }
64996     /** @ignore */
64997     getPoints3d(transform) {
64998         return this._getPoints3d(this._points, transform);
64999     }
65000     /** @ignore */
65001     getPoint3d(index, transform) {
65002         return transform.unprojectBasic(this._points[index], 200);
65003     }
65004     /** @ignore */
65005     getPoints2d() {
65006         return this._points.slice();
65007     }
65008     /** @ignore */
65009     getCentroid2d(transform) {
65010         if (!transform) {
65011             throw new GeometryTagError("Get centroid must be called with a transform for points geometries.");
65012         }
65013         const [minX, minY, maxX, maxY] = this.getRect2d(transform);
65014         const centroidX = minX < maxX ?
65015             (minX + maxX) / 2 :
65016             ((minX + maxX + 1) / 2) % 1;
65017         const centroidY = (minY + maxY) / 2;
65018         return [centroidX, centroidY];
65019     }
65020     /** @ignore */
65021     getCentroid3d(transform) {
65022         let centroid2d = this.getCentroid2d();
65023         return transform.unprojectBasic(centroid2d, 200);
65024     }
65025     /** @ignore */
65026     getRect2d(transform) {
65027         let minX = 1;
65028         let maxX = 0;
65029         let minY = 1;
65030         let maxY = 0;
65031         const points = this._points;
65032         for (const point of points) {
65033             if (point[0] < minX) {
65034                 minX = point[0];
65035             }
65036             if (point[0] > maxX) {
65037                 maxX = point[0];
65038             }
65039             if (point[1] < minY) {
65040                 minY = point[1];
65041             }
65042             if (point[1] > maxY) {
65043                 maxY = point[1];
65044             }
65045         }
65046         if (isSpherical(transform.cameraType)) {
65047             const indices = [];
65048             for (let i = 0; i < points.length; i++) {
65049                 indices[i] = i;
65050             }
65051             indices.sort((a, b) => {
65052                 return points[a][0] < points[b][0] ?
65053                     -1 :
65054                     points[a][0] > points[b][0] ?
65055                         1 :
65056                         a < b ? -1 : 1;
65057             });
65058             let maxDistanceX = points[indices[0]][0] + 1 - points[indices[indices.length - 1]][0];
65059             let leftMostIndex = 0;
65060             for (let i = 0; i < indices.length - 1; i++) {
65061                 const index1 = indices[i];
65062                 const index2 = indices[i + 1];
65063                 const distanceX = points[index2][0] - points[index1][0];
65064                 if (distanceX > maxDistanceX) {
65065                     maxDistanceX = distanceX;
65066                     leftMostIndex = i + 1;
65067                 }
65068             }
65069             if (leftMostIndex > 0) {
65070                 minX = points[indices[leftMostIndex]][0];
65071                 maxX = points[indices[leftMostIndex - 1]][0];
65072             }
65073         }
65074         return [minX, minY, maxX, maxY];
65075     }
65076     /** @ignore */
65077     setCentroid2d(value, transform) {
65078         throw new Error("Not implemented");
65079     }
65080     _getPoints3d(points2d, transform) {
65081         return points2d
65082             .map((point) => {
65083             return transform.unprojectBasic(point, 200);
65084         });
65085     }
65086 }
65087
65088 class CreateTag {
65089     constructor(geometry, transform, viewportCoords) {
65090         this._geometry = geometry;
65091         this._transform = transform;
65092         this._viewportCoords = !!viewportCoords ? viewportCoords : new ViewportCoords();
65093         this._aborted$ = new Subject();
65094         this._created$ = new Subject();
65095         this._glObjectsChanged$ = new Subject();
65096         this._geometryChangedSubscription = this._geometry.changed$
65097             .subscribe(() => {
65098             this._onGeometryChanged();
65099             this._glObjectsChanged$.next(this);
65100         });
65101     }
65102     get geometry() {
65103         return this._geometry;
65104     }
65105     get glObjects() {
65106         return this._glObjects;
65107     }
65108     get aborted$() {
65109         return this._aborted$;
65110     }
65111     get created$() {
65112         return this._created$;
65113     }
65114     get glObjectsChanged$() {
65115         return this._glObjectsChanged$;
65116     }
65117     get geometryChanged$() {
65118         return this._geometry.changed$.pipe(map(() => {
65119             return this;
65120         }));
65121     }
65122     dispose() {
65123         this._geometryChangedSubscription.unsubscribe();
65124     }
65125     _canvasToTransform(canvas) {
65126         const canvasX = Math.round(canvas[0]);
65127         const canvasY = Math.round(canvas[1]);
65128         const transform = `translate(-50%,-50%) translate(${canvasX}px,${canvasY}px)`;
65129         return transform;
65130     }
65131     _colorToBackground(color) {
65132         return "#" + ("000000" + color.toString(16)).substr(-6);
65133     }
65134     _createOutine(polygon3d, color) {
65135         const positions = this._getLinePositions(polygon3d);
65136         const geometry = new BufferGeometry();
65137         geometry.setAttribute("position", new BufferAttribute(positions, 3));
65138         const material = new LineBasicMaterial({
65139             color: color,
65140             linewidth: 1,
65141         });
65142         return new Line(geometry, material);
65143     }
65144     _disposeLine(line) {
65145         if (line == null) {
65146             return;
65147         }
65148         line.geometry.dispose();
65149         line.material.dispose();
65150     }
65151     _getLinePositions(polygon3d) {
65152         const length = polygon3d.length;
65153         const positions = new Float32Array(length * 3);
65154         for (let i = 0; i < length; ++i) {
65155             const index = 3 * i;
65156             const position = polygon3d[i];
65157             positions[index] = position[0];
65158             positions[index + 1] = position[1];
65159             positions[index + 2] = position[2];
65160         }
65161         return positions;
65162     }
65163 }
65164
65165 var earcut_1 = earcut;
65166 var _default$2 = earcut;
65167
65168 function earcut(data, holeIndices, dim) {
65169
65170     dim = dim || 2;
65171
65172     var hasHoles = holeIndices && holeIndices.length,
65173         outerLen = hasHoles ? holeIndices[0] * dim : data.length,
65174         outerNode = linkedList(data, 0, outerLen, dim, true),
65175         triangles = [];
65176
65177     if (!outerNode || outerNode.next === outerNode.prev) return triangles;
65178
65179     var minX, minY, maxX, maxY, x, y, invSize;
65180
65181     if (hasHoles) outerNode = eliminateHoles(data, holeIndices, outerNode, dim);
65182
65183     // if the shape is not too simple, we'll use z-order curve hash later; calculate polygon bbox
65184     if (data.length > 80 * dim) {
65185         minX = maxX = data[0];
65186         minY = maxY = data[1];
65187
65188         for (var i = dim; i < outerLen; i += dim) {
65189             x = data[i];
65190             y = data[i + 1];
65191             if (x < minX) minX = x;
65192             if (y < minY) minY = y;
65193             if (x > maxX) maxX = x;
65194             if (y > maxY) maxY = y;
65195         }
65196
65197         // minX, minY and invSize are later used to transform coords into integers for z-order calculation
65198         invSize = Math.max(maxX - minX, maxY - minY);
65199         invSize = invSize !== 0 ? 1 / invSize : 0;
65200     }
65201
65202     earcutLinked(outerNode, triangles, dim, minX, minY, invSize);
65203
65204     return triangles;
65205 }
65206
65207 // create a circular doubly linked list from polygon points in the specified winding order
65208 function linkedList(data, start, end, dim, clockwise) {
65209     var i, last;
65210
65211     if (clockwise === (signedArea$1(data, start, end, dim) > 0)) {
65212         for (i = start; i < end; i += dim) last = insertNode(i, data[i], data[i + 1], last);
65213     } else {
65214         for (i = end - dim; i >= start; i -= dim) last = insertNode(i, data[i], data[i + 1], last);
65215     }
65216
65217     if (last && equals$1(last, last.next)) {
65218         removeNode(last);
65219         last = last.next;
65220     }
65221
65222     return last;
65223 }
65224
65225 // eliminate colinear or duplicate points
65226 function filterPoints(start, end) {
65227     if (!start) return start;
65228     if (!end) end = start;
65229
65230     var p = start,
65231         again;
65232     do {
65233         again = false;
65234
65235         if (!p.steiner && (equals$1(p, p.next) || area(p.prev, p, p.next) === 0)) {
65236             removeNode(p);
65237             p = end = p.prev;
65238             if (p === p.next) break;
65239             again = true;
65240
65241         } else {
65242             p = p.next;
65243         }
65244     } while (again || p !== end);
65245
65246     return end;
65247 }
65248
65249 // main ear slicing loop which triangulates a polygon (given as a linked list)
65250 function earcutLinked(ear, triangles, dim, minX, minY, invSize, pass) {
65251     if (!ear) return;
65252
65253     // interlink polygon nodes in z-order
65254     if (!pass && invSize) indexCurve(ear, minX, minY, invSize);
65255
65256     var stop = ear,
65257         prev, next;
65258
65259     // iterate through ears, slicing them one by one
65260     while (ear.prev !== ear.next) {
65261         prev = ear.prev;
65262         next = ear.next;
65263
65264         if (invSize ? isEarHashed(ear, minX, minY, invSize) : isEar(ear)) {
65265             // cut off the triangle
65266             triangles.push(prev.i / dim);
65267             triangles.push(ear.i / dim);
65268             triangles.push(next.i / dim);
65269
65270             removeNode(ear);
65271
65272             // skipping the next vertex leads to less sliver triangles
65273             ear = next.next;
65274             stop = next.next;
65275
65276             continue;
65277         }
65278
65279         ear = next;
65280
65281         // if we looped through the whole remaining polygon and can't find any more ears
65282         if (ear === stop) {
65283             // try filtering points and slicing again
65284             if (!pass) {
65285                 earcutLinked(filterPoints(ear), triangles, dim, minX, minY, invSize, 1);
65286
65287             // if this didn't work, try curing all small self-intersections locally
65288             } else if (pass === 1) {
65289                 ear = cureLocalIntersections(filterPoints(ear), triangles, dim);
65290                 earcutLinked(ear, triangles, dim, minX, minY, invSize, 2);
65291
65292             // as a last resort, try splitting the remaining polygon into two
65293             } else if (pass === 2) {
65294                 splitEarcut(ear, triangles, dim, minX, minY, invSize);
65295             }
65296
65297             break;
65298         }
65299     }
65300 }
65301
65302 // check whether a polygon node forms a valid ear with adjacent nodes
65303 function isEar(ear) {
65304     var a = ear.prev,
65305         b = ear,
65306         c = ear.next;
65307
65308     if (area(a, b, c) >= 0) return false; // reflex, can't be an ear
65309
65310     // now make sure we don't have other points inside the potential ear
65311     var p = ear.next.next;
65312
65313     while (p !== ear.prev) {
65314         if (pointInTriangle(a.x, a.y, b.x, b.y, c.x, c.y, p.x, p.y) &&
65315             area(p.prev, p, p.next) >= 0) return false;
65316         p = p.next;
65317     }
65318
65319     return true;
65320 }
65321
65322 function isEarHashed(ear, minX, minY, invSize) {
65323     var a = ear.prev,
65324         b = ear,
65325         c = ear.next;
65326
65327     if (area(a, b, c) >= 0) return false; // reflex, can't be an ear
65328
65329     // triangle bbox; min & max are calculated like this for speed
65330     var minTX = a.x < b.x ? (a.x < c.x ? a.x : c.x) : (b.x < c.x ? b.x : c.x),
65331         minTY = a.y < b.y ? (a.y < c.y ? a.y : c.y) : (b.y < c.y ? b.y : c.y),
65332         maxTX = a.x > b.x ? (a.x > c.x ? a.x : c.x) : (b.x > c.x ? b.x : c.x),
65333         maxTY = a.y > b.y ? (a.y > c.y ? a.y : c.y) : (b.y > c.y ? b.y : c.y);
65334
65335     // z-order range for the current triangle bbox;
65336     var minZ = zOrder(minTX, minTY, minX, minY, invSize),
65337         maxZ = zOrder(maxTX, maxTY, minX, minY, invSize);
65338
65339     var p = ear.prevZ,
65340         n = ear.nextZ;
65341
65342     // look for points inside the triangle in both directions
65343     while (p && p.z >= minZ && n && n.z <= maxZ) {
65344         if (p !== ear.prev && p !== ear.next &&
65345             pointInTriangle(a.x, a.y, b.x, b.y, c.x, c.y, p.x, p.y) &&
65346             area(p.prev, p, p.next) >= 0) return false;
65347         p = p.prevZ;
65348
65349         if (n !== ear.prev && n !== ear.next &&
65350             pointInTriangle(a.x, a.y, b.x, b.y, c.x, c.y, n.x, n.y) &&
65351             area(n.prev, n, n.next) >= 0) return false;
65352         n = n.nextZ;
65353     }
65354
65355     // look for remaining points in decreasing z-order
65356     while (p && p.z >= minZ) {
65357         if (p !== ear.prev && p !== ear.next &&
65358             pointInTriangle(a.x, a.y, b.x, b.y, c.x, c.y, p.x, p.y) &&
65359             area(p.prev, p, p.next) >= 0) return false;
65360         p = p.prevZ;
65361     }
65362
65363     // look for remaining points in increasing z-order
65364     while (n && n.z <= maxZ) {
65365         if (n !== ear.prev && n !== ear.next &&
65366             pointInTriangle(a.x, a.y, b.x, b.y, c.x, c.y, n.x, n.y) &&
65367             area(n.prev, n, n.next) >= 0) return false;
65368         n = n.nextZ;
65369     }
65370
65371     return true;
65372 }
65373
65374 // go through all polygon nodes and cure small local self-intersections
65375 function cureLocalIntersections(start, triangles, dim) {
65376     var p = start;
65377     do {
65378         var a = p.prev,
65379             b = p.next.next;
65380
65381         if (!equals$1(a, b) && intersects(a, p, p.next, b) && locallyInside(a, b) && locallyInside(b, a)) {
65382
65383             triangles.push(a.i / dim);
65384             triangles.push(p.i / dim);
65385             triangles.push(b.i / dim);
65386
65387             // remove two nodes involved
65388             removeNode(p);
65389             removeNode(p.next);
65390
65391             p = start = b;
65392         }
65393         p = p.next;
65394     } while (p !== start);
65395
65396     return filterPoints(p);
65397 }
65398
65399 // try splitting polygon into two and triangulate them independently
65400 function splitEarcut(start, triangles, dim, minX, minY, invSize) {
65401     // look for a valid diagonal that divides the polygon into two
65402     var a = start;
65403     do {
65404         var b = a.next.next;
65405         while (b !== a.prev) {
65406             if (a.i !== b.i && isValidDiagonal(a, b)) {
65407                 // split the polygon in two by the diagonal
65408                 var c = splitPolygon(a, b);
65409
65410                 // filter colinear points around the cuts
65411                 a = filterPoints(a, a.next);
65412                 c = filterPoints(c, c.next);
65413
65414                 // run earcut on each half
65415                 earcutLinked(a, triangles, dim, minX, minY, invSize);
65416                 earcutLinked(c, triangles, dim, minX, minY, invSize);
65417                 return;
65418             }
65419             b = b.next;
65420         }
65421         a = a.next;
65422     } while (a !== start);
65423 }
65424
65425 // link every hole into the outer loop, producing a single-ring polygon without holes
65426 function eliminateHoles(data, holeIndices, outerNode, dim) {
65427     var queue = [],
65428         i, len, start, end, list;
65429
65430     for (i = 0, len = holeIndices.length; i < len; i++) {
65431         start = holeIndices[i] * dim;
65432         end = i < len - 1 ? holeIndices[i + 1] * dim : data.length;
65433         list = linkedList(data, start, end, dim, false);
65434         if (list === list.next) list.steiner = true;
65435         queue.push(getLeftmost(list));
65436     }
65437
65438     queue.sort(compareX);
65439
65440     // process holes from left to right
65441     for (i = 0; i < queue.length; i++) {
65442         eliminateHole(queue[i], outerNode);
65443         outerNode = filterPoints(outerNode, outerNode.next);
65444     }
65445
65446     return outerNode;
65447 }
65448
65449 function compareX(a, b) {
65450     return a.x - b.x;
65451 }
65452
65453 // find a bridge between vertices that connects hole with an outer ring and and link it
65454 function eliminateHole(hole, outerNode) {
65455     outerNode = findHoleBridge(hole, outerNode);
65456     if (outerNode) {
65457         var b = splitPolygon(outerNode, hole);
65458
65459         // filter collinear points around the cuts
65460         filterPoints(outerNode, outerNode.next);
65461         filterPoints(b, b.next);
65462     }
65463 }
65464
65465 // David Eberly's algorithm for finding a bridge between hole and outer polygon
65466 function findHoleBridge(hole, outerNode) {
65467     var p = outerNode,
65468         hx = hole.x,
65469         hy = hole.y,
65470         qx = -Infinity,
65471         m;
65472
65473     // find a segment intersected by a ray from the hole's leftmost point to the left;
65474     // segment's endpoint with lesser x will be potential connection point
65475     do {
65476         if (hy <= p.y && hy >= p.next.y && p.next.y !== p.y) {
65477             var x = p.x + (hy - p.y) * (p.next.x - p.x) / (p.next.y - p.y);
65478             if (x <= hx && x > qx) {
65479                 qx = x;
65480                 if (x === hx) {
65481                     if (hy === p.y) return p;
65482                     if (hy === p.next.y) return p.next;
65483                 }
65484                 m = p.x < p.next.x ? p : p.next;
65485             }
65486         }
65487         p = p.next;
65488     } while (p !== outerNode);
65489
65490     if (!m) return null;
65491
65492     if (hx === qx) return m; // hole touches outer segment; pick leftmost endpoint
65493
65494     // look for points inside the triangle of hole point, segment intersection and endpoint;
65495     // if there are no points found, we have a valid connection;
65496     // otherwise choose the point of the minimum angle with the ray as connection point
65497
65498     var stop = m,
65499         mx = m.x,
65500         my = m.y,
65501         tanMin = Infinity,
65502         tan;
65503
65504     p = m;
65505
65506     do {
65507         if (hx >= p.x && p.x >= mx && hx !== p.x &&
65508                 pointInTriangle(hy < my ? hx : qx, hy, mx, my, hy < my ? qx : hx, hy, p.x, p.y)) {
65509
65510             tan = Math.abs(hy - p.y) / (hx - p.x); // tangential
65511
65512             if (locallyInside(p, hole) &&
65513                 (tan < tanMin || (tan === tanMin && (p.x > m.x || (p.x === m.x && sectorContainsSector(m, p)))))) {
65514                 m = p;
65515                 tanMin = tan;
65516             }
65517         }
65518
65519         p = p.next;
65520     } while (p !== stop);
65521
65522     return m;
65523 }
65524
65525 // whether sector in vertex m contains sector in vertex p in the same coordinates
65526 function sectorContainsSector(m, p) {
65527     return area(m.prev, m, p.prev) < 0 && area(p.next, m, m.next) < 0;
65528 }
65529
65530 // interlink polygon nodes in z-order
65531 function indexCurve(start, minX, minY, invSize) {
65532     var p = start;
65533     do {
65534         if (p.z === null) p.z = zOrder(p.x, p.y, minX, minY, invSize);
65535         p.prevZ = p.prev;
65536         p.nextZ = p.next;
65537         p = p.next;
65538     } while (p !== start);
65539
65540     p.prevZ.nextZ = null;
65541     p.prevZ = null;
65542
65543     sortLinked(p);
65544 }
65545
65546 // Simon Tatham's linked list merge sort algorithm
65547 // http://www.chiark.greenend.org.uk/~sgtatham/algorithms/listsort.html
65548 function sortLinked(list) {
65549     var i, p, q, e, tail, numMerges, pSize, qSize,
65550         inSize = 1;
65551
65552     do {
65553         p = list;
65554         list = null;
65555         tail = null;
65556         numMerges = 0;
65557
65558         while (p) {
65559             numMerges++;
65560             q = p;
65561             pSize = 0;
65562             for (i = 0; i < inSize; i++) {
65563                 pSize++;
65564                 q = q.nextZ;
65565                 if (!q) break;
65566             }
65567             qSize = inSize;
65568
65569             while (pSize > 0 || (qSize > 0 && q)) {
65570
65571                 if (pSize !== 0 && (qSize === 0 || !q || p.z <= q.z)) {
65572                     e = p;
65573                     p = p.nextZ;
65574                     pSize--;
65575                 } else {
65576                     e = q;
65577                     q = q.nextZ;
65578                     qSize--;
65579                 }
65580
65581                 if (tail) tail.nextZ = e;
65582                 else list = e;
65583
65584                 e.prevZ = tail;
65585                 tail = e;
65586             }
65587
65588             p = q;
65589         }
65590
65591         tail.nextZ = null;
65592         inSize *= 2;
65593
65594     } while (numMerges > 1);
65595
65596     return list;
65597 }
65598
65599 // z-order of a point given coords and inverse of the longer side of data bbox
65600 function zOrder(x, y, minX, minY, invSize) {
65601     // coords are transformed into non-negative 15-bit integer range
65602     x = 32767 * (x - minX) * invSize;
65603     y = 32767 * (y - minY) * invSize;
65604
65605     x = (x | (x << 8)) & 0x00FF00FF;
65606     x = (x | (x << 4)) & 0x0F0F0F0F;
65607     x = (x | (x << 2)) & 0x33333333;
65608     x = (x | (x << 1)) & 0x55555555;
65609
65610     y = (y | (y << 8)) & 0x00FF00FF;
65611     y = (y | (y << 4)) & 0x0F0F0F0F;
65612     y = (y | (y << 2)) & 0x33333333;
65613     y = (y | (y << 1)) & 0x55555555;
65614
65615     return x | (y << 1);
65616 }
65617
65618 // find the leftmost node of a polygon ring
65619 function getLeftmost(start) {
65620     var p = start,
65621         leftmost = start;
65622     do {
65623         if (p.x < leftmost.x || (p.x === leftmost.x && p.y < leftmost.y)) leftmost = p;
65624         p = p.next;
65625     } while (p !== start);
65626
65627     return leftmost;
65628 }
65629
65630 // check if a point lies within a convex triangle
65631 function pointInTriangle(ax, ay, bx, by, cx, cy, px, py) {
65632     return (cx - px) * (ay - py) - (ax - px) * (cy - py) >= 0 &&
65633            (ax - px) * (by - py) - (bx - px) * (ay - py) >= 0 &&
65634            (bx - px) * (cy - py) - (cx - px) * (by - py) >= 0;
65635 }
65636
65637 // check if a diagonal between two polygon nodes is valid (lies in polygon interior)
65638 function isValidDiagonal(a, b) {
65639     return a.next.i !== b.i && a.prev.i !== b.i && !intersectsPolygon(a, b) && // dones't intersect other edges
65640            (locallyInside(a, b) && locallyInside(b, a) && middleInside(a, b) && // locally visible
65641             (area(a.prev, a, b.prev) || area(a, b.prev, b)) || // does not create opposite-facing sectors
65642             equals$1(a, b) && area(a.prev, a, a.next) > 0 && area(b.prev, b, b.next) > 0); // special zero-length case
65643 }
65644
65645 // signed area of a triangle
65646 function area(p, q, r) {
65647     return (q.y - p.y) * (r.x - q.x) - (q.x - p.x) * (r.y - q.y);
65648 }
65649
65650 // check if two points are equal
65651 function equals$1(p1, p2) {
65652     return p1.x === p2.x && p1.y === p2.y;
65653 }
65654
65655 // check if two segments intersect
65656 function intersects(p1, q1, p2, q2) {
65657     var o1 = sign(area(p1, q1, p2));
65658     var o2 = sign(area(p1, q1, q2));
65659     var o3 = sign(area(p2, q2, p1));
65660     var o4 = sign(area(p2, q2, q1));
65661
65662     if (o1 !== o2 && o3 !== o4) return true; // general case
65663
65664     if (o1 === 0 && onSegment(p1, p2, q1)) return true; // p1, q1 and p2 are collinear and p2 lies on p1q1
65665     if (o2 === 0 && onSegment(p1, q2, q1)) return true; // p1, q1 and q2 are collinear and q2 lies on p1q1
65666     if (o3 === 0 && onSegment(p2, p1, q2)) return true; // p2, q2 and p1 are collinear and p1 lies on p2q2
65667     if (o4 === 0 && onSegment(p2, q1, q2)) return true; // p2, q2 and q1 are collinear and q1 lies on p2q2
65668
65669     return false;
65670 }
65671
65672 // for collinear points p, q, r, check if point q lies on segment pr
65673 function onSegment(p, q, r) {
65674     return q.x <= Math.max(p.x, r.x) && q.x >= Math.min(p.x, r.x) && q.y <= Math.max(p.y, r.y) && q.y >= Math.min(p.y, r.y);
65675 }
65676
65677 function sign(num) {
65678     return num > 0 ? 1 : num < 0 ? -1 : 0;
65679 }
65680
65681 // check if a polygon diagonal intersects any polygon segments
65682 function intersectsPolygon(a, b) {
65683     var p = a;
65684     do {
65685         if (p.i !== a.i && p.next.i !== a.i && p.i !== b.i && p.next.i !== b.i &&
65686                 intersects(p, p.next, a, b)) return true;
65687         p = p.next;
65688     } while (p !== a);
65689
65690     return false;
65691 }
65692
65693 // check if a polygon diagonal is locally inside the polygon
65694 function locallyInside(a, b) {
65695     return area(a.prev, a, a.next) < 0 ?
65696         area(a, b, a.next) >= 0 && area(a, a.prev, b) >= 0 :
65697         area(a, b, a.prev) < 0 || area(a, a.next, b) < 0;
65698 }
65699
65700 // check if the middle point of a polygon diagonal is inside the polygon
65701 function middleInside(a, b) {
65702     var p = a,
65703         inside = false,
65704         px = (a.x + b.x) / 2,
65705         py = (a.y + b.y) / 2;
65706     do {
65707         if (((p.y > py) !== (p.next.y > py)) && p.next.y !== p.y &&
65708                 (px < (p.next.x - p.x) * (py - p.y) / (p.next.y - p.y) + p.x))
65709             inside = !inside;
65710         p = p.next;
65711     } while (p !== a);
65712
65713     return inside;
65714 }
65715
65716 // link two polygon vertices with a bridge; if the vertices belong to the same ring, it splits polygon into two;
65717 // if one belongs to the outer ring and another to a hole, it merges it into a single ring
65718 function splitPolygon(a, b) {
65719     var a2 = new Node(a.i, a.x, a.y),
65720         b2 = new Node(b.i, b.x, b.y),
65721         an = a.next,
65722         bp = b.prev;
65723
65724     a.next = b;
65725     b.prev = a;
65726
65727     a2.next = an;
65728     an.prev = a2;
65729
65730     b2.next = a2;
65731     a2.prev = b2;
65732
65733     bp.next = b2;
65734     b2.prev = bp;
65735
65736     return b2;
65737 }
65738
65739 // create a node and optionally link it with previous one (in a circular doubly linked list)
65740 function insertNode(i, x, y, last) {
65741     var p = new Node(i, x, y);
65742
65743     if (!last) {
65744         p.prev = p;
65745         p.next = p;
65746
65747     } else {
65748         p.next = last.next;
65749         p.prev = last;
65750         last.next.prev = p;
65751         last.next = p;
65752     }
65753     return p;
65754 }
65755
65756 function removeNode(p) {
65757     p.next.prev = p.prev;
65758     p.prev.next = p.next;
65759
65760     if (p.prevZ) p.prevZ.nextZ = p.nextZ;
65761     if (p.nextZ) p.nextZ.prevZ = p.prevZ;
65762 }
65763
65764 function Node(i, x, y) {
65765     // vertex index in coordinates array
65766     this.i = i;
65767
65768     // vertex coordinates
65769     this.x = x;
65770     this.y = y;
65771
65772     // previous and next vertex nodes in a polygon ring
65773     this.prev = null;
65774     this.next = null;
65775
65776     // z-order curve value
65777     this.z = null;
65778
65779     // previous and next nodes in z-order
65780     this.prevZ = null;
65781     this.nextZ = null;
65782
65783     // indicates whether this is a steiner point
65784     this.steiner = false;
65785 }
65786
65787 // return a percentage difference between the polygon area and its triangulation area;
65788 // used to verify correctness of triangulation
65789 earcut.deviation = function (data, holeIndices, dim, triangles) {
65790     var hasHoles = holeIndices && holeIndices.length;
65791     var outerLen = hasHoles ? holeIndices[0] * dim : data.length;
65792
65793     var polygonArea = Math.abs(signedArea$1(data, 0, outerLen, dim));
65794     if (hasHoles) {
65795         for (var i = 0, len = holeIndices.length; i < len; i++) {
65796             var start = holeIndices[i] * dim;
65797             var end = i < len - 1 ? holeIndices[i + 1] * dim : data.length;
65798             polygonArea -= Math.abs(signedArea$1(data, start, end, dim));
65799         }
65800     }
65801
65802     var trianglesArea = 0;
65803     for (i = 0; i < triangles.length; i += 3) {
65804         var a = triangles[i] * dim;
65805         var b = triangles[i + 1] * dim;
65806         var c = triangles[i + 2] * dim;
65807         trianglesArea += Math.abs(
65808             (data[a] - data[c]) * (data[b + 1] - data[a + 1]) -
65809             (data[a] - data[b]) * (data[c + 1] - data[a + 1]));
65810     }
65811
65812     return polygonArea === 0 && trianglesArea === 0 ? 0 :
65813         Math.abs((trianglesArea - polygonArea) / polygonArea);
65814 };
65815
65816 function signedArea$1(data, start, end, dim) {
65817     var sum = 0;
65818     for (var i = start, j = end - dim; i < end; i += dim) {
65819         sum += (data[j] - data[i]) * (data[i + 1] + data[j + 1]);
65820         j = i;
65821     }
65822     return sum;
65823 }
65824
65825 // turn a polygon in a multi-dimensional array form (e.g. as in GeoJSON) into a form Earcut accepts
65826 earcut.flatten = function (data) {
65827     var dim = data[0][0].length,
65828         result = {vertices: [], holes: [], dimensions: dim},
65829         holeIndex = 0;
65830
65831     for (var i = 0; i < data.length; i++) {
65832         for (var j = 0; j < data[i].length; j++) {
65833             for (var d = 0; d < dim; d++) result.vertices.push(data[i][j][d]);
65834         }
65835         if (i > 0) {
65836             holeIndex += data[i - 1].length;
65837             result.holes.push(holeIndex);
65838         }
65839     }
65840     return result;
65841 };
65842 earcut_1.default = _default$2;
65843
65844 class TinyQueue$1 {
65845     constructor(data = [], compare = defaultCompare$1) {
65846         this.data = data;
65847         this.length = this.data.length;
65848         this.compare = compare;
65849
65850         if (this.length > 0) {
65851             for (let i = (this.length >> 1) - 1; i >= 0; i--) this._down(i);
65852         }
65853     }
65854
65855     push(item) {
65856         this.data.push(item);
65857         this.length++;
65858         this._up(this.length - 1);
65859     }
65860
65861     pop() {
65862         if (this.length === 0) return undefined;
65863
65864         const top = this.data[0];
65865         const bottom = this.data.pop();
65866         this.length--;
65867
65868         if (this.length > 0) {
65869             this.data[0] = bottom;
65870             this._down(0);
65871         }
65872
65873         return top;
65874     }
65875
65876     peek() {
65877         return this.data[0];
65878     }
65879
65880     _up(pos) {
65881         const {data, compare} = this;
65882         const item = data[pos];
65883
65884         while (pos > 0) {
65885             const parent = (pos - 1) >> 1;
65886             const current = data[parent];
65887             if (compare(item, current) >= 0) break;
65888             data[pos] = current;
65889             pos = parent;
65890         }
65891
65892         data[pos] = item;
65893     }
65894
65895     _down(pos) {
65896         const {data, compare} = this;
65897         const halfLength = this.length >> 1;
65898         const item = data[pos];
65899
65900         while (pos < halfLength) {
65901             let left = (pos << 1) + 1;
65902             let best = data[left];
65903             const right = left + 1;
65904
65905             if (right < this.length && compare(data[right], best) < 0) {
65906                 left = right;
65907                 best = data[right];
65908             }
65909             if (compare(best, item) >= 0) break;
65910
65911             data[pos] = best;
65912             pos = left;
65913         }
65914
65915         data[pos] = item;
65916     }
65917 }
65918
65919 function defaultCompare$1(a, b) {
65920     return a < b ? -1 : a > b ? 1 : 0;
65921 }
65922
65923 var tinyqueue$1 = /*#__PURE__*/Object.freeze({
65924     __proto__: null,
65925     'default': TinyQueue$1
65926 });
65927
65928 var require$$0 = /*@__PURE__*/getAugmentedNamespace(tinyqueue$1);
65929
65930 var Queue = require$$0;
65931
65932 if (Queue.default) Queue = Queue.default; // temporary webpack fix
65933
65934 var polylabel_1 = polylabel;
65935 var _default$1 = polylabel;
65936
65937 function polylabel(polygon, precision, debug) {
65938     precision = precision || 1.0;
65939
65940     // find the bounding box of the outer ring
65941     var minX, minY, maxX, maxY;
65942     for (var i = 0; i < polygon[0].length; i++) {
65943         var p = polygon[0][i];
65944         if (!i || p[0] < minX) minX = p[0];
65945         if (!i || p[1] < minY) minY = p[1];
65946         if (!i || p[0] > maxX) maxX = p[0];
65947         if (!i || p[1] > maxY) maxY = p[1];
65948     }
65949
65950     var width = maxX - minX;
65951     var height = maxY - minY;
65952     var cellSize = Math.min(width, height);
65953     var h = cellSize / 2;
65954
65955     if (cellSize === 0) {
65956         var degeneratePoleOfInaccessibility = [minX, minY];
65957         degeneratePoleOfInaccessibility.distance = 0;
65958         return degeneratePoleOfInaccessibility;
65959     }
65960
65961     // a priority queue of cells in order of their "potential" (max distance to polygon)
65962     var cellQueue = new Queue(undefined, compareMax);
65963
65964     // cover polygon with initial cells
65965     for (var x = minX; x < maxX; x += cellSize) {
65966         for (var y = minY; y < maxY; y += cellSize) {
65967             cellQueue.push(new Cell(x + h, y + h, h, polygon));
65968         }
65969     }
65970
65971     // take centroid as the first best guess
65972     var bestCell = getCentroidCell(polygon);
65973
65974     // special case for rectangular polygons
65975     var bboxCell = new Cell(minX + width / 2, minY + height / 2, 0, polygon);
65976     if (bboxCell.d > bestCell.d) bestCell = bboxCell;
65977
65978     var numProbes = cellQueue.length;
65979
65980     while (cellQueue.length) {
65981         // pick the most promising cell from the queue
65982         var cell = cellQueue.pop();
65983
65984         // update the best cell if we found a better one
65985         if (cell.d > bestCell.d) {
65986             bestCell = cell;
65987             if (debug) console.log('found best %d after %d probes', Math.round(1e4 * cell.d) / 1e4, numProbes);
65988         }
65989
65990         // do not drill down further if there's no chance of a better solution
65991         if (cell.max - bestCell.d <= precision) continue;
65992
65993         // split the cell into four cells
65994         h = cell.h / 2;
65995         cellQueue.push(new Cell(cell.x - h, cell.y - h, h, polygon));
65996         cellQueue.push(new Cell(cell.x + h, cell.y - h, h, polygon));
65997         cellQueue.push(new Cell(cell.x - h, cell.y + h, h, polygon));
65998         cellQueue.push(new Cell(cell.x + h, cell.y + h, h, polygon));
65999         numProbes += 4;
66000     }
66001
66002     if (debug) {
66003         console.log('num probes: ' + numProbes);
66004         console.log('best distance: ' + bestCell.d);
66005     }
66006
66007     var poleOfInaccessibility = [bestCell.x, bestCell.y];
66008     poleOfInaccessibility.distance = bestCell.d;
66009     return poleOfInaccessibility;
66010 }
66011
66012 function compareMax(a, b) {
66013     return b.max - a.max;
66014 }
66015
66016 function Cell(x, y, h, polygon) {
66017     this.x = x; // cell center x
66018     this.y = y; // cell center y
66019     this.h = h; // half the cell size
66020     this.d = pointToPolygonDist(x, y, polygon); // distance from cell center to polygon
66021     this.max = this.d + this.h * Math.SQRT2; // max distance to polygon within a cell
66022 }
66023
66024 // signed distance from point to polygon outline (negative if point is outside)
66025 function pointToPolygonDist(x, y, polygon) {
66026     var inside = false;
66027     var minDistSq = Infinity;
66028
66029     for (var k = 0; k < polygon.length; k++) {
66030         var ring = polygon[k];
66031
66032         for (var i = 0, len = ring.length, j = len - 1; i < len; j = i++) {
66033             var a = ring[i];
66034             var b = ring[j];
66035
66036             if ((a[1] > y !== b[1] > y) &&
66037                 (x < (b[0] - a[0]) * (y - a[1]) / (b[1] - a[1]) + a[0])) inside = !inside;
66038
66039             minDistSq = Math.min(minDistSq, getSegDistSq(x, y, a, b));
66040         }
66041     }
66042
66043     return minDistSq === 0 ? 0 : (inside ? 1 : -1) * Math.sqrt(minDistSq);
66044 }
66045
66046 // get polygon centroid
66047 function getCentroidCell(polygon) {
66048     var area = 0;
66049     var x = 0;
66050     var y = 0;
66051     var points = polygon[0];
66052
66053     for (var i = 0, len = points.length, j = len - 1; i < len; j = i++) {
66054         var a = points[i];
66055         var b = points[j];
66056         var f = a[0] * b[1] - b[0] * a[1];
66057         x += (a[0] + b[0]) * f;
66058         y += (a[1] + b[1]) * f;
66059         area += f * 3;
66060     }
66061     if (area === 0) return new Cell(points[0][0], points[0][1], 0, polygon);
66062     return new Cell(x / area, y / area, 0, polygon);
66063 }
66064
66065 // get squared distance from a point to a segment
66066 function getSegDistSq(px, py, a, b) {
66067
66068     var x = a[0];
66069     var y = a[1];
66070     var dx = b[0] - x;
66071     var dy = b[1] - y;
66072
66073     if (dx !== 0 || dy !== 0) {
66074
66075         var t = ((px - x) * dx + (py - y) * dy) / (dx * dx + dy * dy);
66076
66077         if (t > 1) {
66078             x = b[0];
66079             y = b[1];
66080
66081         } else if (t > 0) {
66082             x += dx * t;
66083             y += dy * t;
66084         }
66085     }
66086
66087     dx = px - x;
66088     dy = py - y;
66089
66090     return dx * dx + dy * dy;
66091 }
66092 polylabel_1.default = _default$1;
66093
66094 function DEFAULT_COMPARE (a, b) { return a > b ? 1 : a < b ? -1 : 0; }
66095
66096 class SplayTree {
66097
66098   constructor(compare = DEFAULT_COMPARE, noDuplicates = false) {
66099     this._compare = compare;
66100     this._root = null;
66101     this._size = 0;
66102     this._noDuplicates = !!noDuplicates;
66103   }
66104
66105
66106   rotateLeft(x) {
66107     var y = x.right;
66108     if (y) {
66109       x.right = y.left;
66110       if (y.left) y.left.parent = x;
66111       y.parent = x.parent;
66112     }
66113
66114     if (!x.parent)                this._root = y;
66115     else if (x === x.parent.left) x.parent.left = y;
66116     else                          x.parent.right = y;
66117     if (y) y.left = x;
66118     x.parent = y;
66119   }
66120
66121
66122   rotateRight(x) {
66123     var y = x.left;
66124     if (y) {
66125       x.left = y.right;
66126       if (y.right) y.right.parent = x;
66127       y.parent = x.parent;
66128     }
66129
66130     if (!x.parent)               this._root = y;
66131     else if(x === x.parent.left) x.parent.left = y;
66132     else                         x.parent.right = y;
66133     if (y) y.right = x;
66134     x.parent = y;
66135   }
66136
66137
66138   _splay(x) {
66139     while (x.parent) {
66140       var p = x.parent;
66141       if (!p.parent) {
66142         if (p.left === x) this.rotateRight(p);
66143         else              this.rotateLeft(p);
66144       } else if (p.left === x && p.parent.left === p) {
66145         this.rotateRight(p.parent);
66146         this.rotateRight(p);
66147       } else if (p.right === x && p.parent.right === p) {
66148         this.rotateLeft(p.parent);
66149         this.rotateLeft(p);
66150       } else if (p.left === x && p.parent.right === p) {
66151         this.rotateRight(p);
66152         this.rotateLeft(p);
66153       } else {
66154         this.rotateLeft(p);
66155         this.rotateRight(p);
66156       }
66157     }
66158   }
66159
66160
66161   splay(x) {
66162     var p, gp, ggp, l, r;
66163
66164     while (x.parent) {
66165       p = x.parent;
66166       gp = p.parent;
66167
66168       if (gp && gp.parent) {
66169         ggp = gp.parent;
66170         if (ggp.left === gp) ggp.left  = x;
66171         else                 ggp.right = x;
66172         x.parent = ggp;
66173       } else {
66174         x.parent = null;
66175         this._root = x;
66176       }
66177
66178       l = x.left; r = x.right;
66179
66180       if (x === p.left) { // left
66181         if (gp) {
66182           if (gp.left === p) {
66183             /* zig-zig */
66184             if (p.right) {
66185               gp.left = p.right;
66186               gp.left.parent = gp;
66187             } else gp.left = null;
66188
66189             p.right   = gp;
66190             gp.parent = p;
66191           } else {
66192             /* zig-zag */
66193             if (l) {
66194               gp.right = l;
66195               l.parent = gp;
66196             } else gp.right = null;
66197
66198             x.left    = gp;
66199             gp.parent = x;
66200           }
66201         }
66202         if (r) {
66203           p.left = r;
66204           r.parent = p;
66205         } else p.left = null;
66206
66207         x.right  = p;
66208         p.parent = x;
66209       } else { // right
66210         if (gp) {
66211           if (gp.right === p) {
66212             /* zig-zig */
66213             if (p.left) {
66214               gp.right = p.left;
66215               gp.right.parent = gp;
66216             } else gp.right = null;
66217
66218             p.left = gp;
66219             gp.parent = p;
66220           } else {
66221             /* zig-zag */
66222             if (r) {
66223               gp.left = r;
66224               r.parent = gp;
66225             } else gp.left = null;
66226
66227             x.right   = gp;
66228             gp.parent = x;
66229           }
66230         }
66231         if (l) {
66232           p.right = l;
66233           l.parent = p;
66234         } else p.right = null;
66235
66236         x.left   = p;
66237         p.parent = x;
66238       }
66239     }
66240   }
66241
66242
66243   replace(u, v) {
66244     if (!u.parent) this._root = v;
66245     else if (u === u.parent.left) u.parent.left = v;
66246     else u.parent.right = v;
66247     if (v) v.parent = u.parent;
66248   }
66249
66250
66251   minNode(u = this._root) {
66252     if (u) while (u.left) u = u.left;
66253     return u;
66254   }
66255
66256
66257   maxNode(u = this._root) {
66258     if (u) while (u.right) u = u.right;
66259     return u;
66260   }
66261
66262
66263   insert(key, data) {
66264     var z = this._root;
66265     var p = null;
66266     var comp = this._compare;
66267     var cmp;
66268
66269     if (this._noDuplicates) {
66270       while (z) {
66271         p = z;
66272         cmp = comp(z.key, key);
66273         if (cmp === 0) return;
66274         else if (comp(z.key, key) < 0) z = z.right;
66275         else z = z.left;
66276       }
66277     } else {
66278       while (z) {
66279         p = z;
66280         if (comp(z.key, key) < 0) z = z.right;
66281         else z = z.left;
66282       }
66283     }
66284
66285     z = { key, data, left: null, right: null, parent: p };
66286
66287     if (!p)                          this._root = z;
66288     else if (comp(p.key, z.key) < 0) p.right = z;
66289     else                             p.left  = z;
66290
66291     this.splay(z);
66292     this._size++;
66293     return z;
66294   }
66295
66296
66297   find (key) {
66298     var z    = this._root;
66299     var comp = this._compare;
66300     while (z) {
66301       var cmp = comp(z.key, key);
66302       if      (cmp < 0) z = z.right;
66303       else if (cmp > 0) z = z.left;
66304       else              return z;
66305     }
66306     return null;
66307   }
66308
66309   /**
66310    * Whether the tree contains a node with the given key
66311    * @param  {Key} key
66312    * @return {boolean} true/false
66313    */
66314   contains (key) {
66315     var node       = this._root;
66316     var comparator = this._compare;
66317     while (node)  {
66318       var cmp = comparator(key, node.key);
66319       if      (cmp === 0) return true;
66320       else if (cmp < 0)   node = node.left;
66321       else                node = node.right;
66322     }
66323
66324     return false;
66325   }
66326
66327
66328   remove (key) {
66329     var z = this.find(key);
66330
66331     if (!z) return false;
66332
66333     this.splay(z);
66334
66335     if (!z.left) this.replace(z, z.right);
66336     else if (!z.right) this.replace(z, z.left);
66337     else {
66338       var y = this.minNode(z.right);
66339       if (y.parent !== z) {
66340         this.replace(y, y.right);
66341         y.right = z.right;
66342         y.right.parent = y;
66343       }
66344       this.replace(z, y);
66345       y.left = z.left;
66346       y.left.parent = y;
66347     }
66348
66349     this._size--;
66350     return true;
66351   }
66352
66353
66354   removeNode(z) {
66355     if (!z) return false;
66356
66357     this.splay(z);
66358
66359     if (!z.left) this.replace(z, z.right);
66360     else if (!z.right) this.replace(z, z.left);
66361     else {
66362       var y = this.minNode(z.right);
66363       if (y.parent !== z) {
66364         this.replace(y, y.right);
66365         y.right = z.right;
66366         y.right.parent = y;
66367       }
66368       this.replace(z, y);
66369       y.left = z.left;
66370       y.left.parent = y;
66371     }
66372
66373     this._size--;
66374     return true;
66375   }
66376
66377
66378   erase (key) {
66379     var z = this.find(key);
66380     if (!z) return;
66381
66382     this.splay(z);
66383
66384     var s = z.left;
66385     var t = z.right;
66386
66387     var sMax = null;
66388     if (s) {
66389       s.parent = null;
66390       sMax = this.maxNode(s);
66391       this.splay(sMax);
66392       this._root = sMax;
66393     }
66394     if (t) {
66395       if (s) sMax.right = t;
66396       else   this._root = t;
66397       t.parent = sMax;
66398     }
66399
66400     this._size--;
66401   }
66402
66403   /**
66404    * Removes and returns the node with smallest key
66405    * @return {?Node}
66406    */
66407   pop () {
66408     var node = this._root, returnValue = null;
66409     if (node) {
66410       while (node.left) node = node.left;
66411       returnValue = { key: node.key, data: node.data };
66412       this.remove(node.key);
66413     }
66414     return returnValue;
66415   }
66416
66417
66418   /* eslint-disable class-methods-use-this */
66419
66420   /**
66421    * Successor node
66422    * @param  {Node} node
66423    * @return {?Node}
66424    */
66425   next (node) {
66426     var successor = node;
66427     if (successor) {
66428       if (successor.right) {
66429         successor = successor.right;
66430         while (successor && successor.left) successor = successor.left;
66431       } else {
66432         successor = node.parent;
66433         while (successor && successor.right === node) {
66434           node = successor; successor = successor.parent;
66435         }
66436       }
66437     }
66438     return successor;
66439   }
66440
66441
66442   /**
66443    * Predecessor node
66444    * @param  {Node} node
66445    * @return {?Node}
66446    */
66447   prev (node) {
66448     var predecessor = node;
66449     if (predecessor) {
66450       if (predecessor.left) {
66451         predecessor = predecessor.left;
66452         while (predecessor && predecessor.right) predecessor = predecessor.right;
66453       } else {
66454         predecessor = node.parent;
66455         while (predecessor && predecessor.left === node) {
66456           node = predecessor;
66457           predecessor = predecessor.parent;
66458         }
66459       }
66460     }
66461     return predecessor;
66462   }
66463   /* eslint-enable class-methods-use-this */
66464
66465
66466   /**
66467    * @param  {forEachCallback} callback
66468    * @return {SplayTree}
66469    */
66470   forEach(callback) {
66471     var current = this._root;
66472     var s = [], done = false, i = 0;
66473
66474     while (!done) {
66475       // Reach the left most Node of the current Node
66476       if (current) {
66477         // Place pointer to a tree node on the stack
66478         // before traversing the node's left subtree
66479         s.push(current);
66480         current = current.left;
66481       } else {
66482         // BackTrack from the empty subtree and visit the Node
66483         // at the top of the stack; however, if the stack is
66484         // empty you are done
66485         if (s.length > 0) {
66486           current = s.pop();
66487           callback(current, i++);
66488
66489           // We have visited the node and its left
66490           // subtree. Now, it's right subtree's turn
66491           current = current.right;
66492         } else done = true;
66493       }
66494     }
66495     return this;
66496   }
66497
66498
66499   /**
66500    * Walk key range from `low` to `high`. Stops if `fn` returns a value.
66501    * @param  {Key}      low
66502    * @param  {Key}      high
66503    * @param  {Function} fn
66504    * @param  {*?}       ctx
66505    * @return {SplayTree}
66506    */
66507   range(low, high, fn, ctx) {
66508     const Q = [];
66509     const compare = this._compare;
66510     let node = this._root, cmp;
66511
66512     while (Q.length !== 0 || node) {
66513       if (node) {
66514         Q.push(node);
66515         node = node.left;
66516       } else {
66517         node = Q.pop();
66518         cmp = compare(node.key, high);
66519         if (cmp > 0) {
66520           break;
66521         } else if (compare(node.key, low) >= 0) {
66522           if (fn.call(ctx, node)) return this; // stop if smth is returned
66523         }
66524         node = node.right;
66525       }
66526     }
66527     return this;
66528   }
66529
66530   /**
66531    * Returns all keys in order
66532    * @return {Array<Key>}
66533    */
66534   keys () {
66535     var current = this._root;
66536     var s = [], r = [], done = false;
66537
66538     while (!done) {
66539       if (current) {
66540         s.push(current);
66541         current = current.left;
66542       } else {
66543         if (s.length > 0) {
66544           current = s.pop();
66545           r.push(current.key);
66546           current = current.right;
66547         } else done = true;
66548       }
66549     }
66550     return r;
66551   }
66552
66553
66554   /**
66555    * Returns `data` fields of all nodes in order.
66556    * @return {Array<Value>}
66557    */
66558   values () {
66559     var current = this._root;
66560     var s = [], r = [], done = false;
66561
66562     while (!done) {
66563       if (current) {
66564         s.push(current);
66565         current = current.left;
66566       } else {
66567         if (s.length > 0) {
66568           current = s.pop();
66569           r.push(current.data);
66570           current = current.right;
66571         } else done = true;
66572       }
66573     }
66574     return r;
66575   }
66576
66577
66578   /**
66579    * Returns node at given index
66580    * @param  {number} index
66581    * @return {?Node}
66582    */
66583   at (index) {
66584     // removed after a consideration, more misleading than useful
66585     // index = index % this.size;
66586     // if (index < 0) index = this.size - index;
66587
66588     var current = this._root;
66589     var s = [], done = false, i = 0;
66590
66591     while (!done) {
66592       if (current) {
66593         s.push(current);
66594         current = current.left;
66595       } else {
66596         if (s.length > 0) {
66597           current = s.pop();
66598           if (i === index) return current;
66599           i++;
66600           current = current.right;
66601         } else done = true;
66602       }
66603     }
66604     return null;
66605   }
66606
66607   /**
66608    * Bulk-load items. Both array have to be same size
66609    * @param  {Array<Key>}    keys
66610    * @param  {Array<Value>}  [values]
66611    * @param  {Boolean}       [presort=false] Pre-sort keys and values, using
66612    *                                         tree's comparator. Sorting is done
66613    *                                         in-place
66614    * @return {AVLTree}
66615    */
66616   load(keys = [], values = [], presort = false) {
66617     if (this._size !== 0) throw new Error('bulk-load: tree is not empty');
66618     const size = keys.length;
66619     if (presort) sort(keys, values, 0, size - 1, this._compare);
66620     this._root = loadRecursive(null, keys, values, 0, size);
66621     this._size = size;
66622     return this;
66623   }
66624
66625
66626   min() {
66627     var node = this.minNode(this._root);
66628     if (node) return node.key;
66629     else      return null;
66630   }
66631
66632
66633   max() {
66634     var node = this.maxNode(this._root);
66635     if (node) return node.key;
66636     else      return null;
66637   }
66638
66639   isEmpty() { return this._root === null; }
66640   get size() { return this._size; }
66641
66642
66643   /**
66644    * Create a tree and load it with items
66645    * @param  {Array<Key>}          keys
66646    * @param  {Array<Value>?}        [values]
66647
66648    * @param  {Function?}            [comparator]
66649    * @param  {Boolean?}             [presort=false] Pre-sort keys and values, using
66650    *                                               tree's comparator. Sorting is done
66651    *                                               in-place
66652    * @param  {Boolean?}             [noDuplicates=false]   Allow duplicates
66653    * @return {SplayTree}
66654    */
66655   static createTree(keys, values, comparator, presort, noDuplicates) {
66656     return new SplayTree(comparator, noDuplicates).load(keys, values, presort);
66657   }
66658 }
66659
66660
66661 function loadRecursive (parent, keys, values, start, end) {
66662   const size = end - start;
66663   if (size > 0) {
66664     const middle = start + Math.floor(size / 2);
66665     const key    = keys[middle];
66666     const data   = values[middle];
66667     const node   = { key, data, parent };
66668     node.left    = loadRecursive(node, keys, values, start, middle);
66669     node.right   = loadRecursive(node, keys, values, middle + 1, end);
66670     return node;
66671   }
66672   return null;
66673 }
66674
66675
66676 function sort(keys, values, left, right, compare) {
66677   if (left >= right) return;
66678
66679   const pivot = keys[(left + right) >> 1];
66680   let i = left - 1;
66681   let j = right + 1;
66682
66683   while (true) {
66684     do i++; while (compare(keys[i], pivot) < 0);
66685     do j--; while (compare(keys[j], pivot) > 0);
66686     if (i >= j) break;
66687
66688     let tmp = keys[i];
66689     keys[i] = keys[j];
66690     keys[j] = tmp;
66691
66692     tmp = values[i];
66693     values[i] = values[j];
66694     values[j] = tmp;
66695   }
66696
66697   sort(keys, values,  left,     j, compare);
66698   sort(keys, values, j + 1, right, compare);
66699 }
66700
66701 const NORMAL               = 0;
66702 const NON_CONTRIBUTING     = 1;
66703 const SAME_TRANSITION      = 2;
66704 const DIFFERENT_TRANSITION = 3;
66705
66706 const INTERSECTION = 0;
66707 const UNION        = 1;
66708 const DIFFERENCE   = 2;
66709 const XOR          = 3;
66710
66711 /**
66712  * @param  {SweepEvent} event
66713  * @param  {SweepEvent} prev
66714  * @param  {Operation} operation
66715  */
66716 function computeFields (event, prev, operation) {
66717   // compute inOut and otherInOut fields
66718   if (prev === null) {
66719     event.inOut      = false;
66720     event.otherInOut = true;
66721
66722   // previous line segment in sweepline belongs to the same polygon
66723   } else {
66724     if (event.isSubject === prev.isSubject) {
66725       event.inOut      = !prev.inOut;
66726       event.otherInOut = prev.otherInOut;
66727
66728     // previous line segment in sweepline belongs to the clipping polygon
66729     } else {
66730       event.inOut      = !prev.otherInOut;
66731       event.otherInOut = prev.isVertical() ? !prev.inOut : prev.inOut;
66732     }
66733
66734     // compute prevInResult field
66735     if (prev) {
66736       event.prevInResult = (!inResult(prev, operation) || prev.isVertical())
66737         ? prev.prevInResult : prev;
66738     }
66739   }
66740
66741   // check if the line segment belongs to the Boolean operation
66742   let isInResult = inResult(event, operation);
66743   if (isInResult) {
66744     event.resultTransition = determineResultTransition(event, operation);
66745   } else {
66746     event.resultTransition = 0;
66747   }
66748 }
66749
66750
66751 /* eslint-disable indent */
66752 function inResult(event, operation) {
66753   switch (event.type) {
66754     case NORMAL:
66755       switch (operation) {
66756         case INTERSECTION:
66757           return !event.otherInOut;
66758         case UNION:
66759           return event.otherInOut;
66760         case DIFFERENCE:
66761           // return (event.isSubject && !event.otherInOut) ||
66762           //         (!event.isSubject && event.otherInOut);
66763           return (event.isSubject && event.otherInOut) ||
66764                   (!event.isSubject && !event.otherInOut);
66765         case XOR:
66766           return true;
66767       }
66768       break;
66769     case SAME_TRANSITION:
66770       return operation === INTERSECTION || operation === UNION;
66771     case DIFFERENT_TRANSITION:
66772       return operation === DIFFERENCE;
66773     case NON_CONTRIBUTING:
66774       return false;
66775   }
66776   return false;
66777 }
66778 /* eslint-enable indent */
66779
66780
66781 function determineResultTransition(event, operation) {
66782   let thisIn = !event.inOut;
66783   let thatIn = !event.otherInOut;
66784
66785   let isIn;
66786   switch (operation) {
66787     case INTERSECTION:
66788       isIn = thisIn && thatIn; break;
66789     case UNION:
66790       isIn = thisIn || thatIn; break;
66791     case XOR:
66792       isIn = thisIn ^ thatIn; break;
66793     case DIFFERENCE:
66794       if (event.isSubject) {
66795         isIn = thisIn && !thatIn;
66796       } else {
66797         isIn = thatIn && !thisIn;
66798       }
66799       break;
66800   }
66801   return isIn ? +1 : -1;
66802 }
66803
66804 class SweepEvent {
66805
66806
66807   /**
66808    * Sweepline event
66809    *
66810    * @class {SweepEvent}
66811    * @param {Array.<Number>}  point
66812    * @param {Boolean}         left
66813    * @param {SweepEvent=}     otherEvent
66814    * @param {Boolean}         isSubject
66815    * @param {Number}          edgeType
66816    */
66817   constructor (point, left, otherEvent, isSubject, edgeType) {
66818
66819     /**
66820      * Is left endpoint?
66821      * @type {Boolean}
66822      */
66823     this.left = left;
66824
66825     /**
66826      * @type {Array.<Number>}
66827      */
66828     this.point = point;
66829
66830     /**
66831      * Other edge reference
66832      * @type {SweepEvent}
66833      */
66834     this.otherEvent = otherEvent;
66835
66836     /**
66837      * Belongs to source or clipping polygon
66838      * @type {Boolean}
66839      */
66840     this.isSubject = isSubject;
66841
66842     /**
66843      * Edge contribution type
66844      * @type {Number}
66845      */
66846     this.type = edgeType || NORMAL;
66847
66848
66849     /**
66850      * In-out transition for the sweepline crossing polygon
66851      * @type {Boolean}
66852      */
66853     this.inOut = false;
66854
66855
66856     /**
66857      * @type {Boolean}
66858      */
66859     this.otherInOut = false;
66860
66861     /**
66862      * Previous event in result?
66863      * @type {SweepEvent}
66864      */
66865     this.prevInResult = null;
66866
66867     /**
66868      * Type of result transition (0 = not in result, +1 = out-in, -1, in-out)
66869      * @type {Number}
66870      */
66871     this.resultTransition = 0;
66872
66873     // connection step
66874
66875     /**
66876      * @type {Number}
66877      */
66878     this.otherPos = -1;
66879
66880     /**
66881      * @type {Number}
66882      */
66883     this.outputContourId = -1;
66884
66885     this.isExteriorRing = true;   // TODO: Looks unused, remove?
66886   }
66887
66888
66889   /**
66890    * @param  {Array.<Number>}  p
66891    * @return {Boolean}
66892    */
66893   isBelow (p) {
66894     const p0 = this.point, p1 = this.otherEvent.point;
66895     return this.left
66896       ? (p0[0] - p[0]) * (p1[1] - p[1]) - (p1[0] - p[0]) * (p0[1] - p[1]) > 0
66897       // signedArea(this.point, this.otherEvent.point, p) > 0 :
66898       : (p1[0] - p[0]) * (p0[1] - p[1]) - (p0[0] - p[0]) * (p1[1] - p[1]) > 0;
66899       //signedArea(this.otherEvent.point, this.point, p) > 0;
66900   }
66901
66902
66903   /**
66904    * @param  {Array.<Number>}  p
66905    * @return {Boolean}
66906    */
66907   isAbove (p) {
66908     return !this.isBelow(p);
66909   }
66910
66911
66912   /**
66913    * @return {Boolean}
66914    */
66915   isVertical () {
66916     return this.point[0] === this.otherEvent.point[0];
66917   }
66918
66919
66920   /**
66921    * Does event belong to result?
66922    * @return {Boolean}
66923    */
66924   get inResult() {
66925     return this.resultTransition !== 0;
66926   }
66927
66928
66929   clone () {
66930     const copy = new SweepEvent(
66931       this.point, this.left, this.otherEvent, this.isSubject, this.type);
66932
66933     copy.contourId        = this.contourId;
66934     copy.resultTransition = this.resultTransition;
66935     copy.prevInResult     = this.prevInResult;
66936     copy.isExteriorRing   = this.isExteriorRing;
66937     copy.inOut            = this.inOut;
66938     copy.otherInOut       = this.otherInOut;
66939
66940     return copy;
66941   }
66942 }
66943
66944 function equals(p1, p2) {
66945   if (p1[0] === p2[0]) {
66946     if (p1[1] === p2[1]) {
66947       return true;
66948     } else {
66949       return false;
66950     }
66951   }
66952   return false;
66953 }
66954
66955 // const EPSILON = 1e-9;
66956 // const abs = Math.abs;
66957 // TODO https://github.com/w8r/martinez/issues/6#issuecomment-262847164
66958 // Precision problem.
66959 //
66960 // module.exports = function equals(p1, p2) {
66961 //   return abs(p1[0] - p2[0]) <= EPSILON && abs(p1[1] - p2[1]) <= EPSILON;
66962 // };
66963
66964 const epsilon = 1.1102230246251565e-16;
66965 const splitter = 134217729;
66966 const resulterrbound = (3 + 8 * epsilon) * epsilon;
66967
66968 // fast_expansion_sum_zeroelim routine from oritinal code
66969 function sum(elen, e, flen, f, h) {
66970     let Q, Qnew, hh, bvirt;
66971     let enow = e[0];
66972     let fnow = f[0];
66973     let eindex = 0;
66974     let findex = 0;
66975     if ((fnow > enow) === (fnow > -enow)) {
66976         Q = enow;
66977         enow = e[++eindex];
66978     } else {
66979         Q = fnow;
66980         fnow = f[++findex];
66981     }
66982     let hindex = 0;
66983     if (eindex < elen && findex < flen) {
66984         if ((fnow > enow) === (fnow > -enow)) {
66985             Qnew = enow + Q;
66986             hh = Q - (Qnew - enow);
66987             enow = e[++eindex];
66988         } else {
66989             Qnew = fnow + Q;
66990             hh = Q - (Qnew - fnow);
66991             fnow = f[++findex];
66992         }
66993         Q = Qnew;
66994         if (hh !== 0) {
66995             h[hindex++] = hh;
66996         }
66997         while (eindex < elen && findex < flen) {
66998             if ((fnow > enow) === (fnow > -enow)) {
66999                 Qnew = Q + enow;
67000                 bvirt = Qnew - Q;
67001                 hh = Q - (Qnew - bvirt) + (enow - bvirt);
67002                 enow = e[++eindex];
67003             } else {
67004                 Qnew = Q + fnow;
67005                 bvirt = Qnew - Q;
67006                 hh = Q - (Qnew - bvirt) + (fnow - bvirt);
67007                 fnow = f[++findex];
67008             }
67009             Q = Qnew;
67010             if (hh !== 0) {
67011                 h[hindex++] = hh;
67012             }
67013         }
67014     }
67015     while (eindex < elen) {
67016         Qnew = Q + enow;
67017         bvirt = Qnew - Q;
67018         hh = Q - (Qnew - bvirt) + (enow - bvirt);
67019         enow = e[++eindex];
67020         Q = Qnew;
67021         if (hh !== 0) {
67022             h[hindex++] = hh;
67023         }
67024     }
67025     while (findex < flen) {
67026         Qnew = Q + fnow;
67027         bvirt = Qnew - Q;
67028         hh = Q - (Qnew - bvirt) + (fnow - bvirt);
67029         fnow = f[++findex];
67030         Q = Qnew;
67031         if (hh !== 0) {
67032             h[hindex++] = hh;
67033         }
67034     }
67035     if (Q !== 0 || hindex === 0) {
67036         h[hindex++] = Q;
67037     }
67038     return hindex;
67039 }
67040
67041 function estimate(elen, e) {
67042     let Q = e[0];
67043     for (let i = 1; i < elen; i++) Q += e[i];
67044     return Q;
67045 }
67046
67047 function vec(n) {
67048     return new Float64Array(n);
67049 }
67050
67051 const ccwerrboundA = (3 + 16 * epsilon) * epsilon;
67052 const ccwerrboundB = (2 + 12 * epsilon) * epsilon;
67053 const ccwerrboundC = (9 + 64 * epsilon) * epsilon * epsilon;
67054
67055 const B = vec(4);
67056 const C1 = vec(8);
67057 const C2 = vec(12);
67058 const D = vec(16);
67059 const u = vec(4);
67060
67061 function orient2dadapt(ax, ay, bx, by, cx, cy, detsum) {
67062     let acxtail, acytail, bcxtail, bcytail;
67063     let bvirt, c, ahi, alo, bhi, blo, _i, _j, _0, s1, s0, t1, t0, u3;
67064
67065     const acx = ax - cx;
67066     const bcx = bx - cx;
67067     const acy = ay - cy;
67068     const bcy = by - cy;
67069
67070     s1 = acx * bcy;
67071     c = splitter * acx;
67072     ahi = c - (c - acx);
67073     alo = acx - ahi;
67074     c = splitter * bcy;
67075     bhi = c - (c - bcy);
67076     blo = bcy - bhi;
67077     s0 = alo * blo - (s1 - ahi * bhi - alo * bhi - ahi * blo);
67078     t1 = acy * bcx;
67079     c = splitter * acy;
67080     ahi = c - (c - acy);
67081     alo = acy - ahi;
67082     c = splitter * bcx;
67083     bhi = c - (c - bcx);
67084     blo = bcx - bhi;
67085     t0 = alo * blo - (t1 - ahi * bhi - alo * bhi - ahi * blo);
67086     _i = s0 - t0;
67087     bvirt = s0 - _i;
67088     B[0] = s0 - (_i + bvirt) + (bvirt - t0);
67089     _j = s1 + _i;
67090     bvirt = _j - s1;
67091     _0 = s1 - (_j - bvirt) + (_i - bvirt);
67092     _i = _0 - t1;
67093     bvirt = _0 - _i;
67094     B[1] = _0 - (_i + bvirt) + (bvirt - t1);
67095     u3 = _j + _i;
67096     bvirt = u3 - _j;
67097     B[2] = _j - (u3 - bvirt) + (_i - bvirt);
67098     B[3] = u3;
67099
67100     let det = estimate(4, B);
67101     let errbound = ccwerrboundB * detsum;
67102     if (det >= errbound || -det >= errbound) {
67103         return det;
67104     }
67105
67106     bvirt = ax - acx;
67107     acxtail = ax - (acx + bvirt) + (bvirt - cx);
67108     bvirt = bx - bcx;
67109     bcxtail = bx - (bcx + bvirt) + (bvirt - cx);
67110     bvirt = ay - acy;
67111     acytail = ay - (acy + bvirt) + (bvirt - cy);
67112     bvirt = by - bcy;
67113     bcytail = by - (bcy + bvirt) + (bvirt - cy);
67114
67115     if (acxtail === 0 && acytail === 0 && bcxtail === 0 && bcytail === 0) {
67116         return det;
67117     }
67118
67119     errbound = ccwerrboundC * detsum + resulterrbound * Math.abs(det);
67120     det += (acx * bcytail + bcy * acxtail) - (acy * bcxtail + bcx * acytail);
67121     if (det >= errbound || -det >= errbound) return det;
67122
67123     s1 = acxtail * bcy;
67124     c = splitter * acxtail;
67125     ahi = c - (c - acxtail);
67126     alo = acxtail - ahi;
67127     c = splitter * bcy;
67128     bhi = c - (c - bcy);
67129     blo = bcy - bhi;
67130     s0 = alo * blo - (s1 - ahi * bhi - alo * bhi - ahi * blo);
67131     t1 = acytail * bcx;
67132     c = splitter * acytail;
67133     ahi = c - (c - acytail);
67134     alo = acytail - ahi;
67135     c = splitter * bcx;
67136     bhi = c - (c - bcx);
67137     blo = bcx - bhi;
67138     t0 = alo * blo - (t1 - ahi * bhi - alo * bhi - ahi * blo);
67139     _i = s0 - t0;
67140     bvirt = s0 - _i;
67141     u[0] = s0 - (_i + bvirt) + (bvirt - t0);
67142     _j = s1 + _i;
67143     bvirt = _j - s1;
67144     _0 = s1 - (_j - bvirt) + (_i - bvirt);
67145     _i = _0 - t1;
67146     bvirt = _0 - _i;
67147     u[1] = _0 - (_i + bvirt) + (bvirt - t1);
67148     u3 = _j + _i;
67149     bvirt = u3 - _j;
67150     u[2] = _j - (u3 - bvirt) + (_i - bvirt);
67151     u[3] = u3;
67152     const C1len = sum(4, B, 4, u, C1);
67153
67154     s1 = acx * bcytail;
67155     c = splitter * acx;
67156     ahi = c - (c - acx);
67157     alo = acx - ahi;
67158     c = splitter * bcytail;
67159     bhi = c - (c - bcytail);
67160     blo = bcytail - bhi;
67161     s0 = alo * blo - (s1 - ahi * bhi - alo * bhi - ahi * blo);
67162     t1 = acy * bcxtail;
67163     c = splitter * acy;
67164     ahi = c - (c - acy);
67165     alo = acy - ahi;
67166     c = splitter * bcxtail;
67167     bhi = c - (c - bcxtail);
67168     blo = bcxtail - bhi;
67169     t0 = alo * blo - (t1 - ahi * bhi - alo * bhi - ahi * blo);
67170     _i = s0 - t0;
67171     bvirt = s0 - _i;
67172     u[0] = s0 - (_i + bvirt) + (bvirt - t0);
67173     _j = s1 + _i;
67174     bvirt = _j - s1;
67175     _0 = s1 - (_j - bvirt) + (_i - bvirt);
67176     _i = _0 - t1;
67177     bvirt = _0 - _i;
67178     u[1] = _0 - (_i + bvirt) + (bvirt - t1);
67179     u3 = _j + _i;
67180     bvirt = u3 - _j;
67181     u[2] = _j - (u3 - bvirt) + (_i - bvirt);
67182     u[3] = u3;
67183     const C2len = sum(C1len, C1, 4, u, C2);
67184
67185     s1 = acxtail * bcytail;
67186     c = splitter * acxtail;
67187     ahi = c - (c - acxtail);
67188     alo = acxtail - ahi;
67189     c = splitter * bcytail;
67190     bhi = c - (c - bcytail);
67191     blo = bcytail - bhi;
67192     s0 = alo * blo - (s1 - ahi * bhi - alo * bhi - ahi * blo);
67193     t1 = acytail * bcxtail;
67194     c = splitter * acytail;
67195     ahi = c - (c - acytail);
67196     alo = acytail - ahi;
67197     c = splitter * bcxtail;
67198     bhi = c - (c - bcxtail);
67199     blo = bcxtail - bhi;
67200     t0 = alo * blo - (t1 - ahi * bhi - alo * bhi - ahi * blo);
67201     _i = s0 - t0;
67202     bvirt = s0 - _i;
67203     u[0] = s0 - (_i + bvirt) + (bvirt - t0);
67204     _j = s1 + _i;
67205     bvirt = _j - s1;
67206     _0 = s1 - (_j - bvirt) + (_i - bvirt);
67207     _i = _0 - t1;
67208     bvirt = _0 - _i;
67209     u[1] = _0 - (_i + bvirt) + (bvirt - t1);
67210     u3 = _j + _i;
67211     bvirt = u3 - _j;
67212     u[2] = _j - (u3 - bvirt) + (_i - bvirt);
67213     u[3] = u3;
67214     const Dlen = sum(C2len, C2, 4, u, D);
67215
67216     return D[Dlen - 1];
67217 }
67218
67219 function orient2d(ax, ay, bx, by, cx, cy) {
67220     const detleft = (ay - cy) * (bx - cx);
67221     const detright = (ax - cx) * (by - cy);
67222     const det = detleft - detright;
67223
67224     if (detleft === 0 || detright === 0 || (detleft > 0) !== (detright > 0)) return det;
67225
67226     const detsum = Math.abs(detleft + detright);
67227     if (Math.abs(det) >= ccwerrboundA * detsum) return det;
67228
67229     return -orient2dadapt(ax, ay, bx, by, cx, cy, detsum);
67230 }
67231
67232 /**
67233  * Signed area of the triangle (p0, p1, p2)
67234  * @param  {Array.<Number>} p0
67235  * @param  {Array.<Number>} p1
67236  * @param  {Array.<Number>} p2
67237  * @return {Number}
67238  */
67239 function signedArea(p0, p1, p2) {
67240   const res = orient2d(p0[0], p0[1], p1[0], p1[1], p2[0], p2[1]);
67241   if (res > 0) return -1;
67242   if (res < 0) return 1;
67243   return 0;
67244 }
67245
67246 /**
67247  * @param  {SweepEvent} e1
67248  * @param  {SweepEvent} e2
67249  * @return {Number}
67250  */
67251 function compareEvents(e1, e2) {
67252   const p1 = e1.point;
67253   const p2 = e2.point;
67254
67255   // Different x-coordinate
67256   if (p1[0] > p2[0]) return 1;
67257   if (p1[0] < p2[0]) return -1;
67258
67259   // Different points, but same x-coordinate
67260   // Event with lower y-coordinate is processed first
67261   if (p1[1] !== p2[1]) return p1[1] > p2[1] ? 1 : -1;
67262
67263   return specialCases(e1, e2, p1);
67264 }
67265
67266
67267 /* eslint-disable no-unused-vars */
67268 function specialCases(e1, e2, p1, p2) {
67269   // Same coordinates, but one is a left endpoint and the other is
67270   // a right endpoint. The right endpoint is processed first
67271   if (e1.left !== e2.left)
67272     return e1.left ? 1 : -1;
67273
67274   // const p2 = e1.otherEvent.point, p3 = e2.otherEvent.point;
67275   // const sa = (p1[0] - p3[0]) * (p2[1] - p3[1]) - (p2[0] - p3[0]) * (p1[1] - p3[1])
67276   // Same coordinates, both events
67277   // are left endpoints or right endpoints.
67278   // not collinear
67279   if (signedArea(p1, e1.otherEvent.point, e2.otherEvent.point) !== 0) {
67280     // the event associate to the bottom segment is processed first
67281     return (!e1.isBelow(e2.otherEvent.point)) ? 1 : -1;
67282   }
67283
67284   return (!e1.isSubject && e2.isSubject) ? 1 : -1;
67285 }
67286 /* eslint-enable no-unused-vars */
67287
67288 /**
67289  * @param  {SweepEvent} se
67290  * @param  {Array.<Number>} p
67291  * @param  {Queue} queue
67292  * @return {Queue}
67293  */
67294 function divideSegment(se, p, queue)  {
67295   const r = new SweepEvent(p, false, se,            se.isSubject);
67296   const l = new SweepEvent(p, true,  se.otherEvent, se.isSubject);
67297
67298   /* eslint-disable no-console */
67299   if (equals(se.point, se.otherEvent.point)) {
67300     console.warn('what is that, a collapsed segment?', se);
67301   }
67302   /* eslint-enable no-console */
67303
67304   r.contourId = l.contourId = se.contourId;
67305
67306   // avoid a rounding error. The left event would be processed after the right event
67307   if (compareEvents(l, se.otherEvent) > 0) {
67308     se.otherEvent.left = true;
67309     l.left = false;
67310   }
67311
67312   // avoid a rounding error. The left event would be processed after the right event
67313   // if (compareEvents(se, r) > 0) {}
67314
67315   se.otherEvent.otherEvent = l;
67316   se.otherEvent = r;
67317
67318   queue.push(l);
67319   queue.push(r);
67320
67321   return queue;
67322 }
67323
67324 //const EPS = 1e-9;
67325
67326 /**
67327  * Finds the magnitude of the cross product of two vectors (if we pretend
67328  * they're in three dimensions)
67329  *
67330  * @param {Object} a First vector
67331  * @param {Object} b Second vector
67332  * @private
67333  * @returns {Number} The magnitude of the cross product
67334  */
67335 function crossProduct(a, b) {
67336   return (a[0] * b[1]) - (a[1] * b[0]);
67337 }
67338
67339 /**
67340  * Finds the dot product of two vectors.
67341  *
67342  * @param {Object} a First vector
67343  * @param {Object} b Second vector
67344  * @private
67345  * @returns {Number} The dot product
67346  */
67347 function dotProduct(a, b) {
67348   return (a[0] * b[0]) + (a[1] * b[1]);
67349 }
67350
67351 /**
67352  * Finds the intersection (if any) between two line segments a and b, given the
67353  * line segments' end points a1, a2 and b1, b2.
67354  *
67355  * This algorithm is based on Schneider and Eberly.
67356  * http://www.cimec.org.ar/~ncalvo/Schneider_Eberly.pdf
67357  * Page 244.
67358  *
67359  * @param {Array.<Number>} a1 point of first line
67360  * @param {Array.<Number>} a2 point of first line
67361  * @param {Array.<Number>} b1 point of second line
67362  * @param {Array.<Number>} b2 point of second line
67363  * @param {Boolean=}       noEndpointTouch whether to skip single touchpoints
67364  *                                         (meaning connected segments) as
67365  *                                         intersections
67366  * @returns {Array.<Array.<Number>>|Null} If the lines intersect, the point of
67367  * intersection. If they overlap, the two end points of the overlapping segment.
67368  * Otherwise, null.
67369  */
67370 function intersection$1 (a1, a2, b1, b2, noEndpointTouch) {
67371   // The algorithm expects our lines in the form P + sd, where P is a point,
67372   // s is on the interval [0, 1], and d is a vector.
67373   // We are passed two points. P can be the first point of each pair. The
67374   // vector, then, could be thought of as the distance (in x and y components)
67375   // from the first point to the second point.
67376   // So first, let's make our vectors:
67377   const va = [a2[0] - a1[0], a2[1] - a1[1]];
67378   const vb = [b2[0] - b1[0], b2[1] - b1[1]];
67379   // We also define a function to convert back to regular point form:
67380
67381   /* eslint-disable arrow-body-style */
67382
67383   function toPoint(p, s, d) {
67384     return [
67385       p[0] + s * d[0],
67386       p[1] + s * d[1]
67387     ];
67388   }
67389
67390   /* eslint-enable arrow-body-style */
67391
67392   // The rest is pretty much a straight port of the algorithm.
67393   const e = [b1[0] - a1[0], b1[1] - a1[1]];
67394   let kross    = crossProduct(va, vb);
67395   let sqrKross = kross * kross;
67396   const sqrLenA  = dotProduct(va, va);
67397   //const sqrLenB  = dotProduct(vb, vb);
67398
67399   // Check for line intersection. This works because of the properties of the
67400   // cross product -- specifically, two vectors are parallel if and only if the
67401   // cross product is the 0 vector. The full calculation involves relative error
67402   // to account for possible very small line segments. See Schneider & Eberly
67403   // for details.
67404   if (sqrKross > 0/* EPS * sqrLenB * sqLenA */) {
67405     // If they're not parallel, then (because these are line segments) they
67406     // still might not actually intersect. This code checks that the
67407     // intersection point of the lines is actually on both line segments.
67408     const s = crossProduct(e, vb) / kross;
67409     if (s < 0 || s > 1) {
67410       // not on line segment a
67411       return null;
67412     }
67413     const t = crossProduct(e, va) / kross;
67414     if (t < 0 || t > 1) {
67415       // not on line segment b
67416       return null;
67417     }
67418     if (s === 0 || s === 1) {
67419       // on an endpoint of line segment a
67420       return noEndpointTouch ? null : [toPoint(a1, s, va)];
67421     }
67422     if (t === 0 || t === 1) {
67423       // on an endpoint of line segment b
67424       return noEndpointTouch ? null : [toPoint(b1, t, vb)];
67425     }
67426     return [toPoint(a1, s, va)];
67427   }
67428
67429   // If we've reached this point, then the lines are either parallel or the
67430   // same, but the segments could overlap partially or fully, or not at all.
67431   // So we need to find the overlap, if any. To do that, we can use e, which is
67432   // the (vector) difference between the two initial points. If this is parallel
67433   // with the line itself, then the two lines are the same line, and there will
67434   // be overlap.
67435   //const sqrLenE = dotProduct(e, e);
67436   kross = crossProduct(e, va);
67437   sqrKross = kross * kross;
67438
67439   if (sqrKross > 0 /* EPS * sqLenB * sqLenE */) {
67440   // Lines are just parallel, not the same. No overlap.
67441     return null;
67442   }
67443
67444   const sa = dotProduct(va, e) / sqrLenA;
67445   const sb = sa + dotProduct(va, vb) / sqrLenA;
67446   const smin = Math.min(sa, sb);
67447   const smax = Math.max(sa, sb);
67448
67449   // this is, essentially, the FindIntersection acting on floats from
67450   // Schneider & Eberly, just inlined into this function.
67451   if (smin <= 1 && smax >= 0) {
67452
67453     // overlap on an end point
67454     if (smin === 1) {
67455       return noEndpointTouch ? null : [toPoint(a1, smin > 0 ? smin : 0, va)];
67456     }
67457
67458     if (smax === 0) {
67459       return noEndpointTouch ? null : [toPoint(a1, smax < 1 ? smax : 1, va)];
67460     }
67461
67462     if (noEndpointTouch && smin === 0 && smax === 1) return null;
67463
67464     // There's overlap on a segment -- two points of intersection. Return both.
67465     return [
67466       toPoint(a1, smin > 0 ? smin : 0, va),
67467       toPoint(a1, smax < 1 ? smax : 1, va)
67468     ];
67469   }
67470
67471   return null;
67472 }
67473
67474 /**
67475  * @param  {SweepEvent} se1
67476  * @param  {SweepEvent} se2
67477  * @param  {Queue}      queue
67478  * @return {Number}
67479  */
67480 function possibleIntersection (se1, se2, queue) {
67481   // that disallows self-intersecting polygons,
67482   // did cost us half a day, so I'll leave it
67483   // out of respect
67484   // if (se1.isSubject === se2.isSubject) return;
67485   const inter = intersection$1(
67486     se1.point, se1.otherEvent.point,
67487     se2.point, se2.otherEvent.point
67488   );
67489
67490   const nintersections = inter ? inter.length : 0;
67491   if (nintersections === 0) return 0; // no intersection
67492
67493   // the line segments intersect at an endpoint of both line segments
67494   if ((nintersections === 1) &&
67495       (equals(se1.point, se2.point) ||
67496        equals(se1.otherEvent.point, se2.otherEvent.point))) {
67497     return 0;
67498   }
67499
67500   if (nintersections === 2 && se1.isSubject === se2.isSubject) {
67501     // if(se1.contourId === se2.contourId){
67502     // console.warn('Edges of the same polygon overlap',
67503     //   se1.point, se1.otherEvent.point, se2.point, se2.otherEvent.point);
67504     // }
67505     //throw new Error('Edges of the same polygon overlap');
67506     return 0;
67507   }
67508
67509   // The line segments associated to se1 and se2 intersect
67510   if (nintersections === 1) {
67511
67512     // if the intersection point is not an endpoint of se1
67513     if (!equals(se1.point, inter[0]) && !equals(se1.otherEvent.point, inter[0])) {
67514       divideSegment(se1, inter[0], queue);
67515     }
67516
67517     // if the intersection point is not an endpoint of se2
67518     if (!equals(se2.point, inter[0]) && !equals(se2.otherEvent.point, inter[0])) {
67519       divideSegment(se2, inter[0], queue);
67520     }
67521     return 1;
67522   }
67523
67524   // The line segments associated to se1 and se2 overlap
67525   const events        = [];
67526   let leftCoincide  = false;
67527   let rightCoincide = false;
67528
67529   if (equals(se1.point, se2.point)) {
67530     leftCoincide = true; // linked
67531   } else if (compareEvents(se1, se2) === 1) {
67532     events.push(se2, se1);
67533   } else {
67534     events.push(se1, se2);
67535   }
67536
67537   if (equals(se1.otherEvent.point, se2.otherEvent.point)) {
67538     rightCoincide = true;
67539   } else if (compareEvents(se1.otherEvent, se2.otherEvent) === 1) {
67540     events.push(se2.otherEvent, se1.otherEvent);
67541   } else {
67542     events.push(se1.otherEvent, se2.otherEvent);
67543   }
67544
67545   if ((leftCoincide && rightCoincide) || leftCoincide) {
67546     // both line segments are equal or share the left endpoint
67547     se2.type = NON_CONTRIBUTING;
67548     se1.type = (se2.inOut === se1.inOut)
67549       ? SAME_TRANSITION : DIFFERENT_TRANSITION;
67550
67551     if (leftCoincide && !rightCoincide) {
67552       // honestly no idea, but changing events selection from [2, 1]
67553       // to [0, 1] fixes the overlapping self-intersecting polygons issue
67554       divideSegment(events[1].otherEvent, events[0].point, queue);
67555     }
67556     return 2;
67557   }
67558
67559   // the line segments share the right endpoint
67560   if (rightCoincide) {
67561     divideSegment(events[0], events[1].point, queue);
67562     return 3;
67563   }
67564
67565   // no line segment includes totally the other one
67566   if (events[0] !== events[3].otherEvent) {
67567     divideSegment(events[0], events[1].point, queue);
67568     divideSegment(events[1], events[2].point, queue);
67569     return 3;
67570   }
67571
67572   // one line segment includes the other one
67573   divideSegment(events[0], events[1].point, queue);
67574   divideSegment(events[3].otherEvent, events[2].point, queue);
67575
67576   return 3;
67577 }
67578
67579 /**
67580  * @param  {SweepEvent} le1
67581  * @param  {SweepEvent} le2
67582  * @return {Number}
67583  */
67584 function compareSegments(le1, le2) {
67585   if (le1 === le2) return 0;
67586
67587   // Segments are not collinear
67588   if (signedArea(le1.point, le1.otherEvent.point, le2.point) !== 0 ||
67589     signedArea(le1.point, le1.otherEvent.point, le2.otherEvent.point) !== 0) {
67590
67591     // If they share their left endpoint use the right endpoint to sort
67592     if (equals(le1.point, le2.point)) return le1.isBelow(le2.otherEvent.point) ? -1 : 1;
67593
67594     // Different left endpoint: use the left endpoint to sort
67595     if (le1.point[0] === le2.point[0]) return le1.point[1] < le2.point[1] ? -1 : 1;
67596
67597     // has the line segment associated to e1 been inserted
67598     // into S after the line segment associated to e2 ?
67599     if (compareEvents(le1, le2) === 1) return le2.isAbove(le1.point) ? -1 : 1;
67600
67601     // The line segment associated to e2 has been inserted
67602     // into S after the line segment associated to e1
67603     return le1.isBelow(le2.point) ? -1 : 1;
67604   }
67605
67606   if (le1.isSubject === le2.isSubject) { // same polygon
67607     let p1 = le1.point, p2 = le2.point;
67608     if (p1[0] === p2[0] && p1[1] === p2[1]/*equals(le1.point, le2.point)*/) {
67609       p1 = le1.otherEvent.point; p2 = le2.otherEvent.point;
67610       if (p1[0] === p2[0] && p1[1] === p2[1]) return 0;
67611       else return le1.contourId > le2.contourId ? 1 : -1;
67612     }
67613   } else { // Segments are collinear, but belong to separate polygons
67614     return le1.isSubject ? -1 : 1;
67615   }
67616
67617   return compareEvents(le1, le2) === 1 ? 1 : -1;
67618 }
67619
67620 function subdivide(eventQueue, subject, clipping, sbbox, cbbox, operation) {
67621   const sweepLine = new SplayTree(compareSegments);
67622   const sortedEvents = [];
67623
67624   const rightbound = Math.min(sbbox[2], cbbox[2]);
67625
67626   let prev, next, begin;
67627
67628   while (eventQueue.length !== 0) {
67629     let event = eventQueue.pop();
67630     sortedEvents.push(event);
67631
67632     // optimization by bboxes for intersection and difference goes here
67633     if ((operation === INTERSECTION && event.point[0] > rightbound) ||
67634         (operation === DIFFERENCE   && event.point[0] > sbbox[2])) {
67635       break;
67636     }
67637
67638     if (event.left) {
67639       next  = prev = sweepLine.insert(event);
67640       begin = sweepLine.minNode();
67641
67642       if (prev !== begin) prev = sweepLine.prev(prev);
67643       else                prev = null;
67644
67645       next = sweepLine.next(next);
67646
67647       const prevEvent = prev ? prev.key : null;
67648       let prevprevEvent;
67649       computeFields(event, prevEvent, operation);
67650       if (next) {
67651         if (possibleIntersection(event, next.key, eventQueue) === 2) {
67652           computeFields(event, prevEvent, operation);
67653           computeFields(event, next.key, operation);
67654         }
67655       }
67656
67657       if (prev) {
67658         if (possibleIntersection(prev.key, event, eventQueue) === 2) {
67659           let prevprev = prev;
67660           if (prevprev !== begin) prevprev = sweepLine.prev(prevprev);
67661           else                    prevprev = null;
67662
67663           prevprevEvent = prevprev ? prevprev.key : null;
67664           computeFields(prevEvent, prevprevEvent, operation);
67665           computeFields(event,     prevEvent,     operation);
67666         }
67667       }
67668     } else {
67669       event = event.otherEvent;
67670       next = prev = sweepLine.find(event);
67671
67672       if (prev && next) {
67673
67674         if (prev !== begin) prev = sweepLine.prev(prev);
67675         else                prev = null;
67676
67677         next = sweepLine.next(next);
67678         sweepLine.remove(event);
67679
67680         if (next && prev) {
67681           possibleIntersection(prev.key, next.key, eventQueue);
67682         }
67683       }
67684     }
67685   }
67686   return sortedEvents;
67687 }
67688
67689 class Contour {
67690
67691   /**
67692    * Contour
67693    *
67694    * @class {Contour}
67695    */
67696   constructor() {
67697     this.points = [];
67698     this.holeIds = [];
67699     this.holeOf = null;
67700     this.depth = null;
67701   }
67702
67703   isExterior() {
67704     return this.holeOf == null;
67705   }
67706
67707 }
67708
67709 /**
67710  * @param  {Array.<SweepEvent>} sortedEvents
67711  * @return {Array.<SweepEvent>}
67712  */
67713 function orderEvents(sortedEvents) {
67714   let event, i, len, tmp;
67715   const resultEvents = [];
67716   for (i = 0, len = sortedEvents.length; i < len; i++) {
67717     event = sortedEvents[i];
67718     if ((event.left && event.inResult) ||
67719       (!event.left && event.otherEvent.inResult)) {
67720       resultEvents.push(event);
67721     }
67722   }
67723   // Due to overlapping edges the resultEvents array can be not wholly sorted
67724   let sorted = false;
67725   while (!sorted) {
67726     sorted = true;
67727     for (i = 0, len = resultEvents.length; i < len; i++) {
67728       if ((i + 1) < len &&
67729         compareEvents(resultEvents[i], resultEvents[i + 1]) === 1) {
67730         tmp = resultEvents[i];
67731         resultEvents[i] = resultEvents[i + 1];
67732         resultEvents[i + 1] = tmp;
67733         sorted = false;
67734       }
67735     }
67736   }
67737
67738
67739   for (i = 0, len = resultEvents.length; i < len; i++) {
67740     event = resultEvents[i];
67741     event.otherPos = i;
67742   }
67743
67744   // imagine, the right event is found in the beginning of the queue,
67745   // when his left counterpart is not marked yet
67746   for (i = 0, len = resultEvents.length; i < len; i++) {
67747     event = resultEvents[i];
67748     if (!event.left) {
67749       tmp = event.otherPos;
67750       event.otherPos = event.otherEvent.otherPos;
67751       event.otherEvent.otherPos = tmp;
67752     }
67753   }
67754
67755   return resultEvents;
67756 }
67757
67758
67759 /**
67760  * @param  {Number} pos
67761  * @param  {Array.<SweepEvent>} resultEvents
67762  * @param  {Object>}    processed
67763  * @return {Number}
67764  */
67765 function nextPos(pos, resultEvents, processed, origPos) {
67766   let newPos = pos + 1,
67767       p = resultEvents[pos].point,
67768       p1;
67769   const length = resultEvents.length;
67770
67771   if (newPos < length)
67772     p1 = resultEvents[newPos].point;
67773
67774   while (newPos < length && p1[0] === p[0] && p1[1] === p[1]) {
67775     if (!processed[newPos]) {
67776       return newPos;
67777     } else   {
67778       newPos++;
67779     }
67780     p1 = resultEvents[newPos].point;
67781   }
67782
67783   newPos = pos - 1;
67784
67785   while (processed[newPos] && newPos > origPos) {
67786     newPos--;
67787   }
67788
67789   return newPos;
67790 }
67791
67792
67793 function initializeContourFromContext(event, contours, contourId) {
67794   const contour = new Contour();
67795   if (event.prevInResult != null) {
67796     const prevInResult = event.prevInResult;
67797     // Note that it is valid to query the "previous in result" for its output contour id,
67798     // because we must have already processed it (i.e., assigned an output contour id)
67799     // in an earlier iteration, otherwise it wouldn't be possible that it is "previous in
67800     // result".
67801     const lowerContourId = prevInResult.outputContourId;
67802     const lowerResultTransition = prevInResult.resultTransition;
67803     if (lowerResultTransition > 0) {
67804       // We are inside. Now we have to check if the thing below us is another hole or
67805       // an exterior contour.
67806       const lowerContour = contours[lowerContourId];
67807       if (lowerContour.holeOf != null) {
67808         // The lower contour is a hole => Connect the new contour as a hole to its parent,
67809         // and use same depth.
67810         const parentContourId = lowerContour.holeOf;
67811         contours[parentContourId].holeIds.push(contourId);
67812         contour.holeOf = parentContourId;
67813         contour.depth = contours[lowerContourId].depth;
67814       } else {
67815         // The lower contour is an exterior contour => Connect the new contour as a hole,
67816         // and increment depth.
67817         contours[lowerContourId].holeIds.push(contourId);
67818         contour.holeOf = lowerContourId;
67819         contour.depth = contours[lowerContourId].depth + 1;
67820       }
67821     } else {
67822       // We are outside => this contour is an exterior contour of same depth.
67823       contour.holeOf = null;
67824       contour.depth = contours[lowerContourId].depth;
67825     }
67826   } else {
67827     // There is no lower/previous contour => this contour is an exterior contour of depth 0.
67828     contour.holeOf = null;
67829     contour.depth = 0;
67830   }
67831   return contour;
67832 }
67833
67834 /**
67835  * @param  {Array.<SweepEvent>} sortedEvents
67836  * @return {Array.<*>} polygons
67837  */
67838 function connectEdges(sortedEvents) {
67839   let i, len;
67840   const resultEvents = orderEvents(sortedEvents);
67841
67842   // "false"-filled array
67843   const processed = {};
67844   const contours = [];
67845
67846   for (i = 0, len = resultEvents.length; i < len; i++) {
67847
67848     if (processed[i]) {
67849       continue;
67850     }
67851
67852     const contourId = contours.length;
67853     const contour = initializeContourFromContext(resultEvents[i], contours, contourId);
67854
67855     // Helper function that combines marking an event as processed with assigning its output contour ID
67856     const markAsProcessed = (pos) => {
67857       processed[pos] = true;
67858       resultEvents[pos].outputContourId = contourId;
67859     };
67860
67861     let pos = i;
67862     let origPos = i;
67863
67864     const initial = resultEvents[i].point;
67865     contour.points.push(initial);
67866
67867     /* eslint no-constant-condition: "off" */
67868     while (true) {
67869       markAsProcessed(pos);
67870
67871       pos = resultEvents[pos].otherPos;
67872
67873       markAsProcessed(pos);
67874       contour.points.push(resultEvents[pos].point);
67875
67876       pos = nextPos(pos, resultEvents, processed, origPos);
67877
67878       if (pos == origPos) {
67879         break;
67880       }
67881     }
67882
67883     contours.push(contour);
67884   }
67885
67886   return contours;
67887 }
67888
67889 var tinyqueue = TinyQueue;
67890 var _default = TinyQueue;
67891
67892 function TinyQueue(data, compare) {
67893     if (!(this instanceof TinyQueue)) return new TinyQueue(data, compare);
67894
67895     this.data = data || [];
67896     this.length = this.data.length;
67897     this.compare = compare || defaultCompare;
67898
67899     if (this.length > 0) {
67900         for (var i = (this.length >> 1) - 1; i >= 0; i--) this._down(i);
67901     }
67902 }
67903
67904 function defaultCompare(a, b) {
67905     return a < b ? -1 : a > b ? 1 : 0;
67906 }
67907
67908 TinyQueue.prototype = {
67909
67910     push: function (item) {
67911         this.data.push(item);
67912         this.length++;
67913         this._up(this.length - 1);
67914     },
67915
67916     pop: function () {
67917         if (this.length === 0) return undefined;
67918
67919         var top = this.data[0];
67920         this.length--;
67921
67922         if (this.length > 0) {
67923             this.data[0] = this.data[this.length];
67924             this._down(0);
67925         }
67926         this.data.pop();
67927
67928         return top;
67929     },
67930
67931     peek: function () {
67932         return this.data[0];
67933     },
67934
67935     _up: function (pos) {
67936         var data = this.data;
67937         var compare = this.compare;
67938         var item = data[pos];
67939
67940         while (pos > 0) {
67941             var parent = (pos - 1) >> 1;
67942             var current = data[parent];
67943             if (compare(item, current) >= 0) break;
67944             data[pos] = current;
67945             pos = parent;
67946         }
67947
67948         data[pos] = item;
67949     },
67950
67951     _down: function (pos) {
67952         var data = this.data;
67953         var compare = this.compare;
67954         var halfLength = this.length >> 1;
67955         var item = data[pos];
67956
67957         while (pos < halfLength) {
67958             var left = (pos << 1) + 1;
67959             var right = left + 1;
67960             var best = data[left];
67961
67962             if (right < this.length && compare(data[right], best) < 0) {
67963                 left = right;
67964                 best = data[right];
67965             }
67966             if (compare(best, item) >= 0) break;
67967
67968             data[pos] = best;
67969             pos = left;
67970         }
67971
67972         data[pos] = item;
67973     }
67974 };
67975 tinyqueue.default = _default;
67976
67977 const max = Math.max;
67978 const min = Math.min;
67979
67980 let contourId = 0;
67981
67982
67983 function processPolygon(contourOrHole, isSubject, depth, Q, bbox, isExteriorRing) {
67984   let i, len, s1, s2, e1, e2;
67985   for (i = 0, len = contourOrHole.length - 1; i < len; i++) {
67986     s1 = contourOrHole[i];
67987     s2 = contourOrHole[i + 1];
67988     e1 = new SweepEvent(s1, false, undefined, isSubject);
67989     e2 = new SweepEvent(s2, false, e1,        isSubject);
67990     e1.otherEvent = e2;
67991
67992     if (s1[0] === s2[0] && s1[1] === s2[1]) {
67993       continue; // skip collapsed edges, or it breaks
67994     }
67995
67996     e1.contourId = e2.contourId = depth;
67997     if (!isExteriorRing) {
67998       e1.isExteriorRing = false;
67999       e2.isExteriorRing = false;
68000     }
68001     if (compareEvents(e1, e2) > 0) {
68002       e2.left = true;
68003     } else {
68004       e1.left = true;
68005     }
68006
68007     const x = s1[0], y = s1[1];
68008     bbox[0] = min(bbox[0], x);
68009     bbox[1] = min(bbox[1], y);
68010     bbox[2] = max(bbox[2], x);
68011     bbox[3] = max(bbox[3], y);
68012
68013     // Pushing it so the queue is sorted from left to right,
68014     // with object on the left having the highest priority.
68015     Q.push(e1);
68016     Q.push(e2);
68017   }
68018 }
68019
68020
68021 function fillQueue(subject, clipping, sbbox, cbbox, operation) {
68022   const eventQueue = new tinyqueue(null, compareEvents);
68023   let polygonSet, isExteriorRing, i, ii, j, jj; //, k, kk;
68024
68025   for (i = 0, ii = subject.length; i < ii; i++) {
68026     polygonSet = subject[i];
68027     for (j = 0, jj = polygonSet.length; j < jj; j++) {
68028       isExteriorRing = j === 0;
68029       if (isExteriorRing) contourId++;
68030       processPolygon(polygonSet[j], true, contourId, eventQueue, sbbox, isExteriorRing);
68031     }
68032   }
68033
68034   for (i = 0, ii = clipping.length; i < ii; i++) {
68035     polygonSet = clipping[i];
68036     for (j = 0, jj = polygonSet.length; j < jj; j++) {
68037       isExteriorRing = j === 0;
68038       if (operation === DIFFERENCE) isExteriorRing = false;
68039       if (isExteriorRing) contourId++;
68040       processPolygon(polygonSet[j], false, contourId, eventQueue, cbbox, isExteriorRing);
68041     }
68042   }
68043
68044   return eventQueue;
68045 }
68046
68047 const EMPTY = [];
68048
68049
68050 function trivialOperation(subject, clipping, operation) {
68051   let result = null;
68052   if (subject.length * clipping.length === 0) {
68053     if        (operation === INTERSECTION) {
68054       result = EMPTY;
68055     } else if (operation === DIFFERENCE) {
68056       result = subject;
68057     } else if (operation === UNION ||
68058                operation === XOR) {
68059       result = (subject.length === 0) ? clipping : subject;
68060     }
68061   }
68062   return result;
68063 }
68064
68065
68066 function compareBBoxes(subject, clipping, sbbox, cbbox, operation) {
68067   let result = null;
68068   if (sbbox[0] > cbbox[2] ||
68069       cbbox[0] > sbbox[2] ||
68070       sbbox[1] > cbbox[3] ||
68071       cbbox[1] > sbbox[3]) {
68072     if        (operation === INTERSECTION) {
68073       result = EMPTY;
68074     } else if (operation === DIFFERENCE) {
68075       result = subject;
68076     } else if (operation === UNION ||
68077                operation === XOR) {
68078       result = subject.concat(clipping);
68079     }
68080   }
68081   return result;
68082 }
68083
68084
68085 function boolean(subject, clipping, operation) {
68086   if (typeof subject[0][0][0] === 'number') {
68087     subject = [subject];
68088   }
68089   if (typeof clipping[0][0][0] === 'number') {
68090     clipping = [clipping];
68091   }
68092   let trivial = trivialOperation(subject, clipping, operation);
68093   if (trivial) {
68094     return trivial === EMPTY ? null : trivial;
68095   }
68096   const sbbox = [Infinity, Infinity, -Infinity, -Infinity];
68097   const cbbox = [Infinity, Infinity, -Infinity, -Infinity];
68098
68099   // console.time('fill queue');
68100   const eventQueue = fillQueue(subject, clipping, sbbox, cbbox, operation);
68101   //console.timeEnd('fill queue');
68102
68103   trivial = compareBBoxes(subject, clipping, sbbox, cbbox, operation);
68104   if (trivial) {
68105     return trivial === EMPTY ? null : trivial;
68106   }
68107   // console.time('subdivide edges');
68108   const sortedEvents = subdivide(eventQueue, subject, clipping, sbbox, cbbox, operation);
68109   //console.timeEnd('subdivide edges');
68110
68111   // console.time('connect vertices');
68112   const contours = connectEdges(sortedEvents);
68113   //console.timeEnd('connect vertices');
68114
68115   // Convert contours to polygons
68116   const polygons = [];
68117   for (let i = 0; i < contours.length; i++) {
68118     let contour = contours[i];
68119     if (contour.isExterior()) {
68120       // The exterior ring goes first
68121       let rings = [contour.points];
68122       // Followed by holes if any
68123       for (let j = 0; j < contour.holeIds.length; j++) {
68124         let holeId = contour.holeIds[j];
68125         rings.push(contours[holeId].points);
68126       }
68127       polygons.push(rings);
68128     }
68129   }
68130
68131   return polygons;
68132 }
68133
68134 function intersection (subject, clipping) {
68135   return boolean(subject, clipping, INTERSECTION);
68136 }
68137
68138 /**
68139  * @class VertexGeometry
68140  * @abstract
68141  * @classdesc Represents a vertex geometry.
68142  */
68143 class VertexGeometry extends Geometry {
68144     /**
68145      * Create a vertex geometry.
68146      *
68147      * @constructor
68148      * @ignore
68149      */
68150     constructor() {
68151         super();
68152         this._subsampleThreshold = 0.005;
68153     }
68154     /**
68155      * Finds the polygon pole of inaccessibility, the most distant internal
68156      * point from the polygon outline.
68157      *
68158      * @param {Array<Array<number>>} points2d - 2d points of outline to triangulate.
68159      * @returns {Array<number>} Point of inaccessibility.
68160      * @ignore
68161      */
68162     _getPoleOfInaccessibility2d(points2d) {
68163         let pole2d = polylabel_1([points2d], 3e-2);
68164         return pole2d;
68165     }
68166     _project(points2d, transform) {
68167         const camera = this._createCamera(transform.upVector().toArray(), transform.unprojectSfM([0, 0], 0), transform.unprojectSfM([0, 0], 10));
68168         return this._deunproject(points2d, transform, camera);
68169     }
68170     _subsample(points2d, threshold = this._subsampleThreshold) {
68171         const subsampled = [];
68172         const length = points2d.length;
68173         for (let index = 0; index < length; index++) {
68174             const p1 = points2d[index];
68175             const p2 = points2d[(index + 1) % length];
68176             subsampled.push(p1);
68177             const dist = Math.sqrt(Math.pow((p2[0] - p1[0]), 2) + Math.pow((p2[1] - p1[1]), 2));
68178             const subsamples = Math.floor(dist / threshold);
68179             const coeff = 1 / (subsamples + 1);
68180             for (let i = 1; i <= subsamples; i++) {
68181                 const alpha = i * coeff;
68182                 const subsample = [
68183                     (1 - alpha) * p1[0] + alpha * p2[0],
68184                     (1 - alpha) * p1[1] + alpha * p2[1],
68185                 ];
68186                 subsampled.push(subsample);
68187             }
68188         }
68189         return subsampled;
68190     }
68191     /**
68192      * Triangulates a 2d polygon and returns the triangle
68193      * representation as a flattened array of 3d points.
68194      *
68195      * @param {Array<Array<number>>} points2d - 2d points of outline to triangulate.
68196      * @param {Array<Array<number>>} points3d - 3d points of outline corresponding to the 2d points.
68197      * @param {Array<Array<Array<number>>>} [holes2d] - 2d points of holes to triangulate.
68198      * @param {Array<Array<Array<number>>>} [holes3d] - 3d points of holes corresponding to the 2d points.
68199      * @returns {Array<number>} Flattened array of 3d points ordered based on the triangles.
68200      * @ignore
68201      */
68202     _triangulate(points2d, points3d, holes2d, holes3d) {
68203         let data = [points2d.slice(0, -1)];
68204         for (let hole2d of holes2d != null ? holes2d : []) {
68205             data.push(hole2d.slice(0, -1));
68206         }
68207         let points = points3d.slice(0, -1);
68208         for (let hole3d of holes3d != null ? holes3d : []) {
68209             points = points.concat(hole3d.slice(0, -1));
68210         }
68211         let flattened = earcut_1.flatten(data);
68212         let indices = earcut_1(flattened.vertices, flattened.holes, flattened.dimensions);
68213         let triangles = [];
68214         for (let i = 0; i < indices.length; ++i) {
68215             let point = points[indices[i]];
68216             triangles.push(point[0]);
68217             triangles.push(point[1]);
68218             triangles.push(point[2]);
68219         }
68220         return triangles;
68221     }
68222     _triangulateSpherical(points2d, holes2d, transform) {
68223         const triangles = [];
68224         const epsilon = 1e-9;
68225         const subareasX = 3;
68226         const subareasY = 3;
68227         for (let x = 0; x < subareasX; x++) {
68228             for (let y = 0; y < subareasY; y++) {
68229                 const epsilonX0 = x === 0 ? -epsilon : epsilon;
68230                 const epsilonY0 = y === 0 ? -epsilon : epsilon;
68231                 const x0 = x / subareasX + epsilonX0;
68232                 const y0 = y / subareasY + epsilonY0;
68233                 const x1 = (x + 1) / subareasX + epsilon;
68234                 const y1 = (y + 1) / subareasY + epsilon;
68235                 const bbox2d = [
68236                     [x0, y0],
68237                     [x0, y1],
68238                     [x1, y1],
68239                     [x1, y0],
68240                     [x0, y0],
68241                 ];
68242                 const lookat2d = [
68243                     (2 * x + 1) / (2 * subareasX),
68244                     (2 * y + 1) / (2 * subareasY),
68245                 ];
68246                 triangles.push(...this._triangulateSubarea(points2d, holes2d, bbox2d, lookat2d, transform));
68247             }
68248         }
68249         return triangles;
68250     }
68251     _unproject(points2d, transform, distance = 200) {
68252         return points2d
68253             .map((point) => {
68254             return transform.unprojectBasic(point, distance);
68255         });
68256     }
68257     _createCamera(upVector, position, lookAt) {
68258         const camera = new Camera$1();
68259         camera.up.copy(new Vector3().fromArray(upVector));
68260         camera.position.copy(new Vector3().fromArray(position));
68261         camera.lookAt(new Vector3().fromArray(lookAt));
68262         camera.updateMatrix();
68263         camera.updateMatrixWorld(true);
68264         return camera;
68265     }
68266     _deunproject(points2d, transform, camera) {
68267         return points2d
68268             .map((point2d) => {
68269             const pointWorld = transform.unprojectBasic(point2d, 10000);
68270             const pointCamera = new Vector3(pointWorld[0], pointWorld[1], pointWorld[2])
68271                 .applyMatrix4(camera.matrixWorldInverse);
68272             return [pointCamera.x / pointCamera.z, pointCamera.y / pointCamera.z];
68273         });
68274     }
68275     _triangulateSubarea(points2d, holes2d, bbox2d, lookat2d, transform) {
68276         const intersections = intersection([points2d, ...holes2d], [bbox2d]);
68277         if (!intersections) {
68278             return [];
68279         }
68280         const triangles = [];
68281         const threshold = this._subsampleThreshold;
68282         const camera = this._createCamera(transform.upVector().toArray(), transform.unprojectSfM([0, 0], 0), transform.unprojectBasic(lookat2d, 10));
68283         for (const intersection of intersections) {
68284             const subsampledPolygon2d = this._subsample(intersection[0], threshold);
68285             const polygon2d = this._deunproject(subsampledPolygon2d, transform, camera);
68286             const polygon3d = this._unproject(subsampledPolygon2d, transform);
68287             const polygonHoles2d = [];
68288             const polygonHoles3d = [];
68289             for (let i = 1; i < intersection.length; i++) {
68290                 let subsampledHole2d = this._subsample(intersection[i], threshold);
68291                 const hole2d = this._deunproject(subsampledHole2d, transform, camera);
68292                 const hole3d = this._unproject(subsampledHole2d, transform);
68293                 polygonHoles2d.push(hole2d);
68294                 polygonHoles3d.push(hole3d);
68295             }
68296             triangles.push(...this._triangulate(polygon2d, polygon3d, polygonHoles2d, polygonHoles3d));
68297         }
68298         return triangles;
68299     }
68300 }
68301
68302 /**
68303  * @class RectGeometry
68304  *
68305  * @classdesc Represents a rectangle geometry in the 2D basic image coordinate system.
68306  *
68307  * @example
68308  * ```js
68309  * var basicRect = [0.5, 0.3, 0.7, 0.4];
68310  * var rectGeometry = new RectGeometry(basicRect);
68311  * ```
68312  */
68313 class RectGeometry extends VertexGeometry {
68314     /**
68315      * Create a rectangle geometry.
68316      *
68317      * @constructor
68318      * @param {Array<number>} rect - An array representing the top-left and bottom-right
68319      * corners of the rectangle in basic coordinates. Ordered according to [x0, y0, x1, y1].
68320      *
68321      * @throws {GeometryTagError} Rectangle coordinates must be valid basic coordinates.
68322      */
68323     constructor(rect) {
68324         super();
68325         if (rect.length !== 4) {
68326             throw new GeometryTagError("Rectangle needs to have four values.");
68327         }
68328         if (rect[1] > rect[3]) {
68329             throw new GeometryTagError("Basic Y coordinates values can not be inverted.");
68330         }
68331         for (let coord of rect) {
68332             if (coord < 0 || coord > 1) {
68333                 throw new GeometryTagError("Basic coordinates must be on the interval [0, 1].");
68334             }
68335         }
68336         this._anchorIndex = undefined;
68337         this._rect = rect.slice(0, 4);
68338         this._inverted = this._rect[0] > this._rect[2];
68339     }
68340     /**
68341      * Get anchor index property.
68342      *
68343      * @returns {number} Index representing the current anchor property if
68344      * achoring indexing has been initialized. If anchor indexing has not been
68345      * initialized or has been terminated undefined will be returned.
68346      * @ignore
68347      */
68348     get anchorIndex() {
68349         return this._anchorIndex;
68350     }
68351     /**
68352      * Get inverted property.
68353      *
68354      * @returns {boolean} Boolean determining whether the rect geometry is
68355      * inverted. For spherical the rect geometrye may be inverted.
68356      * @ignore
68357      */
68358     get inverted() {
68359         return this._inverted;
68360     }
68361     /**
68362      * Get rect property.
68363      *
68364      * @returns {Array<number>} Array representing the top-left and bottom-right
68365      * corners of the rectangle in basic coordinates.
68366      */
68367     get rect() {
68368         return this._rect;
68369     }
68370     /**
68371      * Initialize anchor indexing to enable setting opposite vertex.
68372      *
68373      * @param {number} [index] - The index of the vertex to use as anchor.
68374      *
68375      * @throws {GeometryTagError} If anchor indexing has already been initialized.
68376      * @throws {GeometryTagError} If index is not valid (0 to 3).
68377      * @ignore
68378      */
68379     initializeAnchorIndexing(index) {
68380         if (this._anchorIndex !== undefined) {
68381             throw new GeometryTagError("Anchor indexing is already initialized.");
68382         }
68383         if (index < 0 || index > 3) {
68384             throw new GeometryTagError(`Invalid anchor index: ${index}.`);
68385         }
68386         this._anchorIndex = index === undefined ? 0 : index;
68387     }
68388     /**
68389      * Terminate anchor indexing to disable setting pposite vertex.
68390      * @ignore
68391      */
68392     terminateAnchorIndexing() {
68393         this._anchorIndex = undefined;
68394     }
68395     /**
68396      * Set the value of the vertex opposite to the anchor in the polygon
68397      * representation of the rectangle.
68398      *
68399      * @description Setting the opposite vertex may change the anchor index.
68400      *
68401      * @param {Array<number>} opposite - The new value of the vertex opposite to the anchor.
68402      * @param {Transform} transform - The transform of the image related to the rectangle.
68403      *
68404      * @throws {GeometryTagError} When anchor indexing has not been initialized.
68405      * @ignore
68406      */
68407     setOppositeVertex2d(opposite, transform) {
68408         if (this._anchorIndex === undefined) {
68409             throw new GeometryTagError("Anchor indexing needs to be initialized.");
68410         }
68411         const changed = [
68412             Math.max(0, Math.min(1, opposite[0])),
68413             Math.max(0, Math.min(1, opposite[1])),
68414         ];
68415         const original = this._rect.slice();
68416         const anchor = this._anchorIndex === 0 ? [original[0], original[3]] :
68417             this._anchorIndex === 1 ? [original[0], original[1]] :
68418                 this._anchorIndex === 2 ? [original[2], original[1]] :
68419                     [original[2], original[3]];
68420         if (isSpherical(transform.cameraType)) {
68421             const deltaX = this._anchorIndex < 2 ?
68422                 changed[0] - original[2] :
68423                 changed[0] - original[0];
68424             if (!this._inverted && this._anchorIndex < 2 && changed[0] < 0.25 && original[2] > 0.75 && deltaX < -0.5) {
68425                 // right side passes boundary rightward
68426                 this._inverted = true;
68427                 this._anchorIndex = anchor[1] > changed[1] ? 0 : 1;
68428             }
68429             else if (!this._inverted && this._anchorIndex >= 2 && changed[0] < 0.25 && original[2] > 0.75 && deltaX < -0.5) {
68430                 // left side passes right side and boundary rightward
68431                 this._inverted = true;
68432                 this._anchorIndex = anchor[1] > changed[1] ? 0 : 1;
68433             }
68434             else if (this._inverted && this._anchorIndex >= 2 && changed[0] < 0.25 && original[0] > 0.75 && deltaX < -0.5) {
68435                 this._inverted = false;
68436                 if (anchor[0] > changed[0]) {
68437                     // left side passes boundary rightward
68438                     this._anchorIndex = anchor[1] > changed[1] ? 3 : 2;
68439                 }
68440                 else {
68441                     // left side passes right side and boundary rightward
68442                     this._anchorIndex = anchor[1] > changed[1] ? 0 : 1;
68443                 }
68444             }
68445             else if (!this._inverted && this._anchorIndex >= 2 && changed[0] > 0.75 && original[0] < 0.25 && deltaX > 0.5) {
68446                 // left side passes boundary leftward
68447                 this._inverted = true;
68448                 this._anchorIndex = anchor[1] > changed[1] ? 3 : 2;
68449             }
68450             else if (!this._inverted && this._anchorIndex < 2 && changed[0] > 0.75 && original[0] < 0.25 && deltaX > 0.5) {
68451                 // right side passes left side and boundary leftward
68452                 this._inverted = true;
68453                 this._anchorIndex = anchor[1] > changed[1] ? 3 : 2;
68454             }
68455             else if (this._inverted && this._anchorIndex < 2 && changed[0] > 0.75 && original[2] < 0.25 && deltaX > 0.5) {
68456                 this._inverted = false;
68457                 if (anchor[0] > changed[0]) {
68458                     // right side passes boundary leftward
68459                     this._anchorIndex = anchor[1] > changed[1] ? 3 : 2;
68460                 }
68461                 else {
68462                     // right side passes left side and boundary leftward
68463                     this._anchorIndex = anchor[1] > changed[1] ? 0 : 1;
68464                 }
68465             }
68466             else if (this._inverted && this._anchorIndex < 2 && changed[0] > original[0]) {
68467                 // inverted and right side passes left side completing a loop
68468                 this._inverted = false;
68469                 this._anchorIndex = anchor[1] > changed[1] ? 0 : 1;
68470             }
68471             else if (this._inverted && this._anchorIndex >= 2 && changed[0] < original[2]) {
68472                 // inverted and left side passes right side completing a loop
68473                 this._inverted = false;
68474                 this._anchorIndex = anchor[1] > changed[1] ? 3 : 2;
68475             }
68476             else if (this._inverted) {
68477                 // if still inverted only top and bottom can switch
68478                 if (this._anchorIndex < 2) {
68479                     this._anchorIndex = anchor[1] > changed[1] ? 0 : 1;
68480                 }
68481                 else {
68482                     this._anchorIndex = anchor[1] > changed[1] ? 3 : 2;
68483                 }
68484             }
68485             else {
68486                 // if still not inverted treat as non spherical
68487                 if (anchor[0] <= changed[0] && anchor[1] > changed[1]) {
68488                     this._anchorIndex = 0;
68489                 }
68490                 else if (anchor[0] <= changed[0] && anchor[1] <= changed[1]) {
68491                     this._anchorIndex = 1;
68492                 }
68493                 else if (anchor[0] > changed[0] && anchor[1] <= changed[1]) {
68494                     this._anchorIndex = 2;
68495                 }
68496                 else {
68497                     this._anchorIndex = 3;
68498                 }
68499             }
68500             const rect = [];
68501             if (this._anchorIndex === 0) {
68502                 rect[0] = anchor[0];
68503                 rect[1] = changed[1];
68504                 rect[2] = changed[0];
68505                 rect[3] = anchor[1];
68506             }
68507             else if (this._anchorIndex === 1) {
68508                 rect[0] = anchor[0];
68509                 rect[1] = anchor[1];
68510                 rect[2] = changed[0];
68511                 rect[3] = changed[1];
68512             }
68513             else if (this._anchorIndex === 2) {
68514                 rect[0] = changed[0];
68515                 rect[1] = anchor[1];
68516                 rect[2] = anchor[0];
68517                 rect[3] = changed[1];
68518             }
68519             else {
68520                 rect[0] = changed[0];
68521                 rect[1] = changed[1];
68522                 rect[2] = anchor[0];
68523                 rect[3] = anchor[1];
68524             }
68525             if (!this._inverted && rect[0] > rect[2] ||
68526                 this._inverted && rect[0] < rect[2]) {
68527                 rect[0] = original[0];
68528                 rect[2] = original[2];
68529             }
68530             if (rect[1] > rect[3]) {
68531                 rect[1] = original[1];
68532                 rect[3] = original[3];
68533             }
68534             this._rect[0] = rect[0];
68535             this._rect[1] = rect[1];
68536             this._rect[2] = rect[2];
68537             this._rect[3] = rect[3];
68538         }
68539         else {
68540             if (anchor[0] <= changed[0] && anchor[1] > changed[1]) {
68541                 this._anchorIndex = 0;
68542             }
68543             else if (anchor[0] <= changed[0] && anchor[1] <= changed[1]) {
68544                 this._anchorIndex = 1;
68545             }
68546             else if (anchor[0] > changed[0] && anchor[1] <= changed[1]) {
68547                 this._anchorIndex = 2;
68548             }
68549             else {
68550                 this._anchorIndex = 3;
68551             }
68552             const rect = [];
68553             if (this._anchorIndex === 0) {
68554                 rect[0] = anchor[0];
68555                 rect[1] = changed[1];
68556                 rect[2] = changed[0];
68557                 rect[3] = anchor[1];
68558             }
68559             else if (this._anchorIndex === 1) {
68560                 rect[0] = anchor[0];
68561                 rect[1] = anchor[1];
68562                 rect[2] = changed[0];
68563                 rect[3] = changed[1];
68564             }
68565             else if (this._anchorIndex === 2) {
68566                 rect[0] = changed[0];
68567                 rect[1] = anchor[1];
68568                 rect[2] = anchor[0];
68569                 rect[3] = changed[1];
68570             }
68571             else {
68572                 rect[0] = changed[0];
68573                 rect[1] = changed[1];
68574                 rect[2] = anchor[0];
68575                 rect[3] = anchor[1];
68576             }
68577             if (rect[0] > rect[2]) {
68578                 rect[0] = original[0];
68579                 rect[2] = original[2];
68580             }
68581             if (rect[1] > rect[3]) {
68582                 rect[1] = original[1];
68583                 rect[3] = original[3];
68584             }
68585             this._rect[0] = rect[0];
68586             this._rect[1] = rect[1];
68587             this._rect[2] = rect[2];
68588             this._rect[3] = rect[3];
68589         }
68590         this._notifyChanged$.next(this);
68591     }
68592     /**
68593      * Set the value of a vertex in the polygon representation of the rectangle.
68594      *
68595      * @description The polygon is defined to have the first vertex at the
68596      * bottom-left corner with the rest of the vertices following in clockwise order.
68597      *
68598      * @param {number} index - The index of the vertex to be set.
68599      * @param {Array<number>} value - The new value of the vertex.
68600      * @param {Transform} transform - The transform of the image related to the rectangle.
68601      * @ignore
68602      */
68603     setVertex2d(index, value, transform) {
68604         let original = this._rect.slice();
68605         let changed = [
68606             Math.max(0, Math.min(1, value[0])),
68607             Math.max(0, Math.min(1, value[1])),
68608         ];
68609         let rect = [];
68610         if (index === 0) {
68611             rect[0] = changed[0];
68612             rect[1] = original[1];
68613             rect[2] = original[2];
68614             rect[3] = changed[1];
68615         }
68616         else if (index === 1) {
68617             rect[0] = changed[0];
68618             rect[1] = changed[1];
68619             rect[2] = original[2];
68620             rect[3] = original[3];
68621         }
68622         else if (index === 2) {
68623             rect[0] = original[0];
68624             rect[1] = changed[1];
68625             rect[2] = changed[0];
68626             rect[3] = original[3];
68627         }
68628         else if (index === 3) {
68629             rect[0] = original[0];
68630             rect[1] = original[1];
68631             rect[2] = changed[0];
68632             rect[3] = changed[1];
68633         }
68634         if (isSpherical(transform.cameraType)) {
68635             let passingBoundaryLeftward = index < 2 && changed[0] > 0.75 && original[0] < 0.25 ||
68636                 index >= 2 && this._inverted && changed[0] > 0.75 && original[2] < 0.25;
68637             let passingBoundaryRightward = index < 2 && this._inverted && changed[0] < 0.25 && original[0] > 0.75 ||
68638                 index >= 2 && changed[0] < 0.25 && original[2] > 0.75;
68639             if (passingBoundaryLeftward || passingBoundaryRightward) {
68640                 this._inverted = !this._inverted;
68641             }
68642             else {
68643                 if (rect[0] - original[0] < -0.25) {
68644                     rect[0] = original[0];
68645                 }
68646                 if (rect[2] - original[2] > 0.25) {
68647                     rect[2] = original[2];
68648                 }
68649             }
68650             if (!this._inverted && rect[0] > rect[2] ||
68651                 this._inverted && rect[0] < rect[2]) {
68652                 rect[0] = original[0];
68653                 rect[2] = original[2];
68654             }
68655         }
68656         else {
68657             if (rect[0] > rect[2]) {
68658                 rect[0] = original[0];
68659                 rect[2] = original[2];
68660             }
68661         }
68662         if (rect[1] > rect[3]) {
68663             rect[1] = original[1];
68664             rect[3] = original[3];
68665         }
68666         this._rect[0] = rect[0];
68667         this._rect[1] = rect[1];
68668         this._rect[2] = rect[2];
68669         this._rect[3] = rect[3];
68670         this._notifyChanged$.next(this);
68671     }
68672     /** @ignore */
68673     setCentroid2d(value, transform) {
68674         let original = this._rect.slice();
68675         let x0 = original[0];
68676         let x1 = this._inverted ? original[2] + 1 : original[2];
68677         let y0 = original[1];
68678         let y1 = original[3];
68679         let centerX = x0 + (x1 - x0) / 2;
68680         let centerY = y0 + (y1 - y0) / 2;
68681         let translationX = 0;
68682         if (isSpherical(transform.cameraType)) {
68683             translationX = this._inverted ? value[0] + 1 - centerX : value[0] - centerX;
68684         }
68685         else {
68686             let minTranslationX = -x0;
68687             let maxTranslationX = 1 - x1;
68688             translationX = Math.max(minTranslationX, Math.min(maxTranslationX, value[0] - centerX));
68689         }
68690         let minTranslationY = -y0;
68691         let maxTranslationY = 1 - y1;
68692         let translationY = Math.max(minTranslationY, Math.min(maxTranslationY, value[1] - centerY));
68693         this._rect[0] = original[0] + translationX;
68694         this._rect[1] = original[1] + translationY;
68695         this._rect[2] = original[2] + translationX;
68696         this._rect[3] = original[3] + translationY;
68697         if (this._rect[0] < 0) {
68698             this._rect[0] += 1;
68699             this._inverted = !this._inverted;
68700         }
68701         else if (this._rect[0] > 1) {
68702             this._rect[0] -= 1;
68703             this._inverted = !this._inverted;
68704         }
68705         if (this._rect[2] < 0) {
68706             this._rect[2] += 1;
68707             this._inverted = !this._inverted;
68708         }
68709         else if (this._rect[2] > 1) {
68710             this._rect[2] -= 1;
68711             this._inverted = !this._inverted;
68712         }
68713         this._notifyChanged$.next(this);
68714     }
68715     /**
68716      * Get the 3D coordinates for the vertices of the rectangle with
68717      * interpolated points along the lines.
68718      *
68719      * @param {Transform} transform - The transform of the image related to
68720      * the rectangle.
68721      * @returns {Array<Array<number>>} Polygon array of 3D world coordinates
68722      * representing the rectangle.
68723      * @ignore
68724      */
68725     getPoints3d(transform) {
68726         return this._getPoints2d()
68727             .map((point) => {
68728             return transform.unprojectBasic(point, 200);
68729         });
68730     }
68731     /**
68732      * Get the coordinates of a vertex from the polygon representation of the geometry.
68733      *
68734      * @description The first vertex represents the bottom-left corner with the rest of
68735      * the vertices following in clockwise order. The method shifts the right side
68736      * coordinates of the rectangle by one unit to ensure that the vertices are ordered
68737      * clockwise.
68738      *
68739      * @param {number} index - Vertex index.
68740      * @returns {Array<number>} Array representing the 2D basic coordinates of the vertex.
68741      * @ignore
68742      */
68743     getVertex2d(index) {
68744         return this._rectToVertices2d(this._rect)[index];
68745     }
68746     /**
68747      * Get the coordinates of a vertex from the polygon representation of the geometry.
68748      *
68749      * @description The first vertex represents the bottom-left corner with the rest of
68750      * the vertices following in clockwise order. The coordinates will not be shifted
68751      * so they may not appear in clockwise order when layed out on the plane.
68752      *
68753      * @param {number} index - Vertex index.
68754      * @returns {Array<number>} Array representing the 2D basic coordinates of the vertex.
68755      * @ignore
68756      */
68757     getNonAdjustedVertex2d(index) {
68758         return this._rectToNonAdjustedVertices2d(this._rect)[index];
68759     }
68760     /**
68761      * Get a vertex from the polygon representation of the 3D coordinates for the
68762      * vertices of the geometry.
68763      *
68764      * @description The first vertex represents the bottom-left corner with the rest of
68765      * the vertices following in clockwise order.
68766      *
68767      * @param {number} index - Vertex index.
68768      * @param {Transform} transform - The transform of the image related to the geometry.
68769      * @returns {Array<Array<number>>} Polygon array of 3D world coordinates representing
68770      * the vertices of the geometry.
68771      * @ignore
68772      */
68773     getVertex3d(index, transform) {
68774         return transform.unprojectBasic(this._rectToVertices2d(this._rect)[index], 200);
68775     }
68776     /**
68777      * Get a polygon representation of the 2D basic coordinates for the vertices of the rectangle.
68778      *
68779      * @description The first vertex represents the bottom-left corner with the rest of
68780      * the vertices following in clockwise order.
68781      *
68782      * @returns {Array<Array<number>>} Polygon array of 2D basic coordinates representing
68783      * the rectangle vertices.
68784      * @ignore
68785      */
68786     getVertices2d() {
68787         return this._rectToVertices2d(this._rect);
68788     }
68789     /**
68790      * Get a polygon representation of the 3D coordinates for the vertices of the rectangle.
68791      *
68792      * @description The first vertex represents the bottom-left corner with the rest of
68793      * the vertices following in clockwise order.
68794      *
68795      * @param {Transform} transform - The transform of the image related to the rectangle.
68796      * @returns {Array<Array<number>>} Polygon array of 3D world coordinates representing
68797      * the rectangle vertices.
68798      * @ignore
68799      */
68800     getVertices3d(transform) {
68801         return this._rectToVertices2d(this._rect)
68802             .map((vertex) => {
68803             return transform.unprojectBasic(vertex, 200);
68804         });
68805     }
68806     /** @ignore */
68807     getCentroid2d() {
68808         const rect = this._rect;
68809         const x0 = rect[0];
68810         const x1 = this._inverted ? rect[2] + 1 : rect[2];
68811         const y0 = rect[1];
68812         const y1 = rect[3];
68813         const centroidX = (x0 + x1) / 2;
68814         const centroidY = (y0 + y1) / 2;
68815         return [centroidX, centroidY];
68816     }
68817     /** @ignore */
68818     getCentroid3d(transform) {
68819         const centroid2d = this.getCentroid2d();
68820         return transform.unprojectBasic(centroid2d, 200);
68821     }
68822     /**
68823      * @ignore
68824      */
68825     getPoleOfInaccessibility2d() {
68826         return this._getPoleOfInaccessibility2d(this._rectToVertices2d(this._rect));
68827     }
68828     /** @ignore */
68829     getPoleOfInaccessibility3d(transform) {
68830         let pole2d = this._getPoleOfInaccessibility2d(this._rectToVertices2d(this._rect));
68831         return transform.unprojectBasic(pole2d, 200);
68832     }
68833     /** @ignore */
68834     getTriangles3d(transform) {
68835         return isSpherical(transform.cameraType) ?
68836             [] :
68837             this._triangulate(this._project(this._getPoints2d(), transform), this.getPoints3d(transform));
68838     }
68839     /**
68840      * Check if a particular bottom-right value is valid according to the current
68841      * rectangle coordinates.
68842      *
68843      * @param {Array<number>} bottomRight - The bottom-right coordinates to validate
68844      * @returns {boolean} Value indicating whether the provided bottom-right coordinates
68845      * are valid.
68846      * @ignore
68847      */
68848     validate(bottomRight) {
68849         let rect = this._rect;
68850         if (!this._inverted && bottomRight[0] < rect[0] ||
68851             bottomRight[0] - rect[2] > 0.25 ||
68852             bottomRight[1] < rect[1]) {
68853             return false;
68854         }
68855         return true;
68856     }
68857     /**
68858      * Get the 2D coordinates for the vertices of the rectangle with
68859      * interpolated points along the lines.
68860      *
68861      * @returns {Array<Array<number>>} Polygon array of 2D basic coordinates
68862      * representing the rectangle.
68863      */
68864     _getPoints2d() {
68865         let vertices2d = this._rectToVertices2d(this._rect);
68866         let sides = vertices2d.length - 1;
68867         let sections = 10;
68868         let points2d = [];
68869         for (let i = 0; i < sides; ++i) {
68870             let startX = vertices2d[i][0];
68871             let startY = vertices2d[i][1];
68872             let endX = vertices2d[i + 1][0];
68873             let endY = vertices2d[i + 1][1];
68874             let intervalX = (endX - startX) / (sections - 1);
68875             let intervalY = (endY - startY) / (sections - 1);
68876             for (let j = 0; j < sections; ++j) {
68877                 let point = [
68878                     startX + j * intervalX,
68879                     startY + j * intervalY,
68880                 ];
68881                 points2d.push(point);
68882             }
68883         }
68884         return points2d;
68885     }
68886     /**
68887      * Convert the top-left, bottom-right representation of a rectangle to a polygon
68888      * representation of the vertices starting at the bottom-left corner going
68889      * clockwise.
68890      *
68891      * @description The method shifts the right side coordinates of the rectangle
68892      * by one unit to ensure that the vertices are ordered clockwise.
68893      *
68894      * @param {Array<number>} rect - Top-left, bottom-right representation of a
68895      * rectangle.
68896      * @returns {Array<Array<number>>} Polygon representation of the vertices of the
68897      * rectangle.
68898      */
68899     _rectToVertices2d(rect) {
68900         return [
68901             [rect[0], rect[3]],
68902             [rect[0], rect[1]],
68903             [this._inverted ? rect[2] + 1 : rect[2], rect[1]],
68904             [this._inverted ? rect[2] + 1 : rect[2], rect[3]],
68905             [rect[0], rect[3]],
68906         ];
68907     }
68908     /**
68909      * Convert the top-left, bottom-right representation of a rectangle to a polygon
68910      * representation of the vertices starting at the bottom-left corner going
68911      * clockwise.
68912      *
68913      * @description The first vertex represents the bottom-left corner with the rest of
68914      * the vertices following in clockwise order. The coordinates will not be shifted
68915      * to ensure that the vertices are ordered clockwise when layed out on the plane.
68916      *
68917      * @param {Array<number>} rect - Top-left, bottom-right representation of a
68918      * rectangle.
68919      * @returns {Array<Array<number>>} Polygon representation of the vertices of the
68920      * rectangle.
68921      */
68922     _rectToNonAdjustedVertices2d(rect) {
68923         return [
68924             [rect[0], rect[3]],
68925             [rect[0], rect[1]],
68926             [rect[2], rect[1]],
68927             [rect[2], rect[3]],
68928             [rect[0], rect[3]],
68929         ];
68930     }
68931 }
68932
68933 class ExtremePointCreateTag extends CreateTag {
68934     constructor(geometry, options, transform, viewportCoords) {
68935         super(geometry, transform, viewportCoords);
68936         this._options = {
68937             color: options.color == null ? 0xFFFFFF : options.color,
68938             indicateCompleter: options.indicateCompleter == null ? true : options.indicateCompleter,
68939         };
68940         this._rectGeometry = new RectGeometry(this._geometry.getRect2d(transform));
68941         this._createGlObjects();
68942     }
68943     create() {
68944         if (this._geometry.points.length < 3) {
68945             return;
68946         }
68947         this._geometry.removePoint2d(this._geometry.points.length - 1);
68948         this._created$.next(this);
68949     }
68950     dispose() {
68951         super.dispose();
68952         this._disposeObjects();
68953     }
68954     getDOMObjects(camera, size) {
68955         const container = {
68956             offsetHeight: size.height, offsetWidth: size.width,
68957         };
68958         const vNodes = [];
68959         const points2d = this._geometry.getPoints2d();
68960         const length = points2d.length;
68961         for (let index = 0; index < length - 1; index++) {
68962             const nonModifiedIndex = index;
68963             const [pointX, pointY] = points2d[index];
68964             const pointCanvas = this._viewportCoords.basicToCanvasSafe(pointX, pointY, container, this._transform, camera);
68965             if (!pointCanvas) {
68966                 continue;
68967             }
68968             const abort = (e) => {
68969                 e.stopPropagation();
68970                 this._aborted$.next(this);
68971             };
68972             const remove = (e) => {
68973                 e.stopPropagation();
68974                 this._geometry.removePoint2d(nonModifiedIndex);
68975             };
68976             const transform = this._canvasToTransform(pointCanvas);
68977             const completerProperties = {
68978                 onclick: index === 0 && length < 3 ? abort : remove,
68979                 style: { transform: transform },
68980             };
68981             vNodes.push(virtualDom.h("div.mapillary-tag-interactor", completerProperties, []));
68982             const background = this._colorToBackground(this._options.color);
68983             const pointProperties = {
68984                 style: {
68985                     background: background,
68986                     transform: transform,
68987                 },
68988             };
68989             vNodes.push(virtualDom.h("div.mapillary-tag-vertex", pointProperties, []));
68990         }
68991         if (length > 2 && this._options.indicateCompleter === true) {
68992             const [centroidX, centroidY] = this._geometry.getCentroid2d(this._transform);
68993             const centroidCanvas = this._viewportCoords.basicToCanvasSafe(centroidX, centroidY, container, this._transform, camera);
68994             if (!!centroidCanvas) {
68995                 const complete = (e) => {
68996                     e.stopPropagation();
68997                     this._geometry.removePoint2d(this._geometry.points.length - 1);
68998                     this._created$.next(this);
68999                 };
69000                 const transform = this._canvasToTransform(centroidCanvas);
69001                 const completerProperties = {
69002                     onclick: complete,
69003                     style: { transform: transform },
69004                 };
69005                 vNodes.push(virtualDom.h("div.mapillary-tag-completer.mapillary-tag-larger", completerProperties, []));
69006                 const pointProperties = {
69007                     style: {
69008                         background: this._colorToBackground(this._options.color),
69009                         transform: transform,
69010                     },
69011                 };
69012                 vNodes.push(virtualDom.h("div.mapillary-tag-vertex.mapillary-tag-larger", pointProperties, []));
69013                 const dotProperties = {
69014                     style: {
69015                         transform: transform,
69016                     },
69017                 };
69018                 vNodes.push(virtualDom.h("div.mapillary-tag-dot", dotProperties, []));
69019             }
69020         }
69021         return vNodes;
69022     }
69023     _onGeometryChanged() {
69024         this._disposeObjects();
69025         this._rectGeometry = new RectGeometry(this._geometry.getRect2d(this._transform));
69026         this._createGlObjects();
69027     }
69028     _createGlObjects() {
69029         this._glObjects = [];
69030         const polygon3d = this._rectGeometry.getPoints3d(this._transform);
69031         this._outline = this._createOutine(polygon3d, this._options.color);
69032         this._glObjects.push(this._outline);
69033     }
69034     _disposeObjects() {
69035         this._disposeLine(this._outline);
69036         this._outline = null;
69037         this._glObjects = null;
69038     }
69039 }
69040
69041 /**
69042  * @class PolygonGeometry
69043  *
69044  * @classdesc Represents a polygon geometry in the 2D basic image coordinate system.
69045  * All polygons and holes provided to the constructor needs to be closed.
69046  *
69047  * @example
69048  * ```js
69049  * var basicPolygon = [[0.5, 0.3], [0.7, 0.3], [0.6, 0.5], [0.5, 0.3]];
69050  * var polygonGeometry = new PolygonGeometry(basicPolygon);
69051  * ```
69052  */
69053 class PolygonGeometry extends VertexGeometry {
69054     /**
69055      * Create a polygon geometry.
69056      *
69057      * @constructor
69058      * @param {Array<Array<number>>} polygon - Array of polygon vertices. Must be closed.
69059      * @param {Array<Array<Array<number>>>} [holes] - Array of arrays of hole vertices.
69060      * Each array of holes vertices must be closed.
69061      *
69062      * @throws {GeometryTagError} Polygon coordinates must be valid basic coordinates.
69063      */
69064     constructor(polygon, holes) {
69065         super();
69066         let polygonLength = polygon.length;
69067         if (polygonLength < 3) {
69068             throw new GeometryTagError("A polygon must have three or more positions.");
69069         }
69070         if (polygon[0][0] !== polygon[polygonLength - 1][0] ||
69071             polygon[0][1] !== polygon[polygonLength - 1][1]) {
69072             throw new GeometryTagError("First and last positions must be equivalent.");
69073         }
69074         this._polygon = [];
69075         for (let vertex of polygon) {
69076             if (vertex[0] < 0 || vertex[0] > 1 ||
69077                 vertex[1] < 0 || vertex[1] > 1) {
69078                 throw new GeometryTagError("Basic coordinates of polygon must be on the interval [0, 1].");
69079             }
69080             this._polygon.push(vertex.slice());
69081         }
69082         this._holes = [];
69083         if (holes == null) {
69084             return;
69085         }
69086         for (let i = 0; i < holes.length; i++) {
69087             let hole = holes[i];
69088             let holeLength = hole.length;
69089             if (holeLength < 3) {
69090                 throw new GeometryTagError("A polygon hole must have three or more positions.");
69091             }
69092             if (hole[0][0] !== hole[holeLength - 1][0] ||
69093                 hole[0][1] !== hole[holeLength - 1][1]) {
69094                 throw new GeometryTagError("First and last positions of hole must be equivalent.");
69095             }
69096             this._holes.push([]);
69097             for (let vertex of hole) {
69098                 if (vertex[0] < 0 || vertex[0] > 1 ||
69099                     vertex[1] < 0 || vertex[1] > 1) {
69100                     throw new GeometryTagError("Basic coordinates of hole must be on the interval [0, 1].");
69101                 }
69102                 this._holes[i].push(vertex.slice());
69103             }
69104         }
69105     }
69106     /**
69107      * Get polygon property.
69108      * @returns {Array<Array<number>>} Closed 2d polygon.
69109      */
69110     get polygon() {
69111         return this._polygon;
69112     }
69113     /**
69114      * Get holes property.
69115      * @returns {Array<Array<Array<number>>>} Holes of 2d polygon.
69116      */
69117     get holes() {
69118         return this._holes;
69119     }
69120     /**
69121      * Add a vertex to the polygon by appending it after the last vertex.
69122      *
69123      * @param {Array<number>} vertex - Vertex to add.
69124      * @ignore
69125      */
69126     addVertex2d(vertex) {
69127         let clamped = [
69128             Math.max(0, Math.min(1, vertex[0])),
69129             Math.max(0, Math.min(1, vertex[1])),
69130         ];
69131         this._polygon.splice(this._polygon.length - 1, 0, clamped);
69132         this._notifyChanged$.next(this);
69133     }
69134     /**
69135      * Get the coordinates of a vertex from the polygon representation of the geometry.
69136      *
69137      * @param {number} index - Vertex index.
69138      * @returns {Array<number>} Array representing the 2D basic coordinates of the vertex.
69139      * @ignore
69140      */
69141     getVertex2d(index) {
69142         return this._polygon[index].slice();
69143     }
69144     /**
69145      * Remove a vertex from the polygon.
69146      *
69147      * @param {number} index - The index of the vertex to remove.
69148      * @ignore
69149      */
69150     removeVertex2d(index) {
69151         if (index < 0 ||
69152             index >= this._polygon.length ||
69153             this._polygon.length < 4) {
69154             throw new GeometryTagError("Index for removed vertex must be valid.");
69155         }
69156         if (index > 0 && index < this._polygon.length - 1) {
69157             this._polygon.splice(index, 1);
69158         }
69159         else {
69160             this._polygon.splice(0, 1);
69161             this._polygon.pop();
69162             let closing = this._polygon[0].slice();
69163             this._polygon.push(closing);
69164         }
69165         this._notifyChanged$.next(this);
69166     }
69167     /** @ignore */
69168     setVertex2d(index, value, transform) {
69169         let changed = [
69170             Math.max(0, Math.min(1, value[0])),
69171             Math.max(0, Math.min(1, value[1])),
69172         ];
69173         if (index === 0 || index === this._polygon.length - 1) {
69174             this._polygon[0] = changed.slice();
69175             this._polygon[this._polygon.length - 1] = changed.slice();
69176         }
69177         else {
69178             this._polygon[index] = changed.slice();
69179         }
69180         this._notifyChanged$.next(this);
69181     }
69182     /** @ignore */
69183     setCentroid2d(value, transform) {
69184         let xs = this._polygon.map((point) => { return point[0]; });
69185         let ys = this._polygon.map((point) => { return point[1]; });
69186         let minX = Math.min.apply(Math, xs);
69187         let maxX = Math.max.apply(Math, xs);
69188         let minY = Math.min.apply(Math, ys);
69189         let maxY = Math.max.apply(Math, ys);
69190         let centroid = this.getCentroid2d();
69191         let minTranslationX = -minX;
69192         let maxTranslationX = 1 - maxX;
69193         let minTranslationY = -minY;
69194         let maxTranslationY = 1 - maxY;
69195         let translationX = Math.max(minTranslationX, Math.min(maxTranslationX, value[0] - centroid[0]));
69196         let translationY = Math.max(minTranslationY, Math.min(maxTranslationY, value[1] - centroid[1]));
69197         for (let point of this._polygon) {
69198             point[0] += translationX;
69199             point[1] += translationY;
69200         }
69201         this._notifyChanged$.next(this);
69202     }
69203     /** @ignore */
69204     getPoints3d(transform) {
69205         return this._getPoints3d(this._subsample(this._polygon), transform);
69206     }
69207     /** @ignore */
69208     getVertex3d(index, transform) {
69209         return transform.unprojectBasic(this._polygon[index], 200);
69210     }
69211     /** @ignore */
69212     getVertices2d() {
69213         return this._polygon.slice();
69214     }
69215     /** @ignore */
69216     getVertices3d(transform) {
69217         return this._getPoints3d(this._polygon, transform);
69218     }
69219     /**
69220      * Get a polygon representation of the 3D coordinates for the vertices of each hole
69221      * of the geometry. Line segments between vertices will possibly be subsampled
69222      * resulting in a larger number of points than the total number of vertices.
69223      *
69224      * @param {Transform} transform - The transform of the image related to the geometry.
69225      * @returns {Array<Array<Array<number>>>} Array of hole polygons in 3D world coordinates
69226      * representing the vertices of each hole of the geometry.
69227      * @ignore
69228      */
69229     getHolePoints3d(transform) {
69230         return this._holes
69231             .map((hole2d) => {
69232             return this._getPoints3d(this._subsample(hole2d), transform);
69233         });
69234     }
69235     /**
69236      * Get a polygon representation of the 3D coordinates for the vertices of each hole
69237      * of the geometry.
69238      *
69239      * @param {Transform} transform - The transform of the image related to the geometry.
69240      * @returns {Array<Array<Array<number>>>} Array of hole polygons in 3D world coordinates
69241      * representing the vertices of each hole of the geometry.
69242      * @ignore
69243      */
69244     getHoleVertices3d(transform) {
69245         return this._holes
69246             .map((hole2d) => {
69247             return this._getPoints3d(hole2d, transform);
69248         });
69249     }
69250     /** @ignore */
69251     getCentroid2d() {
69252         let polygon = this._polygon;
69253         let area = 0;
69254         let centroidX = 0;
69255         let centroidY = 0;
69256         for (let i = 0; i < polygon.length - 1; i++) {
69257             let xi = polygon[i][0];
69258             let yi = polygon[i][1];
69259             let xi1 = polygon[i + 1][0];
69260             let yi1 = polygon[i + 1][1];
69261             let a = xi * yi1 - xi1 * yi;
69262             area += a;
69263             centroidX += (xi + xi1) * a;
69264             centroidY += (yi + yi1) * a;
69265         }
69266         area /= 2;
69267         centroidX /= 6 * area;
69268         centroidY /= 6 * area;
69269         return [centroidX, centroidY];
69270     }
69271     /** @ignore */
69272     getCentroid3d(transform) {
69273         let centroid2d = this.getCentroid2d();
69274         return transform.unprojectBasic(centroid2d, 200);
69275     }
69276     /** @ignore */
69277     get3dDomainTriangles3d(transform) {
69278         return this._triangulate(this._project(this._polygon, transform), this.getVertices3d(transform), this._holes
69279             .map((hole2d) => {
69280             return this._project(hole2d, transform);
69281         }), this.getHoleVertices3d(transform));
69282     }
69283     /** @ignore */
69284     getTriangles3d(transform) {
69285         if (isSpherical(transform.cameraType)) {
69286             return this._triangulateSpherical(this._polygon.slice(), this.holes.slice(), transform);
69287         }
69288         const points2d = this._project(this._subsample(this._polygon), transform);
69289         const points3d = this.getPoints3d(transform);
69290         const holes2d = this._holes
69291             .map((hole) => {
69292             return this._project(this._subsample(hole), transform);
69293         });
69294         const holes3d = this.getHolePoints3d(transform);
69295         return this._triangulate(points2d, points3d, holes2d, holes3d);
69296     }
69297     /** @ignore */
69298     getPoleOfInaccessibility2d() {
69299         return this._getPoleOfInaccessibility2d(this._polygon.slice());
69300     }
69301     /** @ignore */
69302     getPoleOfInaccessibility3d(transform) {
69303         let pole2d = this._getPoleOfInaccessibility2d(this._polygon.slice());
69304         return transform.unprojectBasic(pole2d, 200);
69305     }
69306     _getPoints3d(points2d, transform) {
69307         return points2d
69308             .map((point) => {
69309             return transform.unprojectBasic(point, 200);
69310         });
69311     }
69312 }
69313
69314 class OutlineCreateTag extends CreateTag {
69315     constructor(geometry, options, transform, viewportCoords) {
69316         super(geometry, transform, viewportCoords);
69317         this._options = { color: options.color == null ? 0xFFFFFF : options.color };
69318         this._createGlObjects();
69319     }
69320     create() {
69321         if (this._geometry instanceof RectGeometry) {
69322             this._created$.next(this);
69323         }
69324         else if (this._geometry instanceof PolygonGeometry) {
69325             const polygonGeometry = this._geometry;
69326             polygonGeometry.removeVertex2d(polygonGeometry.polygon.length - 2);
69327             this._created$.next(this);
69328         }
69329     }
69330     dispose() {
69331         super.dispose();
69332         this._disposeLine(this._outline);
69333         this._disposeObjects();
69334     }
69335     getDOMObjects(camera, size) {
69336         const vNodes = [];
69337         const container = {
69338             offsetHeight: size.height, offsetWidth: size.width,
69339         };
69340         const abort = (e) => {
69341             e.stopPropagation();
69342             this._aborted$.next(this);
69343         };
69344         if (this._geometry instanceof RectGeometry) {
69345             const anchorIndex = this._geometry.anchorIndex;
69346             const vertexIndex = anchorIndex === undefined ? 1 : anchorIndex;
69347             const [basicX, basicY] = this._geometry.getVertex2d(vertexIndex);
69348             const canvasPoint = this._viewportCoords.basicToCanvasSafe(basicX, basicY, container, this._transform, camera);
69349             if (canvasPoint != null) {
69350                 const background = this._colorToBackground(this._options.color);
69351                 const transform = this._canvasToTransform(canvasPoint);
69352                 const pointProperties = {
69353                     style: { background: background, transform: transform },
69354                 };
69355                 const completerProperties = {
69356                     onclick: abort,
69357                     style: { transform: transform },
69358                 };
69359                 vNodes.push(virtualDom.h("div.mapillary-tag-interactor", completerProperties, []));
69360                 vNodes.push(virtualDom.h("div.mapillary-tag-vertex", pointProperties, []));
69361             }
69362         }
69363         else if (this._geometry instanceof PolygonGeometry) {
69364             const polygonGeometry = this._geometry;
69365             const [firstVertexBasicX, firstVertexBasicY] = polygonGeometry.getVertex2d(0);
69366             const firstVertexCanvas = this._viewportCoords.basicToCanvasSafe(firstVertexBasicX, firstVertexBasicY, container, this._transform, camera);
69367             if (firstVertexCanvas != null) {
69368                 const firstOnclick = polygonGeometry.polygon.length > 4 ?
69369                     (e) => {
69370                         e.stopPropagation();
69371                         polygonGeometry.removeVertex2d(polygonGeometry.polygon.length - 2);
69372                         this._created$.next(this);
69373                     } :
69374                     abort;
69375                 const transform = this._canvasToTransform(firstVertexCanvas);
69376                 const completerProperties = {
69377                     onclick: firstOnclick,
69378                     style: { transform: transform },
69379                 };
69380                 const firstClass = polygonGeometry.polygon.length > 4 ?
69381                     "mapillary-tag-completer" :
69382                     "mapillary-tag-interactor";
69383                 vNodes.push(virtualDom.h("div." + firstClass, completerProperties, []));
69384             }
69385             if (polygonGeometry.polygon.length > 3) {
69386                 const [lastVertexBasicX, lastVertexBasicY] = polygonGeometry.getVertex2d(polygonGeometry.polygon.length - 3);
69387                 const lastVertexCanvas = this._viewportCoords.basicToCanvasSafe(lastVertexBasicX, lastVertexBasicY, container, this._transform, camera);
69388                 if (lastVertexCanvas != null) {
69389                     const remove = (e) => {
69390                         e.stopPropagation();
69391                         polygonGeometry.removeVertex2d(polygonGeometry.polygon.length - 3);
69392                     };
69393                     const transform = this._canvasToTransform(lastVertexCanvas);
69394                     const completerProperties = {
69395                         onclick: remove,
69396                         style: { transform: transform },
69397                     };
69398                     vNodes.push(virtualDom.h("div.mapillary-tag-interactor", completerProperties, []));
69399                 }
69400             }
69401             const verticesBasic = polygonGeometry.polygon.slice();
69402             verticesBasic.splice(-2, 2);
69403             for (const vertexBasic of verticesBasic) {
69404                 const vertexCanvas = this._viewportCoords.basicToCanvasSafe(vertexBasic[0], vertexBasic[1], container, this._transform, camera);
69405                 if (vertexCanvas != null) {
69406                     const background = this._colorToBackground(this._options.color);
69407                     const transform = this._canvasToTransform(vertexCanvas);
69408                     const pointProperties = {
69409                         style: {
69410                             background: background,
69411                             transform: transform,
69412                         },
69413                     };
69414                     vNodes.push(virtualDom.h("div.mapillary-tag-vertex", pointProperties, []));
69415                 }
69416             }
69417         }
69418         return vNodes;
69419     }
69420     addPoint(point) {
69421         if (this._geometry instanceof RectGeometry) {
69422             const rectGeometry = this._geometry;
69423             if (!rectGeometry.validate(point)) {
69424                 return;
69425             }
69426             this._created$.next(this);
69427         }
69428         else if (this._geometry instanceof PolygonGeometry) {
69429             const polygonGeometry = this._geometry;
69430             polygonGeometry.addVertex2d(point);
69431         }
69432     }
69433     _onGeometryChanged() {
69434         this._disposeLine(this._outline);
69435         this._disposeObjects();
69436         this._createGlObjects();
69437     }
69438     _disposeObjects() {
69439         this._outline = null;
69440         this._glObjects = [];
69441     }
69442     _createGlObjects() {
69443         const polygon3d = this._geometry instanceof RectGeometry ?
69444             this._geometry.getPoints3d(this._transform) :
69445             this._geometry.getVertices3d(this._transform);
69446         this._outline = this._createOutine(polygon3d, this._options.color);
69447         this._glObjects = [this._outline];
69448     }
69449 }
69450
69451 class TagCreator {
69452     constructor(component, navigator) {
69453         this._component = component;
69454         this._navigator = navigator;
69455         this._tagOperation$ = new Subject();
69456         this._createPoints$ = new Subject();
69457         this._createPolygon$ = new Subject();
69458         this._createRect$ = new Subject();
69459         this._delete$ = new Subject();
69460         this._tag$ = this._tagOperation$.pipe(scan((tag, operation) => {
69461             return operation(tag);
69462         }, null), share());
69463         this._replayedTag$ = this._tag$.pipe(publishReplay(1), refCount());
69464         this._replayedTag$.subscribe();
69465         this._createPoints$.pipe(withLatestFrom(this._component.configuration$, this._navigator.stateService.currentTransform$), map(([coord, conf, transform]) => {
69466             return () => {
69467                 const geometry = new PointsGeometry([
69468                     [coord[0], coord[1]],
69469                     [coord[0], coord[1]],
69470                 ]);
69471                 return new ExtremePointCreateTag(geometry, {
69472                     color: conf.createColor,
69473                     indicateCompleter: conf.indicatePointsCompleter,
69474                 }, transform);
69475             };
69476         }))
69477             .subscribe(this._tagOperation$);
69478         this._createRect$.pipe(withLatestFrom(this._component.configuration$, this._navigator.stateService.currentTransform$), map(([coord, conf, transform]) => {
69479             return () => {
69480                 const geometry = new RectGeometry([
69481                     coord[0],
69482                     coord[1],
69483                     coord[0],
69484                     coord[1],
69485                 ]);
69486                 return new OutlineCreateTag(geometry, { color: conf.createColor }, transform);
69487             };
69488         }))
69489             .subscribe(this._tagOperation$);
69490         this._createPolygon$.pipe(withLatestFrom(this._component.configuration$, this._navigator.stateService.currentTransform$), map(([coord, conf, transform]) => {
69491             return () => {
69492                 const geometry = new PolygonGeometry([
69493                     [coord[0], coord[1]],
69494                     [coord[0], coord[1]],
69495                     [coord[0], coord[1]],
69496                 ]);
69497                 return new OutlineCreateTag(geometry, { color: conf.createColor }, transform);
69498             };
69499         }))
69500             .subscribe(this._tagOperation$);
69501         this._delete$.pipe(map(() => {
69502             return () => {
69503                 return null;
69504             };
69505         }))
69506             .subscribe(this._tagOperation$);
69507     }
69508     get createRect$() {
69509         return this._createRect$;
69510     }
69511     get createPolygon$() {
69512         return this._createPolygon$;
69513     }
69514     get createPoints$() {
69515         return this._createPoints$;
69516     }
69517     get delete$() {
69518         return this._delete$;
69519     }
69520     get tag$() {
69521         return this._tag$;
69522     }
69523     get replayedTag$() {
69524         return this._replayedTag$;
69525     }
69526 }
69527
69528 class TagDOMRenderer {
69529     render(tags, createTag, atlas, camera, size) {
69530         let vNodes = [];
69531         for (const tag of tags) {
69532             vNodes = vNodes.concat(tag.getDOMObjects(atlas, camera, size));
69533         }
69534         if (createTag != null) {
69535             vNodes = vNodes.concat(createTag.getDOMObjects(camera, size));
69536         }
69537         return virtualDom.h("div.mapillary-tag-container", {}, vNodes);
69538     }
69539     clear() {
69540         return virtualDom.h("div", {}, []);
69541     }
69542 }
69543
69544 class TagScene {
69545     constructor(scene, raycaster) {
69546         this._createTag = null;
69547         this._needsRender = false;
69548         this._raycaster = !!raycaster ? raycaster : new Raycaster();
69549         this._scene = !!scene ? scene : new Scene();
69550         this._objectTags = {};
69551         this._retrievableObjects = [];
69552         this._tags = {};
69553     }
69554     get needsRender() {
69555         return this._needsRender;
69556     }
69557     add(tags) {
69558         for (let tag of tags) {
69559             if (tag.tag.id in this._tags) {
69560                 this._remove(tag.tag.id);
69561             }
69562             this._add(tag);
69563         }
69564         this._needsRender = true;
69565     }
69566     addCreateTag(tag) {
69567         for (const object of tag.glObjects) {
69568             this._scene.add(object);
69569         }
69570         this._createTag = { tag: tag, objects: tag.glObjects };
69571         this._needsRender = true;
69572     }
69573     clear() {
69574         for (const id of Object.keys(this._tags)) {
69575             this._remove(id);
69576         }
69577         this._needsRender = false;
69578     }
69579     get(id) {
69580         return this.has(id) ? this._tags[id].tag : undefined;
69581     }
69582     has(id) {
69583         return id in this._tags;
69584     }
69585     hasCreateTag() {
69586         return this._createTag != null;
69587     }
69588     intersectObjects([viewportX, viewportY], camera) {
69589         this._raycaster.setFromCamera(new Vector2(viewportX, viewportY), camera);
69590         const intersects = this._raycaster.intersectObjects(this._retrievableObjects);
69591         const intersectedIds = [];
69592         for (const intersect of intersects) {
69593             if (intersect.object.uuid in this._objectTags) {
69594                 intersectedIds.push(this._objectTags[intersect.object.uuid]);
69595             }
69596         }
69597         return intersectedIds;
69598     }
69599     remove(ids) {
69600         for (const id of ids) {
69601             this._remove(id);
69602         }
69603         this._needsRender = true;
69604     }
69605     removeAll() {
69606         for (const id of Object.keys(this._tags)) {
69607             this._remove(id);
69608         }
69609         this._needsRender = true;
69610     }
69611     removeCreateTag() {
69612         if (this._createTag == null) {
69613             return;
69614         }
69615         for (const object of this._createTag.objects) {
69616             this._scene.remove(object);
69617         }
69618         this._createTag.tag.dispose();
69619         this._createTag = null;
69620         this._needsRender = true;
69621     }
69622     render(perspectiveCamera, renderer) {
69623         renderer.render(this._scene, perspectiveCamera);
69624         this._needsRender = false;
69625     }
69626     update() {
69627         this._needsRender = true;
69628     }
69629     updateCreateTagObjects(tag) {
69630         if (this._createTag.tag !== tag) {
69631             throw new Error("Create tags do not have the same reference.");
69632         }
69633         for (let object of this._createTag.objects) {
69634             this._scene.remove(object);
69635         }
69636         for (const object of tag.glObjects) {
69637             this._scene.add(object);
69638         }
69639         this._createTag.objects = tag.glObjects;
69640         this._needsRender = true;
69641     }
69642     updateObjects(tag) {
69643         const id = tag.tag.id;
69644         if (this._tags[id].tag !== tag) {
69645             throw new Error("Tags do not have the same reference.");
69646         }
69647         const tagObjects = this._tags[id];
69648         this._removeObjects(tagObjects);
69649         delete this._tags[id];
69650         this._add(tag);
69651         this._needsRender = true;
69652     }
69653     _add(tag) {
69654         const id = tag.tag.id;
69655         const tagObjects = { tag: tag, objects: [], retrievableObjects: [] };
69656         this._tags[id] = tagObjects;
69657         for (const object of tag.getGLObjects()) {
69658             tagObjects.objects.push(object);
69659             this._scene.add(object);
69660         }
69661         for (const retrievableObject of tag.getRetrievableObjects()) {
69662             tagObjects.retrievableObjects.push(retrievableObject);
69663             this._retrievableObjects.push(retrievableObject);
69664             this._objectTags[retrievableObject.uuid] = tag.tag.id;
69665         }
69666     }
69667     _remove(id) {
69668         const tagObjects = this._tags[id];
69669         this._removeObjects(tagObjects);
69670         tagObjects.tag.dispose();
69671         delete this._tags[id];
69672     }
69673     _removeObjects(tagObjects) {
69674         for (const object of tagObjects.objects) {
69675             this._scene.remove(object);
69676         }
69677         for (const retrievableObject of tagObjects.retrievableObjects) {
69678             const index = this._retrievableObjects.indexOf(retrievableObject);
69679             if (index !== -1) {
69680                 this._retrievableObjects.splice(index, 1);
69681             }
69682         }
69683     }
69684 }
69685
69686 /**
69687  * Enumeration for tag modes
69688  * @enum {number}
69689  * @readonly
69690  * @description Modes for the interaction in the tag component.
69691  */
69692 var TagMode;
69693 (function (TagMode) {
69694     /**
69695      * Disables creating tags.
69696      */
69697     TagMode[TagMode["Default"] = 0] = "Default";
69698     /**
69699      * Create a point geometry through a click.
69700      */
69701     TagMode[TagMode["CreatePoint"] = 1] = "CreatePoint";
69702     /**
69703      * Create a points geometry through clicks.
69704      */
69705     TagMode[TagMode["CreatePoints"] = 2] = "CreatePoints";
69706     /**
69707      * Create a polygon geometry through clicks.
69708      */
69709     TagMode[TagMode["CreatePolygon"] = 3] = "CreatePolygon";
69710     /**
69711      * Create a rect geometry through clicks.
69712      */
69713     TagMode[TagMode["CreateRect"] = 4] = "CreateRect";
69714     /**
69715      * Create a rect geometry through drag.
69716      *
69717      * @description Claims the mouse which results in mouse handlers like
69718      * drag pan and scroll zoom becoming inactive.
69719      */
69720     TagMode[TagMode["CreateRectDrag"] = 5] = "CreateRectDrag";
69721 })(TagMode || (TagMode = {}));
69722
69723 var TagOperation;
69724 (function (TagOperation) {
69725     TagOperation[TagOperation["None"] = 0] = "None";
69726     TagOperation[TagOperation["Centroid"] = 1] = "Centroid";
69727     TagOperation[TagOperation["Vertex"] = 2] = "Vertex";
69728 })(TagOperation || (TagOperation = {}));
69729
69730 class RenderTag {
69731     constructor(tag, transform, viewportCoords) {
69732         this._tag = tag;
69733         this._transform = transform;
69734         this._viewportCoords = !!viewportCoords ? viewportCoords : new ViewportCoords();
69735         this._glObjectsChanged$ = new Subject();
69736         this._interact$ = new Subject();
69737     }
69738     get glObjectsChanged$() {
69739         return this._glObjectsChanged$;
69740     }
69741     get interact$() {
69742         return this._interact$;
69743     }
69744     get tag() {
69745         return this._tag;
69746     }
69747 }
69748
69749 class OutlineRenderTagBase extends RenderTag {
69750     constructor(tag, transform) {
69751         super(tag, transform);
69752         this._geometryChangedSubscription = this._tag.geometry.changed$
69753             .subscribe(() => {
69754             this._onGeometryChanged();
69755         });
69756         this._changedSubscription = this._tag.changed$
69757             .subscribe(() => {
69758             const glObjectsChanged = this._onTagChanged();
69759             if (glObjectsChanged) {
69760                 this._glObjectsChanged$.next(this);
69761             }
69762         });
69763     }
69764     dispose() {
69765         this._changedSubscription.unsubscribe();
69766         this._geometryChangedSubscription.unsubscribe();
69767     }
69768     _colorToCss(color) {
69769         return "#" + ("000000" + color.toString(16)).substr(-6);
69770     }
69771     _createFill() {
69772         let triangles = this._getTriangles();
69773         let positions = new Float32Array(triangles);
69774         let geometry = new BufferGeometry();
69775         geometry.setAttribute("position", new BufferAttribute(positions, 3));
69776         geometry.computeBoundingSphere();
69777         let material = new MeshBasicMaterial({ side: DoubleSide, transparent: true });
69778         this._updateFillMaterial(material);
69779         return new Mesh(geometry, material);
69780     }
69781     _createLine(points3d) {
69782         let positions = this._getLinePositions(points3d);
69783         let geometry = new BufferGeometry();
69784         geometry.setAttribute("position", new BufferAttribute(positions, 3));
69785         geometry.computeBoundingSphere();
69786         let material = new LineBasicMaterial();
69787         this._updateLineBasicMaterial(material);
69788         const line = new Line(geometry, material);
69789         line.renderOrder = 1;
69790         return line;
69791     }
69792     _createOutline() {
69793         return this._createLine(this._getPoints3d());
69794     }
69795     _disposeFill() {
69796         if (this._fill == null) {
69797             return;
69798         }
69799         this._fill.geometry.dispose();
69800         this._fill.material.dispose();
69801         this._fill = null;
69802     }
69803     _disposeOutline() {
69804         if (this._outline == null) {
69805             return;
69806         }
69807         this._outline.geometry.dispose();
69808         this._outline.material.dispose();
69809         this._outline = null;
69810     }
69811     _getLinePositions(points3d) {
69812         let length = points3d.length;
69813         let positions = new Float32Array(length * 3);
69814         for (let i = 0; i < length; ++i) {
69815             let index = 3 * i;
69816             let position = points3d[i];
69817             positions[index + 0] = position[0];
69818             positions[index + 1] = position[1];
69819             positions[index + 2] = position[2];
69820         }
69821         return positions;
69822     }
69823     _interact(operation, cursor, vertexIndex) {
69824         return (e) => {
69825             let offsetX = e.offsetX - e.target.offsetWidth / 2;
69826             let offsetY = e.offsetY - e.target.offsetHeight / 2;
69827             this._interact$.next({
69828                 cursor: cursor,
69829                 offsetX: offsetX,
69830                 offsetY: offsetY,
69831                 operation: operation,
69832                 tag: this._tag,
69833                 vertexIndex: vertexIndex,
69834             });
69835         };
69836     }
69837     _updateFillGeometry() {
69838         let triangles = this._getTriangles();
69839         let positions = new Float32Array(triangles);
69840         let geometry = this._fill.geometry;
69841         let attribute = geometry.getAttribute("position");
69842         if (attribute.array.length === positions.length) {
69843             attribute.set(positions);
69844             attribute.needsUpdate = true;
69845         }
69846         else {
69847             geometry.deleteAttribute("position");
69848             geometry.setAttribute("position", new BufferAttribute(positions, 3));
69849         }
69850         geometry.computeBoundingSphere();
69851     }
69852     _updateLine(line, points3d) {
69853         let positions = this._getLinePositions(points3d);
69854         let geometry = line.geometry;
69855         let attribute = geometry.getAttribute("position");
69856         attribute.set(positions);
69857         attribute.needsUpdate = true;
69858         geometry.computeBoundingSphere();
69859     }
69860     _updateOulineGeometry() {
69861         this._updateLine(this._outline, this._getPoints3d());
69862     }
69863 }
69864
69865 /**
69866  * @class OutlineRenderTag
69867  * @classdesc Tag visualizing the properties of an OutlineTag.
69868  */
69869 class ExtremePointRenderTag extends OutlineRenderTagBase {
69870     constructor(tag, transform) {
69871         super(tag, transform);
69872         this._rectGeometry = new RectGeometry(this._tag.geometry.getRect2d(transform));
69873         this._fill = !isSpherical(transform.cameraType) ?
69874             this._createFill() : null;
69875         this._outline = this._tag.lineWidth >= 1 ?
69876             this._createOutline() :
69877             null;
69878     }
69879     dispose() {
69880         super.dispose();
69881         this._disposeFill();
69882         this._disposeOutline();
69883     }
69884     getDOMObjects(atlas, camera, size) {
69885         const vNodes = [];
69886         const container = {
69887             offsetHeight: size.height, offsetWidth: size.width,
69888         };
69889         if (!this._tag.editable) {
69890             return vNodes;
69891         }
69892         const lineColor = this._colorToCss(this._tag.lineColor);
69893         const points2d = this._tag.geometry.getPoints2d();
69894         for (let i = 0; i < points2d.length; i++) {
69895             const [vertexBasicX, vertexBasicY] = points2d[i];
69896             const vertexCanvas = this._viewportCoords.basicToCanvasSafe(vertexBasicX, vertexBasicY, container, this._transform, camera);
69897             if (vertexCanvas == null) {
69898                 continue;
69899             }
69900             const cursor = "crosshair";
69901             const interact = this._interact(TagOperation.Vertex, cursor, i);
69902             const vertexCanvasX = Math.round(vertexCanvas[0]);
69903             const vertexCanvasY = Math.round(vertexCanvas[1]);
69904             const transform = `translate(-50%, -50%) translate(${vertexCanvasX}px,${vertexCanvasY}px)`;
69905             const properties = {
69906                 onpointerdown: interact,
69907                 style: { background: lineColor, transform: transform, cursor: cursor },
69908             };
69909             vNodes.push(virtualDom.h("div.mapillary-tag-resizer", properties, []));
69910             if (!this._tag.indicateVertices) {
69911                 continue;
69912             }
69913             const pointProperties = {
69914                 style: { background: lineColor, transform: transform },
69915             };
69916             vNodes.push(virtualDom.h("div.mapillary-tag-vertex", pointProperties, []));
69917         }
69918         return vNodes;
69919     }
69920     getGLObjects() {
69921         const glObjects = [];
69922         if (this._fill != null) {
69923             glObjects.push(this._fill);
69924         }
69925         if (this._outline != null) {
69926             glObjects.push(this._outline);
69927         }
69928         return glObjects;
69929     }
69930     getRetrievableObjects() {
69931         return this._fill != null ? [this._fill] : [];
69932     }
69933     _onGeometryChanged() {
69934         this._rectGeometry = new RectGeometry(this._tag.geometry.getRect2d(this._transform));
69935         if (this._fill != null) {
69936             this._updateFillGeometry();
69937         }
69938         if (this._outline != null) {
69939             this._updateOulineGeometry();
69940         }
69941     }
69942     _onTagChanged() {
69943         let glObjectsChanged = false;
69944         if (this._fill != null) {
69945             this._updateFillMaterial(this._fill.material);
69946         }
69947         if (this._outline == null) {
69948             if (this._tag.lineWidth >= 1) {
69949                 this._outline = this._createOutline();
69950                 glObjectsChanged = true;
69951             }
69952         }
69953         else {
69954             this._updateOutlineMaterial();
69955         }
69956         return glObjectsChanged;
69957     }
69958     _getPoints3d() {
69959         return this._rectGeometry.getPoints3d(this._transform);
69960     }
69961     _getTriangles() {
69962         return this._rectGeometry.getTriangles3d(this._transform);
69963     }
69964     _updateFillMaterial(material) {
69965         material.color = new Color(this._tag.fillColor);
69966         material.opacity = this._tag.fillOpacity;
69967         material.needsUpdate = true;
69968     }
69969     _updateLineBasicMaterial(material) {
69970         material.color = new Color(this._tag.lineColor);
69971         material.linewidth = Math.max(this._tag.lineWidth, 1);
69972         material.visible = this._tag.lineWidth >= 1 && this._tag.lineOpacity > 0;
69973         material.opacity = this._tag.lineOpacity;
69974         material.transparent = this._tag.lineOpacity < 1;
69975         material.needsUpdate = true;
69976     }
69977     _updateOutlineMaterial() {
69978         let material = this._outline.material;
69979         this._updateLineBasicMaterial(material);
69980     }
69981 }
69982
69983 /**
69984  * @class Tag
69985  * @abstract
69986  * @classdesc Abstract class representing the basic functionality of for a tag.
69987  */
69988 class Tag extends EventEmitter {
69989     /**
69990      * Create a tag.
69991      *
69992      * @constructor
69993      * @param {string} id
69994      * @param {Geometry} geometry
69995      */
69996     constructor(id, geometry) {
69997         super();
69998         this._id = id;
69999         this._geometry = geometry;
70000         this._notifyChanged$ = new Subject();
70001         this._notifyChanged$
70002             .subscribe((t) => {
70003             const type = "tag";
70004             const event = {
70005                 target: this,
70006                 type,
70007             };
70008             this.fire(type, event);
70009         });
70010         this._geometry.changed$
70011             .subscribe((g) => {
70012             const type = "geometry";
70013             const event = {
70014                 target: this,
70015                 type,
70016             };
70017             this.fire(type, event);
70018         });
70019     }
70020     /**
70021      * Get id property.
70022      * @returns {string}
70023      */
70024     get id() {
70025         return this._id;
70026     }
70027     /**
70028      * Get geometry property.
70029      * @returns {Geometry} The geometry of the tag.
70030      */
70031     get geometry() {
70032         return this._geometry;
70033     }
70034     /**
70035      * Get changed observable.
70036      * @returns {Observable<Tag>}
70037      * @ignore
70038      */
70039     get changed$() {
70040         return this._notifyChanged$;
70041     }
70042     /**
70043      * Get geometry changed observable.
70044      * @returns {Observable<Tag>}
70045      * @ignore
70046      */
70047     get geometryChanged$() {
70048         return this._geometry.changed$.pipe(map(() => {
70049             return this;
70050         }), share());
70051     }
70052     fire(type, event) {
70053         super.fire(type, event);
70054     }
70055     off(type, handler) {
70056         super.off(type, handler);
70057     }
70058     on(type, handler) {
70059         super.on(type, handler);
70060     }
70061 }
70062
70063 /**
70064  * @class ExtremePointTag
70065  *
70066  * @classdesc Tag holding properties for visualizing a extreme points
70067  * and their outline.
70068  *
70069  * @example
70070  * ```js
70071  * var geometry = new PointsGeometry([[0.3, 0.3], [0.5, 0.4]]);
70072  * var tag = new ExtremePointTag(
70073  *     "id-1",
70074  *     geometry
70075  *     { editable: true, lineColor: 0xff0000 });
70076  *
70077  * tagComponent.add([tag]);
70078  * ```
70079  */
70080 class ExtremePointTag extends Tag {
70081     /**
70082      * Create an extreme point tag.
70083      *
70084      * @override
70085      * @constructor
70086      * @param {string} id - Unique identifier of the tag.
70087      * @param {PointsGeometry} geometry - Geometry defining points of tag.
70088      * @param {ExtremePointTagOptions} options - Options defining the visual appearance and
70089      * behavior of the extreme point tag.
70090      */
70091     constructor(id, geometry, options) {
70092         super(id, geometry);
70093         options = !!options ? options : {};
70094         this._editable = options.editable == null ? false : options.editable;
70095         this._fillColor = options.fillColor == null ? 0xFFFFFF : options.fillColor;
70096         this._fillOpacity = options.fillOpacity == null ? 0.0 : options.fillOpacity;
70097         this._indicateVertices = options.indicateVertices == null ? true : options.indicateVertices;
70098         this._lineColor = options.lineColor == null ? 0xFFFFFF : options.lineColor;
70099         this._lineOpacity = options.lineOpacity == null ? 1 : options.lineOpacity;
70100         this._lineWidth = options.lineWidth == null ? 1 : options.lineWidth;
70101     }
70102     /**
70103      * Get editable property.
70104      * @returns {boolean} Value indicating if tag is editable.
70105      */
70106     get editable() {
70107         return this._editable;
70108     }
70109     /**
70110      * Set editable property.
70111      * @param {boolean}
70112      *
70113      * @fires changed
70114      */
70115     set editable(value) {
70116         this._editable = value;
70117         this._notifyChanged$.next(this);
70118     }
70119     /**
70120      * Get fill color property.
70121      * @returns {number}
70122      */
70123     get fillColor() {
70124         return this._fillColor;
70125     }
70126     /**
70127      * Set fill color property.
70128      * @param {number}
70129      *
70130      * @fires changed
70131      */
70132     set fillColor(value) {
70133         this._fillColor = value;
70134         this._notifyChanged$.next(this);
70135     }
70136     /**
70137      * Get fill opacity property.
70138      * @returns {number}
70139      */
70140     get fillOpacity() {
70141         return this._fillOpacity;
70142     }
70143     /**
70144      * Set fill opacity property.
70145      * @param {number}
70146      *
70147      * @fires changed
70148      */
70149     set fillOpacity(value) {
70150         this._fillOpacity = value;
70151         this._notifyChanged$.next(this);
70152     }
70153     /** @inheritdoc */
70154     get geometry() {
70155         return this._geometry;
70156     }
70157     /**
70158      * Get indicate vertices property.
70159      * @returns {boolean} Value indicating if vertices should be indicated
70160      * when tag is editable.
70161      */
70162     get indicateVertices() {
70163         return this._indicateVertices;
70164     }
70165     /**
70166      * Set indicate vertices property.
70167      * @param {boolean}
70168      *
70169      * @fires changed
70170      */
70171     set indicateVertices(value) {
70172         this._indicateVertices = value;
70173         this._notifyChanged$.next(this);
70174     }
70175     /**
70176      * Get line color property.
70177      * @returns {number}
70178      */
70179     get lineColor() {
70180         return this._lineColor;
70181     }
70182     /**
70183      * Set line color property.
70184      * @param {number}
70185      *
70186      * @fires changed
70187      */
70188     set lineColor(value) {
70189         this._lineColor = value;
70190         this._notifyChanged$.next(this);
70191     }
70192     /**
70193      * Get line opacity property.
70194      * @returns {number}
70195      */
70196     get lineOpacity() {
70197         return this._lineOpacity;
70198     }
70199     /**
70200      * Set line opacity property.
70201      * @param {number}
70202      *
70203      * @fires changed
70204      */
70205     set lineOpacity(value) {
70206         this._lineOpacity = value;
70207         this._notifyChanged$.next(this);
70208     }
70209     /**
70210      * Get line width property.
70211      * @returns {number}
70212      */
70213     get lineWidth() {
70214         return this._lineWidth;
70215     }
70216     /**
70217      * Set line width property.
70218      * @param {number}
70219      *
70220      * @fires changed
70221      */
70222     set lineWidth(value) {
70223         this._lineWidth = value;
70224         this._notifyChanged$.next(this);
70225     }
70226     /**
70227      * Set options for tag.
70228      *
70229      * @description Sets all the option properties provided and keeps
70230      * the rest of the values as is.
70231      *
70232      * @param {ExtremePointTagOptions} options - Extreme point tag options
70233      *
70234      * @fires changed
70235      */
70236     setOptions(options) {
70237         this._editable = options.editable == null ? this._editable : options.editable;
70238         this._indicateVertices = options.indicateVertices == null ? this._indicateVertices : options.indicateVertices;
70239         this._lineColor = options.lineColor == null ? this._lineColor : options.lineColor;
70240         this._lineWidth = options.lineWidth == null ? this._lineWidth : options.lineWidth;
70241         this._fillColor = options.fillColor == null ? this._fillColor : options.fillColor;
70242         this._fillOpacity = options.fillOpacity == null ? this._fillOpacity : options.fillOpacity;
70243         this._notifyChanged$.next(this);
70244     }
70245 }
70246
70247 /**
70248  * Enumeration for tag domains.
70249  * @enum {number}
70250  * @readonly
70251  * @description Defines where lines between two vertices are treated
70252  * as straight.
70253  *
70254  * Only applicable for polygons. For rectangles lines between
70255  * vertices are always treated as straight in the distorted 2D
70256  * projection and bended in the undistorted 3D space.
70257  */
70258 var TagDomain;
70259 (function (TagDomain) {
70260     /**
70261      * Treats lines between two vertices as straight in the
70262      * distorted 2D projection, i.e. on the image. If the image
70263      * is distorted this will result in bended lines when rendered
70264      * in the undistorted 3D space.
70265      */
70266     TagDomain[TagDomain["TwoDimensional"] = 0] = "TwoDimensional";
70267     /**
70268      * Treats lines as straight in the undistorted 3D space. If the
70269      * image is distorted this will result in bended lines when rendered
70270      * on the distorted 2D projection of the image.
70271      */
70272     TagDomain[TagDomain["ThreeDimensional"] = 1] = "ThreeDimensional";
70273 })(TagDomain || (TagDomain = {}));
70274
70275 /**
70276  * @class OutlineRenderTag
70277  * @classdesc Tag visualizing the properties of an OutlineTag.
70278  */
70279 class OutlineRenderTag extends OutlineRenderTagBase {
70280     constructor(tag, transform) {
70281         super(tag, transform);
70282         this._fill = !isSpherical(transform.cameraType) ?
70283             this._createFill() :
70284             tag.domain === TagDomain.TwoDimensional &&
70285                 tag.geometry instanceof PolygonGeometry ?
70286                 this._createFill() :
70287                 null;
70288         this._holes = this._tag.lineWidth >= 1 ?
70289             this._createHoles() :
70290             [];
70291         this._outline = this._tag.lineWidth >= 1 ?
70292             this._createOutline() :
70293             null;
70294     }
70295     dispose() {
70296         super.dispose();
70297         this._disposeFill();
70298         this._disposeHoles();
70299         this._disposeOutline();
70300     }
70301     getDOMObjects(atlas, camera, size) {
70302         const vNodes = [];
70303         const isRect = this._tag.geometry instanceof RectGeometry;
70304         const isPerspective = !isSpherical(this._transform.cameraType);
70305         const container = {
70306             offsetHeight: size.height, offsetWidth: size.width,
70307         };
70308         if (this._tag.icon != null && (isRect || isPerspective)) {
70309             const [iconBasicX, iconBasicY] = this._tag.geometry instanceof RectGeometry ?
70310                 this._tag.geometry.getVertex2d(this._tag.iconIndex) :
70311                 this._tag.geometry.getPoleOfInaccessibility2d();
70312             const iconCanvas = this._viewportCoords.basicToCanvasSafe(iconBasicX, iconBasicY, container, this._transform, camera);
70313             if (iconCanvas != null) {
70314                 const interact = () => {
70315                     this._interact$.next({ offsetX: 0, offsetY: 0, operation: TagOperation.None, tag: this._tag });
70316                 };
70317                 if (atlas.loaded) {
70318                     const sprite = atlas.getDOMSprite(this._tag.icon, this._tag.iconFloat);
70319                     const iconCanvasX = Math.round(iconCanvas[0]);
70320                     const iconCanvasY = Math.round(iconCanvas[1]);
70321                     const transform = `translate(${iconCanvasX}px,${iconCanvasY}px)`;
70322                     const click = (e) => {
70323                         e.stopPropagation();
70324                         this._tag.click$.next(this._tag);
70325                     };
70326                     const properties = {
70327                         onclick: click,
70328                         onpointerdown: interact,
70329                         style: { transform: transform },
70330                     };
70331                     vNodes.push(virtualDom.h("div.mapillary-tag-symbol", properties, [sprite]));
70332                 }
70333             }
70334         }
70335         else if (this._tag.text != null && (isRect || isPerspective)) {
70336             const [textBasicX, textBasicY] = this._tag.geometry instanceof RectGeometry ?
70337                 this._tag.geometry.getVertex2d(3) :
70338                 this._tag.geometry.getPoleOfInaccessibility2d();
70339             const textCanvas = this._viewportCoords.basicToCanvasSafe(textBasicX, textBasicY, container, this._transform, camera);
70340             if (textCanvas != null) {
70341                 const textCanvasX = Math.round(textCanvas[0]);
70342                 const textCanvasY = Math.round(textCanvas[1]);
70343                 const transform = this._tag.geometry instanceof RectGeometry ?
70344                     `translate(${textCanvasX}px,${textCanvasY}px)` :
70345                     `translate(-50%, -50%) translate(${textCanvasX}px,${textCanvasY}px)`;
70346                 const interact = () => {
70347                     this._interact$.next({ offsetX: 0, offsetY: 0, operation: TagOperation.None, tag: this._tag });
70348                 };
70349                 const properties = {
70350                     onpointerdown: interact,
70351                     style: {
70352                         color: this._colorToCss(this._tag.textColor),
70353                         transform: transform,
70354                     },
70355                     textContent: this._tag.text,
70356                 };
70357                 vNodes.push(virtualDom.h("span.mapillary-tag-symbol", properties, []));
70358             }
70359         }
70360         if (!this._tag.editable) {
70361             return vNodes;
70362         }
70363         const lineColor = this._colorToCss(this._tag.lineColor);
70364         if (this._tag.geometry instanceof RectGeometry) {
70365             const [centroidBasicX, centroidBasicY] = this._tag.geometry.getCentroid2d();
70366             const centroidCanvas = this._viewportCoords.basicToCanvasSafe(centroidBasicX, centroidBasicY, container, this._transform, camera);
70367             if (centroidCanvas != null) {
70368                 const interact = this._interact(TagOperation.Centroid, "move");
70369                 const centroidCanvasX = Math.round(centroidCanvas[0]);
70370                 const centroidCanvasY = Math.round(centroidCanvas[1]);
70371                 const transform = `translate(-50%, -50%) translate(${centroidCanvasX}px,${centroidCanvasY}px)`;
70372                 const properties = {
70373                     onpointerdown: interact,
70374                     style: { background: lineColor, transform: transform },
70375                 };
70376                 vNodes.push(virtualDom.h("div.mapillary-tag-mover", properties, []));
70377             }
70378         }
70379         const vertices2d = this._tag.geometry.getVertices2d();
70380         for (let i = 0; i < vertices2d.length - 1; i++) {
70381             if (isRect &&
70382                 ((this._tag.icon != null && i === this._tag.iconIndex) ||
70383                     (this._tag.icon == null && this._tag.text != null && i === 3))) {
70384                 continue;
70385             }
70386             const [vertexBasicX, vertexBasicY] = vertices2d[i];
70387             const vertexCanvas = this._viewportCoords.basicToCanvasSafe(vertexBasicX, vertexBasicY, container, this._transform, camera);
70388             if (vertexCanvas == null) {
70389                 continue;
70390             }
70391             const cursor = isRect ?
70392                 i % 2 === 0 ? "nesw-resize" : "nwse-resize" :
70393                 "crosshair";
70394             const interact = this._interact(TagOperation.Vertex, cursor, i);
70395             const vertexCanvasX = Math.round(vertexCanvas[0]);
70396             const vertexCanvasY = Math.round(vertexCanvas[1]);
70397             const transform = `translate(-50%, -50%) translate(${vertexCanvasX}px,${vertexCanvasY}px)`;
70398             const properties = {
70399                 onpointerdown: interact,
70400                 style: { background: lineColor, transform: transform, cursor: cursor },
70401             };
70402             vNodes.push(virtualDom.h("div.mapillary-tag-resizer", properties, []));
70403             if (!this._tag.indicateVertices) {
70404                 continue;
70405             }
70406             const pointProperties = {
70407                 style: { background: lineColor, transform: transform },
70408             };
70409             vNodes.push(virtualDom.h("div.mapillary-tag-vertex", pointProperties, []));
70410         }
70411         return vNodes;
70412     }
70413     getGLObjects() {
70414         const glObjects = [];
70415         if (this._fill != null) {
70416             glObjects.push(this._fill);
70417         }
70418         for (const hole of this._holes) {
70419             glObjects.push(hole);
70420         }
70421         if (this._outline != null) {
70422             glObjects.push(this._outline);
70423         }
70424         return glObjects;
70425     }
70426     getRetrievableObjects() {
70427         return this._fill != null ? [this._fill] : [];
70428     }
70429     _onGeometryChanged() {
70430         if (this._fill != null) {
70431             this._updateFillGeometry();
70432         }
70433         if (this._holes.length > 0) {
70434             this._updateHoleGeometries();
70435         }
70436         if (this._outline != null) {
70437             this._updateOulineGeometry();
70438         }
70439     }
70440     _onTagChanged() {
70441         let glObjectsChanged = false;
70442         if (this._fill != null) {
70443             this._updateFillMaterial(this._fill.material);
70444         }
70445         if (this._outline == null) {
70446             if (this._tag.lineWidth >= 1) {
70447                 this._holes = this._createHoles();
70448                 this._outline = this._createOutline();
70449                 glObjectsChanged = true;
70450             }
70451         }
70452         else {
70453             this._updateHoleMaterials();
70454             this._updateOutlineMaterial();
70455         }
70456         return glObjectsChanged;
70457     }
70458     _getPoints3d() {
70459         return this._in3dDomain() ?
70460             this._tag.geometry.getVertices3d(this._transform) :
70461             this._tag.geometry.getPoints3d(this._transform);
70462     }
70463     _getTriangles() {
70464         return this._in3dDomain() ?
70465             this._tag.geometry.get3dDomainTriangles3d(this._transform) :
70466             this._tag.geometry.getTriangles3d(this._transform);
70467     }
70468     _updateFillMaterial(material) {
70469         material.color = new Color(this._tag.fillColor);
70470         material.opacity = this._tag.fillOpacity;
70471         material.needsUpdate = true;
70472     }
70473     _updateLineBasicMaterial(material) {
70474         material.color = new Color(this._tag.lineColor);
70475         material.linewidth = Math.max(this._tag.lineWidth, 1);
70476         material.visible = this._tag.lineWidth >= 1 && this._tag.lineOpacity > 0;
70477         material.opacity = this._tag.lineOpacity;
70478         material.transparent = this._tag.lineOpacity < 1;
70479         material.needsUpdate = true;
70480     }
70481     _createHoles() {
70482         let holes = [];
70483         if (this._tag.geometry instanceof PolygonGeometry) {
70484             let holes3d = this._getHoles3d();
70485             for (let holePoints3d of holes3d) {
70486                 let hole = this._createLine(holePoints3d);
70487                 holes.push(hole);
70488             }
70489         }
70490         return holes;
70491     }
70492     _disposeHoles() {
70493         for (let hole of this._holes) {
70494             hole.geometry.dispose();
70495             hole.material.dispose();
70496         }
70497         this._holes = [];
70498     }
70499     _getHoles3d() {
70500         const polygonGeometry = this._tag.geometry;
70501         return this._in3dDomain() ?
70502             polygonGeometry.getHoleVertices3d(this._transform) :
70503             polygonGeometry.getHolePoints3d(this._transform);
70504     }
70505     _in3dDomain() {
70506         return this._tag.geometry instanceof PolygonGeometry && this._tag.domain === TagDomain.ThreeDimensional;
70507     }
70508     _updateHoleGeometries() {
70509         let holes3d = this._getHoles3d();
70510         if (holes3d.length !== this._holes.length) {
70511             throw new Error("Changing the number of holes is not supported.");
70512         }
70513         for (let i = 0; i < this._holes.length; i++) {
70514             let holePoints3d = holes3d[i];
70515             let hole = this._holes[i];
70516             this._updateLine(hole, holePoints3d);
70517         }
70518     }
70519     _updateHoleMaterials() {
70520         for (const hole of this._holes) {
70521             this._updateLineBasicMaterial(hole.material);
70522         }
70523     }
70524     _updateOutlineMaterial() {
70525         this._updateLineBasicMaterial(this._outline.material);
70526     }
70527 }
70528
70529 /**
70530  * Enumeration for alignments
70531  * @enum {number}
70532  * @readonly
70533  */
70534 var Alignment;
70535 (function (Alignment) {
70536     /**
70537      * Align to bottom
70538      */
70539     Alignment[Alignment["Bottom"] = 0] = "Bottom";
70540     /**
70541      * Align to bottom left
70542      */
70543     Alignment[Alignment["BottomLeft"] = 1] = "BottomLeft";
70544     /**
70545      * Align to bottom right
70546      */
70547     Alignment[Alignment["BottomRight"] = 2] = "BottomRight";
70548     /**
70549      * Align to center
70550      */
70551     Alignment[Alignment["Center"] = 3] = "Center";
70552     /**
70553      * Align to left
70554      */
70555     Alignment[Alignment["Left"] = 4] = "Left";
70556     /**
70557      * Align to right
70558      */
70559     Alignment[Alignment["Right"] = 5] = "Right";
70560     /**
70561      * Align to top
70562      */
70563     Alignment[Alignment["Top"] = 6] = "Top";
70564     /**
70565      * Align to top left
70566      */
70567     Alignment[Alignment["TopLeft"] = 7] = "TopLeft";
70568     /**
70569      * Align to top right
70570      */
70571     Alignment[Alignment["TopRight"] = 8] = "TopRight";
70572 })(Alignment || (Alignment = {}));
70573
70574 /**
70575  * @class OutlineTag
70576  *
70577  * @classdesc Tag holding properties for visualizing a geometry outline.
70578  *
70579  * @example
70580  * ```js
70581  * var geometry = new RectGeometry([0.3, 0.3, 0.5, 0.4]);
70582  * var tag = new OutlineTag(
70583  *     "id-1",
70584  *     geometry
70585  *     { editable: true, lineColor: 0xff0000 });
70586  *
70587  * tagComponent.add([tag]);
70588  * ```
70589  */
70590 class OutlineTag extends Tag {
70591     /**
70592      * Create an outline tag.
70593      *
70594      * @override
70595      * @constructor
70596      * @param {string} id - Unique identifier of the tag.
70597      * @param {VertexGeometry} geometry - Geometry defining vertices of tag.
70598      * @param {OutlineTagOptions} options - Options defining the visual appearance and
70599      * behavior of the outline tag.
70600      */
70601     constructor(id, geometry, options) {
70602         super(id, geometry);
70603         options = !!options ? options : {};
70604         const domain = options.domain != null && geometry instanceof PolygonGeometry ?
70605             options.domain : TagDomain.TwoDimensional;
70606         const twoDimensionalPolygon = this._twoDimensionalPolygon(domain, geometry);
70607         this._domain = domain;
70608         this._editable = options.editable == null || twoDimensionalPolygon ? false : options.editable;
70609         this._fillColor = options.fillColor == null ? 0xFFFFFF : options.fillColor;
70610         this._fillOpacity = options.fillOpacity == null ? 0.0 : options.fillOpacity;
70611         this._icon = options.icon === undefined ? null : options.icon;
70612         this._iconFloat = options.iconFloat == null ? Alignment.Center : options.iconFloat;
70613         this._iconIndex = options.iconIndex == null ? 3 : options.iconIndex;
70614         this._indicateVertices = options.indicateVertices == null ? true : options.indicateVertices;
70615         this._lineColor = options.lineColor == null ? 0xFFFFFF : options.lineColor;
70616         this._lineOpacity = options.lineOpacity == null ? 1 : options.lineOpacity;
70617         this._lineWidth = options.lineWidth == null ? 1 : options.lineWidth;
70618         this._text = options.text === undefined ? null : options.text;
70619         this._textColor = options.textColor == null ? 0xFFFFFF : options.textColor;
70620         this._click$ = new Subject();
70621         this._click$
70622             .subscribe(() => {
70623             const type = "click";
70624             const event = {
70625                 target: this,
70626                 type,
70627             };
70628             this.fire(type, event);
70629         });
70630     }
70631     /**
70632      * Click observable.
70633      *
70634      * @description An observable emitting the tag when the icon of the
70635      * tag has been clicked.
70636      *
70637      * @returns {Observable<Tag>}
70638      */
70639     get click$() {
70640         return this._click$;
70641     }
70642     /**
70643      * Get domain property.
70644      *
70645      * @description Readonly property that can only be set in constructor.
70646      *
70647      * @returns Value indicating the domain of the tag.
70648      */
70649     get domain() {
70650         return this._domain;
70651     }
70652     /**
70653      * Get editable property.
70654      * @returns {boolean} Value indicating if tag is editable.
70655      */
70656     get editable() {
70657         return this._editable;
70658     }
70659     /**
70660      * Set editable property.
70661      * @param {boolean}
70662      *
70663      * @fires changed
70664      */
70665     set editable(value) {
70666         if (this._twoDimensionalPolygon(this._domain, this._geometry)) {
70667             return;
70668         }
70669         this._editable = value;
70670         this._notifyChanged$.next(this);
70671     }
70672     /**
70673      * Get fill color property.
70674      * @returns {number}
70675      */
70676     get fillColor() {
70677         return this._fillColor;
70678     }
70679     /**
70680      * Set fill color property.
70681      * @param {number}
70682      *
70683      * @fires changed
70684      */
70685     set fillColor(value) {
70686         this._fillColor = value;
70687         this._notifyChanged$.next(this);
70688     }
70689     /**
70690      * Get fill opacity property.
70691      * @returns {number}
70692      */
70693     get fillOpacity() {
70694         return this._fillOpacity;
70695     }
70696     /**
70697      * Set fill opacity property.
70698      * @param {number}
70699      *
70700      * @fires changed
70701      */
70702     set fillOpacity(value) {
70703         this._fillOpacity = value;
70704         this._notifyChanged$.next(this);
70705     }
70706     /** @inheritdoc */
70707     get geometry() {
70708         return this._geometry;
70709     }
70710     /**
70711      * Get icon property.
70712      * @returns {string}
70713      */
70714     get icon() {
70715         return this._icon;
70716     }
70717     /**
70718      * Set icon property.
70719      * @param {string}
70720      *
70721      * @fires changed
70722      */
70723     set icon(value) {
70724         this._icon = value;
70725         this._notifyChanged$.next(this);
70726     }
70727     /**
70728      * Get icon float property.
70729      * @returns {Alignment}
70730      */
70731     get iconFloat() {
70732         return this._iconFloat;
70733     }
70734     /**
70735      * Set icon float property.
70736      * @param {Alignment}
70737      *
70738      * @fires changed
70739      */
70740     set iconFloat(value) {
70741         this._iconFloat = value;
70742         this._notifyChanged$.next(this);
70743     }
70744     /**
70745      * Get icon index property.
70746      * @returns {number}
70747      */
70748     get iconIndex() {
70749         return this._iconIndex;
70750     }
70751     /**
70752      * Set icon index property.
70753      * @param {number}
70754      *
70755      * @fires changed
70756      */
70757     set iconIndex(value) {
70758         this._iconIndex = value;
70759         this._notifyChanged$.next(this);
70760     }
70761     /**
70762      * Get indicate vertices property.
70763      * @returns {boolean} Value indicating if vertices should be indicated
70764      * when tag is editable.
70765      */
70766     get indicateVertices() {
70767         return this._indicateVertices;
70768     }
70769     /**
70770      * Set indicate vertices property.
70771      * @param {boolean}
70772      *
70773      * @fires changed
70774      */
70775     set indicateVertices(value) {
70776         this._indicateVertices = value;
70777         this._notifyChanged$.next(this);
70778     }
70779     /**
70780      * Get line color property.
70781      * @returns {number}
70782      */
70783     get lineColor() {
70784         return this._lineColor;
70785     }
70786     /**
70787      * Set line color property.
70788      * @param {number}
70789      *
70790      * @fires changed
70791      */
70792     set lineColor(value) {
70793         this._lineColor = value;
70794         this._notifyChanged$.next(this);
70795     }
70796     /**
70797      * Get line opacity property.
70798      * @returns {number}
70799      */
70800     get lineOpacity() {
70801         return this._lineOpacity;
70802     }
70803     /**
70804      * Set line opacity property.
70805      * @param {number}
70806      *
70807      * @fires changed
70808      */
70809     set lineOpacity(value) {
70810         this._lineOpacity = value;
70811         this._notifyChanged$.next(this);
70812     }
70813     /**
70814      * Get line width property.
70815      * @returns {number}
70816      */
70817     get lineWidth() {
70818         return this._lineWidth;
70819     }
70820     /**
70821      * Set line width property.
70822      * @param {number}
70823      *
70824      * @fires changed
70825      */
70826     set lineWidth(value) {
70827         this._lineWidth = value;
70828         this._notifyChanged$.next(this);
70829     }
70830     /**
70831      * Get text property.
70832      * @returns {string}
70833      */
70834     get text() {
70835         return this._text;
70836     }
70837     /**
70838      * Set text property.
70839      * @param {string}
70840      *
70841      * @fires changed
70842      */
70843     set text(value) {
70844         this._text = value;
70845         this._notifyChanged$.next(this);
70846     }
70847     /**
70848      * Get text color property.
70849      * @returns {number}
70850      */
70851     get textColor() {
70852         return this._textColor;
70853     }
70854     /**
70855      * Set text color property.
70856      * @param {number}
70857      *
70858      * @fires changed
70859      */
70860     set textColor(value) {
70861         this._textColor = value;
70862         this._notifyChanged$.next(this);
70863     }
70864     fire(type, event) {
70865         super.fire(type, event);
70866     }
70867     off(type, handler) {
70868         super.off(type, handler);
70869     }
70870     on(type, handler) {
70871         super.on(type, handler);
70872     }
70873     /**
70874      * Set options for tag.
70875      *
70876      * @description Sets all the option properties provided and keeps
70877      * the rest of the values as is.
70878      *
70879      * @param {OutlineTagOptions} options - Outline tag options
70880      *
70881      * @fires changed
70882      */
70883     setOptions(options) {
70884         const twoDimensionalPolygon = this._twoDimensionalPolygon(this._domain, this._geometry);
70885         this._editable = twoDimensionalPolygon || options.editable == null ? this._editable : options.editable;
70886         this._icon = options.icon === undefined ? this._icon : options.icon;
70887         this._iconFloat = options.iconFloat == null ? this._iconFloat : options.iconFloat;
70888         this._iconIndex = options.iconIndex == null ? this._iconIndex : options.iconIndex;
70889         this._indicateVertices = options.indicateVertices == null ? this._indicateVertices : options.indicateVertices;
70890         this._lineColor = options.lineColor == null ? this._lineColor : options.lineColor;
70891         this._lineWidth = options.lineWidth == null ? this._lineWidth : options.lineWidth;
70892         this._fillColor = options.fillColor == null ? this._fillColor : options.fillColor;
70893         this._fillOpacity = options.fillOpacity == null ? this._fillOpacity : options.fillOpacity;
70894         this._text = options.text === undefined ? this._text : options.text;
70895         this._textColor = options.textColor == null ? this._textColor : options.textColor;
70896         this._notifyChanged$.next(this);
70897     }
70898     _twoDimensionalPolygon(domain, geometry) {
70899         return domain !== TagDomain.ThreeDimensional && geometry instanceof PolygonGeometry;
70900     }
70901 }
70902
70903 /**
70904  * @class SpotRenderTag
70905  * @classdesc Tag visualizing the properties of a SpotTag.
70906  */
70907 class SpotRenderTag extends RenderTag {
70908     dispose() { }
70909     getDOMObjects(atlas, camera, size) {
70910         const tag = this._tag;
70911         const container = {
70912             offsetHeight: size.height, offsetWidth: size.width,
70913         };
70914         const vNodes = [];
70915         const [centroidBasicX, centroidBasicY] = tag.geometry.getCentroid2d();
70916         const centroidCanvas = this._viewportCoords.basicToCanvasSafe(centroidBasicX, centroidBasicY, container, this._transform, camera);
70917         if (centroidCanvas != null) {
70918             const interactNone = (e) => {
70919                 this._interact$.next({ offsetX: 0, offsetY: 0, operation: TagOperation.None, tag: tag });
70920             };
70921             const canvasX = Math.round(centroidCanvas[0]);
70922             const canvasY = Math.round(centroidCanvas[1]);
70923             if (tag.icon != null) {
70924                 if (atlas.loaded) {
70925                     const sprite = atlas.getDOMSprite(tag.icon, Alignment.Bottom);
70926                     const iconTransform = `translate(${canvasX}px,${canvasY + 8}px)`;
70927                     const properties = {
70928                         onpointerdown: interactNone,
70929                         style: {
70930                             pointerEvents: "all",
70931                             transform: iconTransform,
70932                         },
70933                     };
70934                     vNodes.push(virtualDom.h("div", properties, [sprite]));
70935                 }
70936             }
70937             else if (tag.text != null) {
70938                 const textTransform = `translate(-50%,0%) translate(${canvasX}px,${canvasY + 8}px)`;
70939                 const properties = {
70940                     onpointerdown: interactNone,
70941                     style: {
70942                         color: this._colorToCss(tag.textColor),
70943                         transform: textTransform,
70944                     },
70945                     textContent: tag.text,
70946                 };
70947                 vNodes.push(virtualDom.h("span.mapillary-tag-symbol", properties, []));
70948             }
70949             const interact = this._interact(TagOperation.Centroid, tag, "move");
70950             const background = this._colorToCss(tag.color);
70951             const transform = `translate(-50%,-50%) translate(${canvasX}px,${canvasY}px)`;
70952             if (tag.editable) {
70953                 let interactorProperties = {
70954                     onpointerdown: interact,
70955                     style: {
70956                         background: background,
70957                         transform: transform,
70958                     },
70959                 };
70960                 vNodes.push(virtualDom.h("div.mapillary-tag-spot-interactor", interactorProperties, []));
70961             }
70962             const pointProperties = {
70963                 style: {
70964                     background: background,
70965                     transform: transform,
70966                 },
70967             };
70968             vNodes.push(virtualDom.h("div.mapillary-tag-vertex", pointProperties, []));
70969         }
70970         return vNodes;
70971     }
70972     getGLObjects() { return []; }
70973     getRetrievableObjects() { return []; }
70974     _colorToCss(color) {
70975         return "#" + ("000000" + color.toString(16)).substr(-6);
70976     }
70977     _interact(operation, tag, cursor, vertexIndex) {
70978         return (e) => {
70979             const offsetX = e.offsetX - e.target.offsetWidth / 2;
70980             const offsetY = e.offsetY - e.target.offsetHeight / 2;
70981             this._interact$.next({
70982                 cursor: cursor,
70983                 offsetX: offsetX,
70984                 offsetY: offsetY,
70985                 operation: operation,
70986                 tag: tag,
70987                 vertexIndex: vertexIndex,
70988             });
70989         };
70990     }
70991 }
70992
70993 /**
70994  * @class SpotTag
70995  *
70996  * @classdesc Tag holding properties for visualizing the centroid of a geometry.
70997  *
70998  * @example
70999  * ```js
71000  * var geometry = new PointGeometry([0.3, 0.3]);
71001  * var tag = new SpotTag(
71002  *     "id-1",
71003  *     geometry
71004  *     { editable: true, color: 0xff0000 });
71005  *
71006  * tagComponent.add([tag]);
71007  * ```
71008  */
71009 class SpotTag extends Tag {
71010     /**
71011      * Create a spot tag.
71012      *
71013      * @override
71014      * @constructor
71015      * @param {string} id
71016      * @param {Geometry} geometry
71017      * @param {IOutlineTagOptions} options - Options defining the visual appearance and
71018      * behavior of the spot tag.
71019      */
71020     constructor(id, geometry, options) {
71021         super(id, geometry);
71022         options = !!options ? options : {};
71023         this._color = options.color == null ? 0xFFFFFF : options.color;
71024         this._editable = options.editable == null ? false : options.editable;
71025         this._icon = options.icon === undefined ? null : options.icon;
71026         this._text = options.text === undefined ? null : options.text;
71027         this._textColor = options.textColor == null ? 0xFFFFFF : options.textColor;
71028     }
71029     /**
71030      * Get color property.
71031      * @returns {number} The color of the spot as a hexagonal number;
71032      */
71033     get color() {
71034         return this._color;
71035     }
71036     /**
71037      * Set color property.
71038      * @param {number}
71039      *
71040      * @fires changed
71041      */
71042     set color(value) {
71043         this._color = value;
71044         this._notifyChanged$.next(this);
71045     }
71046     /**
71047      * Get editable property.
71048      * @returns {boolean} Value indicating if tag is editable.
71049      */
71050     get editable() {
71051         return this._editable;
71052     }
71053     /**
71054      * Set editable property.
71055      * @param {boolean}
71056      *
71057      * @fires changed
71058      */
71059     set editable(value) {
71060         this._editable = value;
71061         this._notifyChanged$.next(this);
71062     }
71063     /**
71064      * Get icon property.
71065      * @returns {string}
71066      */
71067     get icon() {
71068         return this._icon;
71069     }
71070     /**
71071      * Set icon property.
71072      * @param {string}
71073      *
71074      * @fires changed
71075      */
71076     set icon(value) {
71077         this._icon = value;
71078         this._notifyChanged$.next(this);
71079     }
71080     /**
71081      * Get text property.
71082      * @returns {string}
71083      */
71084     get text() {
71085         return this._text;
71086     }
71087     /**
71088      * Set text property.
71089      * @param {string}
71090      *
71091      * @fires changed
71092      */
71093     set text(value) {
71094         this._text = value;
71095         this._notifyChanged$.next(this);
71096     }
71097     /**
71098      * Get text color property.
71099      * @returns {number}
71100      */
71101     get textColor() {
71102         return this._textColor;
71103     }
71104     /**
71105      * Set text color property.
71106      * @param {number}
71107      *
71108      * @fires changed
71109      */
71110     set textColor(value) {
71111         this._textColor = value;
71112         this._notifyChanged$.next(this);
71113     }
71114     /**
71115      * Set options for tag.
71116      *
71117      * @description Sets all the option properties provided and keps
71118      * the rest of the values as is.
71119      *
71120      * @param {SpotTagOptions} options - Spot tag options
71121      *
71122      * @fires changed
71123      */
71124     setOptions(options) {
71125         this._color = options.color == null ? this._color : options.color;
71126         this._editable = options.editable == null ? this._editable : options.editable;
71127         this._icon = options.icon === undefined ? this._icon : options.icon;
71128         this._text = options.text === undefined ? this._text : options.text;
71129         this._textColor = options.textColor == null ? this._textColor : options.textColor;
71130         this._notifyChanged$.next(this);
71131     }
71132 }
71133
71134 class TagSet {
71135     constructor() {
71136         this._active = false;
71137         this._hash = {};
71138         this._hashDeactivated = {};
71139         this._notifyChanged$ = new Subject();
71140     }
71141     get active() {
71142         return this._active;
71143     }
71144     get changed$() {
71145         return this._notifyChanged$;
71146     }
71147     activate(transform) {
71148         if (this._active) {
71149             return;
71150         }
71151         for (const id in this._hashDeactivated) {
71152             if (!this._hashDeactivated.hasOwnProperty(id)) {
71153                 continue;
71154             }
71155             const tag = this._hashDeactivated[id];
71156             this._add(tag, transform);
71157         }
71158         this._hashDeactivated = {};
71159         this._active = true;
71160         this._notifyChanged$.next(this);
71161     }
71162     deactivate() {
71163         if (!this._active) {
71164             return;
71165         }
71166         for (const id in this._hash) {
71167             if (!this._hash.hasOwnProperty(id)) {
71168                 continue;
71169             }
71170             this._hashDeactivated[id] = this._hash[id].tag;
71171         }
71172         this._hash = {};
71173         this._active = false;
71174     }
71175     add(tags, transform) {
71176         this._assertActivationState(true);
71177         for (const tag of tags) {
71178             this._add(tag, transform);
71179         }
71180         this._notifyChanged$.next(this);
71181     }
71182     addDeactivated(tags) {
71183         this._assertActivationState(false);
71184         for (const tag of tags) {
71185             if (!(tag instanceof OutlineTag ||
71186                 tag instanceof SpotTag ||
71187                 tag instanceof ExtremePointTag)) {
71188                 throw new Error("Tag type not supported");
71189             }
71190             this._hashDeactivated[tag.id] = tag;
71191         }
71192     }
71193     get(id) {
71194         return this.has(id) ? this._hash[id] : undefined;
71195     }
71196     getAll() {
71197         const hash = this._hash;
71198         return Object.keys(hash)
71199             .map((id) => {
71200             return hash[id];
71201         });
71202     }
71203     getAllDeactivated() {
71204         const hashDeactivated = this._hashDeactivated;
71205         return Object.keys(hashDeactivated)
71206             .map((id) => {
71207             return hashDeactivated[id];
71208         });
71209     }
71210     getDeactivated(id) {
71211         return this.hasDeactivated(id) ? this._hashDeactivated[id] : undefined;
71212     }
71213     has(id) {
71214         return id in this._hash;
71215     }
71216     hasDeactivated(id) {
71217         return id in this._hashDeactivated;
71218     }
71219     remove(ids) {
71220         this._assertActivationState(true);
71221         const hash = this._hash;
71222         for (const id of ids) {
71223             if (!(id in hash)) {
71224                 continue;
71225             }
71226             delete hash[id];
71227         }
71228         this._notifyChanged$.next(this);
71229     }
71230     removeAll() {
71231         this._assertActivationState(true);
71232         this._hash = {};
71233         this._notifyChanged$.next(this);
71234     }
71235     removeAllDeactivated() {
71236         this._assertActivationState(false);
71237         this._hashDeactivated = {};
71238     }
71239     removeDeactivated(ids) {
71240         this._assertActivationState(false);
71241         const hashDeactivated = this._hashDeactivated;
71242         for (const id of ids) {
71243             if (!(id in hashDeactivated)) {
71244                 continue;
71245             }
71246             delete hashDeactivated[id];
71247         }
71248     }
71249     _add(tag, transform) {
71250         if (tag instanceof OutlineTag) {
71251             this._hash[tag.id] = new OutlineRenderTag(tag, transform);
71252         }
71253         else if (tag instanceof SpotTag) {
71254             this._hash[tag.id] = new SpotRenderTag(tag, transform);
71255         }
71256         else if (tag instanceof ExtremePointTag) {
71257             this._hash[tag.id] = new ExtremePointRenderTag(tag, transform);
71258         }
71259         else {
71260             throw new Error("Tag type not supported");
71261         }
71262     }
71263     _assertActivationState(should) {
71264         if (should !== this._active) {
71265             throw new Error("Tag set not in correct state for operation.");
71266         }
71267     }
71268 }
71269
71270 /**
71271  * @class PointGeometry
71272  *
71273  * @classdesc Represents a point geometry in the 2D basic image coordinate system.
71274  *
71275  * @example
71276  * ```js
71277  * var basicPoint = [0.5, 0.7];
71278  * var pointGeometry = new PointGeometry(basicPoint);
71279  * ```
71280  */
71281 class PointGeometry extends Geometry {
71282     /**
71283      * Create a point geometry.
71284      *
71285      * @constructor
71286      * @param {Array<number>} point - An array representing the basic coordinates of
71287      * the point.
71288      *
71289      * @throws {GeometryTagError} Point coordinates must be valid basic coordinates.
71290      */
71291     constructor(point) {
71292         super();
71293         let x = point[0];
71294         let y = point[1];
71295         if (x < 0 || x > 1 || y < 0 || y > 1) {
71296             throw new GeometryTagError("Basic coordinates must be on the interval [0, 1].");
71297         }
71298         this._point = point.slice();
71299     }
71300     /**
71301      * Get point property.
71302      * @returns {Array<number>} Array representing the basic coordinates of the point.
71303      */
71304     get point() {
71305         return this._point;
71306     }
71307     /**
71308      * Get the 2D basic coordinates for the centroid of the point, i.e. the 2D
71309      * basic coordinates of the point itself.
71310      *
71311      * @returns {Array<number>} 2D basic coordinates representing the centroid.
71312      * @ignore
71313      */
71314     getCentroid2d() {
71315         return this._point.slice();
71316     }
71317     /**
71318      * Get the 3D world coordinates for the centroid of the point, i.e. the 3D
71319      * world coordinates of the point itself.
71320      *
71321      * @param {Transform} transform - The transform of the image related to the point.
71322      * @returns {Array<number>} 3D world coordinates representing the centroid.
71323      * @ignore
71324      */
71325     getCentroid3d(transform) {
71326         return transform.unprojectBasic(this._point, 200);
71327     }
71328     /**
71329      * Set the centroid of the point, i.e. the point coordinates.
71330      *
71331      * @param {Array<number>} value - The new value of the centroid.
71332      * @param {Transform} transform - The transform of the image related to the point.
71333      * @ignore
71334      */
71335     setCentroid2d(value, transform) {
71336         let changed = [
71337             Math.max(0, Math.min(1, value[0])),
71338             Math.max(0, Math.min(1, value[1])),
71339         ];
71340         this._point[0] = changed[0];
71341         this._point[1] = changed[1];
71342         this._notifyChanged$.next(this);
71343     }
71344 }
71345
71346 class TagHandlerBase extends HandlerBase {
71347     constructor(component, container, navigator, viewportCoords) {
71348         super(component, container, navigator);
71349         this._name = `${this._component.name}-${this._getNameExtension()}`;
71350         this._viewportCoords = viewportCoords;
71351     }
71352     _getConfiguration(enable) {
71353         return {};
71354     }
71355     _mouseEventToBasic(event, element, camera, transform, offsetX, offsetY) {
71356         offsetX = offsetX != null ? offsetX : 0;
71357         offsetY = offsetY != null ? offsetY : 0;
71358         const [canvasX, canvasY] = this._viewportCoords.canvasPosition(event, element);
71359         const basic = this._viewportCoords.canvasToBasic(canvasX - offsetX, canvasY - offsetY, element, transform, camera.perspective);
71360         return basic;
71361     }
71362 }
71363
71364 class CreateHandlerBase extends TagHandlerBase {
71365     constructor(component, container, navigator, viewportCoords, tagCreator) {
71366         super(component, container, navigator, viewportCoords);
71367         this._tagCreator = tagCreator;
71368         this._geometryCreated$ = new Subject();
71369     }
71370     get geometryCreated$() {
71371         return this._geometryCreated$;
71372     }
71373     _enable() {
71374         this._enableCreate();
71375         this._container.container.classList.add("component-tag-create");
71376     }
71377     _disable() {
71378         this._container.container.classList.remove("component-tag-create");
71379         this._disableCreate();
71380     }
71381     _validateBasic(basic) {
71382         const x = basic[0];
71383         const y = basic[1];
71384         return 0 <= x && x <= 1 && 0 <= y && y <= 1;
71385     }
71386     _mouseEventToBasic$(mouseEvent$) {
71387         return mouseEvent$.pipe(withLatestFrom(this._container.renderService.renderCamera$, this._navigator.stateService.currentTransform$), map(([event, camera, transform]) => {
71388             return this._mouseEventToBasic(event, this._container.container, camera, transform);
71389         }));
71390     }
71391 }
71392
71393 class CreatePointHandler extends CreateHandlerBase {
71394     _enableCreate() {
71395         this._container.mouseService.deferPixels(this._name, 4);
71396         this._geometryCreatedSubscription = this._mouseEventToBasic$(this._container.mouseService.proximateClick$).pipe(filter(this._validateBasic), map((basic) => {
71397             return new PointGeometry(basic);
71398         }))
71399             .subscribe(this._geometryCreated$);
71400     }
71401     _disableCreate() {
71402         this._container.mouseService.undeferPixels(this._name);
71403         this._geometryCreatedSubscription.unsubscribe();
71404     }
71405     _getNameExtension() {
71406         return "create-point";
71407     }
71408 }
71409
71410 class CreateVertexHandler extends CreateHandlerBase {
71411     _enableCreate() {
71412         this._container.mouseService.deferPixels(this._name, 4);
71413         const transformChanged$ = this._navigator.stateService.currentTransform$.pipe(map(() => { }), publishReplay(1), refCount());
71414         this._deleteSubscription = transformChanged$.pipe(skip(1))
71415             .subscribe(this._tagCreator.delete$);
71416         const basicClick$ = this._mouseEventToBasic$(this._container.mouseService.proximateClick$).pipe(share());
71417         this._createSubscription = transformChanged$.pipe(switchMap(() => {
71418             return basicClick$.pipe(filter(this._validateBasic), take(1));
71419         }))
71420             .subscribe(this._create$);
71421         this._setVertexSubscription = this._tagCreator.tag$.pipe(switchMap((tag) => {
71422             return !!tag ?
71423                 combineLatest(of(tag), merge(this._container.mouseService.mouseMove$, this._container.mouseService.domMouseMove$), this._container.renderService.renderCamera$, this._navigator.stateService.currentTransform$) :
71424                 empty();
71425         }))
71426             .subscribe(([tag, event, camera, transform]) => {
71427             const basicPoint = this._mouseEventToBasic(event, this._container.container, camera, transform);
71428             this._setVertex2d(tag, basicPoint, transform);
71429         });
71430         this._addPointSubscription = this._tagCreator.tag$.pipe(switchMap((tag) => {
71431             return !!tag ?
71432                 combineLatest(of(tag), basicClick$) :
71433                 empty();
71434         }))
71435             .subscribe(([tag, basicPoint]) => {
71436             this._addPoint(tag, basicPoint);
71437         });
71438         this._geometryCreateSubscription = this._tagCreator.tag$.pipe(switchMap((tag) => {
71439             return !!tag ?
71440                 tag.created$.pipe(map((t) => {
71441                     return t.geometry;
71442                 })) :
71443                 empty();
71444         }))
71445             .subscribe(this._geometryCreated$);
71446     }
71447     _disableCreate() {
71448         this._container.mouseService.undeferPixels(this._name);
71449         this._tagCreator.delete$.next(null);
71450         this._addPointSubscription.unsubscribe();
71451         this._createSubscription.unsubscribe();
71452         this._deleteSubscription.unsubscribe();
71453         this._geometryCreateSubscription.unsubscribe();
71454         this._setVertexSubscription.unsubscribe();
71455     }
71456 }
71457
71458 class CreatePointsHandler extends CreateVertexHandler {
71459     get _create$() {
71460         return this._tagCreator.createPoints$;
71461     }
71462     _addPoint(tag, basicPoint) {
71463         tag.geometry.addPoint2d(basicPoint);
71464     }
71465     _getNameExtension() {
71466         return "create-points";
71467     }
71468     _setVertex2d(tag, basicPoint, transform) {
71469         tag.geometry.setPoint2d((tag.geometry).points.length - 1, basicPoint, transform);
71470     }
71471 }
71472
71473 class CreatePolygonHandler extends CreateVertexHandler {
71474     get _create$() {
71475         return this._tagCreator.createPolygon$;
71476     }
71477     _addPoint(tag, basicPoint) {
71478         tag.addPoint(basicPoint);
71479     }
71480     _getNameExtension() {
71481         return "create-polygon";
71482     }
71483     _setVertex2d(tag, basicPoint, transform) {
71484         tag.geometry.setVertex2d(tag.geometry.polygon.length - 2, basicPoint, transform);
71485     }
71486 }
71487
71488 class CreateRectHandler extends CreateVertexHandler {
71489     get _create$() {
71490         return this._tagCreator.createRect$;
71491     }
71492     _addPoint(tag, basicPoint) {
71493         const rectGeometry = tag.geometry;
71494         if (!rectGeometry.validate(basicPoint)) {
71495             basicPoint = rectGeometry.getNonAdjustedVertex2d(3);
71496         }
71497         tag.addPoint(basicPoint);
71498     }
71499     _enable() {
71500         super._enable();
71501         this._initializeAnchorIndexingSubscription = this._tagCreator.tag$.pipe(filter((tag) => {
71502             return !!tag;
71503         }))
71504             .subscribe((tag) => {
71505             tag.geometry.initializeAnchorIndexing();
71506         });
71507     }
71508     _disable() {
71509         super._disable();
71510         this._initializeAnchorIndexingSubscription.unsubscribe();
71511     }
71512     _getNameExtension() {
71513         return "create-rect";
71514     }
71515     _setVertex2d(tag, basicPoint, transform) {
71516         tag.geometry.setOppositeVertex2d(basicPoint, transform);
71517     }
71518 }
71519
71520 class CreateRectDragHandler extends CreateHandlerBase {
71521     _enableCreate() {
71522         this._container.mouseService.claimMouse(this._name, 2);
71523         this._deleteSubscription = this._navigator.stateService.currentTransform$.pipe(map((transform) => { return null; }), skip(1))
71524             .subscribe(this._tagCreator.delete$);
71525         this._createSubscription = this._mouseEventToBasic$(this._container.mouseService.filtered$(this._name, this._container.mouseService.mouseDragStart$)).pipe(filter(this._validateBasic))
71526             .subscribe(this._tagCreator.createRect$);
71527         this._initializeAnchorIndexingSubscription = this._tagCreator.tag$.pipe(filter((tag) => {
71528             return !!tag;
71529         }))
71530             .subscribe((tag) => {
71531             tag.geometry.initializeAnchorIndexing();
71532         });
71533         const basicMouse$ = combineLatest(merge(this._container.mouseService.filtered$(this._name, this._container.mouseService.mouseMove$), this._container.mouseService.filtered$(this._name, this._container.mouseService.domMouseMove$)), this._container.renderService.renderCamera$).pipe(withLatestFrom(this._navigator.stateService.currentTransform$), map(([[event, camera], transform]) => {
71534             return this._mouseEventToBasic(event, this._container.container, camera, transform);
71535         }));
71536         this._setVertexSubscription = this._tagCreator.tag$.pipe(switchMap((tag) => {
71537             return !!tag ?
71538                 combineLatest(of(tag), basicMouse$, this._navigator.stateService.currentTransform$) :
71539                 empty();
71540         }))
71541             .subscribe(([tag, basicPoint, transform]) => {
71542             tag.geometry.setOppositeVertex2d(basicPoint, transform);
71543         });
71544         const basicMouseDragEnd$ = this._container.mouseService.mouseDragEnd$.pipe(withLatestFrom(this._mouseEventToBasic$(this._container.mouseService.filtered$(this._name, this._container.mouseService.mouseDrag$)).pipe(filter(this._validateBasic)), (event, basicPoint) => {
71545             return basicPoint;
71546         }), share());
71547         this._addPointSubscription = this._tagCreator.tag$.pipe(switchMap((tag) => {
71548             return !!tag ?
71549                 combineLatest(of(tag), basicMouseDragEnd$) :
71550                 empty();
71551         }))
71552             .subscribe(([tag, basicPoint]) => {
71553             const rectGeometry = tag.geometry;
71554             if (!rectGeometry.validate(basicPoint)) {
71555                 basicPoint = rectGeometry.getNonAdjustedVertex2d(3);
71556             }
71557             tag.addPoint(basicPoint);
71558         });
71559         this._geometryCreatedSubscription = this._tagCreator.tag$.pipe(switchMap((tag) => {
71560             return !!tag ?
71561                 tag.created$.pipe(map((t) => {
71562                     return t.geometry;
71563                 })) :
71564                 empty();
71565         }))
71566             .subscribe(this._geometryCreated$);
71567     }
71568     _disableCreate() {
71569         this._container.mouseService.unclaimMouse(this._name);
71570         this._tagCreator.delete$.next(null);
71571         this._addPointSubscription.unsubscribe();
71572         this._createSubscription.unsubscribe();
71573         this._deleteSubscription.unsubscribe();
71574         this._geometryCreatedSubscription.unsubscribe();
71575         this._initializeAnchorIndexingSubscription.unsubscribe();
71576         this._setVertexSubscription.unsubscribe();
71577     }
71578     _getNameExtension() {
71579         return "create-rect-drag";
71580     }
71581 }
71582
71583 class EditVertexHandler extends TagHandlerBase {
71584     constructor(component, container, navigator, viewportCoords, tagSet) {
71585         super(component, container, navigator, viewportCoords);
71586         this._tagSet = tagSet;
71587     }
71588     _enable() {
71589         const interaction$ = this._tagSet.changed$.pipe(map((tagSet) => {
71590             return tagSet.getAll();
71591         }), switchMap((tags) => {
71592             return from(tags).pipe(mergeMap((tag) => {
71593                 return tag.interact$;
71594             }));
71595         }), switchMap((interaction) => {
71596             return concat(of(interaction), this._container.mouseService.documentMouseUp$.pipe(map(() => {
71597                 return { offsetX: 0, offsetY: 0, operation: TagOperation.None, tag: null };
71598             }), first()));
71599         }), share());
71600         merge(this._container.mouseService.mouseMove$, this._container.mouseService.domMouseMove$).pipe(share());
71601         this._claimMouseSubscription = interaction$.pipe(switchMap((interaction) => {
71602             return !!interaction.tag ? this._container.mouseService.domMouseDragStart$ : empty();
71603         }))
71604             .subscribe(() => {
71605             this._container.mouseService.claimMouse(this._name, 3);
71606         });
71607         this._cursorSubscription = interaction$.pipe(map((interaction) => {
71608             return interaction.cursor;
71609         }), distinctUntilChanged())
71610             .subscribe((cursor) => {
71611             const interactionCursors = ["crosshair", "move", "nesw-resize", "nwse-resize"];
71612             for (const interactionCursor of interactionCursors) {
71613                 this._container.container.classList.remove(`component-tag-edit-${interactionCursor}`);
71614             }
71615             if (!!cursor) {
71616                 this._container.container.classList.add(`component-tag-edit-${cursor}`);
71617             }
71618         });
71619         this._unclaimMouseSubscription = this._container.mouseService
71620             .filtered$(this._name, this._container.mouseService.domMouseDragEnd$)
71621             .subscribe((e) => {
71622             this._container.mouseService.unclaimMouse(this._name);
71623         });
71624         this._preventDefaultSubscription = interaction$.pipe(switchMap((interaction) => {
71625             return !!interaction.tag ?
71626                 this._container.mouseService.documentMouseMove$ :
71627                 empty();
71628         }))
71629             .subscribe((event) => {
71630             event.preventDefault(); // prevent selection of content outside the viewer
71631         });
71632         this._updateGeometrySubscription = interaction$.pipe(switchMap((interaction) => {
71633             if (interaction.operation === TagOperation.None || !interaction.tag) {
71634                 return empty();
71635             }
71636             const mouseDrag$ = this._container.mouseService
71637                 .filtered$(this._name, this._container.mouseService.domMouseDrag$).pipe(filter((event) => {
71638                 return this._viewportCoords.insideElement(event, this._container.container);
71639             }));
71640             return combineLatest(mouseDrag$, this._container.renderService.renderCamera$).pipe(withLatestFrom(of(interaction), this._navigator.stateService.currentTransform$, ([event, render], i, transform) => {
71641                 return [event, render, i, transform];
71642             }));
71643         }))
71644             .subscribe(([mouseEvent, renderCamera, interaction, transform]) => {
71645             const basic = this._mouseEventToBasic(mouseEvent, this._container.container, renderCamera, transform, interaction.offsetX, interaction.offsetY);
71646             const geometry = interaction.tag.geometry;
71647             if (interaction.operation === TagOperation.Centroid) {
71648                 geometry.setCentroid2d(basic, transform);
71649             }
71650             else if (interaction.operation === TagOperation.Vertex) {
71651                 geometry.setVertex2d(interaction.vertexIndex, basic, transform);
71652             }
71653         });
71654     }
71655     _disable() {
71656         this._claimMouseSubscription.unsubscribe();
71657         this._cursorSubscription.unsubscribe();
71658         this._preventDefaultSubscription.unsubscribe();
71659         this._unclaimMouseSubscription.unsubscribe();
71660         this._updateGeometrySubscription.unsubscribe();
71661     }
71662     _getNameExtension() {
71663         return "edit-vertex";
71664     }
71665 }
71666
71667 /**
71668  * @class TagComponent
71669  *
71670  * @classdesc Component for showing and editing tags with different
71671  * geometries composed from 2D basic image coordinates (see the
71672  * {@link Viewer} class documentation for more information about coordinate
71673  * systems).
71674  *
71675  * The `add` method is used for adding new tags or replacing
71676  * tags already in the set. Tags are removed by id.
71677  *
71678  * If a tag already in the set has the same
71679  * id as one of the tags added, the old tag will be removed and
71680  * the added tag will take its place.
71681  *
71682  * The tag component mode can be set to either be non interactive or
71683  * to be in creating mode of a certain geometry type.
71684  *
71685  * The tag properties can be updated at any time and the change will
71686  * be visibile immediately.
71687  *
71688  * Tags are only relevant to a single image because they are based on
71689  * 2D basic image coordinates. Tags related to a certain image should
71690  * be removed when the viewer is moved to another image.
71691  *
71692  * To retrive and use the tag component
71693  *
71694  * @example
71695  * ```js
71696  * var viewer = new Viewer({ component: { tag: true } }, ...);
71697  *
71698  * var tagComponent = viewer.getComponent("tag");
71699  * ```
71700  */
71701 class TagComponent extends Component {
71702     /** @ignore */
71703     constructor(name, container, navigator) {
71704         super(name, container, navigator);
71705         this._tagDomRenderer = new TagDOMRenderer();
71706         this._tagScene = new TagScene();
71707         this._tagSet = new TagSet();
71708         this._tagCreator = new TagCreator(this, navigator);
71709         this._viewportCoords = new ViewportCoords();
71710         this._createHandlers = {
71711             "CreatePoint": new CreatePointHandler(this, container, navigator, this._viewportCoords, this._tagCreator),
71712             "CreatePoints": new CreatePointsHandler(this, container, navigator, this._viewportCoords, this._tagCreator),
71713             "CreatePolygon": new CreatePolygonHandler(this, container, navigator, this._viewportCoords, this._tagCreator),
71714             "CreateRect": new CreateRectHandler(this, container, navigator, this._viewportCoords, this._tagCreator),
71715             "CreateRectDrag": new CreateRectDragHandler(this, container, navigator, this._viewportCoords, this._tagCreator),
71716             "Default": undefined,
71717         };
71718         this._editVertexHandler =
71719             new EditVertexHandler(this, container, navigator, this._viewportCoords, this._tagSet);
71720         this._renderTags$ = this._tagSet.changed$.pipe(map((tagSet) => {
71721             const tags = tagSet.getAll();
71722             // ensure that tags are always rendered in the same order
71723             // to avoid hover tracking problems on first resize.
71724             tags.sort((t1, t2) => {
71725                 const id1 = t1.tag.id;
71726                 const id2 = t2.tag.id;
71727                 if (id1 < id2) {
71728                     return -1;
71729                 }
71730                 if (id1 > id2) {
71731                     return 1;
71732                 }
71733                 return 0;
71734             });
71735             return tags;
71736         }), share());
71737         this._tagChanged$ = this._renderTags$.pipe(switchMap((tags) => {
71738             return from(tags).pipe(mergeMap((tag) => {
71739                 return merge(tag.tag.changed$, tag.tag.geometryChanged$);
71740             }));
71741         }), share());
71742         this._renderTagGLChanged$ = this._renderTags$.pipe(switchMap((tags) => {
71743             return from(tags).pipe(mergeMap((tag) => {
71744                 return tag.glObjectsChanged$;
71745             }));
71746         }), share());
71747         this._createGeometryChanged$ = this._tagCreator.tag$.pipe(switchMap((tag) => {
71748             return tag != null ?
71749                 tag.geometryChanged$ :
71750                 empty();
71751         }), share());
71752         this._createGLObjectsChanged$ = this._tagCreator.tag$.pipe(switchMap((tag) => {
71753             return tag != null ?
71754                 tag.glObjectsChanged$ :
71755                 empty();
71756         }), share());
71757         this._creatingConfiguration$ = this._configuration$.pipe(distinctUntilChanged((c1, c2) => {
71758             return c1.mode === c2.mode;
71759         }, (configuration) => {
71760             return {
71761                 createColor: configuration.createColor,
71762                 mode: configuration.mode,
71763             };
71764         }), publishReplay(1), refCount());
71765         this._creatingConfiguration$
71766             .subscribe((configuration) => {
71767             const type = "tagmode";
71768             const event = {
71769                 mode: configuration.mode,
71770                 target: this,
71771                 type,
71772             };
71773             this.fire(type, event);
71774         });
71775     }
71776     /**
71777      * Add tags to the tag set or replace tags in the tag set.
71778      *
71779      * @description If a tag already in the set has the same
71780      * id as one of the tags added, the old tag will be removed
71781      * the added tag will take its place.
71782      *
71783      * @param {Array<Tag>} tags - Tags to add.
71784      *
71785      * @example
71786      * ```js
71787      * tagComponent.add([tag1, tag2]);
71788      * ```
71789      */
71790     add(tags) {
71791         if (this._activated) {
71792             this._navigator.stateService.currentTransform$.pipe(first())
71793                 .subscribe((transform) => {
71794                 this._tagSet.add(tags, transform);
71795                 const renderTags = tags
71796                     .map((tag) => {
71797                     return this._tagSet.get(tag.id);
71798                 });
71799                 this._tagScene.add(renderTags);
71800             });
71801         }
71802         else {
71803             this._tagSet.addDeactivated(tags);
71804         }
71805     }
71806     /**
71807      * Calculate the smallest rectangle containing all the points
71808      * in the points geometry.
71809      *
71810      * @description The result may be different depending on if the
71811      * current image is an spherical or not. If the
71812      * current image is an spherical the rectangle may
71813      * wrap the horizontal border of the image.
71814      *
71815      * @returns {Promise<Array<number>>} Promise to the rectangle
71816      * on the format specified for the {@link RectGeometry} in basic
71817      * coordinates.
71818      */
71819     calculateRect(geometry) {
71820         return new Promise((resolve, reject) => {
71821             this._navigator.stateService.currentTransform$.pipe(first(), map((transform) => {
71822                 return geometry.getRect2d(transform);
71823             }))
71824                 .subscribe((rect) => {
71825                 resolve(rect);
71826             }, (error) => {
71827                 reject(error);
71828             });
71829         });
71830     }
71831     /**
71832      * Force the creation of a geometry programatically using its
71833      * current vertices.
71834      *
71835      * @description The method only has an effect when the tag
71836      * mode is either of the following modes:
71837      *
71838      * {@link TagMode.CreatePoints}
71839      * {@link TagMode.CreatePolygon}
71840      * {@link TagMode.CreateRect}
71841      * {@link TagMode.CreateRectDrag}
71842      *
71843      * In the case of points or polygon creation, only the created
71844      * vertices are used, i.e. the mouse position is disregarded.
71845      *
71846      * In the case of rectangle creation the position of the mouse
71847      * at the time of the method call is used as one of the vertices
71848      * defining the rectangle.
71849      *
71850      * @fires geometrycreate
71851      *
71852      * @example
71853      * ```js
71854      * tagComponent.on("geometrycreate", function(geometry) {
71855      *     console.log(geometry);
71856      * });
71857      *
71858      * tagComponent.create();
71859      * ```
71860      */
71861     create() {
71862         this._tagCreator.replayedTag$.pipe(first(), filter((tag) => {
71863             return !!tag;
71864         }))
71865             .subscribe((tag) => {
71866             tag.create();
71867         });
71868     }
71869     /**
71870      * Change the current tag mode.
71871      *
71872      * @description Change the tag mode to one of the create modes for creating new geometries.
71873      *
71874      * @param {TagMode} mode - New tag mode.
71875      *
71876      * @fires tagmode
71877      *
71878      * @example
71879      * ```js
71880      * tagComponent.changeMode(TagMode.CreateRect);
71881      * ```
71882      */
71883     changeMode(mode) {
71884         this.configure({ mode: mode });
71885     }
71886     fire(type, event) {
71887         super.fire(type, event);
71888     }
71889     /**
71890      * Returns the tag in the tag set with the specified id, or
71891      * undefined if the id matches no tag.
71892      *
71893      * @param {string} tagId - Id of the tag.
71894      *
71895      * @example
71896      * ```js
71897      * var tag = tagComponent.get("tagId");
71898      * ```
71899      */
71900     get(tagId) {
71901         if (this._activated) {
71902             const renderTag = this._tagSet.get(tagId);
71903             return renderTag !== undefined ? renderTag.tag : undefined;
71904         }
71905         else {
71906             return this._tagSet.getDeactivated(tagId);
71907         }
71908     }
71909     /**
71910      * Returns an array of all tags.
71911      *
71912      * @example
71913      * ```js
71914      * var tags = tagComponent.getAll();
71915      * ```
71916      */
71917     getAll() {
71918         if (this.activated) {
71919             return this._tagSet
71920                 .getAll()
71921                 .map((renderTag) => {
71922                 return renderTag.tag;
71923             });
71924         }
71925         else {
71926             return this._tagSet.getAllDeactivated();
71927         }
71928     }
71929     /**
71930      * Returns an array of tag ids for tags that contain the specified point.
71931      *
71932      * @description The pixel point must lie inside the polygon or rectangle
71933      * of an added tag for the tag id to be returned. Tag ids for
71934      * tags that do not have a fill will also be returned if the point is inside
71935      * the geometry of the tag. Tags with point geometries can not be retrieved.
71936      *
71937      * No tag ids will be returned for polygons rendered in cropped spherical or
71938      * rectangles rendered in spherical.
71939      *
71940      * Notice that the pixelPoint argument requires x, y coordinates from pixel space.
71941      *
71942      * With this function, you can use the coordinates provided by mouse
71943      * events to get information out of the tag component.
71944      *
71945      * If no tag at exist the pixel point, an empty array will be returned.
71946      *
71947      * @param {Array<number>} pixelPoint - Pixel coordinates on the viewer element.
71948      * @returns {Promise<Array<string>>} Promise to the ids of the tags that
71949      * contain the specified pixel point.
71950      *
71951      * @example
71952      * ```js
71953      * tagComponent.getTagIdsAt([100, 100])
71954      *     .then((tagIds) => { console.log(tagIds); });
71955      * ```
71956      */
71957     getTagIdsAt(pixelPoint) {
71958         return new Promise((resolve, reject) => {
71959             this._container.renderService.renderCamera$.pipe(first(), map((render) => {
71960                 const viewport = this._viewportCoords
71961                     .canvasToViewport(pixelPoint[0], pixelPoint[1], this._container.container);
71962                 const ids = this._tagScene.intersectObjects(viewport, render.perspective);
71963                 return ids;
71964             }))
71965                 .subscribe((ids) => {
71966                 resolve(ids);
71967             }, (error) => {
71968                 reject(error);
71969             });
71970         });
71971     }
71972     /**
71973      * Check if a tag exist in the tag set.
71974      *
71975      * @param {string} tagId - Id of the tag.
71976      *
71977      * @example
71978      * ```js
71979      * var tagExists = tagComponent.has("tagId");
71980      * ```
71981      */
71982     has(tagId) {
71983         return this._activated ? this._tagSet.has(tagId) : this._tagSet.hasDeactivated(tagId);
71984     }
71985     off(type, handler) {
71986         super.off(type, handler);
71987     }
71988     on(type, handler) {
71989         super.on(type, handler);
71990     }
71991     /**
71992      * Remove tags with the specified ids from the tag set.
71993      *
71994      * @param {Array<string>} tagIds - Ids for tags to remove.
71995      *
71996      * @example
71997      * ```js
71998      * tagComponent.remove(["id-1", "id-2"]);
71999      * ```
72000      */
72001     remove(tagIds) {
72002         if (this._activated) {
72003             this._tagSet.remove(tagIds);
72004             this._tagScene.remove(tagIds);
72005         }
72006         else {
72007             this._tagSet.removeDeactivated(tagIds);
72008         }
72009     }
72010     /**
72011      * Remove all tags from the tag set.
72012      *
72013      * @example
72014      * ```js
72015      * tagComponent.removeAll();
72016      * ```
72017      */
72018     removeAll() {
72019         if (this._activated) {
72020             this._tagSet.removeAll();
72021             this._tagScene.removeAll();
72022         }
72023         else {
72024             this._tagSet.removeAllDeactivated();
72025         }
72026     }
72027     _activate() {
72028         this._editVertexHandler.enable();
72029         const handlerGeometryCreated$ = from(Object.keys(this._createHandlers)).pipe(map((key) => {
72030             return this._createHandlers[key];
72031         }), filter((handler) => {
72032             return !!handler;
72033         }), mergeMap((handler) => {
72034             return handler.geometryCreated$;
72035         }), share());
72036         const subs = this._subscriptions;
72037         subs.push(handlerGeometryCreated$
72038             .subscribe((geometry) => {
72039             const type = "geometrycreate";
72040             const event = {
72041                 geometry,
72042                 target: this,
72043                 type,
72044             };
72045             this.fire(type, event);
72046         }));
72047         subs.push(this._tagCreator.tag$.pipe(skipWhile((tag) => {
72048             return tag == null;
72049         }), distinctUntilChanged())
72050             .subscribe((tag) => {
72051             const type = tag != null ?
72052                 "tagcreatestart" :
72053                 "tagcreateend";
72054             const event = {
72055                 target: this,
72056                 type,
72057             };
72058             this.fire(type, event);
72059         }));
72060         subs.push(handlerGeometryCreated$
72061             .subscribe(() => {
72062             this.changeMode(TagMode.Default);
72063         }));
72064         subs.push(this._creatingConfiguration$
72065             .subscribe((configuration) => {
72066             this._disableCreateHandlers();
72067             const mode = TagMode[configuration.mode];
72068             const handler = this._createHandlers[mode];
72069             if (!!handler) {
72070                 handler.enable();
72071             }
72072         }));
72073         subs.push(this._renderTags$
72074             .subscribe(() => {
72075             const type = "tags";
72076             const event = {
72077                 target: this,
72078                 type,
72079             };
72080             this.fire(type, event);
72081         }));
72082         subs.push(this._tagCreator.tag$.pipe(switchMap((tag) => {
72083             return tag != null ?
72084                 tag.aborted$.pipe(map(() => { return null; })) :
72085                 empty();
72086         }))
72087             .subscribe(() => { this.changeMode(TagMode.Default); }));
72088         subs.push(this._tagCreator.tag$
72089             .subscribe((tag) => {
72090             if (this._tagScene.hasCreateTag()) {
72091                 this._tagScene.removeCreateTag();
72092             }
72093             if (tag != null) {
72094                 this._tagScene.addCreateTag(tag);
72095             }
72096         }));
72097         subs.push(this._createGLObjectsChanged$
72098             .subscribe((tag) => {
72099             this._tagScene.updateCreateTagObjects(tag);
72100         }));
72101         subs.push(this._renderTagGLChanged$
72102             .subscribe((tag) => {
72103             this._tagScene.updateObjects(tag);
72104         }));
72105         subs.push(this._tagChanged$
72106             .subscribe(() => {
72107             this._tagScene.update();
72108         }));
72109         subs.push(combineLatest(this._renderTags$.pipe(startWith([]), tap(() => {
72110             this._container.domRenderer.render$.next({
72111                 name: this._name,
72112                 vNode: this._tagDomRenderer.clear(),
72113             });
72114         })), this._container.renderService.renderCamera$, this._container.spriteService.spriteAtlas$, this._container.renderService.size$, this._tagChanged$.pipe(startWith(null)), merge(this._tagCreator.tag$, this._createGeometryChanged$).pipe(startWith(null))).pipe(map(([renderTags, rc, atlas, size, , ct]) => {
72115             return {
72116                 name: this._name,
72117                 vNode: this._tagDomRenderer.render(renderTags, ct, atlas, rc.perspective, size),
72118             };
72119         }))
72120             .subscribe(this._container.domRenderer.render$));
72121         subs.push(this._navigator.stateService.currentState$.pipe(map((frame) => {
72122             const tagScene = this._tagScene;
72123             return {
72124                 name: this._name,
72125                 renderer: {
72126                     frameId: frame.id,
72127                     needsRender: tagScene.needsRender,
72128                     render: tagScene.render.bind(tagScene),
72129                     pass: RenderPass$1.Opaque,
72130                 },
72131             };
72132         }))
72133             .subscribe(this._container.glRenderer.render$));
72134         this._navigator.stateService.currentTransform$.pipe(first())
72135             .subscribe((transform) => {
72136             this._tagSet.activate(transform);
72137             this._tagScene.add(this._tagSet.getAll());
72138         });
72139     }
72140     _deactivate() {
72141         this._editVertexHandler.disable();
72142         this._disableCreateHandlers();
72143         this._tagScene.clear();
72144         this._tagSet.deactivate();
72145         this._tagCreator.delete$.next(null);
72146         this._subscriptions.unsubscribe();
72147         this._container.container.classList.remove("component-tag-create");
72148     }
72149     _getDefaultConfiguration() {
72150         return {
72151             createColor: 0xFFFFFF,
72152             indicatePointsCompleter: true,
72153             mode: TagMode.Default,
72154         };
72155     }
72156     _disableCreateHandlers() {
72157         const createHandlers = this._createHandlers;
72158         for (const key in createHandlers) {
72159             if (!createHandlers.hasOwnProperty(key)) {
72160                 continue;
72161             }
72162             const handler = createHandlers[key];
72163             if (!!handler) {
72164                 handler.disable();
72165             }
72166         }
72167     }
72168 }
72169 /** @inheritdoc */
72170 TagComponent.componentName = "tag";
72171
72172 /**
72173  * @class ZoomComponent
72174  *
72175  * @classdesc Component rendering UI elements used for zooming.
72176  *
72177  * @example
72178  * ```js
72179  * var viewer = new Viewer({ ... });
72180  *
72181  * var zoomComponent = viewer.getComponent("zoom");
72182  * zoomComponent.configure({ size: ComponentSize.Small });
72183  * ```
72184  */
72185 class ZoomComponent extends Component {
72186     constructor(name, container, navigator) {
72187         super(name, container, navigator);
72188         this._viewportCoords = new ViewportCoords();
72189         this._zoomDelta$ = new Subject();
72190     }
72191     _activate() {
72192         const subs = this._subscriptions;
72193         subs.push(combineLatest(this._navigator.stateService.currentState$, this._navigator.stateService.state$, this._configuration$, this._container.renderService.size$).pipe(map(([frame, state, configuration, size]) => {
72194             const zoom = frame.state.zoom;
72195             const zoomInIcon = virtualDom.h("div.mapillary-zoom-in-icon", []);
72196             const zoomInButton = zoom >= 3 || state === State.Waiting ?
72197                 virtualDom.h("div.mapillary-zoom-in-button-inactive", [zoomInIcon]) :
72198                 virtualDom.h("div.mapillary-zoom-in-button", { onclick: () => { this._zoomDelta$.next(1); } }, [zoomInIcon]);
72199             const zoomOutIcon = virtualDom.h("div.mapillary-zoom-out-icon", []);
72200             const zoomOutButton = zoom <= 0 || state === State.Waiting ?
72201                 virtualDom.h("div.mapillary-zoom-out-button-inactive", [zoomOutIcon]) :
72202                 virtualDom.h("div.mapillary-zoom-out-button", { onclick: () => { this._zoomDelta$.next(-1); } }, [zoomOutIcon]);
72203             const compact = configuration.size === ComponentSize.Small ||
72204                 configuration.size === ComponentSize.Automatic && size.width < 640 ?
72205                 ".mapillary-zoom-compact" : "";
72206             return {
72207                 name: this._name,
72208                 vNode: virtualDom.h("div.mapillary-zoom-container" + compact, { oncontextmenu: (event) => { event.preventDefault(); } }, [zoomInButton, zoomOutButton]),
72209             };
72210         }))
72211             .subscribe(this._container.domRenderer.render$));
72212         subs.push(this._zoomDelta$.pipe(withLatestFrom(this._container.renderService.renderCamera$, this._navigator.stateService.currentTransform$))
72213             .subscribe(([zoomDelta, render, transform]) => {
72214             const unprojected = this._viewportCoords.unprojectFromViewport(0, 0, render.perspective);
72215             const reference = transform.projectBasic(unprojected.toArray());
72216             this._navigator.stateService.zoomIn(zoomDelta, reference);
72217         }));
72218     }
72219     _deactivate() {
72220         this._subscriptions.unsubscribe();
72221     }
72222     _getDefaultConfiguration() {
72223         return { size: ComponentSize.Automatic };
72224     }
72225 }
72226 ZoomComponent.componentName = "zoom";
72227
72228 class ImageFallbackComponent extends Component {
72229     constructor(name, container, navigator, dom) {
72230         super(name, container, navigator);
72231         this._canvasId = `${container.id}-${this._name}`;
72232         this._dom = !!dom ? dom : new DOM();
72233     }
72234     _activate() {
72235         const canvasSize$ = this._container.domRenderer.element$.pipe(map(() => {
72236             return this._dom.document.getElementById(this._canvasId);
72237         }), filter((canvas) => {
72238             return !!canvas;
72239         }), map((canvas) => {
72240             const adaptableDomRenderer = canvas.parentElement;
72241             const width = adaptableDomRenderer.offsetWidth;
72242             const height = adaptableDomRenderer.offsetHeight;
72243             return [canvas, { height: height, width: width }];
72244         }), distinctUntilChanged((s1, s2) => {
72245             return s1.height === s2.height && s1.width === s2.width;
72246         }, ([, size]) => {
72247             return size;
72248         }));
72249         this._subscriptions.push(combineLatest(canvasSize$, this._navigator.stateService.currentImage$)
72250             .subscribe(([[canvas, size], image]) => {
72251             canvas.width = size.width;
72252             canvas.height = size.height;
72253             canvas
72254                 .getContext("2d")
72255                 .drawImage(image.image, 0, 0, size.width, size.height);
72256         }));
72257         this._container.domRenderer.renderAdaptive$.next({ name: this._name, vNode: virtualDom.h(`canvas#${this._canvasId}`, []) });
72258     }
72259     _deactivate() {
72260         this._subscriptions.unsubscribe();
72261     }
72262     _getDefaultConfiguration() {
72263         return {};
72264     }
72265 }
72266 ImageFallbackComponent.componentName = "imagefallback";
72267
72268 /**
72269  * @class NavigationFallbackComponent
72270  *
72271  * @classdesc Fallback navigation component for environments without WebGL support.
72272  *
72273  * Replaces the functionality in the Direction and Sequence components.
72274  */
72275 class NavigationFallbackComponent extends Component {
72276     /** @ignore */
72277     constructor(name, container, navigator) {
72278         super(name, container, navigator);
72279         this._seqNames = {};
72280         this._seqNames[NavigationDirection[NavigationDirection.Prev]] = "-prev";
72281         this._seqNames[NavigationDirection[NavigationDirection.Next]] = "-next";
72282         this._spaTopNames = {};
72283         this._spaTopNames[NavigationDirection[NavigationDirection.TurnLeft]] = "-turn-left";
72284         this._spaTopNames[NavigationDirection[NavigationDirection.StepLeft]] = "-left";
72285         this._spaTopNames[NavigationDirection[NavigationDirection.StepForward]] = "-forward";
72286         this._spaTopNames[NavigationDirection[NavigationDirection.StepRight]] = "-right";
72287         this._spaTopNames[NavigationDirection[NavigationDirection.TurnRight]] = "-turn-right";
72288         this._spaBottomNames = {};
72289         this._spaBottomNames[NavigationDirection[NavigationDirection.TurnU]] = "-turn-around";
72290         this._spaBottomNames[NavigationDirection[NavigationDirection.StepBackward]] = "-backward";
72291     }
72292     _activate() {
72293         this._subscriptions.push(combineLatest(this._navigator.stateService.currentImage$, this._configuration$).pipe(switchMap(([image, configuration]) => {
72294             const sequenceEdges$ = configuration.sequence ?
72295                 image.sequenceEdges$.pipe(map((status) => {
72296                     return status.edges
72297                         .map((edge) => {
72298                         return edge.data.direction;
72299                     });
72300                 })) :
72301                 of([]);
72302             const spatialEdges$ = !isSpherical(image.cameraType) &&
72303                 configuration.spatial ?
72304                 image.spatialEdges$.pipe(map((status) => {
72305                     return status.edges
72306                         .map((edge) => {
72307                         return edge.data.direction;
72308                     });
72309                 })) :
72310                 of([]);
72311             return combineLatest(sequenceEdges$, spatialEdges$).pipe(map(([seq, spa]) => {
72312                 return seq.concat(spa);
72313             }));
72314         }), map((edgeDirections) => {
72315             const seqs = this._createArrowRow(this._seqNames, edgeDirections);
72316             const spaTops = this._createArrowRow(this._spaTopNames, edgeDirections);
72317             const spaBottoms = this._createArrowRow(this._spaBottomNames, edgeDirections);
72318             const seqContainer = virtualDom.h(`div.mapillary-navigation-sequence`, seqs);
72319             const spaTopContainer = virtualDom.h(`div.NavigationSpatialTop`, spaTops);
72320             const spaBottomContainer = virtualDom.h(`div.mapillary-navigation-spatial-bottom`, spaBottoms);
72321             const spaContainer = virtualDom.h(`div.mapillary-navigation-spatial`, [spaTopContainer, spaBottomContainer]);
72322             return { name: this._name, vNode: virtualDom.h(`div.NavigationContainer`, [seqContainer, spaContainer]) };
72323         }))
72324             .subscribe(this._container.domRenderer.render$));
72325     }
72326     _deactivate() {
72327         this._subscriptions.unsubscribe();
72328     }
72329     _getDefaultConfiguration() {
72330         return { sequence: true, spatial: true };
72331     }
72332     _createArrowRow(arrowNames, edgeDirections) {
72333         const arrows = [];
72334         for (const arrowName in arrowNames) {
72335             if (!(arrowNames.hasOwnProperty(arrowName))) {
72336                 continue;
72337             }
72338             const direction = NavigationDirection[arrowName];
72339             if (edgeDirections.indexOf(direction) !== -1) {
72340                 arrows.push(this._createVNode(direction, arrowNames[arrowName], "visible"));
72341             }
72342             else {
72343                 arrows.push(this._createVNode(direction, arrowNames[arrowName], "hidden"));
72344             }
72345         }
72346         return arrows;
72347     }
72348     _createVNode(direction, name, visibility) {
72349         return virtualDom.h(`span.mapillary-navigation-button.mapillary-navigation${name}`, {
72350             onclick: () => {
72351                 this._navigator.moveDir$(direction)
72352                     .subscribe(undefined, (error) => {
72353                     if (!(error instanceof CancelMapillaryError)) {
72354                         console.error(error);
72355                     }
72356                 });
72357             },
72358             style: {
72359                 visibility: visibility,
72360             },
72361         }, []);
72362     }
72363 }
72364 NavigationFallbackComponent.componentName = "navigationfallback";
72365
72366 /*! pako 2.0.3 https://github.com/nodeca/pako @license (MIT AND Zlib) */
72367 // (C) 1995-2013 Jean-loup Gailly and Mark Adler
72368 // (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin
72369 //
72370 // This software is provided 'as-is', without any express or implied
72371 // warranty. In no event will the authors be held liable for any damages
72372 // arising from the use of this software.
72373 //
72374 // Permission is granted to anyone to use this software for any purpose,
72375 // including commercial applications, and to alter it and redistribute it
72376 // freely, subject to the following restrictions:
72377 //
72378 // 1. The origin of this software must not be misrepresented; you must not
72379 //   claim that you wrote the original software. If you use this software
72380 //   in a product, an acknowledgment in the product documentation would be
72381 //   appreciated but is not required.
72382 // 2. Altered source versions must be plainly marked as such, and must not be
72383 //   misrepresented as being the original software.
72384 // 3. This notice may not be removed or altered from any source distribution.
72385
72386 /* eslint-disable space-unary-ops */
72387
72388 /* Public constants ==========================================================*/
72389 /* ===========================================================================*/
72390
72391
72392 //const Z_FILTERED          = 1;
72393 //const Z_HUFFMAN_ONLY      = 2;
72394 //const Z_RLE               = 3;
72395 const Z_FIXED               = 4;
72396 //const Z_DEFAULT_STRATEGY  = 0;
72397
72398 /* Possible values of the data_type field (though see inflate()) */
72399 const Z_BINARY              = 0;
72400 const Z_TEXT                = 1;
72401 //const Z_ASCII             = 1; // = Z_TEXT
72402 const Z_UNKNOWN             = 2;
72403
72404 /*============================================================================*/
72405
72406
72407 function zero(buf) { let len = buf.length; while (--len >= 0) { buf[len] = 0; } }
72408
72409 // From zutil.h
72410
72411 const STORED_BLOCK = 0;
72412 const STATIC_TREES = 1;
72413 const DYN_TREES    = 2;
72414 /* The three kinds of block type */
72415
72416 const MIN_MATCH    = 3;
72417 const MAX_MATCH    = 258;
72418 /* The minimum and maximum match lengths */
72419
72420 // From deflate.h
72421 /* ===========================================================================
72422  * Internal compression state.
72423  */
72424
72425 const LENGTH_CODES  = 29;
72426 /* number of length codes, not counting the special END_BLOCK code */
72427
72428 const LITERALS      = 256;
72429 /* number of literal bytes 0..255 */
72430
72431 const L_CODES       = LITERALS + 1 + LENGTH_CODES;
72432 /* number of Literal or Length codes, including the END_BLOCK code */
72433
72434 const D_CODES       = 30;
72435 /* number of distance codes */
72436
72437 const BL_CODES      = 19;
72438 /* number of codes used to transfer the bit lengths */
72439
72440 const HEAP_SIZE     = 2 * L_CODES + 1;
72441 /* maximum heap size */
72442
72443 const MAX_BITS      = 15;
72444 /* All codes must not exceed MAX_BITS bits */
72445
72446 const Buf_size      = 16;
72447 /* size of bit buffer in bi_buf */
72448
72449
72450 /* ===========================================================================
72451  * Constants
72452  */
72453
72454 const MAX_BL_BITS = 7;
72455 /* Bit length codes must not exceed MAX_BL_BITS bits */
72456
72457 const END_BLOCK   = 256;
72458 /* end of block literal code */
72459
72460 const REP_3_6     = 16;
72461 /* repeat previous bit length 3-6 times (2 bits of repeat count) */
72462
72463 const REPZ_3_10   = 17;
72464 /* repeat a zero length 3-10 times  (3 bits of repeat count) */
72465
72466 const REPZ_11_138 = 18;
72467 /* repeat a zero length 11-138 times  (7 bits of repeat count) */
72468
72469 /* eslint-disable comma-spacing,array-bracket-spacing */
72470 const extra_lbits =   /* extra bits for each length code */
72471   new Uint8Array([0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0]);
72472
72473 const extra_dbits =   /* extra bits for each distance code */
72474   new Uint8Array([0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13]);
72475
72476 const extra_blbits =  /* extra bits for each bit length code */
72477   new Uint8Array([0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7]);
72478
72479 const bl_order =
72480   new Uint8Array([16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15]);
72481 /* eslint-enable comma-spacing,array-bracket-spacing */
72482
72483 /* The lengths of the bit length codes are sent in order of decreasing
72484  * probability, to avoid transmitting the lengths for unused bit length codes.
72485  */
72486
72487 /* ===========================================================================
72488  * Local data. These are initialized only once.
72489  */
72490
72491 // We pre-fill arrays with 0 to avoid uninitialized gaps
72492
72493 const DIST_CODE_LEN = 512; /* see definition of array dist_code below */
72494
72495 // !!!! Use flat array instead of structure, Freq = i*2, Len = i*2+1
72496 const static_ltree  = new Array((L_CODES + 2) * 2);
72497 zero(static_ltree);
72498 /* The static literal tree. Since the bit lengths are imposed, there is no
72499  * need for the L_CODES extra codes used during heap construction. However
72500  * The codes 286 and 287 are needed to build a canonical tree (see _tr_init
72501  * below).
72502  */
72503
72504 const static_dtree  = new Array(D_CODES * 2);
72505 zero(static_dtree);
72506 /* The static distance tree. (Actually a trivial tree since all codes use
72507  * 5 bits.)
72508  */
72509
72510 const _dist_code    = new Array(DIST_CODE_LEN);
72511 zero(_dist_code);
72512 /* Distance codes. The first 256 values correspond to the distances
72513  * 3 .. 258, the last 256 values correspond to the top 8 bits of
72514  * the 15 bit distances.
72515  */
72516
72517 const _length_code  = new Array(MAX_MATCH - MIN_MATCH + 1);
72518 zero(_length_code);
72519 /* length code for each normalized match length (0 == MIN_MATCH) */
72520
72521 const base_length   = new Array(LENGTH_CODES);
72522 zero(base_length);
72523 /* First normalized length for each code (0 = MIN_MATCH) */
72524
72525 const base_dist     = new Array(D_CODES);
72526 zero(base_dist);
72527 /* First normalized distance for each code (0 = distance of 1) */
72528
72529
72530 function StaticTreeDesc(static_tree, extra_bits, extra_base, elems, max_length) {
72531
72532   this.static_tree  = static_tree;  /* static tree or NULL */
72533   this.extra_bits   = extra_bits;   /* extra bits for each code or NULL */
72534   this.extra_base   = extra_base;   /* base index for extra_bits */
72535   this.elems        = elems;        /* max number of elements in the tree */
72536   this.max_length   = max_length;   /* max bit length for the codes */
72537
72538   // show if `static_tree` has data or dummy - needed for monomorphic objects
72539   this.has_stree    = static_tree && static_tree.length;
72540 }
72541
72542
72543 let static_l_desc;
72544 let static_d_desc;
72545 let static_bl_desc;
72546
72547
72548 function TreeDesc(dyn_tree, stat_desc) {
72549   this.dyn_tree = dyn_tree;     /* the dynamic tree */
72550   this.max_code = 0;            /* largest code with non zero frequency */
72551   this.stat_desc = stat_desc;   /* the corresponding static tree */
72552 }
72553
72554
72555
72556 const d_code = (dist) => {
72557
72558   return dist < 256 ? _dist_code[dist] : _dist_code[256 + (dist >>> 7)];
72559 };
72560
72561
72562 /* ===========================================================================
72563  * Output a short LSB first on the stream.
72564  * IN assertion: there is enough room in pendingBuf.
72565  */
72566 const put_short = (s, w) => {
72567 //    put_byte(s, (uch)((w) & 0xff));
72568 //    put_byte(s, (uch)((ush)(w) >> 8));
72569   s.pending_buf[s.pending++] = (w) & 0xff;
72570   s.pending_buf[s.pending++] = (w >>> 8) & 0xff;
72571 };
72572
72573
72574 /* ===========================================================================
72575  * Send a value on a given number of bits.
72576  * IN assertion: length <= 16 and value fits in length bits.
72577  */
72578 const send_bits = (s, value, length) => {
72579
72580   if (s.bi_valid > (Buf_size - length)) {
72581     s.bi_buf |= (value << s.bi_valid) & 0xffff;
72582     put_short(s, s.bi_buf);
72583     s.bi_buf = value >> (Buf_size - s.bi_valid);
72584     s.bi_valid += length - Buf_size;
72585   } else {
72586     s.bi_buf |= (value << s.bi_valid) & 0xffff;
72587     s.bi_valid += length;
72588   }
72589 };
72590
72591
72592 const send_code = (s, c, tree) => {
72593
72594   send_bits(s, tree[c * 2]/*.Code*/, tree[c * 2 + 1]/*.Len*/);
72595 };
72596
72597
72598 /* ===========================================================================
72599  * Reverse the first len bits of a code, using straightforward code (a faster
72600  * method would use a table)
72601  * IN assertion: 1 <= len <= 15
72602  */
72603 const bi_reverse = (code, len) => {
72604
72605   let res = 0;
72606   do {
72607     res |= code & 1;
72608     code >>>= 1;
72609     res <<= 1;
72610   } while (--len > 0);
72611   return res >>> 1;
72612 };
72613
72614
72615 /* ===========================================================================
72616  * Flush the bit buffer, keeping at most 7 bits in it.
72617  */
72618 const bi_flush = (s) => {
72619
72620   if (s.bi_valid === 16) {
72621     put_short(s, s.bi_buf);
72622     s.bi_buf = 0;
72623     s.bi_valid = 0;
72624
72625   } else if (s.bi_valid >= 8) {
72626     s.pending_buf[s.pending++] = s.bi_buf & 0xff;
72627     s.bi_buf >>= 8;
72628     s.bi_valid -= 8;
72629   }
72630 };
72631
72632
72633 /* ===========================================================================
72634  * Compute the optimal bit lengths for a tree and update the total bit length
72635  * for the current block.
72636  * IN assertion: the fields freq and dad are set, heap[heap_max] and
72637  *    above are the tree nodes sorted by increasing frequency.
72638  * OUT assertions: the field len is set to the optimal bit length, the
72639  *     array bl_count contains the frequencies for each bit length.
72640  *     The length opt_len is updated; static_len is also updated if stree is
72641  *     not null.
72642  */
72643 const gen_bitlen = (s, desc) =>
72644 //    deflate_state *s;
72645 //    tree_desc *desc;    /* the tree descriptor */
72646 {
72647   const tree            = desc.dyn_tree;
72648   const max_code        = desc.max_code;
72649   const stree           = desc.stat_desc.static_tree;
72650   const has_stree       = desc.stat_desc.has_stree;
72651   const extra           = desc.stat_desc.extra_bits;
72652   const base            = desc.stat_desc.extra_base;
72653   const max_length      = desc.stat_desc.max_length;
72654   let h;              /* heap index */
72655   let n, m;           /* iterate over the tree elements */
72656   let bits;           /* bit length */
72657   let xbits;          /* extra bits */
72658   let f;              /* frequency */
72659   let overflow = 0;   /* number of elements with bit length too large */
72660
72661   for (bits = 0; bits <= MAX_BITS; bits++) {
72662     s.bl_count[bits] = 0;
72663   }
72664
72665   /* In a first pass, compute the optimal bit lengths (which may
72666    * overflow in the case of the bit length tree).
72667    */
72668   tree[s.heap[s.heap_max] * 2 + 1]/*.Len*/ = 0; /* root of the heap */
72669
72670   for (h = s.heap_max + 1; h < HEAP_SIZE; h++) {
72671     n = s.heap[h];
72672     bits = tree[tree[n * 2 + 1]/*.Dad*/ * 2 + 1]/*.Len*/ + 1;
72673     if (bits > max_length) {
72674       bits = max_length;
72675       overflow++;
72676     }
72677     tree[n * 2 + 1]/*.Len*/ = bits;
72678     /* We overwrite tree[n].Dad which is no longer needed */
72679
72680     if (n > max_code) { continue; } /* not a leaf node */
72681
72682     s.bl_count[bits]++;
72683     xbits = 0;
72684     if (n >= base) {
72685       xbits = extra[n - base];
72686     }
72687     f = tree[n * 2]/*.Freq*/;
72688     s.opt_len += f * (bits + xbits);
72689     if (has_stree) {
72690       s.static_len += f * (stree[n * 2 + 1]/*.Len*/ + xbits);
72691     }
72692   }
72693   if (overflow === 0) { return; }
72694
72695   // Trace((stderr,"\nbit length overflow\n"));
72696   /* This happens for example on obj2 and pic of the Calgary corpus */
72697
72698   /* Find the first bit length which could increase: */
72699   do {
72700     bits = max_length - 1;
72701     while (s.bl_count[bits] === 0) { bits--; }
72702     s.bl_count[bits]--;      /* move one leaf down the tree */
72703     s.bl_count[bits + 1] += 2; /* move one overflow item as its brother */
72704     s.bl_count[max_length]--;
72705     /* The brother of the overflow item also moves one step up,
72706      * but this does not affect bl_count[max_length]
72707      */
72708     overflow -= 2;
72709   } while (overflow > 0);
72710
72711   /* Now recompute all bit lengths, scanning in increasing frequency.
72712    * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all
72713    * lengths instead of fixing only the wrong ones. This idea is taken
72714    * from 'ar' written by Haruhiko Okumura.)
72715    */
72716   for (bits = max_length; bits !== 0; bits--) {
72717     n = s.bl_count[bits];
72718     while (n !== 0) {
72719       m = s.heap[--h];
72720       if (m > max_code) { continue; }
72721       if (tree[m * 2 + 1]/*.Len*/ !== bits) {
72722         // Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits));
72723         s.opt_len += (bits - tree[m * 2 + 1]/*.Len*/) * tree[m * 2]/*.Freq*/;
72724         tree[m * 2 + 1]/*.Len*/ = bits;
72725       }
72726       n--;
72727     }
72728   }
72729 };
72730
72731
72732 /* ===========================================================================
72733  * Generate the codes for a given tree and bit counts (which need not be
72734  * optimal).
72735  * IN assertion: the array bl_count contains the bit length statistics for
72736  * the given tree and the field len is set for all tree elements.
72737  * OUT assertion: the field code is set for all tree elements of non
72738  *     zero code length.
72739  */
72740 const gen_codes = (tree, max_code, bl_count) =>
72741 //    ct_data *tree;             /* the tree to decorate */
72742 //    int max_code;              /* largest code with non zero frequency */
72743 //    ushf *bl_count;            /* number of codes at each bit length */
72744 {
72745   const next_code = new Array(MAX_BITS + 1); /* next code value for each bit length */
72746   let code = 0;              /* running code value */
72747   let bits;                  /* bit index */
72748   let n;                     /* code index */
72749
72750   /* The distribution counts are first used to generate the code values
72751    * without bit reversal.
72752    */
72753   for (bits = 1; bits <= MAX_BITS; bits++) {
72754     next_code[bits] = code = (code + bl_count[bits - 1]) << 1;
72755   }
72756   /* Check that the bit counts in bl_count are consistent. The last code
72757    * must be all ones.
72758    */
72759   //Assert (code + bl_count[MAX_BITS]-1 == (1<<MAX_BITS)-1,
72760   //        "inconsistent bit counts");
72761   //Tracev((stderr,"\ngen_codes: max_code %d ", max_code));
72762
72763   for (n = 0;  n <= max_code; n++) {
72764     let len = tree[n * 2 + 1]/*.Len*/;
72765     if (len === 0) { continue; }
72766     /* Now reverse the bits */
72767     tree[n * 2]/*.Code*/ = bi_reverse(next_code[len]++, len);
72768
72769     //Tracecv(tree != static_ltree, (stderr,"\nn %3d %c l %2d c %4x (%x) ",
72770     //     n, (isgraph(n) ? n : ' '), len, tree[n].Code, next_code[len]-1));
72771   }
72772 };
72773
72774
72775 /* ===========================================================================
72776  * Initialize the various 'constant' tables.
72777  */
72778 const tr_static_init = () => {
72779
72780   let n;        /* iterates over tree elements */
72781   let bits;     /* bit counter */
72782   let length;   /* length value */
72783   let code;     /* code value */
72784   let dist;     /* distance index */
72785   const bl_count = new Array(MAX_BITS + 1);
72786   /* number of codes at each bit length for an optimal tree */
72787
72788   // do check in _tr_init()
72789   //if (static_init_done) return;
72790
72791   /* For some embedded targets, global variables are not initialized: */
72792 /*#ifdef NO_INIT_GLOBAL_POINTERS
72793   static_l_desc.static_tree = static_ltree;
72794   static_l_desc.extra_bits = extra_lbits;
72795   static_d_desc.static_tree = static_dtree;
72796   static_d_desc.extra_bits = extra_dbits;
72797   static_bl_desc.extra_bits = extra_blbits;
72798 #endif*/
72799
72800   /* Initialize the mapping length (0..255) -> length code (0..28) */
72801   length = 0;
72802   for (code = 0; code < LENGTH_CODES - 1; code++) {
72803     base_length[code] = length;
72804     for (n = 0; n < (1 << extra_lbits[code]); n++) {
72805       _length_code[length++] = code;
72806     }
72807   }
72808   //Assert (length == 256, "tr_static_init: length != 256");
72809   /* Note that the length 255 (match length 258) can be represented
72810    * in two different ways: code 284 + 5 bits or code 285, so we
72811    * overwrite length_code[255] to use the best encoding:
72812    */
72813   _length_code[length - 1] = code;
72814
72815   /* Initialize the mapping dist (0..32K) -> dist code (0..29) */
72816   dist = 0;
72817   for (code = 0; code < 16; code++) {
72818     base_dist[code] = dist;
72819     for (n = 0; n < (1 << extra_dbits[code]); n++) {
72820       _dist_code[dist++] = code;
72821     }
72822   }
72823   //Assert (dist == 256, "tr_static_init: dist != 256");
72824   dist >>= 7; /* from now on, all distances are divided by 128 */
72825   for (; code < D_CODES; code++) {
72826     base_dist[code] = dist << 7;
72827     for (n = 0; n < (1 << (extra_dbits[code] - 7)); n++) {
72828       _dist_code[256 + dist++] = code;
72829     }
72830   }
72831   //Assert (dist == 256, "tr_static_init: 256+dist != 512");
72832
72833   /* Construct the codes of the static literal tree */
72834   for (bits = 0; bits <= MAX_BITS; bits++) {
72835     bl_count[bits] = 0;
72836   }
72837
72838   n = 0;
72839   while (n <= 143) {
72840     static_ltree[n * 2 + 1]/*.Len*/ = 8;
72841     n++;
72842     bl_count[8]++;
72843   }
72844   while (n <= 255) {
72845     static_ltree[n * 2 + 1]/*.Len*/ = 9;
72846     n++;
72847     bl_count[9]++;
72848   }
72849   while (n <= 279) {
72850     static_ltree[n * 2 + 1]/*.Len*/ = 7;
72851     n++;
72852     bl_count[7]++;
72853   }
72854   while (n <= 287) {
72855     static_ltree[n * 2 + 1]/*.Len*/ = 8;
72856     n++;
72857     bl_count[8]++;
72858   }
72859   /* Codes 286 and 287 do not exist, but we must include them in the
72860    * tree construction to get a canonical Huffman tree (longest code
72861    * all ones)
72862    */
72863   gen_codes(static_ltree, L_CODES + 1, bl_count);
72864
72865   /* The static distance tree is trivial: */
72866   for (n = 0; n < D_CODES; n++) {
72867     static_dtree[n * 2 + 1]/*.Len*/ = 5;
72868     static_dtree[n * 2]/*.Code*/ = bi_reverse(n, 5);
72869   }
72870
72871   // Now data ready and we can init static trees
72872   static_l_desc = new StaticTreeDesc(static_ltree, extra_lbits, LITERALS + 1, L_CODES, MAX_BITS);
72873   static_d_desc = new StaticTreeDesc(static_dtree, extra_dbits, 0,          D_CODES, MAX_BITS);
72874   static_bl_desc = new StaticTreeDesc(new Array(0), extra_blbits, 0,         BL_CODES, MAX_BL_BITS);
72875
72876   //static_init_done = true;
72877 };
72878
72879
72880 /* ===========================================================================
72881  * Initialize a new block.
72882  */
72883 const init_block = (s) => {
72884
72885   let n; /* iterates over tree elements */
72886
72887   /* Initialize the trees. */
72888   for (n = 0; n < L_CODES;  n++) { s.dyn_ltree[n * 2]/*.Freq*/ = 0; }
72889   for (n = 0; n < D_CODES;  n++) { s.dyn_dtree[n * 2]/*.Freq*/ = 0; }
72890   for (n = 0; n < BL_CODES; n++) { s.bl_tree[n * 2]/*.Freq*/ = 0; }
72891
72892   s.dyn_ltree[END_BLOCK * 2]/*.Freq*/ = 1;
72893   s.opt_len = s.static_len = 0;
72894   s.last_lit = s.matches = 0;
72895 };
72896
72897
72898 /* ===========================================================================
72899  * Flush the bit buffer and align the output on a byte boundary
72900  */
72901 const bi_windup = (s) =>
72902 {
72903   if (s.bi_valid > 8) {
72904     put_short(s, s.bi_buf);
72905   } else if (s.bi_valid > 0) {
72906     //put_byte(s, (Byte)s->bi_buf);
72907     s.pending_buf[s.pending++] = s.bi_buf;
72908   }
72909   s.bi_buf = 0;
72910   s.bi_valid = 0;
72911 };
72912
72913 /* ===========================================================================
72914  * Copy a stored block, storing first the length and its
72915  * one's complement if requested.
72916  */
72917 const copy_block = (s, buf, len, header) =>
72918 //DeflateState *s;
72919 //charf    *buf;    /* the input data */
72920 //unsigned len;     /* its length */
72921 //int      header;  /* true if block header must be written */
72922 {
72923   bi_windup(s);        /* align on byte boundary */
72924
72925   if (header) {
72926     put_short(s, len);
72927     put_short(s, ~len);
72928   }
72929 //  while (len--) {
72930 //    put_byte(s, *buf++);
72931 //  }
72932   s.pending_buf.set(s.window.subarray(buf, buf + len), s.pending);
72933   s.pending += len;
72934 };
72935
72936 /* ===========================================================================
72937  * Compares to subtrees, using the tree depth as tie breaker when
72938  * the subtrees have equal frequency. This minimizes the worst case length.
72939  */
72940 const smaller = (tree, n, m, depth) => {
72941
72942   const _n2 = n * 2;
72943   const _m2 = m * 2;
72944   return (tree[_n2]/*.Freq*/ < tree[_m2]/*.Freq*/ ||
72945          (tree[_n2]/*.Freq*/ === tree[_m2]/*.Freq*/ && depth[n] <= depth[m]));
72946 };
72947
72948 /* ===========================================================================
72949  * Restore the heap property by moving down the tree starting at node k,
72950  * exchanging a node with the smallest of its two sons if necessary, stopping
72951  * when the heap property is re-established (each father smaller than its
72952  * two sons).
72953  */
72954 const pqdownheap = (s, tree, k) =>
72955 //    deflate_state *s;
72956 //    ct_data *tree;  /* the tree to restore */
72957 //    int k;               /* node to move down */
72958 {
72959   const v = s.heap[k];
72960   let j = k << 1;  /* left son of k */
72961   while (j <= s.heap_len) {
72962     /* Set j to the smallest of the two sons: */
72963     if (j < s.heap_len &&
72964       smaller(tree, s.heap[j + 1], s.heap[j], s.depth)) {
72965       j++;
72966     }
72967     /* Exit if v is smaller than both sons */
72968     if (smaller(tree, v, s.heap[j], s.depth)) { break; }
72969
72970     /* Exchange v with the smallest son */
72971     s.heap[k] = s.heap[j];
72972     k = j;
72973
72974     /* And continue down the tree, setting j to the left son of k */
72975     j <<= 1;
72976   }
72977   s.heap[k] = v;
72978 };
72979
72980
72981 // inlined manually
72982 // const SMALLEST = 1;
72983
72984 /* ===========================================================================
72985  * Send the block data compressed using the given Huffman trees
72986  */
72987 const compress_block = (s, ltree, dtree) =>
72988 //    deflate_state *s;
72989 //    const ct_data *ltree; /* literal tree */
72990 //    const ct_data *dtree; /* distance tree */
72991 {
72992   let dist;           /* distance of matched string */
72993   let lc;             /* match length or unmatched char (if dist == 0) */
72994   let lx = 0;         /* running index in l_buf */
72995   let code;           /* the code to send */
72996   let extra;          /* number of extra bits to send */
72997
72998   if (s.last_lit !== 0) {
72999     do {
73000       dist = (s.pending_buf[s.d_buf + lx * 2] << 8) | (s.pending_buf[s.d_buf + lx * 2 + 1]);
73001       lc = s.pending_buf[s.l_buf + lx];
73002       lx++;
73003
73004       if (dist === 0) {
73005         send_code(s, lc, ltree); /* send a literal byte */
73006         //Tracecv(isgraph(lc), (stderr," '%c' ", lc));
73007       } else {
73008         /* Here, lc is the match length - MIN_MATCH */
73009         code = _length_code[lc];
73010         send_code(s, code + LITERALS + 1, ltree); /* send the length code */
73011         extra = extra_lbits[code];
73012         if (extra !== 0) {
73013           lc -= base_length[code];
73014           send_bits(s, lc, extra);       /* send the extra length bits */
73015         }
73016         dist--; /* dist is now the match distance - 1 */
73017         code = d_code(dist);
73018         //Assert (code < D_CODES, "bad d_code");
73019
73020         send_code(s, code, dtree);       /* send the distance code */
73021         extra = extra_dbits[code];
73022         if (extra !== 0) {
73023           dist -= base_dist[code];
73024           send_bits(s, dist, extra);   /* send the extra distance bits */
73025         }
73026       } /* literal or match pair ? */
73027
73028       /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */
73029       //Assert((uInt)(s->pending) < s->lit_bufsize + 2*lx,
73030       //       "pendingBuf overflow");
73031
73032     } while (lx < s.last_lit);
73033   }
73034
73035   send_code(s, END_BLOCK, ltree);
73036 };
73037
73038
73039 /* ===========================================================================
73040  * Construct one Huffman tree and assigns the code bit strings and lengths.
73041  * Update the total bit length for the current block.
73042  * IN assertion: the field freq is set for all tree elements.
73043  * OUT assertions: the fields len and code are set to the optimal bit length
73044  *     and corresponding code. The length opt_len is updated; static_len is
73045  *     also updated if stree is not null. The field max_code is set.
73046  */
73047 const build_tree = (s, desc) =>
73048 //    deflate_state *s;
73049 //    tree_desc *desc; /* the tree descriptor */
73050 {
73051   const tree     = desc.dyn_tree;
73052   const stree    = desc.stat_desc.static_tree;
73053   const has_stree = desc.stat_desc.has_stree;
73054   const elems    = desc.stat_desc.elems;
73055   let n, m;          /* iterate over heap elements */
73056   let max_code = -1; /* largest code with non zero frequency */
73057   let node;          /* new node being created */
73058
73059   /* Construct the initial heap, with least frequent element in
73060    * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1].
73061    * heap[0] is not used.
73062    */
73063   s.heap_len = 0;
73064   s.heap_max = HEAP_SIZE;
73065
73066   for (n = 0; n < elems; n++) {
73067     if (tree[n * 2]/*.Freq*/ !== 0) {
73068       s.heap[++s.heap_len] = max_code = n;
73069       s.depth[n] = 0;
73070
73071     } else {
73072       tree[n * 2 + 1]/*.Len*/ = 0;
73073     }
73074   }
73075
73076   /* The pkzip format requires that at least one distance code exists,
73077    * and that at least one bit should be sent even if there is only one
73078    * possible code. So to avoid special checks later on we force at least
73079    * two codes of non zero frequency.
73080    */
73081   while (s.heap_len < 2) {
73082     node = s.heap[++s.heap_len] = (max_code < 2 ? ++max_code : 0);
73083     tree[node * 2]/*.Freq*/ = 1;
73084     s.depth[node] = 0;
73085     s.opt_len--;
73086
73087     if (has_stree) {
73088       s.static_len -= stree[node * 2 + 1]/*.Len*/;
73089     }
73090     /* node is 0 or 1 so it does not have extra bits */
73091   }
73092   desc.max_code = max_code;
73093
73094   /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree,
73095    * establish sub-heaps of increasing lengths:
73096    */
73097   for (n = (s.heap_len >> 1/*int /2*/); n >= 1; n--) { pqdownheap(s, tree, n); }
73098
73099   /* Construct the Huffman tree by repeatedly combining the least two
73100    * frequent nodes.
73101    */
73102   node = elems;              /* next internal node of the tree */
73103   do {
73104     //pqremove(s, tree, n);  /* n = node of least frequency */
73105     /*** pqremove ***/
73106     n = s.heap[1/*SMALLEST*/];
73107     s.heap[1/*SMALLEST*/] = s.heap[s.heap_len--];
73108     pqdownheap(s, tree, 1/*SMALLEST*/);
73109     /***/
73110
73111     m = s.heap[1/*SMALLEST*/]; /* m = node of next least frequency */
73112
73113     s.heap[--s.heap_max] = n; /* keep the nodes sorted by frequency */
73114     s.heap[--s.heap_max] = m;
73115
73116     /* Create a new node father of n and m */
73117     tree[node * 2]/*.Freq*/ = tree[n * 2]/*.Freq*/ + tree[m * 2]/*.Freq*/;
73118     s.depth[node] = (s.depth[n] >= s.depth[m] ? s.depth[n] : s.depth[m]) + 1;
73119     tree[n * 2 + 1]/*.Dad*/ = tree[m * 2 + 1]/*.Dad*/ = node;
73120
73121     /* and insert the new node in the heap */
73122     s.heap[1/*SMALLEST*/] = node++;
73123     pqdownheap(s, tree, 1/*SMALLEST*/);
73124
73125   } while (s.heap_len >= 2);
73126
73127   s.heap[--s.heap_max] = s.heap[1/*SMALLEST*/];
73128
73129   /* At this point, the fields freq and dad are set. We can now
73130    * generate the bit lengths.
73131    */
73132   gen_bitlen(s, desc);
73133
73134   /* The field len is now set, we can generate the bit codes */
73135   gen_codes(tree, max_code, s.bl_count);
73136 };
73137
73138
73139 /* ===========================================================================
73140  * Scan a literal or distance tree to determine the frequencies of the codes
73141  * in the bit length tree.
73142  */
73143 const scan_tree = (s, tree, max_code) =>
73144 //    deflate_state *s;
73145 //    ct_data *tree;   /* the tree to be scanned */
73146 //    int max_code;    /* and its largest code of non zero frequency */
73147 {
73148   let n;                     /* iterates over all tree elements */
73149   let prevlen = -1;          /* last emitted length */
73150   let curlen;                /* length of current code */
73151
73152   let nextlen = tree[0 * 2 + 1]/*.Len*/; /* length of next code */
73153
73154   let count = 0;             /* repeat count of the current code */
73155   let max_count = 7;         /* max repeat count */
73156   let min_count = 4;         /* min repeat count */
73157
73158   if (nextlen === 0) {
73159     max_count = 138;
73160     min_count = 3;
73161   }
73162   tree[(max_code + 1) * 2 + 1]/*.Len*/ = 0xffff; /* guard */
73163
73164   for (n = 0; n <= max_code; n++) {
73165     curlen = nextlen;
73166     nextlen = tree[(n + 1) * 2 + 1]/*.Len*/;
73167
73168     if (++count < max_count && curlen === nextlen) {
73169       continue;
73170
73171     } else if (count < min_count) {
73172       s.bl_tree[curlen * 2]/*.Freq*/ += count;
73173
73174     } else if (curlen !== 0) {
73175
73176       if (curlen !== prevlen) { s.bl_tree[curlen * 2]/*.Freq*/++; }
73177       s.bl_tree[REP_3_6 * 2]/*.Freq*/++;
73178
73179     } else if (count <= 10) {
73180       s.bl_tree[REPZ_3_10 * 2]/*.Freq*/++;
73181
73182     } else {
73183       s.bl_tree[REPZ_11_138 * 2]/*.Freq*/++;
73184     }
73185
73186     count = 0;
73187     prevlen = curlen;
73188
73189     if (nextlen === 0) {
73190       max_count = 138;
73191       min_count = 3;
73192
73193     } else if (curlen === nextlen) {
73194       max_count = 6;
73195       min_count = 3;
73196
73197     } else {
73198       max_count = 7;
73199       min_count = 4;
73200     }
73201   }
73202 };
73203
73204
73205 /* ===========================================================================
73206  * Send a literal or distance tree in compressed form, using the codes in
73207  * bl_tree.
73208  */
73209 const send_tree = (s, tree, max_code) =>
73210 //    deflate_state *s;
73211 //    ct_data *tree; /* the tree to be scanned */
73212 //    int max_code;       /* and its largest code of non zero frequency */
73213 {
73214   let n;                     /* iterates over all tree elements */
73215   let prevlen = -1;          /* last emitted length */
73216   let curlen;                /* length of current code */
73217
73218   let nextlen = tree[0 * 2 + 1]/*.Len*/; /* length of next code */
73219
73220   let count = 0;             /* repeat count of the current code */
73221   let max_count = 7;         /* max repeat count */
73222   let min_count = 4;         /* min repeat count */
73223
73224   /* tree[max_code+1].Len = -1; */  /* guard already set */
73225   if (nextlen === 0) {
73226     max_count = 138;
73227     min_count = 3;
73228   }
73229
73230   for (n = 0; n <= max_code; n++) {
73231     curlen = nextlen;
73232     nextlen = tree[(n + 1) * 2 + 1]/*.Len*/;
73233
73234     if (++count < max_count && curlen === nextlen) {
73235       continue;
73236
73237     } else if (count < min_count) {
73238       do { send_code(s, curlen, s.bl_tree); } while (--count !== 0);
73239
73240     } else if (curlen !== 0) {
73241       if (curlen !== prevlen) {
73242         send_code(s, curlen, s.bl_tree);
73243         count--;
73244       }
73245       //Assert(count >= 3 && count <= 6, " 3_6?");
73246       send_code(s, REP_3_6, s.bl_tree);
73247       send_bits(s, count - 3, 2);
73248
73249     } else if (count <= 10) {
73250       send_code(s, REPZ_3_10, s.bl_tree);
73251       send_bits(s, count - 3, 3);
73252
73253     } else {
73254       send_code(s, REPZ_11_138, s.bl_tree);
73255       send_bits(s, count - 11, 7);
73256     }
73257
73258     count = 0;
73259     prevlen = curlen;
73260     if (nextlen === 0) {
73261       max_count = 138;
73262       min_count = 3;
73263
73264     } else if (curlen === nextlen) {
73265       max_count = 6;
73266       min_count = 3;
73267
73268     } else {
73269       max_count = 7;
73270       min_count = 4;
73271     }
73272   }
73273 };
73274
73275
73276 /* ===========================================================================
73277  * Construct the Huffman tree for the bit lengths and return the index in
73278  * bl_order of the last bit length code to send.
73279  */
73280 const build_bl_tree = (s) => {
73281
73282   let max_blindex;  /* index of last bit length code of non zero freq */
73283
73284   /* Determine the bit length frequencies for literal and distance trees */
73285   scan_tree(s, s.dyn_ltree, s.l_desc.max_code);
73286   scan_tree(s, s.dyn_dtree, s.d_desc.max_code);
73287
73288   /* Build the bit length tree: */
73289   build_tree(s, s.bl_desc);
73290   /* opt_len now includes the length of the tree representations, except
73291    * the lengths of the bit lengths codes and the 5+5+4 bits for the counts.
73292    */
73293
73294   /* Determine the number of bit length codes to send. The pkzip format
73295    * requires that at least 4 bit length codes be sent. (appnote.txt says
73296    * 3 but the actual value used is 4.)
73297    */
73298   for (max_blindex = BL_CODES - 1; max_blindex >= 3; max_blindex--) {
73299     if (s.bl_tree[bl_order[max_blindex] * 2 + 1]/*.Len*/ !== 0) {
73300       break;
73301     }
73302   }
73303   /* Update opt_len to include the bit length tree and counts */
73304   s.opt_len += 3 * (max_blindex + 1) + 5 + 5 + 4;
73305   //Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld",
73306   //        s->opt_len, s->static_len));
73307
73308   return max_blindex;
73309 };
73310
73311
73312 /* ===========================================================================
73313  * Send the header for a block using dynamic Huffman trees: the counts, the
73314  * lengths of the bit length codes, the literal tree and the distance tree.
73315  * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4.
73316  */
73317 const send_all_trees = (s, lcodes, dcodes, blcodes) =>
73318 //    deflate_state *s;
73319 //    int lcodes, dcodes, blcodes; /* number of codes for each tree */
73320 {
73321   let rank;                    /* index in bl_order */
73322
73323   //Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes");
73324   //Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES,
73325   //        "too many codes");
73326   //Tracev((stderr, "\nbl counts: "));
73327   send_bits(s, lcodes - 257, 5); /* not +255 as stated in appnote.txt */
73328   send_bits(s, dcodes - 1,   5);
73329   send_bits(s, blcodes - 4,  4); /* not -3 as stated in appnote.txt */
73330   for (rank = 0; rank < blcodes; rank++) {
73331     //Tracev((stderr, "\nbl code %2d ", bl_order[rank]));
73332     send_bits(s, s.bl_tree[bl_order[rank] * 2 + 1]/*.Len*/, 3);
73333   }
73334   //Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent));
73335
73336   send_tree(s, s.dyn_ltree, lcodes - 1); /* literal tree */
73337   //Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent));
73338
73339   send_tree(s, s.dyn_dtree, dcodes - 1); /* distance tree */
73340   //Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent));
73341 };
73342
73343
73344 /* ===========================================================================
73345  * Check if the data type is TEXT or BINARY, using the following algorithm:
73346  * - TEXT if the two conditions below are satisfied:
73347  *    a) There are no non-portable control characters belonging to the
73348  *       "black list" (0..6, 14..25, 28..31).
73349  *    b) There is at least one printable character belonging to the
73350  *       "white list" (9 {TAB}, 10 {LF}, 13 {CR}, 32..255).
73351  * - BINARY otherwise.
73352  * - The following partially-portable control characters form a
73353  *   "gray list" that is ignored in this detection algorithm:
73354  *   (7 {BEL}, 8 {BS}, 11 {VT}, 12 {FF}, 26 {SUB}, 27 {ESC}).
73355  * IN assertion: the fields Freq of dyn_ltree are set.
73356  */
73357 const detect_data_type = (s) => {
73358   /* black_mask is the bit mask of black-listed bytes
73359    * set bits 0..6, 14..25, and 28..31
73360    * 0xf3ffc07f = binary 11110011111111111100000001111111
73361    */
73362   let black_mask = 0xf3ffc07f;
73363   let n;
73364
73365   /* Check for non-textual ("black-listed") bytes. */
73366   for (n = 0; n <= 31; n++, black_mask >>>= 1) {
73367     if ((black_mask & 1) && (s.dyn_ltree[n * 2]/*.Freq*/ !== 0)) {
73368       return Z_BINARY;
73369     }
73370   }
73371
73372   /* Check for textual ("white-listed") bytes. */
73373   if (s.dyn_ltree[9 * 2]/*.Freq*/ !== 0 || s.dyn_ltree[10 * 2]/*.Freq*/ !== 0 ||
73374       s.dyn_ltree[13 * 2]/*.Freq*/ !== 0) {
73375     return Z_TEXT;
73376   }
73377   for (n = 32; n < LITERALS; n++) {
73378     if (s.dyn_ltree[n * 2]/*.Freq*/ !== 0) {
73379       return Z_TEXT;
73380     }
73381   }
73382
73383   /* There are no "black-listed" or "white-listed" bytes:
73384    * this stream either is empty or has tolerated ("gray-listed") bytes only.
73385    */
73386   return Z_BINARY;
73387 };
73388
73389
73390 let static_init_done = false;
73391
73392 /* ===========================================================================
73393  * Initialize the tree data structures for a new zlib stream.
73394  */
73395 const _tr_init = (s) =>
73396 {
73397
73398   if (!static_init_done) {
73399     tr_static_init();
73400     static_init_done = true;
73401   }
73402
73403   s.l_desc  = new TreeDesc(s.dyn_ltree, static_l_desc);
73404   s.d_desc  = new TreeDesc(s.dyn_dtree, static_d_desc);
73405   s.bl_desc = new TreeDesc(s.bl_tree, static_bl_desc);
73406
73407   s.bi_buf = 0;
73408   s.bi_valid = 0;
73409
73410   /* Initialize the first block of the first file: */
73411   init_block(s);
73412 };
73413
73414
73415 /* ===========================================================================
73416  * Send a stored block
73417  */
73418 const _tr_stored_block = (s, buf, stored_len, last) =>
73419 //DeflateState *s;
73420 //charf *buf;       /* input block */
73421 //ulg stored_len;   /* length of input block */
73422 //int last;         /* one if this is the last block for a file */
73423 {
73424   send_bits(s, (STORED_BLOCK << 1) + (last ? 1 : 0), 3);    /* send block type */
73425   copy_block(s, buf, stored_len, true); /* with header */
73426 };
73427
73428
73429 /* ===========================================================================
73430  * Send one empty static block to give enough lookahead for inflate.
73431  * This takes 10 bits, of which 7 may remain in the bit buffer.
73432  */
73433 const _tr_align = (s) => {
73434   send_bits(s, STATIC_TREES << 1, 3);
73435   send_code(s, END_BLOCK, static_ltree);
73436   bi_flush(s);
73437 };
73438
73439
73440 /* ===========================================================================
73441  * Determine the best encoding for the current block: dynamic trees, static
73442  * trees or store, and output the encoded block to the zip file.
73443  */
73444 const _tr_flush_block = (s, buf, stored_len, last) =>
73445 //DeflateState *s;
73446 //charf *buf;       /* input block, or NULL if too old */
73447 //ulg stored_len;   /* length of input block */
73448 //int last;         /* one if this is the last block for a file */
73449 {
73450   let opt_lenb, static_lenb;  /* opt_len and static_len in bytes */
73451   let max_blindex = 0;        /* index of last bit length code of non zero freq */
73452
73453   /* Build the Huffman trees unless a stored block is forced */
73454   if (s.level > 0) {
73455
73456     /* Check if the file is binary or text */
73457     if (s.strm.data_type === Z_UNKNOWN) {
73458       s.strm.data_type = detect_data_type(s);
73459     }
73460
73461     /* Construct the literal and distance trees */
73462     build_tree(s, s.l_desc);
73463     // Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len,
73464     //        s->static_len));
73465
73466     build_tree(s, s.d_desc);
73467     // Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len,
73468     //        s->static_len));
73469     /* At this point, opt_len and static_len are the total bit lengths of
73470      * the compressed block data, excluding the tree representations.
73471      */
73472
73473     /* Build the bit length tree for the above two trees, and get the index
73474      * in bl_order of the last bit length code to send.
73475      */
73476     max_blindex = build_bl_tree(s);
73477
73478     /* Determine the best encoding. Compute the block lengths in bytes. */
73479     opt_lenb = (s.opt_len + 3 + 7) >>> 3;
73480     static_lenb = (s.static_len + 3 + 7) >>> 3;
73481
73482     // Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ",
73483     //        opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len,
73484     //        s->last_lit));
73485
73486     if (static_lenb <= opt_lenb) { opt_lenb = static_lenb; }
73487
73488   } else {
73489     // Assert(buf != (char*)0, "lost buf");
73490     opt_lenb = static_lenb = stored_len + 5; /* force a stored block */
73491   }
73492
73493   if ((stored_len + 4 <= opt_lenb) && (buf !== -1)) {
73494     /* 4: two words for the lengths */
73495
73496     /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE.
73497      * Otherwise we can't have processed more than WSIZE input bytes since
73498      * the last block flush, because compression would have been
73499      * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to
73500      * transform a block into a stored block.
73501      */
73502     _tr_stored_block(s, buf, stored_len, last);
73503
73504   } else if (s.strategy === Z_FIXED || static_lenb === opt_lenb) {
73505
73506     send_bits(s, (STATIC_TREES << 1) + (last ? 1 : 0), 3);
73507     compress_block(s, static_ltree, static_dtree);
73508
73509   } else {
73510     send_bits(s, (DYN_TREES << 1) + (last ? 1 : 0), 3);
73511     send_all_trees(s, s.l_desc.max_code + 1, s.d_desc.max_code + 1, max_blindex + 1);
73512     compress_block(s, s.dyn_ltree, s.dyn_dtree);
73513   }
73514   // Assert (s->compressed_len == s->bits_sent, "bad compressed size");
73515   /* The above check is made mod 2^32, for files larger than 512 MB
73516    * and uLong implemented on 32 bits.
73517    */
73518   init_block(s);
73519
73520   if (last) {
73521     bi_windup(s);
73522   }
73523   // Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3,
73524   //       s->compressed_len-7*last));
73525 };
73526
73527 /* ===========================================================================
73528  * Save the match info and tally the frequency counts. Return true if
73529  * the current block must be flushed.
73530  */
73531 const _tr_tally = (s, dist, lc) =>
73532 //    deflate_state *s;
73533 //    unsigned dist;  /* distance of matched string */
73534 //    unsigned lc;    /* match length-MIN_MATCH or unmatched char (if dist==0) */
73535 {
73536   //let out_length, in_length, dcode;
73537
73538   s.pending_buf[s.d_buf + s.last_lit * 2]     = (dist >>> 8) & 0xff;
73539   s.pending_buf[s.d_buf + s.last_lit * 2 + 1] = dist & 0xff;
73540
73541   s.pending_buf[s.l_buf + s.last_lit] = lc & 0xff;
73542   s.last_lit++;
73543
73544   if (dist === 0) {
73545     /* lc is the unmatched char */
73546     s.dyn_ltree[lc * 2]/*.Freq*/++;
73547   } else {
73548     s.matches++;
73549     /* Here, lc is the match length - MIN_MATCH */
73550     dist--;             /* dist = match distance - 1 */
73551     //Assert((ush)dist < (ush)MAX_DIST(s) &&
73552     //       (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) &&
73553     //       (ush)d_code(dist) < (ush)D_CODES,  "_tr_tally: bad match");
73554
73555     s.dyn_ltree[(_length_code[lc] + LITERALS + 1) * 2]/*.Freq*/++;
73556     s.dyn_dtree[d_code(dist) * 2]/*.Freq*/++;
73557   }
73558
73559 // (!) This block is disabled in zlib defaults,
73560 // don't enable it for binary compatibility
73561
73562 //#ifdef TRUNCATE_BLOCK
73563 //  /* Try to guess if it is profitable to stop the current block here */
73564 //  if ((s.last_lit & 0x1fff) === 0 && s.level > 2) {
73565 //    /* Compute an upper bound for the compressed length */
73566 //    out_length = s.last_lit*8;
73567 //    in_length = s.strstart - s.block_start;
73568 //
73569 //    for (dcode = 0; dcode < D_CODES; dcode++) {
73570 //      out_length += s.dyn_dtree[dcode*2]/*.Freq*/ * (5 + extra_dbits[dcode]);
73571 //    }
73572 //    out_length >>>= 3;
73573 //    //Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ",
73574 //    //       s->last_lit, in_length, out_length,
73575 //    //       100L - out_length*100L/in_length));
73576 //    if (s.matches < (s.last_lit>>1)/*int /2*/ && out_length < (in_length>>1)/*int /2*/) {
73577 //      return true;
73578 //    }
73579 //  }
73580 //#endif
73581
73582   return (s.last_lit === s.lit_bufsize - 1);
73583   /* We avoid equality with lit_bufsize because of wraparound at 64K
73584    * on 16 bit machines and because stored blocks are restricted to
73585    * 64K-1 bytes.
73586    */
73587 };
73588
73589 var _tr_init_1  = _tr_init;
73590 var _tr_stored_block_1 = _tr_stored_block;
73591 var _tr_flush_block_1  = _tr_flush_block;
73592 var _tr_tally_1 = _tr_tally;
73593 var _tr_align_1 = _tr_align;
73594
73595 var trees = {
73596         _tr_init: _tr_init_1,
73597         _tr_stored_block: _tr_stored_block_1,
73598         _tr_flush_block: _tr_flush_block_1,
73599         _tr_tally: _tr_tally_1,
73600         _tr_align: _tr_align_1
73601 };
73602
73603 // Note: adler32 takes 12% for level 0 and 2% for level 6.
73604 // It isn't worth it to make additional optimizations as in original.
73605 // Small size is preferable.
73606
73607 // (C) 1995-2013 Jean-loup Gailly and Mark Adler
73608 // (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin
73609 //
73610 // This software is provided 'as-is', without any express or implied
73611 // warranty. In no event will the authors be held liable for any damages
73612 // arising from the use of this software.
73613 //
73614 // Permission is granted to anyone to use this software for any purpose,
73615 // including commercial applications, and to alter it and redistribute it
73616 // freely, subject to the following restrictions:
73617 //
73618 // 1. The origin of this software must not be misrepresented; you must not
73619 //   claim that you wrote the original software. If you use this software
73620 //   in a product, an acknowledgment in the product documentation would be
73621 //   appreciated but is not required.
73622 // 2. Altered source versions must be plainly marked as such, and must not be
73623 //   misrepresented as being the original software.
73624 // 3. This notice may not be removed or altered from any source distribution.
73625
73626 const adler32 = (adler, buf, len, pos) => {
73627   let s1 = (adler & 0xffff) |0,
73628       s2 = ((adler >>> 16) & 0xffff) |0,
73629       n = 0;
73630
73631   while (len !== 0) {
73632     // Set limit ~ twice less than 5552, to keep
73633     // s2 in 31-bits, because we force signed ints.
73634     // in other case %= will fail.
73635     n = len > 2000 ? 2000 : len;
73636     len -= n;
73637
73638     do {
73639       s1 = (s1 + buf[pos++]) |0;
73640       s2 = (s2 + s1) |0;
73641     } while (--n);
73642
73643     s1 %= 65521;
73644     s2 %= 65521;
73645   }
73646
73647   return (s1 | (s2 << 16)) |0;
73648 };
73649
73650
73651 var adler32_1 = adler32;
73652
73653 // Note: we can't get significant speed boost here.
73654 // So write code to minimize size - no pregenerated tables
73655 // and array tools dependencies.
73656
73657 // (C) 1995-2013 Jean-loup Gailly and Mark Adler
73658 // (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin
73659 //
73660 // This software is provided 'as-is', without any express or implied
73661 // warranty. In no event will the authors be held liable for any damages
73662 // arising from the use of this software.
73663 //
73664 // Permission is granted to anyone to use this software for any purpose,
73665 // including commercial applications, and to alter it and redistribute it
73666 // freely, subject to the following restrictions:
73667 //
73668 // 1. The origin of this software must not be misrepresented; you must not
73669 //   claim that you wrote the original software. If you use this software
73670 //   in a product, an acknowledgment in the product documentation would be
73671 //   appreciated but is not required.
73672 // 2. Altered source versions must be plainly marked as such, and must not be
73673 //   misrepresented as being the original software.
73674 // 3. This notice may not be removed or altered from any source distribution.
73675
73676 // Use ordinary array, since untyped makes no boost here
73677 const makeTable = () => {
73678   let c, table = [];
73679
73680   for (var n = 0; n < 256; n++) {
73681     c = n;
73682     for (var k = 0; k < 8; k++) {
73683       c = ((c & 1) ? (0xEDB88320 ^ (c >>> 1)) : (c >>> 1));
73684     }
73685     table[n] = c;
73686   }
73687
73688   return table;
73689 };
73690
73691 // Create table on load. Just 255 signed longs. Not a problem.
73692 const crcTable = new Uint32Array(makeTable());
73693
73694
73695 const crc32 = (crc, buf, len, pos) => {
73696   const t = crcTable;
73697   const end = pos + len;
73698
73699   crc ^= -1;
73700
73701   for (let i = pos; i < end; i++) {
73702     crc = (crc >>> 8) ^ t[(crc ^ buf[i]) & 0xFF];
73703   }
73704
73705   return (crc ^ (-1)); // >>> 0;
73706 };
73707
73708
73709 var crc32_1 = crc32;
73710
73711 // (C) 1995-2013 Jean-loup Gailly and Mark Adler
73712 // (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin
73713 //
73714 // This software is provided 'as-is', without any express or implied
73715 // warranty. In no event will the authors be held liable for any damages
73716 // arising from the use of this software.
73717 //
73718 // Permission is granted to anyone to use this software for any purpose,
73719 // including commercial applications, and to alter it and redistribute it
73720 // freely, subject to the following restrictions:
73721 //
73722 // 1. The origin of this software must not be misrepresented; you must not
73723 //   claim that you wrote the original software. If you use this software
73724 //   in a product, an acknowledgment in the product documentation would be
73725 //   appreciated but is not required.
73726 // 2. Altered source versions must be plainly marked as such, and must not be
73727 //   misrepresented as being the original software.
73728 // 3. This notice may not be removed or altered from any source distribution.
73729
73730 var messages = {
73731   2:      'need dictionary',     /* Z_NEED_DICT       2  */
73732   1:      'stream end',          /* Z_STREAM_END      1  */
73733   0:      '',                    /* Z_OK              0  */
73734   '-1':   'file error',          /* Z_ERRNO         (-1) */
73735   '-2':   'stream error',        /* Z_STREAM_ERROR  (-2) */
73736   '-3':   'data error',          /* Z_DATA_ERROR    (-3) */
73737   '-4':   'insufficient memory', /* Z_MEM_ERROR     (-4) */
73738   '-5':   'buffer error',        /* Z_BUF_ERROR     (-5) */
73739   '-6':   'incompatible version' /* Z_VERSION_ERROR (-6) */
73740 };
73741
73742 // (C) 1995-2013 Jean-loup Gailly and Mark Adler
73743 // (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin
73744 //
73745 // This software is provided 'as-is', without any express or implied
73746 // warranty. In no event will the authors be held liable for any damages
73747 // arising from the use of this software.
73748 //
73749 // Permission is granted to anyone to use this software for any purpose,
73750 // including commercial applications, and to alter it and redistribute it
73751 // freely, subject to the following restrictions:
73752 //
73753 // 1. The origin of this software must not be misrepresented; you must not
73754 //   claim that you wrote the original software. If you use this software
73755 //   in a product, an acknowledgment in the product documentation would be
73756 //   appreciated but is not required.
73757 // 2. Altered source versions must be plainly marked as such, and must not be
73758 //   misrepresented as being the original software.
73759 // 3. This notice may not be removed or altered from any source distribution.
73760
73761 var constants = {
73762
73763   /* Allowed flush values; see deflate() and inflate() below for details */
73764   Z_NO_FLUSH:         0,
73765   Z_PARTIAL_FLUSH:    1,
73766   Z_SYNC_FLUSH:       2,
73767   Z_FULL_FLUSH:       3,
73768   Z_FINISH:           4,
73769   Z_BLOCK:            5,
73770   Z_TREES:            6,
73771
73772   /* Return codes for the compression/decompression functions. Negative values
73773   * are errors, positive values are used for special but normal events.
73774   */
73775   Z_OK:               0,
73776   Z_STREAM_END:       1,
73777   Z_NEED_DICT:        2,
73778   Z_ERRNO:           -1,
73779   Z_STREAM_ERROR:    -2,
73780   Z_DATA_ERROR:      -3,
73781   Z_MEM_ERROR:       -4,
73782   Z_BUF_ERROR:       -5,
73783   //Z_VERSION_ERROR: -6,
73784
73785   /* compression levels */
73786   Z_NO_COMPRESSION:         0,
73787   Z_BEST_SPEED:             1,
73788   Z_BEST_COMPRESSION:       9,
73789   Z_DEFAULT_COMPRESSION:   -1,
73790
73791
73792   Z_FILTERED:               1,
73793   Z_HUFFMAN_ONLY:           2,
73794   Z_RLE:                    3,
73795   Z_FIXED:                  4,
73796   Z_DEFAULT_STRATEGY:       0,
73797
73798   /* Possible values of the data_type field (though see inflate()) */
73799   Z_BINARY:                 0,
73800   Z_TEXT:                   1,
73801   //Z_ASCII:                1, // = Z_TEXT (deprecated)
73802   Z_UNKNOWN:                2,
73803
73804   /* The deflate compression method */
73805   Z_DEFLATED:               8
73806   //Z_NULL:                 null // Use -1 or null inline, depending on var type
73807 };
73808
73809 // (C) 1995-2013 Jean-loup Gailly and Mark Adler
73810 // (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin
73811 //
73812 // This software is provided 'as-is', without any express or implied
73813 // warranty. In no event will the authors be held liable for any damages
73814 // arising from the use of this software.
73815 //
73816 // Permission is granted to anyone to use this software for any purpose,
73817 // including commercial applications, and to alter it and redistribute it
73818 // freely, subject to the following restrictions:
73819 //
73820 // 1. The origin of this software must not be misrepresented; you must not
73821 //   claim that you wrote the original software. If you use this software
73822 //   in a product, an acknowledgment in the product documentation would be
73823 //   appreciated but is not required.
73824 // 2. Altered source versions must be plainly marked as such, and must not be
73825 //   misrepresented as being the original software.
73826 // 3. This notice may not be removed or altered from any source distribution.
73827
73828 const { _tr_init: _tr_init$1, _tr_stored_block: _tr_stored_block$1, _tr_flush_block: _tr_flush_block$1, _tr_tally: _tr_tally$1, _tr_align: _tr_align$1 } = trees;
73829
73830
73831
73832
73833 /* Public constants ==========================================================*/
73834 /* ===========================================================================*/
73835
73836 const {
73837   Z_NO_FLUSH, Z_PARTIAL_FLUSH, Z_FULL_FLUSH, Z_FINISH, Z_BLOCK,
73838   Z_OK, Z_STREAM_END, Z_STREAM_ERROR, Z_DATA_ERROR, Z_BUF_ERROR,
73839   Z_DEFAULT_COMPRESSION,
73840   Z_FILTERED, Z_HUFFMAN_ONLY, Z_RLE, Z_FIXED: Z_FIXED$1, Z_DEFAULT_STRATEGY,
73841   Z_UNKNOWN: Z_UNKNOWN$1,
73842   Z_DEFLATED
73843 } = constants;
73844
73845 /*============================================================================*/
73846
73847
73848 const MAX_MEM_LEVEL = 9;
73849 /* Maximum value for memLevel in deflateInit2 */
73850 const MAX_WBITS = 15;
73851 /* 32K LZ77 window */
73852 const DEF_MEM_LEVEL = 8;
73853
73854
73855 const LENGTH_CODES$1  = 29;
73856 /* number of length codes, not counting the special END_BLOCK code */
73857 const LITERALS$1      = 256;
73858 /* number of literal bytes 0..255 */
73859 const L_CODES$1       = LITERALS$1 + 1 + LENGTH_CODES$1;
73860 /* number of Literal or Length codes, including the END_BLOCK code */
73861 const D_CODES$1       = 30;
73862 /* number of distance codes */
73863 const BL_CODES$1      = 19;
73864 /* number of codes used to transfer the bit lengths */
73865 const HEAP_SIZE$1     = 2 * L_CODES$1 + 1;
73866 /* maximum heap size */
73867 const MAX_BITS$1  = 15;
73868 /* All codes must not exceed MAX_BITS bits */
73869
73870 const MIN_MATCH$1 = 3;
73871 const MAX_MATCH$1 = 258;
73872 const MIN_LOOKAHEAD = (MAX_MATCH$1 + MIN_MATCH$1 + 1);
73873
73874 const PRESET_DICT = 0x20;
73875
73876 const INIT_STATE = 42;
73877 const EXTRA_STATE = 69;
73878 const NAME_STATE = 73;
73879 const COMMENT_STATE = 91;
73880 const HCRC_STATE = 103;
73881 const BUSY_STATE = 113;
73882 const FINISH_STATE = 666;
73883
73884 const BS_NEED_MORE      = 1; /* block not completed, need more input or more output */
73885 const BS_BLOCK_DONE     = 2; /* block flush performed */
73886 const BS_FINISH_STARTED = 3; /* finish started, need only more output at next deflate */
73887 const BS_FINISH_DONE    = 4; /* finish done, accept no more input or output */
73888
73889 const OS_CODE = 0x03; // Unix :) . Don't detect, use this default.
73890
73891 const err = (strm, errorCode) => {
73892   strm.msg = messages[errorCode];
73893   return errorCode;
73894 };
73895
73896 const rank = (f) => {
73897   return ((f) << 1) - ((f) > 4 ? 9 : 0);
73898 };
73899
73900 const zero$1 = (buf) => {
73901   let len = buf.length; while (--len >= 0) { buf[len] = 0; }
73902 };
73903
73904
73905 /* eslint-disable new-cap */
73906 let HASH_ZLIB = (s, prev, data) => ((prev << s.hash_shift) ^ data) & s.hash_mask;
73907 // This hash causes less collisions, https://github.com/nodeca/pako/issues/135
73908 // But breaks binary compatibility
73909 //let HASH_FAST = (s, prev, data) => ((prev << 8) + (prev >> 8) + (data << 4)) & s.hash_mask;
73910 let HASH = HASH_ZLIB;
73911
73912 /* =========================================================================
73913  * Flush as much pending output as possible. All deflate() output goes
73914  * through this function so some applications may wish to modify it
73915  * to avoid allocating a large strm->output buffer and copying into it.
73916  * (See also read_buf()).
73917  */
73918 const flush_pending = (strm) => {
73919   const s = strm.state;
73920
73921   //_tr_flush_bits(s);
73922   let len = s.pending;
73923   if (len > strm.avail_out) {
73924     len = strm.avail_out;
73925   }
73926   if (len === 0) { return; }
73927
73928   strm.output.set(s.pending_buf.subarray(s.pending_out, s.pending_out + len), strm.next_out);
73929   strm.next_out += len;
73930   s.pending_out += len;
73931   strm.total_out += len;
73932   strm.avail_out -= len;
73933   s.pending -= len;
73934   if (s.pending === 0) {
73935     s.pending_out = 0;
73936   }
73937 };
73938
73939
73940 const flush_block_only = (s, last) => {
73941   _tr_flush_block$1(s, (s.block_start >= 0 ? s.block_start : -1), s.strstart - s.block_start, last);
73942   s.block_start = s.strstart;
73943   flush_pending(s.strm);
73944 };
73945
73946
73947 const put_byte = (s, b) => {
73948   s.pending_buf[s.pending++] = b;
73949 };
73950
73951
73952 /* =========================================================================
73953  * Put a short in the pending buffer. The 16-bit value is put in MSB order.
73954  * IN assertion: the stream state is correct and there is enough room in
73955  * pending_buf.
73956  */
73957 const putShortMSB = (s, b) => {
73958
73959   //  put_byte(s, (Byte)(b >> 8));
73960 //  put_byte(s, (Byte)(b & 0xff));
73961   s.pending_buf[s.pending++] = (b >>> 8) & 0xff;
73962   s.pending_buf[s.pending++] = b & 0xff;
73963 };
73964
73965
73966 /* ===========================================================================
73967  * Read a new buffer from the current input stream, update the adler32
73968  * and total number of bytes read.  All deflate() input goes through
73969  * this function so some applications may wish to modify it to avoid
73970  * allocating a large strm->input buffer and copying from it.
73971  * (See also flush_pending()).
73972  */
73973 const read_buf = (strm, buf, start, size) => {
73974
73975   let len = strm.avail_in;
73976
73977   if (len > size) { len = size; }
73978   if (len === 0) { return 0; }
73979
73980   strm.avail_in -= len;
73981
73982   // zmemcpy(buf, strm->next_in, len);
73983   buf.set(strm.input.subarray(strm.next_in, strm.next_in + len), start);
73984   if (strm.state.wrap === 1) {
73985     strm.adler = adler32_1(strm.adler, buf, len, start);
73986   }
73987
73988   else if (strm.state.wrap === 2) {
73989     strm.adler = crc32_1(strm.adler, buf, len, start);
73990   }
73991
73992   strm.next_in += len;
73993   strm.total_in += len;
73994
73995   return len;
73996 };
73997
73998
73999 /* ===========================================================================
74000  * Set match_start to the longest match starting at the given string and
74001  * return its length. Matches shorter or equal to prev_length are discarded,
74002  * in which case the result is equal to prev_length and match_start is
74003  * garbage.
74004  * IN assertions: cur_match is the head of the hash chain for the current
74005  *   string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1
74006  * OUT assertion: the match length is not greater than s->lookahead.
74007  */
74008 const longest_match = (s, cur_match) => {
74009
74010   let chain_length = s.max_chain_length;      /* max hash chain length */
74011   let scan = s.strstart; /* current string */
74012   let match;                       /* matched string */
74013   let len;                           /* length of current match */
74014   let best_len = s.prev_length;              /* best match length so far */
74015   let nice_match = s.nice_match;             /* stop if match long enough */
74016   const limit = (s.strstart > (s.w_size - MIN_LOOKAHEAD)) ?
74017       s.strstart - (s.w_size - MIN_LOOKAHEAD) : 0/*NIL*/;
74018
74019   const _win = s.window; // shortcut
74020
74021   const wmask = s.w_mask;
74022   const prev  = s.prev;
74023
74024   /* Stop when cur_match becomes <= limit. To simplify the code,
74025    * we prevent matches with the string of window index 0.
74026    */
74027
74028   const strend = s.strstart + MAX_MATCH$1;
74029   let scan_end1  = _win[scan + best_len - 1];
74030   let scan_end   = _win[scan + best_len];
74031
74032   /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
74033    * It is easy to get rid of this optimization if necessary.
74034    */
74035   // Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever");
74036
74037   /* Do not waste too much time if we already have a good match: */
74038   if (s.prev_length >= s.good_match) {
74039     chain_length >>= 2;
74040   }
74041   /* Do not look for matches beyond the end of the input. This is necessary
74042    * to make deflate deterministic.
74043    */
74044   if (nice_match > s.lookahead) { nice_match = s.lookahead; }
74045
74046   // Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead");
74047
74048   do {
74049     // Assert(cur_match < s->strstart, "no future");
74050     match = cur_match;
74051
74052     /* Skip to next match if the match length cannot increase
74053      * or if the match length is less than 2.  Note that the checks below
74054      * for insufficient lookahead only occur occasionally for performance
74055      * reasons.  Therefore uninitialized memory will be accessed, and
74056      * conditional jumps will be made that depend on those values.
74057      * However the length of the match is limited to the lookahead, so
74058      * the output of deflate is not affected by the uninitialized values.
74059      */
74060
74061     if (_win[match + best_len]     !== scan_end  ||
74062         _win[match + best_len - 1] !== scan_end1 ||
74063         _win[match]                !== _win[scan] ||
74064         _win[++match]              !== _win[scan + 1]) {
74065       continue;
74066     }
74067
74068     /* The check at best_len-1 can be removed because it will be made
74069      * again later. (This heuristic is not always a win.)
74070      * It is not necessary to compare scan[2] and match[2] since they
74071      * are always equal when the other bytes match, given that
74072      * the hash keys are equal and that HASH_BITS >= 8.
74073      */
74074     scan += 2;
74075     match++;
74076     // Assert(*scan == *match, "match[2]?");
74077
74078     /* We check for insufficient lookahead only every 8th comparison;
74079      * the 256th check will be made at strstart+258.
74080      */
74081     do {
74082       /*jshint noempty:false*/
74083     } while (_win[++scan] === _win[++match] && _win[++scan] === _win[++match] &&
74084              _win[++scan] === _win[++match] && _win[++scan] === _win[++match] &&
74085              _win[++scan] === _win[++match] && _win[++scan] === _win[++match] &&
74086              _win[++scan] === _win[++match] && _win[++scan] === _win[++match] &&
74087              scan < strend);
74088
74089     // Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
74090
74091     len = MAX_MATCH$1 - (strend - scan);
74092     scan = strend - MAX_MATCH$1;
74093
74094     if (len > best_len) {
74095       s.match_start = cur_match;
74096       best_len = len;
74097       if (len >= nice_match) {
74098         break;
74099       }
74100       scan_end1  = _win[scan + best_len - 1];
74101       scan_end   = _win[scan + best_len];
74102     }
74103   } while ((cur_match = prev[cur_match & wmask]) > limit && --chain_length !== 0);
74104
74105   if (best_len <= s.lookahead) {
74106     return best_len;
74107   }
74108   return s.lookahead;
74109 };
74110
74111
74112 /* ===========================================================================
74113  * Fill the window when the lookahead becomes insufficient.
74114  * Updates strstart and lookahead.
74115  *
74116  * IN assertion: lookahead < MIN_LOOKAHEAD
74117  * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD
74118  *    At least one byte has been read, or avail_in == 0; reads are
74119  *    performed for at least two bytes (required for the zip translate_eol
74120  *    option -- not supported here).
74121  */
74122 const fill_window = (s) => {
74123
74124   const _w_size = s.w_size;
74125   let p, n, m, more, str;
74126
74127   //Assert(s->lookahead < MIN_LOOKAHEAD, "already enough lookahead");
74128
74129   do {
74130     more = s.window_size - s.lookahead - s.strstart;
74131
74132     // JS ints have 32 bit, block below not needed
74133     /* Deal with !@#$% 64K limit: */
74134     //if (sizeof(int) <= 2) {
74135     //    if (more == 0 && s->strstart == 0 && s->lookahead == 0) {
74136     //        more = wsize;
74137     //
74138     //  } else if (more == (unsigned)(-1)) {
74139     //        /* Very unlikely, but possible on 16 bit machine if
74140     //         * strstart == 0 && lookahead == 1 (input done a byte at time)
74141     //         */
74142     //        more--;
74143     //    }
74144     //}
74145
74146
74147     /* If the window is almost full and there is insufficient lookahead,
74148      * move the upper half to the lower one to make room in the upper half.
74149      */
74150     if (s.strstart >= _w_size + (_w_size - MIN_LOOKAHEAD)) {
74151
74152       s.window.set(s.window.subarray(_w_size, _w_size + _w_size), 0);
74153       s.match_start -= _w_size;
74154       s.strstart -= _w_size;
74155       /* we now have strstart >= MAX_DIST */
74156       s.block_start -= _w_size;
74157
74158       /* Slide the hash table (could be avoided with 32 bit values
74159        at the expense of memory usage). We slide even when level == 0
74160        to keep the hash table consistent if we switch back to level > 0
74161        later. (Using level 0 permanently is not an optimal usage of
74162        zlib, so we don't care about this pathological case.)
74163        */
74164
74165       n = s.hash_size;
74166       p = n;
74167
74168       do {
74169         m = s.head[--p];
74170         s.head[p] = (m >= _w_size ? m - _w_size : 0);
74171       } while (--n);
74172
74173       n = _w_size;
74174       p = n;
74175
74176       do {
74177         m = s.prev[--p];
74178         s.prev[p] = (m >= _w_size ? m - _w_size : 0);
74179         /* If n is not on any hash chain, prev[n] is garbage but
74180          * its value will never be used.
74181          */
74182       } while (--n);
74183
74184       more += _w_size;
74185     }
74186     if (s.strm.avail_in === 0) {
74187       break;
74188     }
74189
74190     /* If there was no sliding:
74191      *    strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 &&
74192      *    more == window_size - lookahead - strstart
74193      * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1)
74194      * => more >= window_size - 2*WSIZE + 2
74195      * In the BIG_MEM or MMAP case (not yet supported),
74196      *   window_size == input_size + MIN_LOOKAHEAD  &&
74197      *   strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD.
74198      * Otherwise, window_size == 2*WSIZE so more >= 2.
74199      * If there was sliding, more >= WSIZE. So in all cases, more >= 2.
74200      */
74201     //Assert(more >= 2, "more < 2");
74202     n = read_buf(s.strm, s.window, s.strstart + s.lookahead, more);
74203     s.lookahead += n;
74204
74205     /* Initialize the hash value now that we have some input: */
74206     if (s.lookahead + s.insert >= MIN_MATCH$1) {
74207       str = s.strstart - s.insert;
74208       s.ins_h = s.window[str];
74209
74210       /* UPDATE_HASH(s, s->ins_h, s->window[str + 1]); */
74211       s.ins_h = HASH(s, s.ins_h, s.window[str + 1]);
74212 //#if MIN_MATCH != 3
74213 //        Call update_hash() MIN_MATCH-3 more times
74214 //#endif
74215       while (s.insert) {
74216         /* UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]); */
74217         s.ins_h = HASH(s, s.ins_h, s.window[str + MIN_MATCH$1 - 1]);
74218
74219         s.prev[str & s.w_mask] = s.head[s.ins_h];
74220         s.head[s.ins_h] = str;
74221         str++;
74222         s.insert--;
74223         if (s.lookahead + s.insert < MIN_MATCH$1) {
74224           break;
74225         }
74226       }
74227     }
74228     /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage,
74229      * but this is not important since only literal bytes will be emitted.
74230      */
74231
74232   } while (s.lookahead < MIN_LOOKAHEAD && s.strm.avail_in !== 0);
74233
74234   /* If the WIN_INIT bytes after the end of the current data have never been
74235    * written, then zero those bytes in order to avoid memory check reports of
74236    * the use of uninitialized (or uninitialised as Julian writes) bytes by
74237    * the longest match routines.  Update the high water mark for the next
74238    * time through here.  WIN_INIT is set to MAX_MATCH since the longest match
74239    * routines allow scanning to strstart + MAX_MATCH, ignoring lookahead.
74240    */
74241 //  if (s.high_water < s.window_size) {
74242 //    const curr = s.strstart + s.lookahead;
74243 //    let init = 0;
74244 //
74245 //    if (s.high_water < curr) {
74246 //      /* Previous high water mark below current data -- zero WIN_INIT
74247 //       * bytes or up to end of window, whichever is less.
74248 //       */
74249 //      init = s.window_size - curr;
74250 //      if (init > WIN_INIT)
74251 //        init = WIN_INIT;
74252 //      zmemzero(s->window + curr, (unsigned)init);
74253 //      s->high_water = curr + init;
74254 //    }
74255 //    else if (s->high_water < (ulg)curr + WIN_INIT) {
74256 //      /* High water mark at or above current data, but below current data
74257 //       * plus WIN_INIT -- zero out to current data plus WIN_INIT, or up
74258 //       * to end of window, whichever is less.
74259 //       */
74260 //      init = (ulg)curr + WIN_INIT - s->high_water;
74261 //      if (init > s->window_size - s->high_water)
74262 //        init = s->window_size - s->high_water;
74263 //      zmemzero(s->window + s->high_water, (unsigned)init);
74264 //      s->high_water += init;
74265 //    }
74266 //  }
74267 //
74268 //  Assert((ulg)s->strstart <= s->window_size - MIN_LOOKAHEAD,
74269 //    "not enough room for search");
74270 };
74271
74272 /* ===========================================================================
74273  * Copy without compression as much as possible from the input stream, return
74274  * the current block state.
74275  * This function does not insert new strings in the dictionary since
74276  * uncompressible data is probably not useful. This function is used
74277  * only for the level=0 compression option.
74278  * NOTE: this function should be optimized to avoid extra copying from
74279  * window to pending_buf.
74280  */
74281 const deflate_stored = (s, flush) => {
74282
74283   /* Stored blocks are limited to 0xffff bytes, pending_buf is limited
74284    * to pending_buf_size, and each stored block has a 5 byte header:
74285    */
74286   let max_block_size = 0xffff;
74287
74288   if (max_block_size > s.pending_buf_size - 5) {
74289     max_block_size = s.pending_buf_size - 5;
74290   }
74291
74292   /* Copy as much as possible from input to output: */
74293   for (;;) {
74294     /* Fill the window as much as possible: */
74295     if (s.lookahead <= 1) {
74296
74297       //Assert(s->strstart < s->w_size+MAX_DIST(s) ||
74298       //  s->block_start >= (long)s->w_size, "slide too late");
74299 //      if (!(s.strstart < s.w_size + (s.w_size - MIN_LOOKAHEAD) ||
74300 //        s.block_start >= s.w_size)) {
74301 //        throw  new Error("slide too late");
74302 //      }
74303
74304       fill_window(s);
74305       if (s.lookahead === 0 && flush === Z_NO_FLUSH) {
74306         return BS_NEED_MORE;
74307       }
74308
74309       if (s.lookahead === 0) {
74310         break;
74311       }
74312       /* flush the current block */
74313     }
74314     //Assert(s->block_start >= 0L, "block gone");
74315 //    if (s.block_start < 0) throw new Error("block gone");
74316
74317     s.strstart += s.lookahead;
74318     s.lookahead = 0;
74319
74320     /* Emit a stored block if pending_buf will be full: */
74321     const max_start = s.block_start + max_block_size;
74322
74323     if (s.strstart === 0 || s.strstart >= max_start) {
74324       /* strstart == 0 is possible when wraparound on 16-bit machine */
74325       s.lookahead = s.strstart - max_start;
74326       s.strstart = max_start;
74327       /*** FLUSH_BLOCK(s, 0); ***/
74328       flush_block_only(s, false);
74329       if (s.strm.avail_out === 0) {
74330         return BS_NEED_MORE;
74331       }
74332       /***/
74333
74334
74335     }
74336     /* Flush if we may have to slide, otherwise block_start may become
74337      * negative and the data will be gone:
74338      */
74339     if (s.strstart - s.block_start >= (s.w_size - MIN_LOOKAHEAD)) {
74340       /*** FLUSH_BLOCK(s, 0); ***/
74341       flush_block_only(s, false);
74342       if (s.strm.avail_out === 0) {
74343         return BS_NEED_MORE;
74344       }
74345       /***/
74346     }
74347   }
74348
74349   s.insert = 0;
74350
74351   if (flush === Z_FINISH) {
74352     /*** FLUSH_BLOCK(s, 1); ***/
74353     flush_block_only(s, true);
74354     if (s.strm.avail_out === 0) {
74355       return BS_FINISH_STARTED;
74356     }
74357     /***/
74358     return BS_FINISH_DONE;
74359   }
74360
74361   if (s.strstart > s.block_start) {
74362     /*** FLUSH_BLOCK(s, 0); ***/
74363     flush_block_only(s, false);
74364     if (s.strm.avail_out === 0) {
74365       return BS_NEED_MORE;
74366     }
74367     /***/
74368   }
74369
74370   return BS_NEED_MORE;
74371 };
74372
74373 /* ===========================================================================
74374  * Compress as much as possible from the input stream, return the current
74375  * block state.
74376  * This function does not perform lazy evaluation of matches and inserts
74377  * new strings in the dictionary only for unmatched strings or for short
74378  * matches. It is used only for the fast compression options.
74379  */
74380 const deflate_fast = (s, flush) => {
74381
74382   let hash_head;        /* head of the hash chain */
74383   let bflush;           /* set if current block must be flushed */
74384
74385   for (;;) {
74386     /* Make sure that we always have enough lookahead, except
74387      * at the end of the input file. We need MAX_MATCH bytes
74388      * for the next match, plus MIN_MATCH bytes to insert the
74389      * string following the next match.
74390      */
74391     if (s.lookahead < MIN_LOOKAHEAD) {
74392       fill_window(s);
74393       if (s.lookahead < MIN_LOOKAHEAD && flush === Z_NO_FLUSH) {
74394         return BS_NEED_MORE;
74395       }
74396       if (s.lookahead === 0) {
74397         break; /* flush the current block */
74398       }
74399     }
74400
74401     /* Insert the string window[strstart .. strstart+2] in the
74402      * dictionary, and set hash_head to the head of the hash chain:
74403      */
74404     hash_head = 0/*NIL*/;
74405     if (s.lookahead >= MIN_MATCH$1) {
74406       /*** INSERT_STRING(s, s.strstart, hash_head); ***/
74407       s.ins_h = HASH(s, s.ins_h, s.window[s.strstart + MIN_MATCH$1 - 1]);
74408       hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h];
74409       s.head[s.ins_h] = s.strstart;
74410       /***/
74411     }
74412
74413     /* Find the longest match, discarding those <= prev_length.
74414      * At this point we have always match_length < MIN_MATCH
74415      */
74416     if (hash_head !== 0/*NIL*/ && ((s.strstart - hash_head) <= (s.w_size - MIN_LOOKAHEAD))) {
74417       /* To simplify the code, we prevent matches with the string
74418        * of window index 0 (in particular we have to avoid a match
74419        * of the string with itself at the start of the input file).
74420        */
74421       s.match_length = longest_match(s, hash_head);
74422       /* longest_match() sets match_start */
74423     }
74424     if (s.match_length >= MIN_MATCH$1) {
74425       // check_match(s, s.strstart, s.match_start, s.match_length); // for debug only
74426
74427       /*** _tr_tally_dist(s, s.strstart - s.match_start,
74428                      s.match_length - MIN_MATCH, bflush); ***/
74429       bflush = _tr_tally$1(s, s.strstart - s.match_start, s.match_length - MIN_MATCH$1);
74430
74431       s.lookahead -= s.match_length;
74432
74433       /* Insert new strings in the hash table only if the match length
74434        * is not too large. This saves time but degrades compression.
74435        */
74436       if (s.match_length <= s.max_lazy_match/*max_insert_length*/ && s.lookahead >= MIN_MATCH$1) {
74437         s.match_length--; /* string at strstart already in table */
74438         do {
74439           s.strstart++;
74440           /*** INSERT_STRING(s, s.strstart, hash_head); ***/
74441           s.ins_h = HASH(s, s.ins_h, s.window[s.strstart + MIN_MATCH$1 - 1]);
74442           hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h];
74443           s.head[s.ins_h] = s.strstart;
74444           /***/
74445           /* strstart never exceeds WSIZE-MAX_MATCH, so there are
74446            * always MIN_MATCH bytes ahead.
74447            */
74448         } while (--s.match_length !== 0);
74449         s.strstart++;
74450       } else
74451       {
74452         s.strstart += s.match_length;
74453         s.match_length = 0;
74454         s.ins_h = s.window[s.strstart];
74455         /* UPDATE_HASH(s, s.ins_h, s.window[s.strstart+1]); */
74456         s.ins_h = HASH(s, s.ins_h, s.window[s.strstart + 1]);
74457
74458 //#if MIN_MATCH != 3
74459 //                Call UPDATE_HASH() MIN_MATCH-3 more times
74460 //#endif
74461         /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not
74462          * matter since it will be recomputed at next deflate call.
74463          */
74464       }
74465     } else {
74466       /* No match, output a literal byte */
74467       //Tracevv((stderr,"%c", s.window[s.strstart]));
74468       /*** _tr_tally_lit(s, s.window[s.strstart], bflush); ***/
74469       bflush = _tr_tally$1(s, 0, s.window[s.strstart]);
74470
74471       s.lookahead--;
74472       s.strstart++;
74473     }
74474     if (bflush) {
74475       /*** FLUSH_BLOCK(s, 0); ***/
74476       flush_block_only(s, false);
74477       if (s.strm.avail_out === 0) {
74478         return BS_NEED_MORE;
74479       }
74480       /***/
74481     }
74482   }
74483   s.insert = ((s.strstart < (MIN_MATCH$1 - 1)) ? s.strstart : MIN_MATCH$1 - 1);
74484   if (flush === Z_FINISH) {
74485     /*** FLUSH_BLOCK(s, 1); ***/
74486     flush_block_only(s, true);
74487     if (s.strm.avail_out === 0) {
74488       return BS_FINISH_STARTED;
74489     }
74490     /***/
74491     return BS_FINISH_DONE;
74492   }
74493   if (s.last_lit) {
74494     /*** FLUSH_BLOCK(s, 0); ***/
74495     flush_block_only(s, false);
74496     if (s.strm.avail_out === 0) {
74497       return BS_NEED_MORE;
74498     }
74499     /***/
74500   }
74501   return BS_BLOCK_DONE;
74502 };
74503
74504 /* ===========================================================================
74505  * Same as above, but achieves better compression. We use a lazy
74506  * evaluation for matches: a match is finally adopted only if there is
74507  * no better match at the next window position.
74508  */
74509 const deflate_slow = (s, flush) => {
74510
74511   let hash_head;          /* head of hash chain */
74512   let bflush;              /* set if current block must be flushed */
74513
74514   let max_insert;
74515
74516   /* Process the input block. */
74517   for (;;) {
74518     /* Make sure that we always have enough lookahead, except
74519      * at the end of the input file. We need MAX_MATCH bytes
74520      * for the next match, plus MIN_MATCH bytes to insert the
74521      * string following the next match.
74522      */
74523     if (s.lookahead < MIN_LOOKAHEAD) {
74524       fill_window(s);
74525       if (s.lookahead < MIN_LOOKAHEAD && flush === Z_NO_FLUSH) {
74526         return BS_NEED_MORE;
74527       }
74528       if (s.lookahead === 0) { break; } /* flush the current block */
74529     }
74530
74531     /* Insert the string window[strstart .. strstart+2] in the
74532      * dictionary, and set hash_head to the head of the hash chain:
74533      */
74534     hash_head = 0/*NIL*/;
74535     if (s.lookahead >= MIN_MATCH$1) {
74536       /*** INSERT_STRING(s, s.strstart, hash_head); ***/
74537       s.ins_h = HASH(s, s.ins_h, s.window[s.strstart + MIN_MATCH$1 - 1]);
74538       hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h];
74539       s.head[s.ins_h] = s.strstart;
74540       /***/
74541     }
74542
74543     /* Find the longest match, discarding those <= prev_length.
74544      */
74545     s.prev_length = s.match_length;
74546     s.prev_match = s.match_start;
74547     s.match_length = MIN_MATCH$1 - 1;
74548
74549     if (hash_head !== 0/*NIL*/ && s.prev_length < s.max_lazy_match &&
74550         s.strstart - hash_head <= (s.w_size - MIN_LOOKAHEAD)/*MAX_DIST(s)*/) {
74551       /* To simplify the code, we prevent matches with the string
74552        * of window index 0 (in particular we have to avoid a match
74553        * of the string with itself at the start of the input file).
74554        */
74555       s.match_length = longest_match(s, hash_head);
74556       /* longest_match() sets match_start */
74557
74558       if (s.match_length <= 5 &&
74559          (s.strategy === Z_FILTERED || (s.match_length === MIN_MATCH$1 && s.strstart - s.match_start > 4096/*TOO_FAR*/))) {
74560
74561         /* If prev_match is also MIN_MATCH, match_start is garbage
74562          * but we will ignore the current match anyway.
74563          */
74564         s.match_length = MIN_MATCH$1 - 1;
74565       }
74566     }
74567     /* If there was a match at the previous step and the current
74568      * match is not better, output the previous match:
74569      */
74570     if (s.prev_length >= MIN_MATCH$1 && s.match_length <= s.prev_length) {
74571       max_insert = s.strstart + s.lookahead - MIN_MATCH$1;
74572       /* Do not insert strings in hash table beyond this. */
74573
74574       //check_match(s, s.strstart-1, s.prev_match, s.prev_length);
74575
74576       /***_tr_tally_dist(s, s.strstart - 1 - s.prev_match,
74577                      s.prev_length - MIN_MATCH, bflush);***/
74578       bflush = _tr_tally$1(s, s.strstart - 1 - s.prev_match, s.prev_length - MIN_MATCH$1);
74579       /* Insert in hash table all strings up to the end of the match.
74580        * strstart-1 and strstart are already inserted. If there is not
74581        * enough lookahead, the last two strings are not inserted in
74582        * the hash table.
74583        */
74584       s.lookahead -= s.prev_length - 1;
74585       s.prev_length -= 2;
74586       do {
74587         if (++s.strstart <= max_insert) {
74588           /*** INSERT_STRING(s, s.strstart, hash_head); ***/
74589           s.ins_h = HASH(s, s.ins_h, s.window[s.strstart + MIN_MATCH$1 - 1]);
74590           hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h];
74591           s.head[s.ins_h] = s.strstart;
74592           /***/
74593         }
74594       } while (--s.prev_length !== 0);
74595       s.match_available = 0;
74596       s.match_length = MIN_MATCH$1 - 1;
74597       s.strstart++;
74598
74599       if (bflush) {
74600         /*** FLUSH_BLOCK(s, 0); ***/
74601         flush_block_only(s, false);
74602         if (s.strm.avail_out === 0) {
74603           return BS_NEED_MORE;
74604         }
74605         /***/
74606       }
74607
74608     } else if (s.match_available) {
74609       /* If there was no match at the previous position, output a
74610        * single literal. If there was a match but the current match
74611        * is longer, truncate the previous match to a single literal.
74612        */
74613       //Tracevv((stderr,"%c", s->window[s->strstart-1]));
74614       /*** _tr_tally_lit(s, s.window[s.strstart-1], bflush); ***/
74615       bflush = _tr_tally$1(s, 0, s.window[s.strstart - 1]);
74616
74617       if (bflush) {
74618         /*** FLUSH_BLOCK_ONLY(s, 0) ***/
74619         flush_block_only(s, false);
74620         /***/
74621       }
74622       s.strstart++;
74623       s.lookahead--;
74624       if (s.strm.avail_out === 0) {
74625         return BS_NEED_MORE;
74626       }
74627     } else {
74628       /* There is no previous match to compare with, wait for
74629        * the next step to decide.
74630        */
74631       s.match_available = 1;
74632       s.strstart++;
74633       s.lookahead--;
74634     }
74635   }
74636   //Assert (flush != Z_NO_FLUSH, "no flush?");
74637   if (s.match_available) {
74638     //Tracevv((stderr,"%c", s->window[s->strstart-1]));
74639     /*** _tr_tally_lit(s, s.window[s.strstart-1], bflush); ***/
74640     bflush = _tr_tally$1(s, 0, s.window[s.strstart - 1]);
74641
74642     s.match_available = 0;
74643   }
74644   s.insert = s.strstart < MIN_MATCH$1 - 1 ? s.strstart : MIN_MATCH$1 - 1;
74645   if (flush === Z_FINISH) {
74646     /*** FLUSH_BLOCK(s, 1); ***/
74647     flush_block_only(s, true);
74648     if (s.strm.avail_out === 0) {
74649       return BS_FINISH_STARTED;
74650     }
74651     /***/
74652     return BS_FINISH_DONE;
74653   }
74654   if (s.last_lit) {
74655     /*** FLUSH_BLOCK(s, 0); ***/
74656     flush_block_only(s, false);
74657     if (s.strm.avail_out === 0) {
74658       return BS_NEED_MORE;
74659     }
74660     /***/
74661   }
74662
74663   return BS_BLOCK_DONE;
74664 };
74665
74666
74667 /* ===========================================================================
74668  * For Z_RLE, simply look for runs of bytes, generate matches only of distance
74669  * one.  Do not maintain a hash table.  (It will be regenerated if this run of
74670  * deflate switches away from Z_RLE.)
74671  */
74672 const deflate_rle = (s, flush) => {
74673
74674   let bflush;            /* set if current block must be flushed */
74675   let prev;              /* byte at distance one to match */
74676   let scan, strend;      /* scan goes up to strend for length of run */
74677
74678   const _win = s.window;
74679
74680   for (;;) {
74681     /* Make sure that we always have enough lookahead, except
74682      * at the end of the input file. We need MAX_MATCH bytes
74683      * for the longest run, plus one for the unrolled loop.
74684      */
74685     if (s.lookahead <= MAX_MATCH$1) {
74686       fill_window(s);
74687       if (s.lookahead <= MAX_MATCH$1 && flush === Z_NO_FLUSH) {
74688         return BS_NEED_MORE;
74689       }
74690       if (s.lookahead === 0) { break; } /* flush the current block */
74691     }
74692
74693     /* See how many times the previous byte repeats */
74694     s.match_length = 0;
74695     if (s.lookahead >= MIN_MATCH$1 && s.strstart > 0) {
74696       scan = s.strstart - 1;
74697       prev = _win[scan];
74698       if (prev === _win[++scan] && prev === _win[++scan] && prev === _win[++scan]) {
74699         strend = s.strstart + MAX_MATCH$1;
74700         do {
74701           /*jshint noempty:false*/
74702         } while (prev === _win[++scan] && prev === _win[++scan] &&
74703                  prev === _win[++scan] && prev === _win[++scan] &&
74704                  prev === _win[++scan] && prev === _win[++scan] &&
74705                  prev === _win[++scan] && prev === _win[++scan] &&
74706                  scan < strend);
74707         s.match_length = MAX_MATCH$1 - (strend - scan);
74708         if (s.match_length > s.lookahead) {
74709           s.match_length = s.lookahead;
74710         }
74711       }
74712       //Assert(scan <= s->window+(uInt)(s->window_size-1), "wild scan");
74713     }
74714
74715     /* Emit match if have run of MIN_MATCH or longer, else emit literal */
74716     if (s.match_length >= MIN_MATCH$1) {
74717       //check_match(s, s.strstart, s.strstart - 1, s.match_length);
74718
74719       /*** _tr_tally_dist(s, 1, s.match_length - MIN_MATCH, bflush); ***/
74720       bflush = _tr_tally$1(s, 1, s.match_length - MIN_MATCH$1);
74721
74722       s.lookahead -= s.match_length;
74723       s.strstart += s.match_length;
74724       s.match_length = 0;
74725     } else {
74726       /* No match, output a literal byte */
74727       //Tracevv((stderr,"%c", s->window[s->strstart]));
74728       /*** _tr_tally_lit(s, s.window[s.strstart], bflush); ***/
74729       bflush = _tr_tally$1(s, 0, s.window[s.strstart]);
74730
74731       s.lookahead--;
74732       s.strstart++;
74733     }
74734     if (bflush) {
74735       /*** FLUSH_BLOCK(s, 0); ***/
74736       flush_block_only(s, false);
74737       if (s.strm.avail_out === 0) {
74738         return BS_NEED_MORE;
74739       }
74740       /***/
74741     }
74742   }
74743   s.insert = 0;
74744   if (flush === Z_FINISH) {
74745     /*** FLUSH_BLOCK(s, 1); ***/
74746     flush_block_only(s, true);
74747     if (s.strm.avail_out === 0) {
74748       return BS_FINISH_STARTED;
74749     }
74750     /***/
74751     return BS_FINISH_DONE;
74752   }
74753   if (s.last_lit) {
74754     /*** FLUSH_BLOCK(s, 0); ***/
74755     flush_block_only(s, false);
74756     if (s.strm.avail_out === 0) {
74757       return BS_NEED_MORE;
74758     }
74759     /***/
74760   }
74761   return BS_BLOCK_DONE;
74762 };
74763
74764 /* ===========================================================================
74765  * For Z_HUFFMAN_ONLY, do not look for matches.  Do not maintain a hash table.
74766  * (It will be regenerated if this run of deflate switches away from Huffman.)
74767  */
74768 const deflate_huff = (s, flush) => {
74769
74770   let bflush;             /* set if current block must be flushed */
74771
74772   for (;;) {
74773     /* Make sure that we have a literal to write. */
74774     if (s.lookahead === 0) {
74775       fill_window(s);
74776       if (s.lookahead === 0) {
74777         if (flush === Z_NO_FLUSH) {
74778           return BS_NEED_MORE;
74779         }
74780         break;      /* flush the current block */
74781       }
74782     }
74783
74784     /* Output a literal byte */
74785     s.match_length = 0;
74786     //Tracevv((stderr,"%c", s->window[s->strstart]));
74787     /*** _tr_tally_lit(s, s.window[s.strstart], bflush); ***/
74788     bflush = _tr_tally$1(s, 0, s.window[s.strstart]);
74789     s.lookahead--;
74790     s.strstart++;
74791     if (bflush) {
74792       /*** FLUSH_BLOCK(s, 0); ***/
74793       flush_block_only(s, false);
74794       if (s.strm.avail_out === 0) {
74795         return BS_NEED_MORE;
74796       }
74797       /***/
74798     }
74799   }
74800   s.insert = 0;
74801   if (flush === Z_FINISH) {
74802     /*** FLUSH_BLOCK(s, 1); ***/
74803     flush_block_only(s, true);
74804     if (s.strm.avail_out === 0) {
74805       return BS_FINISH_STARTED;
74806     }
74807     /***/
74808     return BS_FINISH_DONE;
74809   }
74810   if (s.last_lit) {
74811     /*** FLUSH_BLOCK(s, 0); ***/
74812     flush_block_only(s, false);
74813     if (s.strm.avail_out === 0) {
74814       return BS_NEED_MORE;
74815     }
74816     /***/
74817   }
74818   return BS_BLOCK_DONE;
74819 };
74820
74821 /* Values for max_lazy_match, good_match and max_chain_length, depending on
74822  * the desired pack level (0..9). The values given below have been tuned to
74823  * exclude worst case performance for pathological files. Better values may be
74824  * found for specific files.
74825  */
74826 function Config(good_length, max_lazy, nice_length, max_chain, func) {
74827
74828   this.good_length = good_length;
74829   this.max_lazy = max_lazy;
74830   this.nice_length = nice_length;
74831   this.max_chain = max_chain;
74832   this.func = func;
74833 }
74834
74835 const configuration_table = [
74836   /*      good lazy nice chain */
74837   new Config(0, 0, 0, 0, deflate_stored),          /* 0 store only */
74838   new Config(4, 4, 8, 4, deflate_fast),            /* 1 max speed, no lazy matches */
74839   new Config(4, 5, 16, 8, deflate_fast),           /* 2 */
74840   new Config(4, 6, 32, 32, deflate_fast),          /* 3 */
74841
74842   new Config(4, 4, 16, 16, deflate_slow),          /* 4 lazy matches */
74843   new Config(8, 16, 32, 32, deflate_slow),         /* 5 */
74844   new Config(8, 16, 128, 128, deflate_slow),       /* 6 */
74845   new Config(8, 32, 128, 256, deflate_slow),       /* 7 */
74846   new Config(32, 128, 258, 1024, deflate_slow),    /* 8 */
74847   new Config(32, 258, 258, 4096, deflate_slow)     /* 9 max compression */
74848 ];
74849
74850
74851 /* ===========================================================================
74852  * Initialize the "longest match" routines for a new zlib stream
74853  */
74854 const lm_init = (s) => {
74855
74856   s.window_size = 2 * s.w_size;
74857
74858   /*** CLEAR_HASH(s); ***/
74859   zero$1(s.head); // Fill with NIL (= 0);
74860
74861   /* Set the default configuration parameters:
74862    */
74863   s.max_lazy_match = configuration_table[s.level].max_lazy;
74864   s.good_match = configuration_table[s.level].good_length;
74865   s.nice_match = configuration_table[s.level].nice_length;
74866   s.max_chain_length = configuration_table[s.level].max_chain;
74867
74868   s.strstart = 0;
74869   s.block_start = 0;
74870   s.lookahead = 0;
74871   s.insert = 0;
74872   s.match_length = s.prev_length = MIN_MATCH$1 - 1;
74873   s.match_available = 0;
74874   s.ins_h = 0;
74875 };
74876
74877
74878 function DeflateState() {
74879   this.strm = null;            /* pointer back to this zlib stream */
74880   this.status = 0;            /* as the name implies */
74881   this.pending_buf = null;      /* output still pending */
74882   this.pending_buf_size = 0;  /* size of pending_buf */
74883   this.pending_out = 0;       /* next pending byte to output to the stream */
74884   this.pending = 0;           /* nb of bytes in the pending buffer */
74885   this.wrap = 0;              /* bit 0 true for zlib, bit 1 true for gzip */
74886   this.gzhead = null;         /* gzip header information to write */
74887   this.gzindex = 0;           /* where in extra, name, or comment */
74888   this.method = Z_DEFLATED; /* can only be DEFLATED */
74889   this.last_flush = -1;   /* value of flush param for previous deflate call */
74890
74891   this.w_size = 0;  /* LZ77 window size (32K by default) */
74892   this.w_bits = 0;  /* log2(w_size)  (8..16) */
74893   this.w_mask = 0;  /* w_size - 1 */
74894
74895   this.window = null;
74896   /* Sliding window. Input bytes are read into the second half of the window,
74897    * and move to the first half later to keep a dictionary of at least wSize
74898    * bytes. With this organization, matches are limited to a distance of
74899    * wSize-MAX_MATCH bytes, but this ensures that IO is always
74900    * performed with a length multiple of the block size.
74901    */
74902
74903   this.window_size = 0;
74904   /* Actual size of window: 2*wSize, except when the user input buffer
74905    * is directly used as sliding window.
74906    */
74907
74908   this.prev = null;
74909   /* Link to older string with same hash index. To limit the size of this
74910    * array to 64K, this link is maintained only for the last 32K strings.
74911    * An index in this array is thus a window index modulo 32K.
74912    */
74913
74914   this.head = null;   /* Heads of the hash chains or NIL. */
74915
74916   this.ins_h = 0;       /* hash index of string to be inserted */
74917   this.hash_size = 0;   /* number of elements in hash table */
74918   this.hash_bits = 0;   /* log2(hash_size) */
74919   this.hash_mask = 0;   /* hash_size-1 */
74920
74921   this.hash_shift = 0;
74922   /* Number of bits by which ins_h must be shifted at each input
74923    * step. It must be such that after MIN_MATCH steps, the oldest
74924    * byte no longer takes part in the hash key, that is:
74925    *   hash_shift * MIN_MATCH >= hash_bits
74926    */
74927
74928   this.block_start = 0;
74929   /* Window position at the beginning of the current output block. Gets
74930    * negative when the window is moved backwards.
74931    */
74932
74933   this.match_length = 0;      /* length of best match */
74934   this.prev_match = 0;        /* previous match */
74935   this.match_available = 0;   /* set if previous match exists */
74936   this.strstart = 0;          /* start of string to insert */
74937   this.match_start = 0;       /* start of matching string */
74938   this.lookahead = 0;         /* number of valid bytes ahead in window */
74939
74940   this.prev_length = 0;
74941   /* Length of the best match at previous step. Matches not greater than this
74942    * are discarded. This is used in the lazy match evaluation.
74943    */
74944
74945   this.max_chain_length = 0;
74946   /* To speed up deflation, hash chains are never searched beyond this
74947    * length.  A higher limit improves compression ratio but degrades the
74948    * speed.
74949    */
74950
74951   this.max_lazy_match = 0;
74952   /* Attempt to find a better match only when the current match is strictly
74953    * smaller than this value. This mechanism is used only for compression
74954    * levels >= 4.
74955    */
74956   // That's alias to max_lazy_match, don't use directly
74957   //this.max_insert_length = 0;
74958   /* Insert new strings in the hash table only if the match length is not
74959    * greater than this length. This saves time but degrades compression.
74960    * max_insert_length is used only for compression levels <= 3.
74961    */
74962
74963   this.level = 0;     /* compression level (1..9) */
74964   this.strategy = 0;  /* favor or force Huffman coding*/
74965
74966   this.good_match = 0;
74967   /* Use a faster search when the previous match is longer than this */
74968
74969   this.nice_match = 0; /* Stop searching when current match exceeds this */
74970
74971               /* used by trees.c: */
74972
74973   /* Didn't use ct_data typedef below to suppress compiler warning */
74974
74975   // struct ct_data_s dyn_ltree[HEAP_SIZE];   /* literal and length tree */
74976   // struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */
74977   // struct ct_data_s bl_tree[2*BL_CODES+1];  /* Huffman tree for bit lengths */
74978
74979   // Use flat array of DOUBLE size, with interleaved fata,
74980   // because JS does not support effective
74981   this.dyn_ltree  = new Uint16Array(HEAP_SIZE$1 * 2);
74982   this.dyn_dtree  = new Uint16Array((2 * D_CODES$1 + 1) * 2);
74983   this.bl_tree    = new Uint16Array((2 * BL_CODES$1 + 1) * 2);
74984   zero$1(this.dyn_ltree);
74985   zero$1(this.dyn_dtree);
74986   zero$1(this.bl_tree);
74987
74988   this.l_desc   = null;         /* desc. for literal tree */
74989   this.d_desc   = null;         /* desc. for distance tree */
74990   this.bl_desc  = null;         /* desc. for bit length tree */
74991
74992   //ush bl_count[MAX_BITS+1];
74993   this.bl_count = new Uint16Array(MAX_BITS$1 + 1);
74994   /* number of codes at each bit length for an optimal tree */
74995
74996   //int heap[2*L_CODES+1];      /* heap used to build the Huffman trees */
74997   this.heap = new Uint16Array(2 * L_CODES$1 + 1);  /* heap used to build the Huffman trees */
74998   zero$1(this.heap);
74999
75000   this.heap_len = 0;               /* number of elements in the heap */
75001   this.heap_max = 0;               /* element of largest frequency */
75002   /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used.
75003    * The same heap array is used to build all trees.
75004    */
75005
75006   this.depth = new Uint16Array(2 * L_CODES$1 + 1); //uch depth[2*L_CODES+1];
75007   zero$1(this.depth);
75008   /* Depth of each subtree used as tie breaker for trees of equal frequency
75009    */
75010
75011   this.l_buf = 0;          /* buffer index for literals or lengths */
75012
75013   this.lit_bufsize = 0;
75014   /* Size of match buffer for literals/lengths.  There are 4 reasons for
75015    * limiting lit_bufsize to 64K:
75016    *   - frequencies can be kept in 16 bit counters
75017    *   - if compression is not successful for the first block, all input
75018    *     data is still in the window so we can still emit a stored block even
75019    *     when input comes from standard input.  (This can also be done for
75020    *     all blocks if lit_bufsize is not greater than 32K.)
75021    *   - if compression is not successful for a file smaller than 64K, we can
75022    *     even emit a stored file instead of a stored block (saving 5 bytes).
75023    *     This is applicable only for zip (not gzip or zlib).
75024    *   - creating new Huffman trees less frequently may not provide fast
75025    *     adaptation to changes in the input data statistics. (Take for
75026    *     example a binary file with poorly compressible code followed by
75027    *     a highly compressible string table.) Smaller buffer sizes give
75028    *     fast adaptation but have of course the overhead of transmitting
75029    *     trees more frequently.
75030    *   - I can't count above 4
75031    */
75032
75033   this.last_lit = 0;      /* running index in l_buf */
75034
75035   this.d_buf = 0;
75036   /* Buffer index for distances. To simplify the code, d_buf and l_buf have
75037    * the same number of elements. To use different lengths, an extra flag
75038    * array would be necessary.
75039    */
75040
75041   this.opt_len = 0;       /* bit length of current block with optimal trees */
75042   this.static_len = 0;    /* bit length of current block with static trees */
75043   this.matches = 0;       /* number of string matches in current block */
75044   this.insert = 0;        /* bytes at end of window left to insert */
75045
75046
75047   this.bi_buf = 0;
75048   /* Output buffer. bits are inserted starting at the bottom (least
75049    * significant bits).
75050    */
75051   this.bi_valid = 0;
75052   /* Number of valid bits in bi_buf.  All bits above the last valid bit
75053    * are always zero.
75054    */
75055
75056   // Used for window memory init. We safely ignore it for JS. That makes
75057   // sense only for pointers and memory check tools.
75058   //this.high_water = 0;
75059   /* High water mark offset in window for initialized bytes -- bytes above
75060    * this are set to zero in order to avoid memory check warnings when
75061    * longest match routines access bytes past the input.  This is then
75062    * updated to the new high water mark.
75063    */
75064 }
75065
75066
75067 const deflateResetKeep = (strm) => {
75068
75069   if (!strm || !strm.state) {
75070     return err(strm, Z_STREAM_ERROR);
75071   }
75072
75073   strm.total_in = strm.total_out = 0;
75074   strm.data_type = Z_UNKNOWN$1;
75075
75076   const s = strm.state;
75077   s.pending = 0;
75078   s.pending_out = 0;
75079
75080   if (s.wrap < 0) {
75081     s.wrap = -s.wrap;
75082     /* was made negative by deflate(..., Z_FINISH); */
75083   }
75084   s.status = (s.wrap ? INIT_STATE : BUSY_STATE);
75085   strm.adler = (s.wrap === 2) ?
75086     0  // crc32(0, Z_NULL, 0)
75087   :
75088     1; // adler32(0, Z_NULL, 0)
75089   s.last_flush = Z_NO_FLUSH;
75090   _tr_init$1(s);
75091   return Z_OK;
75092 };
75093
75094
75095 const deflateReset = (strm) => {
75096
75097   const ret = deflateResetKeep(strm);
75098   if (ret === Z_OK) {
75099     lm_init(strm.state);
75100   }
75101   return ret;
75102 };
75103
75104
75105 const deflateSetHeader = (strm, head) => {
75106
75107   if (!strm || !strm.state) { return Z_STREAM_ERROR; }
75108   if (strm.state.wrap !== 2) { return Z_STREAM_ERROR; }
75109   strm.state.gzhead = head;
75110   return Z_OK;
75111 };
75112
75113
75114 const deflateInit2 = (strm, level, method, windowBits, memLevel, strategy) => {
75115
75116   if (!strm) { // === Z_NULL
75117     return Z_STREAM_ERROR;
75118   }
75119   let wrap = 1;
75120
75121   if (level === Z_DEFAULT_COMPRESSION) {
75122     level = 6;
75123   }
75124
75125   if (windowBits < 0) { /* suppress zlib wrapper */
75126     wrap = 0;
75127     windowBits = -windowBits;
75128   }
75129
75130   else if (windowBits > 15) {
75131     wrap = 2;           /* write gzip wrapper instead */
75132     windowBits -= 16;
75133   }
75134
75135
75136   if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method !== Z_DEFLATED ||
75137     windowBits < 8 || windowBits > 15 || level < 0 || level > 9 ||
75138     strategy < 0 || strategy > Z_FIXED$1) {
75139     return err(strm, Z_STREAM_ERROR);
75140   }
75141
75142
75143   if (windowBits === 8) {
75144     windowBits = 9;
75145   }
75146   /* until 256-byte window bug fixed */
75147
75148   const s = new DeflateState();
75149
75150   strm.state = s;
75151   s.strm = strm;
75152
75153   s.wrap = wrap;
75154   s.gzhead = null;
75155   s.w_bits = windowBits;
75156   s.w_size = 1 << s.w_bits;
75157   s.w_mask = s.w_size - 1;
75158
75159   s.hash_bits = memLevel + 7;
75160   s.hash_size = 1 << s.hash_bits;
75161   s.hash_mask = s.hash_size - 1;
75162   s.hash_shift = ~~((s.hash_bits + MIN_MATCH$1 - 1) / MIN_MATCH$1);
75163
75164   s.window = new Uint8Array(s.w_size * 2);
75165   s.head = new Uint16Array(s.hash_size);
75166   s.prev = new Uint16Array(s.w_size);
75167
75168   // Don't need mem init magic for JS.
75169   //s.high_water = 0;  /* nothing written to s->window yet */
75170
75171   s.lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */
75172
75173   s.pending_buf_size = s.lit_bufsize * 4;
75174
75175   //overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2);
75176   //s->pending_buf = (uchf *) overlay;
75177   s.pending_buf = new Uint8Array(s.pending_buf_size);
75178
75179   // It is offset from `s.pending_buf` (size is `s.lit_bufsize * 2`)
75180   //s->d_buf = overlay + s->lit_bufsize/sizeof(ush);
75181   s.d_buf = 1 * s.lit_bufsize;
75182
75183   //s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize;
75184   s.l_buf = (1 + 2) * s.lit_bufsize;
75185
75186   s.level = level;
75187   s.strategy = strategy;
75188   s.method = method;
75189
75190   return deflateReset(strm);
75191 };
75192
75193 const deflateInit = (strm, level) => {
75194
75195   return deflateInit2(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY);
75196 };
75197
75198
75199 const deflate = (strm, flush) => {
75200
75201   let beg, val; // for gzip header write only
75202
75203   if (!strm || !strm.state ||
75204     flush > Z_BLOCK || flush < 0) {
75205     return strm ? err(strm, Z_STREAM_ERROR) : Z_STREAM_ERROR;
75206   }
75207
75208   const s = strm.state;
75209
75210   if (!strm.output ||
75211       (!strm.input && strm.avail_in !== 0) ||
75212       (s.status === FINISH_STATE && flush !== Z_FINISH)) {
75213     return err(strm, (strm.avail_out === 0) ? Z_BUF_ERROR : Z_STREAM_ERROR);
75214   }
75215
75216   s.strm = strm; /* just in case */
75217   const old_flush = s.last_flush;
75218   s.last_flush = flush;
75219
75220   /* Write the header */
75221   if (s.status === INIT_STATE) {
75222
75223     if (s.wrap === 2) { // GZIP header
75224       strm.adler = 0;  //crc32(0L, Z_NULL, 0);
75225       put_byte(s, 31);
75226       put_byte(s, 139);
75227       put_byte(s, 8);
75228       if (!s.gzhead) { // s->gzhead == Z_NULL
75229         put_byte(s, 0);
75230         put_byte(s, 0);
75231         put_byte(s, 0);
75232         put_byte(s, 0);
75233         put_byte(s, 0);
75234         put_byte(s, s.level === 9 ? 2 :
75235                     (s.strategy >= Z_HUFFMAN_ONLY || s.level < 2 ?
75236                      4 : 0));
75237         put_byte(s, OS_CODE);
75238         s.status = BUSY_STATE;
75239       }
75240       else {
75241         put_byte(s, (s.gzhead.text ? 1 : 0) +
75242                     (s.gzhead.hcrc ? 2 : 0) +
75243                     (!s.gzhead.extra ? 0 : 4) +
75244                     (!s.gzhead.name ? 0 : 8) +
75245                     (!s.gzhead.comment ? 0 : 16)
75246         );
75247         put_byte(s, s.gzhead.time & 0xff);
75248         put_byte(s, (s.gzhead.time >> 8) & 0xff);
75249         put_byte(s, (s.gzhead.time >> 16) & 0xff);
75250         put_byte(s, (s.gzhead.time >> 24) & 0xff);
75251         put_byte(s, s.level === 9 ? 2 :
75252                     (s.strategy >= Z_HUFFMAN_ONLY || s.level < 2 ?
75253                      4 : 0));
75254         put_byte(s, s.gzhead.os & 0xff);
75255         if (s.gzhead.extra && s.gzhead.extra.length) {
75256           put_byte(s, s.gzhead.extra.length & 0xff);
75257           put_byte(s, (s.gzhead.extra.length >> 8) & 0xff);
75258         }
75259         if (s.gzhead.hcrc) {
75260           strm.adler = crc32_1(strm.adler, s.pending_buf, s.pending, 0);
75261         }
75262         s.gzindex = 0;
75263         s.status = EXTRA_STATE;
75264       }
75265     }
75266     else // DEFLATE header
75267     {
75268       let header = (Z_DEFLATED + ((s.w_bits - 8) << 4)) << 8;
75269       let level_flags = -1;
75270
75271       if (s.strategy >= Z_HUFFMAN_ONLY || s.level < 2) {
75272         level_flags = 0;
75273       } else if (s.level < 6) {
75274         level_flags = 1;
75275       } else if (s.level === 6) {
75276         level_flags = 2;
75277       } else {
75278         level_flags = 3;
75279       }
75280       header |= (level_flags << 6);
75281       if (s.strstart !== 0) { header |= PRESET_DICT; }
75282       header += 31 - (header % 31);
75283
75284       s.status = BUSY_STATE;
75285       putShortMSB(s, header);
75286
75287       /* Save the adler32 of the preset dictionary: */
75288       if (s.strstart !== 0) {
75289         putShortMSB(s, strm.adler >>> 16);
75290         putShortMSB(s, strm.adler & 0xffff);
75291       }
75292       strm.adler = 1; // adler32(0L, Z_NULL, 0);
75293     }
75294   }
75295
75296 //#ifdef GZIP
75297   if (s.status === EXTRA_STATE) {
75298     if (s.gzhead.extra/* != Z_NULL*/) {
75299       beg = s.pending;  /* start of bytes to update crc */
75300
75301       while (s.gzindex < (s.gzhead.extra.length & 0xffff)) {
75302         if (s.pending === s.pending_buf_size) {
75303           if (s.gzhead.hcrc && s.pending > beg) {
75304             strm.adler = crc32_1(strm.adler, s.pending_buf, s.pending - beg, beg);
75305           }
75306           flush_pending(strm);
75307           beg = s.pending;
75308           if (s.pending === s.pending_buf_size) {
75309             break;
75310           }
75311         }
75312         put_byte(s, s.gzhead.extra[s.gzindex] & 0xff);
75313         s.gzindex++;
75314       }
75315       if (s.gzhead.hcrc && s.pending > beg) {
75316         strm.adler = crc32_1(strm.adler, s.pending_buf, s.pending - beg, beg);
75317       }
75318       if (s.gzindex === s.gzhead.extra.length) {
75319         s.gzindex = 0;
75320         s.status = NAME_STATE;
75321       }
75322     }
75323     else {
75324       s.status = NAME_STATE;
75325     }
75326   }
75327   if (s.status === NAME_STATE) {
75328     if (s.gzhead.name/* != Z_NULL*/) {
75329       beg = s.pending;  /* start of bytes to update crc */
75330       //int val;
75331
75332       do {
75333         if (s.pending === s.pending_buf_size) {
75334           if (s.gzhead.hcrc && s.pending > beg) {
75335             strm.adler = crc32_1(strm.adler, s.pending_buf, s.pending - beg, beg);
75336           }
75337           flush_pending(strm);
75338           beg = s.pending;
75339           if (s.pending === s.pending_buf_size) {
75340             val = 1;
75341             break;
75342           }
75343         }
75344         // JS specific: little magic to add zero terminator to end of string
75345         if (s.gzindex < s.gzhead.name.length) {
75346           val = s.gzhead.name.charCodeAt(s.gzindex++) & 0xff;
75347         } else {
75348           val = 0;
75349         }
75350         put_byte(s, val);
75351       } while (val !== 0);
75352
75353       if (s.gzhead.hcrc && s.pending > beg) {
75354         strm.adler = crc32_1(strm.adler, s.pending_buf, s.pending - beg, beg);
75355       }
75356       if (val === 0) {
75357         s.gzindex = 0;
75358         s.status = COMMENT_STATE;
75359       }
75360     }
75361     else {
75362       s.status = COMMENT_STATE;
75363     }
75364   }
75365   if (s.status === COMMENT_STATE) {
75366     if (s.gzhead.comment/* != Z_NULL*/) {
75367       beg = s.pending;  /* start of bytes to update crc */
75368       //int val;
75369
75370       do {
75371         if (s.pending === s.pending_buf_size) {
75372           if (s.gzhead.hcrc && s.pending > beg) {
75373             strm.adler = crc32_1(strm.adler, s.pending_buf, s.pending - beg, beg);
75374           }
75375           flush_pending(strm);
75376           beg = s.pending;
75377           if (s.pending === s.pending_buf_size) {
75378             val = 1;
75379             break;
75380           }
75381         }
75382         // JS specific: little magic to add zero terminator to end of string
75383         if (s.gzindex < s.gzhead.comment.length) {
75384           val = s.gzhead.comment.charCodeAt(s.gzindex++) & 0xff;
75385         } else {
75386           val = 0;
75387         }
75388         put_byte(s, val);
75389       } while (val !== 0);
75390
75391       if (s.gzhead.hcrc && s.pending > beg) {
75392         strm.adler = crc32_1(strm.adler, s.pending_buf, s.pending - beg, beg);
75393       }
75394       if (val === 0) {
75395         s.status = HCRC_STATE;
75396       }
75397     }
75398     else {
75399       s.status = HCRC_STATE;
75400     }
75401   }
75402   if (s.status === HCRC_STATE) {
75403     if (s.gzhead.hcrc) {
75404       if (s.pending + 2 > s.pending_buf_size) {
75405         flush_pending(strm);
75406       }
75407       if (s.pending + 2 <= s.pending_buf_size) {
75408         put_byte(s, strm.adler & 0xff);
75409         put_byte(s, (strm.adler >> 8) & 0xff);
75410         strm.adler = 0; //crc32(0L, Z_NULL, 0);
75411         s.status = BUSY_STATE;
75412       }
75413     }
75414     else {
75415       s.status = BUSY_STATE;
75416     }
75417   }
75418 //#endif
75419
75420   /* Flush as much pending output as possible */
75421   if (s.pending !== 0) {
75422     flush_pending(strm);
75423     if (strm.avail_out === 0) {
75424       /* Since avail_out is 0, deflate will be called again with
75425        * more output space, but possibly with both pending and
75426        * avail_in equal to zero. There won't be anything to do,
75427        * but this is not an error situation so make sure we
75428        * return OK instead of BUF_ERROR at next call of deflate:
75429        */
75430       s.last_flush = -1;
75431       return Z_OK;
75432     }
75433
75434     /* Make sure there is something to do and avoid duplicate consecutive
75435      * flushes. For repeated and useless calls with Z_FINISH, we keep
75436      * returning Z_STREAM_END instead of Z_BUF_ERROR.
75437      */
75438   } else if (strm.avail_in === 0 && rank(flush) <= rank(old_flush) &&
75439     flush !== Z_FINISH) {
75440     return err(strm, Z_BUF_ERROR);
75441   }
75442
75443   /* User must not provide more input after the first FINISH: */
75444   if (s.status === FINISH_STATE && strm.avail_in !== 0) {
75445     return err(strm, Z_BUF_ERROR);
75446   }
75447
75448   /* Start a new block or continue the current one.
75449    */
75450   if (strm.avail_in !== 0 || s.lookahead !== 0 ||
75451     (flush !== Z_NO_FLUSH && s.status !== FINISH_STATE)) {
75452     let bstate = (s.strategy === Z_HUFFMAN_ONLY) ? deflate_huff(s, flush) :
75453       (s.strategy === Z_RLE ? deflate_rle(s, flush) :
75454         configuration_table[s.level].func(s, flush));
75455
75456     if (bstate === BS_FINISH_STARTED || bstate === BS_FINISH_DONE) {
75457       s.status = FINISH_STATE;
75458     }
75459     if (bstate === BS_NEED_MORE || bstate === BS_FINISH_STARTED) {
75460       if (strm.avail_out === 0) {
75461         s.last_flush = -1;
75462         /* avoid BUF_ERROR next call, see above */
75463       }
75464       return Z_OK;
75465       /* If flush != Z_NO_FLUSH && avail_out == 0, the next call
75466        * of deflate should use the same flush parameter to make sure
75467        * that the flush is complete. So we don't have to output an
75468        * empty block here, this will be done at next call. This also
75469        * ensures that for a very small output buffer, we emit at most
75470        * one empty block.
75471        */
75472     }
75473     if (bstate === BS_BLOCK_DONE) {
75474       if (flush === Z_PARTIAL_FLUSH) {
75475         _tr_align$1(s);
75476       }
75477       else if (flush !== Z_BLOCK) { /* FULL_FLUSH or SYNC_FLUSH */
75478
75479         _tr_stored_block$1(s, 0, 0, false);
75480         /* For a full flush, this empty block will be recognized
75481          * as a special marker by inflate_sync().
75482          */
75483         if (flush === Z_FULL_FLUSH) {
75484           /*** CLEAR_HASH(s); ***/             /* forget history */
75485           zero$1(s.head); // Fill with NIL (= 0);
75486
75487           if (s.lookahead === 0) {
75488             s.strstart = 0;
75489             s.block_start = 0;
75490             s.insert = 0;
75491           }
75492         }
75493       }
75494       flush_pending(strm);
75495       if (strm.avail_out === 0) {
75496         s.last_flush = -1; /* avoid BUF_ERROR at next call, see above */
75497         return Z_OK;
75498       }
75499     }
75500   }
75501   //Assert(strm->avail_out > 0, "bug2");
75502   //if (strm.avail_out <= 0) { throw new Error("bug2");}
75503
75504   if (flush !== Z_FINISH) { return Z_OK; }
75505   if (s.wrap <= 0) { return Z_STREAM_END; }
75506
75507   /* Write the trailer */
75508   if (s.wrap === 2) {
75509     put_byte(s, strm.adler & 0xff);
75510     put_byte(s, (strm.adler >> 8) & 0xff);
75511     put_byte(s, (strm.adler >> 16) & 0xff);
75512     put_byte(s, (strm.adler >> 24) & 0xff);
75513     put_byte(s, strm.total_in & 0xff);
75514     put_byte(s, (strm.total_in >> 8) & 0xff);
75515     put_byte(s, (strm.total_in >> 16) & 0xff);
75516     put_byte(s, (strm.total_in >> 24) & 0xff);
75517   }
75518   else
75519   {
75520     putShortMSB(s, strm.adler >>> 16);
75521     putShortMSB(s, strm.adler & 0xffff);
75522   }
75523
75524   flush_pending(strm);
75525   /* If avail_out is zero, the application will call deflate again
75526    * to flush the rest.
75527    */
75528   if (s.wrap > 0) { s.wrap = -s.wrap; }
75529   /* write the trailer only once! */
75530   return s.pending !== 0 ? Z_OK : Z_STREAM_END;
75531 };
75532
75533
75534 const deflateEnd = (strm) => {
75535
75536   if (!strm/*== Z_NULL*/ || !strm.state/*== Z_NULL*/) {
75537     return Z_STREAM_ERROR;
75538   }
75539
75540   const status = strm.state.status;
75541   if (status !== INIT_STATE &&
75542     status !== EXTRA_STATE &&
75543     status !== NAME_STATE &&
75544     status !== COMMENT_STATE &&
75545     status !== HCRC_STATE &&
75546     status !== BUSY_STATE &&
75547     status !== FINISH_STATE
75548   ) {
75549     return err(strm, Z_STREAM_ERROR);
75550   }
75551
75552   strm.state = null;
75553
75554   return status === BUSY_STATE ? err(strm, Z_DATA_ERROR) : Z_OK;
75555 };
75556
75557
75558 /* =========================================================================
75559  * Initializes the compression dictionary from the given byte
75560  * sequence without producing any compressed output.
75561  */
75562 const deflateSetDictionary = (strm, dictionary) => {
75563
75564   let dictLength = dictionary.length;
75565
75566   if (!strm/*== Z_NULL*/ || !strm.state/*== Z_NULL*/) {
75567     return Z_STREAM_ERROR;
75568   }
75569
75570   const s = strm.state;
75571   const wrap = s.wrap;
75572
75573   if (wrap === 2 || (wrap === 1 && s.status !== INIT_STATE) || s.lookahead) {
75574     return Z_STREAM_ERROR;
75575   }
75576
75577   /* when using zlib wrappers, compute Adler-32 for provided dictionary */
75578   if (wrap === 1) {
75579     /* adler32(strm->adler, dictionary, dictLength); */
75580     strm.adler = adler32_1(strm.adler, dictionary, dictLength, 0);
75581   }
75582
75583   s.wrap = 0;   /* avoid computing Adler-32 in read_buf */
75584
75585   /* if dictionary would fill window, just replace the history */
75586   if (dictLength >= s.w_size) {
75587     if (wrap === 0) {            /* already empty otherwise */
75588       /*** CLEAR_HASH(s); ***/
75589       zero$1(s.head); // Fill with NIL (= 0);
75590       s.strstart = 0;
75591       s.block_start = 0;
75592       s.insert = 0;
75593     }
75594     /* use the tail */
75595     // dictionary = dictionary.slice(dictLength - s.w_size);
75596     let tmpDict = new Uint8Array(s.w_size);
75597     tmpDict.set(dictionary.subarray(dictLength - s.w_size, dictLength), 0);
75598     dictionary = tmpDict;
75599     dictLength = s.w_size;
75600   }
75601   /* insert dictionary into window and hash */
75602   const avail = strm.avail_in;
75603   const next = strm.next_in;
75604   const input = strm.input;
75605   strm.avail_in = dictLength;
75606   strm.next_in = 0;
75607   strm.input = dictionary;
75608   fill_window(s);
75609   while (s.lookahead >= MIN_MATCH$1) {
75610     let str = s.strstart;
75611     let n = s.lookahead - (MIN_MATCH$1 - 1);
75612     do {
75613       /* UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]); */
75614       s.ins_h = HASH(s, s.ins_h, s.window[str + MIN_MATCH$1 - 1]);
75615
75616       s.prev[str & s.w_mask] = s.head[s.ins_h];
75617
75618       s.head[s.ins_h] = str;
75619       str++;
75620     } while (--n);
75621     s.strstart = str;
75622     s.lookahead = MIN_MATCH$1 - 1;
75623     fill_window(s);
75624   }
75625   s.strstart += s.lookahead;
75626   s.block_start = s.strstart;
75627   s.insert = s.lookahead;
75628   s.lookahead = 0;
75629   s.match_length = s.prev_length = MIN_MATCH$1 - 1;
75630   s.match_available = 0;
75631   strm.next_in = next;
75632   strm.input = input;
75633   strm.avail_in = avail;
75634   s.wrap = wrap;
75635   return Z_OK;
75636 };
75637
75638
75639 var deflateInit_1 = deflateInit;
75640 var deflateInit2_1 = deflateInit2;
75641 var deflateReset_1 = deflateReset;
75642 var deflateResetKeep_1 = deflateResetKeep;
75643 var deflateSetHeader_1 = deflateSetHeader;
75644 var deflate_2 = deflate;
75645 var deflateEnd_1 = deflateEnd;
75646 var deflateSetDictionary_1 = deflateSetDictionary;
75647 var deflateInfo = 'pako deflate (from Nodeca project)';
75648
75649 /* Not implemented
75650 module.exports.deflateBound = deflateBound;
75651 module.exports.deflateCopy = deflateCopy;
75652 module.exports.deflateParams = deflateParams;
75653 module.exports.deflatePending = deflatePending;
75654 module.exports.deflatePrime = deflatePrime;
75655 module.exports.deflateTune = deflateTune;
75656 */
75657
75658 var deflate_1 = {
75659         deflateInit: deflateInit_1,
75660         deflateInit2: deflateInit2_1,
75661         deflateReset: deflateReset_1,
75662         deflateResetKeep: deflateResetKeep_1,
75663         deflateSetHeader: deflateSetHeader_1,
75664         deflate: deflate_2,
75665         deflateEnd: deflateEnd_1,
75666         deflateSetDictionary: deflateSetDictionary_1,
75667         deflateInfo: deflateInfo
75668 };
75669
75670 const _has = (obj, key) => {
75671   return Object.prototype.hasOwnProperty.call(obj, key);
75672 };
75673
75674 var assign = function (obj /*from1, from2, from3, ...*/) {
75675   const sources = Array.prototype.slice.call(arguments, 1);
75676   while (sources.length) {
75677     const source = sources.shift();
75678     if (!source) { continue; }
75679
75680     if (typeof source !== 'object') {
75681       throw new TypeError(source + 'must be non-object');
75682     }
75683
75684     for (const p in source) {
75685       if (_has(source, p)) {
75686         obj[p] = source[p];
75687       }
75688     }
75689   }
75690
75691   return obj;
75692 };
75693
75694
75695 // Join array of chunks to single array.
75696 var flattenChunks = (chunks) => {
75697   // calculate data length
75698   let len = 0;
75699
75700   for (let i = 0, l = chunks.length; i < l; i++) {
75701     len += chunks[i].length;
75702   }
75703
75704   // join chunks
75705   const result = new Uint8Array(len);
75706
75707   for (let i = 0, pos = 0, l = chunks.length; i < l; i++) {
75708     let chunk = chunks[i];
75709     result.set(chunk, pos);
75710     pos += chunk.length;
75711   }
75712
75713   return result;
75714 };
75715
75716 var common = {
75717         assign: assign,
75718         flattenChunks: flattenChunks
75719 };
75720
75721 // String encode/decode helpers
75722
75723
75724 // Quick check if we can use fast array to bin string conversion
75725 //
75726 // - apply(Array) can fail on Android 2.2
75727 // - apply(Uint8Array) can fail on iOS 5.1 Safari
75728 //
75729 let STR_APPLY_UIA_OK = true;
75730
75731 try { String.fromCharCode.apply(null, new Uint8Array(1)); } catch (__) { STR_APPLY_UIA_OK = false; }
75732
75733
75734 // Table with utf8 lengths (calculated by first byte of sequence)
75735 // Note, that 5 & 6-byte values and some 4-byte values can not be represented in JS,
75736 // because max possible codepoint is 0x10ffff
75737 const _utf8len = new Uint8Array(256);
75738 for (let q = 0; q < 256; q++) {
75739   _utf8len[q] = (q >= 252 ? 6 : q >= 248 ? 5 : q >= 240 ? 4 : q >= 224 ? 3 : q >= 192 ? 2 : 1);
75740 }
75741 _utf8len[254] = _utf8len[254] = 1; // Invalid sequence start
75742
75743
75744 // convert string to array (typed, when possible)
75745 var string2buf = (str) => {
75746   let buf, c, c2, m_pos, i, str_len = str.length, buf_len = 0;
75747
75748   // count binary size
75749   for (m_pos = 0; m_pos < str_len; m_pos++) {
75750     c = str.charCodeAt(m_pos);
75751     if ((c & 0xfc00) === 0xd800 && (m_pos + 1 < str_len)) {
75752       c2 = str.charCodeAt(m_pos + 1);
75753       if ((c2 & 0xfc00) === 0xdc00) {
75754         c = 0x10000 + ((c - 0xd800) << 10) + (c2 - 0xdc00);
75755         m_pos++;
75756       }
75757     }
75758     buf_len += c < 0x80 ? 1 : c < 0x800 ? 2 : c < 0x10000 ? 3 : 4;
75759   }
75760
75761   // allocate buffer
75762   buf = new Uint8Array(buf_len);
75763
75764   // convert
75765   for (i = 0, m_pos = 0; i < buf_len; m_pos++) {
75766     c = str.charCodeAt(m_pos);
75767     if ((c & 0xfc00) === 0xd800 && (m_pos + 1 < str_len)) {
75768       c2 = str.charCodeAt(m_pos + 1);
75769       if ((c2 & 0xfc00) === 0xdc00) {
75770         c = 0x10000 + ((c - 0xd800) << 10) + (c2 - 0xdc00);
75771         m_pos++;
75772       }
75773     }
75774     if (c < 0x80) {
75775       /* one byte */
75776       buf[i++] = c;
75777     } else if (c < 0x800) {
75778       /* two bytes */
75779       buf[i++] = 0xC0 | (c >>> 6);
75780       buf[i++] = 0x80 | (c & 0x3f);
75781     } else if (c < 0x10000) {
75782       /* three bytes */
75783       buf[i++] = 0xE0 | (c >>> 12);
75784       buf[i++] = 0x80 | (c >>> 6 & 0x3f);
75785       buf[i++] = 0x80 | (c & 0x3f);
75786     } else {
75787       /* four bytes */
75788       buf[i++] = 0xf0 | (c >>> 18);
75789       buf[i++] = 0x80 | (c >>> 12 & 0x3f);
75790       buf[i++] = 0x80 | (c >>> 6 & 0x3f);
75791       buf[i++] = 0x80 | (c & 0x3f);
75792     }
75793   }
75794
75795   return buf;
75796 };
75797
75798 // Helper
75799 const buf2binstring = (buf, len) => {
75800   // On Chrome, the arguments in a function call that are allowed is `65534`.
75801   // If the length of the buffer is smaller than that, we can use this optimization,
75802   // otherwise we will take a slower path.
75803   if (len < 65534) {
75804     if (buf.subarray && STR_APPLY_UIA_OK) {
75805       return String.fromCharCode.apply(null, buf.length === len ? buf : buf.subarray(0, len));
75806     }
75807   }
75808
75809   let result = '';
75810   for (let i = 0; i < len; i++) {
75811     result += String.fromCharCode(buf[i]);
75812   }
75813   return result;
75814 };
75815
75816
75817 // convert array to string
75818 var buf2string = (buf, max) => {
75819   let i, out;
75820   const len = max || buf.length;
75821
75822   // Reserve max possible length (2 words per char)
75823   // NB: by unknown reasons, Array is significantly faster for
75824   //     String.fromCharCode.apply than Uint16Array.
75825   const utf16buf = new Array(len * 2);
75826
75827   for (out = 0, i = 0; i < len;) {
75828     let c = buf[i++];
75829     // quick process ascii
75830     if (c < 0x80) { utf16buf[out++] = c; continue; }
75831
75832     let c_len = _utf8len[c];
75833     // skip 5 & 6 byte codes
75834     if (c_len > 4) { utf16buf[out++] = 0xfffd; i += c_len - 1; continue; }
75835
75836     // apply mask on first byte
75837     c &= c_len === 2 ? 0x1f : c_len === 3 ? 0x0f : 0x07;
75838     // join the rest
75839     while (c_len > 1 && i < len) {
75840       c = (c << 6) | (buf[i++] & 0x3f);
75841       c_len--;
75842     }
75843
75844     // terminated by end of string?
75845     if (c_len > 1) { utf16buf[out++] = 0xfffd; continue; }
75846
75847     if (c < 0x10000) {
75848       utf16buf[out++] = c;
75849     } else {
75850       c -= 0x10000;
75851       utf16buf[out++] = 0xd800 | ((c >> 10) & 0x3ff);
75852       utf16buf[out++] = 0xdc00 | (c & 0x3ff);
75853     }
75854   }
75855
75856   return buf2binstring(utf16buf, out);
75857 };
75858
75859
75860 // Calculate max possible position in utf8 buffer,
75861 // that will not break sequence. If that's not possible
75862 // - (very small limits) return max size as is.
75863 //
75864 // buf[] - utf8 bytes array
75865 // max   - length limit (mandatory);
75866 var utf8border = (buf, max) => {
75867
75868   max = max || buf.length;
75869   if (max > buf.length) { max = buf.length; }
75870
75871   // go back from last position, until start of sequence found
75872   let pos = max - 1;
75873   while (pos >= 0 && (buf[pos] & 0xC0) === 0x80) { pos--; }
75874
75875   // Very small and broken sequence,
75876   // return max, because we should return something anyway.
75877   if (pos < 0) { return max; }
75878
75879   // If we came to start of buffer - that means buffer is too small,
75880   // return max too.
75881   if (pos === 0) { return max; }
75882
75883   return (pos + _utf8len[buf[pos]] > max) ? pos : max;
75884 };
75885
75886 var strings = {
75887         string2buf: string2buf,
75888         buf2string: buf2string,
75889         utf8border: utf8border
75890 };
75891
75892 // (C) 1995-2013 Jean-loup Gailly and Mark Adler
75893 // (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin
75894 //
75895 // This software is provided 'as-is', without any express or implied
75896 // warranty. In no event will the authors be held liable for any damages
75897 // arising from the use of this software.
75898 //
75899 // Permission is granted to anyone to use this software for any purpose,
75900 // including commercial applications, and to alter it and redistribute it
75901 // freely, subject to the following restrictions:
75902 //
75903 // 1. The origin of this software must not be misrepresented; you must not
75904 //   claim that you wrote the original software. If you use this software
75905 //   in a product, an acknowledgment in the product documentation would be
75906 //   appreciated but is not required.
75907 // 2. Altered source versions must be plainly marked as such, and must not be
75908 //   misrepresented as being the original software.
75909 // 3. This notice may not be removed or altered from any source distribution.
75910
75911 function ZStream() {
75912   /* next input byte */
75913   this.input = null; // JS specific, because we have no pointers
75914   this.next_in = 0;
75915   /* number of bytes available at input */
75916   this.avail_in = 0;
75917   /* total number of input bytes read so far */
75918   this.total_in = 0;
75919   /* next output byte should be put there */
75920   this.output = null; // JS specific, because we have no pointers
75921   this.next_out = 0;
75922   /* remaining free space at output */
75923   this.avail_out = 0;
75924   /* total number of bytes output so far */
75925   this.total_out = 0;
75926   /* last error message, NULL if no error */
75927   this.msg = ''/*Z_NULL*/;
75928   /* not visible by applications */
75929   this.state = null;
75930   /* best guess about the data type: binary or text */
75931   this.data_type = 2/*Z_UNKNOWN*/;
75932   /* adler32 value of the uncompressed data */
75933   this.adler = 0;
75934 }
75935
75936 var zstream = ZStream;
75937
75938 const toString = Object.prototype.toString;
75939
75940 /* Public constants ==========================================================*/
75941 /* ===========================================================================*/
75942
75943 const {
75944   Z_NO_FLUSH: Z_NO_FLUSH$1, Z_SYNC_FLUSH, Z_FULL_FLUSH: Z_FULL_FLUSH$1, Z_FINISH: Z_FINISH$1,
75945   Z_OK: Z_OK$1, Z_STREAM_END: Z_STREAM_END$1,
75946   Z_DEFAULT_COMPRESSION: Z_DEFAULT_COMPRESSION$1,
75947   Z_DEFAULT_STRATEGY: Z_DEFAULT_STRATEGY$1,
75948   Z_DEFLATED: Z_DEFLATED$1
75949 } = constants;
75950
75951 /* ===========================================================================*/
75952
75953
75954 /**
75955  * class Deflate
75956  *
75957  * Generic JS-style wrapper for zlib calls. If you don't need
75958  * streaming behaviour - use more simple functions: [[deflate]],
75959  * [[deflateRaw]] and [[gzip]].
75960  **/
75961
75962 /* internal
75963  * Deflate.chunks -> Array
75964  *
75965  * Chunks of output data, if [[Deflate#onData]] not overridden.
75966  **/
75967
75968 /**
75969  * Deflate.result -> Uint8Array
75970  *
75971  * Compressed result, generated by default [[Deflate#onData]]
75972  * and [[Deflate#onEnd]] handlers. Filled after you push last chunk
75973  * (call [[Deflate#push]] with `Z_FINISH` / `true` param).
75974  **/
75975
75976 /**
75977  * Deflate.err -> Number
75978  *
75979  * Error code after deflate finished. 0 (Z_OK) on success.
75980  * You will not need it in real life, because deflate errors
75981  * are possible only on wrong options or bad `onData` / `onEnd`
75982  * custom handlers.
75983  **/
75984
75985 /**
75986  * Deflate.msg -> String
75987  *
75988  * Error message, if [[Deflate.err]] != 0
75989  **/
75990
75991
75992 /**
75993  * new Deflate(options)
75994  * - options (Object): zlib deflate options.
75995  *
75996  * Creates new deflator instance with specified params. Throws exception
75997  * on bad params. Supported options:
75998  *
75999  * - `level`
76000  * - `windowBits`
76001  * - `memLevel`
76002  * - `strategy`
76003  * - `dictionary`
76004  *
76005  * [http://zlib.net/manual.html#Advanced](http://zlib.net/manual.html#Advanced)
76006  * for more information on these.
76007  *
76008  * Additional options, for internal needs:
76009  *
76010  * - `chunkSize` - size of generated data chunks (16K by default)
76011  * - `raw` (Boolean) - do raw deflate
76012  * - `gzip` (Boolean) - create gzip wrapper
76013  * - `header` (Object) - custom header for gzip
76014  *   - `text` (Boolean) - true if compressed data believed to be text
76015  *   - `time` (Number) - modification time, unix timestamp
76016  *   - `os` (Number) - operation system code
76017  *   - `extra` (Array) - array of bytes with extra data (max 65536)
76018  *   - `name` (String) - file name (binary string)
76019  *   - `comment` (String) - comment (binary string)
76020  *   - `hcrc` (Boolean) - true if header crc should be added
76021  *
76022  * ##### Example:
76023  *
76024  * ```javascript
76025  * const pako = require('pako')
76026  *   , chunk1 = new Uint8Array([1,2,3,4,5,6,7,8,9])
76027  *   , chunk2 = new Uint8Array([10,11,12,13,14,15,16,17,18,19]);
76028  *
76029  * const deflate = new pako.Deflate({ level: 3});
76030  *
76031  * deflate.push(chunk1, false);
76032  * deflate.push(chunk2, true);  // true -> last chunk
76033  *
76034  * if (deflate.err) { throw new Error(deflate.err); }
76035  *
76036  * console.log(deflate.result);
76037  * ```
76038  **/
76039 function Deflate(options) {
76040   this.options = common.assign({
76041     level: Z_DEFAULT_COMPRESSION$1,
76042     method: Z_DEFLATED$1,
76043     chunkSize: 16384,
76044     windowBits: 15,
76045     memLevel: 8,
76046     strategy: Z_DEFAULT_STRATEGY$1
76047   }, options || {});
76048
76049   let opt = this.options;
76050
76051   if (opt.raw && (opt.windowBits > 0)) {
76052     opt.windowBits = -opt.windowBits;
76053   }
76054
76055   else if (opt.gzip && (opt.windowBits > 0) && (opt.windowBits < 16)) {
76056     opt.windowBits += 16;
76057   }
76058
76059   this.err    = 0;      // error code, if happens (0 = Z_OK)
76060   this.msg    = '';     // error message
76061   this.ended  = false;  // used to avoid multiple onEnd() calls
76062   this.chunks = [];     // chunks of compressed data
76063
76064   this.strm = new zstream();
76065   this.strm.avail_out = 0;
76066
76067   let status = deflate_1.deflateInit2(
76068     this.strm,
76069     opt.level,
76070     opt.method,
76071     opt.windowBits,
76072     opt.memLevel,
76073     opt.strategy
76074   );
76075
76076   if (status !== Z_OK$1) {
76077     throw new Error(messages[status]);
76078   }
76079
76080   if (opt.header) {
76081     deflate_1.deflateSetHeader(this.strm, opt.header);
76082   }
76083
76084   if (opt.dictionary) {
76085     let dict;
76086     // Convert data if needed
76087     if (typeof opt.dictionary === 'string') {
76088       // If we need to compress text, change encoding to utf8.
76089       dict = strings.string2buf(opt.dictionary);
76090     } else if (toString.call(opt.dictionary) === '[object ArrayBuffer]') {
76091       dict = new Uint8Array(opt.dictionary);
76092     } else {
76093       dict = opt.dictionary;
76094     }
76095
76096     status = deflate_1.deflateSetDictionary(this.strm, dict);
76097
76098     if (status !== Z_OK$1) {
76099       throw new Error(messages[status]);
76100     }
76101
76102     this._dict_set = true;
76103   }
76104 }
76105
76106 /**
76107  * Deflate#push(data[, flush_mode]) -> Boolean
76108  * - data (Uint8Array|ArrayBuffer|String): input data. Strings will be
76109  *   converted to utf8 byte sequence.
76110  * - flush_mode (Number|Boolean): 0..6 for corresponding Z_NO_FLUSH..Z_TREE modes.
76111  *   See constants. Skipped or `false` means Z_NO_FLUSH, `true` means Z_FINISH.
76112  *
76113  * Sends input data to deflate pipe, generating [[Deflate#onData]] calls with
76114  * new compressed chunks. Returns `true` on success. The last data block must
76115  * have `flush_mode` Z_FINISH (or `true`). That will flush internal pending
76116  * buffers and call [[Deflate#onEnd]].
76117  *
76118  * On fail call [[Deflate#onEnd]] with error code and return false.
76119  *
76120  * ##### Example
76121  *
76122  * ```javascript
76123  * push(chunk, false); // push one of data chunks
76124  * ...
76125  * push(chunk, true);  // push last chunk
76126  * ```
76127  **/
76128 Deflate.prototype.push = function (data, flush_mode) {
76129   const strm = this.strm;
76130   const chunkSize = this.options.chunkSize;
76131   let status, _flush_mode;
76132
76133   if (this.ended) { return false; }
76134
76135   if (flush_mode === ~~flush_mode) _flush_mode = flush_mode;
76136   else _flush_mode = flush_mode === true ? Z_FINISH$1 : Z_NO_FLUSH$1;
76137
76138   // Convert data if needed
76139   if (typeof data === 'string') {
76140     // If we need to compress text, change encoding to utf8.
76141     strm.input = strings.string2buf(data);
76142   } else if (toString.call(data) === '[object ArrayBuffer]') {
76143     strm.input = new Uint8Array(data);
76144   } else {
76145     strm.input = data;
76146   }
76147
76148   strm.next_in = 0;
76149   strm.avail_in = strm.input.length;
76150
76151   for (;;) {
76152     if (strm.avail_out === 0) {
76153       strm.output = new Uint8Array(chunkSize);
76154       strm.next_out = 0;
76155       strm.avail_out = chunkSize;
76156     }
76157
76158     // Make sure avail_out > 6 to avoid repeating markers
76159     if ((_flush_mode === Z_SYNC_FLUSH || _flush_mode === Z_FULL_FLUSH$1) && strm.avail_out <= 6) {
76160       this.onData(strm.output.subarray(0, strm.next_out));
76161       strm.avail_out = 0;
76162       continue;
76163     }
76164
76165     status = deflate_1.deflate(strm, _flush_mode);
76166
76167     // Ended => flush and finish
76168     if (status === Z_STREAM_END$1) {
76169       if (strm.next_out > 0) {
76170         this.onData(strm.output.subarray(0, strm.next_out));
76171       }
76172       status = deflate_1.deflateEnd(this.strm);
76173       this.onEnd(status);
76174       this.ended = true;
76175       return status === Z_OK$1;
76176     }
76177
76178     // Flush if out buffer full
76179     if (strm.avail_out === 0) {
76180       this.onData(strm.output);
76181       continue;
76182     }
76183
76184     // Flush if requested and has data
76185     if (_flush_mode > 0 && strm.next_out > 0) {
76186       this.onData(strm.output.subarray(0, strm.next_out));
76187       strm.avail_out = 0;
76188       continue;
76189     }
76190
76191     if (strm.avail_in === 0) break;
76192   }
76193
76194   return true;
76195 };
76196
76197
76198 /**
76199  * Deflate#onData(chunk) -> Void
76200  * - chunk (Uint8Array): output data.
76201  *
76202  * By default, stores data blocks in `chunks[]` property and glue
76203  * those in `onEnd`. Override this handler, if you need another behaviour.
76204  **/
76205 Deflate.prototype.onData = function (chunk) {
76206   this.chunks.push(chunk);
76207 };
76208
76209
76210 /**
76211  * Deflate#onEnd(status) -> Void
76212  * - status (Number): deflate status. 0 (Z_OK) on success,
76213  *   other if not.
76214  *
76215  * Called once after you tell deflate that the input stream is
76216  * complete (Z_FINISH). By default - join collected chunks,
76217  * free memory and fill `results` / `err` properties.
76218  **/
76219 Deflate.prototype.onEnd = function (status) {
76220   // On success - join
76221   if (status === Z_OK$1) {
76222     this.result = common.flattenChunks(this.chunks);
76223   }
76224   this.chunks = [];
76225   this.err = status;
76226   this.msg = this.strm.msg;
76227 };
76228
76229 // (C) 1995-2013 Jean-loup Gailly and Mark Adler
76230 // (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin
76231 //
76232 // This software is provided 'as-is', without any express or implied
76233 // warranty. In no event will the authors be held liable for any damages
76234 // arising from the use of this software.
76235 //
76236 // Permission is granted to anyone to use this software for any purpose,
76237 // including commercial applications, and to alter it and redistribute it
76238 // freely, subject to the following restrictions:
76239 //
76240 // 1. The origin of this software must not be misrepresented; you must not
76241 //   claim that you wrote the original software. If you use this software
76242 //   in a product, an acknowledgment in the product documentation would be
76243 //   appreciated but is not required.
76244 // 2. Altered source versions must be plainly marked as such, and must not be
76245 //   misrepresented as being the original software.
76246 // 3. This notice may not be removed or altered from any source distribution.
76247
76248 // See state defs from inflate.js
76249 const BAD = 30;       /* got a data error -- remain here until reset */
76250 const TYPE = 12;      /* i: waiting for type bits, including last-flag bit */
76251
76252 /*
76253    Decode literal, length, and distance codes and write out the resulting
76254    literal and match bytes until either not enough input or output is
76255    available, an end-of-block is encountered, or a data error is encountered.
76256    When large enough input and output buffers are supplied to inflate(), for
76257    example, a 16K input buffer and a 64K output buffer, more than 95% of the
76258    inflate execution time is spent in this routine.
76259
76260    Entry assumptions:
76261
76262         state.mode === LEN
76263         strm.avail_in >= 6
76264         strm.avail_out >= 258
76265         start >= strm.avail_out
76266         state.bits < 8
76267
76268    On return, state.mode is one of:
76269
76270         LEN -- ran out of enough output space or enough available input
76271         TYPE -- reached end of block code, inflate() to interpret next block
76272         BAD -- error in block data
76273
76274    Notes:
76275
76276     - The maximum input bits used by a length/distance pair is 15 bits for the
76277       length code, 5 bits for the length extra, 15 bits for the distance code,
76278       and 13 bits for the distance extra.  This totals 48 bits, or six bytes.
76279       Therefore if strm.avail_in >= 6, then there is enough input to avoid
76280       checking for available input while decoding.
76281
76282     - The maximum bytes that a single length/distance pair can output is 258
76283       bytes, which is the maximum length that can be coded.  inflate_fast()
76284       requires strm.avail_out >= 258 for each loop to avoid checking for
76285       output space.
76286  */
76287 var inffast = function inflate_fast(strm, start) {
76288   let _in;                    /* local strm.input */
76289   let last;                   /* have enough input while in < last */
76290   let _out;                   /* local strm.output */
76291   let beg;                    /* inflate()'s initial strm.output */
76292   let end;                    /* while out < end, enough space available */
76293 //#ifdef INFLATE_STRICT
76294   let dmax;                   /* maximum distance from zlib header */
76295 //#endif
76296   let wsize;                  /* window size or zero if not using window */
76297   let whave;                  /* valid bytes in the window */
76298   let wnext;                  /* window write index */
76299   // Use `s_window` instead `window`, avoid conflict with instrumentation tools
76300   let s_window;               /* allocated sliding window, if wsize != 0 */
76301   let hold;                   /* local strm.hold */
76302   let bits;                   /* local strm.bits */
76303   let lcode;                  /* local strm.lencode */
76304   let dcode;                  /* local strm.distcode */
76305   let lmask;                  /* mask for first level of length codes */
76306   let dmask;                  /* mask for first level of distance codes */
76307   let here;                   /* retrieved table entry */
76308   let op;                     /* code bits, operation, extra bits, or */
76309                               /*  window position, window bytes to copy */
76310   let len;                    /* match length, unused bytes */
76311   let dist;                   /* match distance */
76312   let from;                   /* where to copy match from */
76313   let from_source;
76314
76315
76316   let input, output; // JS specific, because we have no pointers
76317
76318   /* copy state to local variables */
76319   const state = strm.state;
76320   //here = state.here;
76321   _in = strm.next_in;
76322   input = strm.input;
76323   last = _in + (strm.avail_in - 5);
76324   _out = strm.next_out;
76325   output = strm.output;
76326   beg = _out - (start - strm.avail_out);
76327   end = _out + (strm.avail_out - 257);
76328 //#ifdef INFLATE_STRICT
76329   dmax = state.dmax;
76330 //#endif
76331   wsize = state.wsize;
76332   whave = state.whave;
76333   wnext = state.wnext;
76334   s_window = state.window;
76335   hold = state.hold;
76336   bits = state.bits;
76337   lcode = state.lencode;
76338   dcode = state.distcode;
76339   lmask = (1 << state.lenbits) - 1;
76340   dmask = (1 << state.distbits) - 1;
76341
76342
76343   /* decode literals and length/distances until end-of-block or not enough
76344      input data or output space */
76345
76346   top:
76347   do {
76348     if (bits < 15) {
76349       hold += input[_in++] << bits;
76350       bits += 8;
76351       hold += input[_in++] << bits;
76352       bits += 8;
76353     }
76354
76355     here = lcode[hold & lmask];
76356
76357     dolen:
76358     for (;;) { // Goto emulation
76359       op = here >>> 24/*here.bits*/;
76360       hold >>>= op;
76361       bits -= op;
76362       op = (here >>> 16) & 0xff/*here.op*/;
76363       if (op === 0) {                          /* literal */
76364         //Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ?
76365         //        "inflate:         literal '%c'\n" :
76366         //        "inflate:         literal 0x%02x\n", here.val));
76367         output[_out++] = here & 0xffff/*here.val*/;
76368       }
76369       else if (op & 16) {                     /* length base */
76370         len = here & 0xffff/*here.val*/;
76371         op &= 15;                           /* number of extra bits */
76372         if (op) {
76373           if (bits < op) {
76374             hold += input[_in++] << bits;
76375             bits += 8;
76376           }
76377           len += hold & ((1 << op) - 1);
76378           hold >>>= op;
76379           bits -= op;
76380         }
76381         //Tracevv((stderr, "inflate:         length %u\n", len));
76382         if (bits < 15) {
76383           hold += input[_in++] << bits;
76384           bits += 8;
76385           hold += input[_in++] << bits;
76386           bits += 8;
76387         }
76388         here = dcode[hold & dmask];
76389
76390         dodist:
76391         for (;;) { // goto emulation
76392           op = here >>> 24/*here.bits*/;
76393           hold >>>= op;
76394           bits -= op;
76395           op = (here >>> 16) & 0xff/*here.op*/;
76396
76397           if (op & 16) {                      /* distance base */
76398             dist = here & 0xffff/*here.val*/;
76399             op &= 15;                       /* number of extra bits */
76400             if (bits < op) {
76401               hold += input[_in++] << bits;
76402               bits += 8;
76403               if (bits < op) {
76404                 hold += input[_in++] << bits;
76405                 bits += 8;
76406               }
76407             }
76408             dist += hold & ((1 << op) - 1);
76409 //#ifdef INFLATE_STRICT
76410             if (dist > dmax) {
76411               strm.msg = 'invalid distance too far back';
76412               state.mode = BAD;
76413               break top;
76414             }
76415 //#endif
76416             hold >>>= op;
76417             bits -= op;
76418             //Tracevv((stderr, "inflate:         distance %u\n", dist));
76419             op = _out - beg;                /* max distance in output */
76420             if (dist > op) {                /* see if copy from window */
76421               op = dist - op;               /* distance back in window */
76422               if (op > whave) {
76423                 if (state.sane) {
76424                   strm.msg = 'invalid distance too far back';
76425                   state.mode = BAD;
76426                   break top;
76427                 }
76428
76429 // (!) This block is disabled in zlib defaults,
76430 // don't enable it for binary compatibility
76431 //#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR
76432 //                if (len <= op - whave) {
76433 //                  do {
76434 //                    output[_out++] = 0;
76435 //                  } while (--len);
76436 //                  continue top;
76437 //                }
76438 //                len -= op - whave;
76439 //                do {
76440 //                  output[_out++] = 0;
76441 //                } while (--op > whave);
76442 //                if (op === 0) {
76443 //                  from = _out - dist;
76444 //                  do {
76445 //                    output[_out++] = output[from++];
76446 //                  } while (--len);
76447 //                  continue top;
76448 //                }
76449 //#endif
76450               }
76451               from = 0; // window index
76452               from_source = s_window;
76453               if (wnext === 0) {           /* very common case */
76454                 from += wsize - op;
76455                 if (op < len) {         /* some from window */
76456                   len -= op;
76457                   do {
76458                     output[_out++] = s_window[from++];
76459                   } while (--op);
76460                   from = _out - dist;  /* rest from output */
76461                   from_source = output;
76462                 }
76463               }
76464               else if (wnext < op) {      /* wrap around window */
76465                 from += wsize + wnext - op;
76466                 op -= wnext;
76467                 if (op < len) {         /* some from end of window */
76468                   len -= op;
76469                   do {
76470                     output[_out++] = s_window[from++];
76471                   } while (--op);
76472                   from = 0;
76473                   if (wnext < len) {  /* some from start of window */
76474                     op = wnext;
76475                     len -= op;
76476                     do {
76477                       output[_out++] = s_window[from++];
76478                     } while (--op);
76479                     from = _out - dist;      /* rest from output */
76480                     from_source = output;
76481                   }
76482                 }
76483               }
76484               else {                      /* contiguous in window */
76485                 from += wnext - op;
76486                 if (op < len) {         /* some from window */
76487                   len -= op;
76488                   do {
76489                     output[_out++] = s_window[from++];
76490                   } while (--op);
76491                   from = _out - dist;  /* rest from output */
76492                   from_source = output;
76493                 }
76494               }
76495               while (len > 2) {
76496                 output[_out++] = from_source[from++];
76497                 output[_out++] = from_source[from++];
76498                 output[_out++] = from_source[from++];
76499                 len -= 3;
76500               }
76501               if (len) {
76502                 output[_out++] = from_source[from++];
76503                 if (len > 1) {
76504                   output[_out++] = from_source[from++];
76505                 }
76506               }
76507             }
76508             else {
76509               from = _out - dist;          /* copy direct from output */
76510               do {                        /* minimum length is three */
76511                 output[_out++] = output[from++];
76512                 output[_out++] = output[from++];
76513                 output[_out++] = output[from++];
76514                 len -= 3;
76515               } while (len > 2);
76516               if (len) {
76517                 output[_out++] = output[from++];
76518                 if (len > 1) {
76519                   output[_out++] = output[from++];
76520                 }
76521               }
76522             }
76523           }
76524           else if ((op & 64) === 0) {          /* 2nd level distance code */
76525             here = dcode[(here & 0xffff)/*here.val*/ + (hold & ((1 << op) - 1))];
76526             continue dodist;
76527           }
76528           else {
76529             strm.msg = 'invalid distance code';
76530             state.mode = BAD;
76531             break top;
76532           }
76533
76534           break; // need to emulate goto via "continue"
76535         }
76536       }
76537       else if ((op & 64) === 0) {              /* 2nd level length code */
76538         here = lcode[(here & 0xffff)/*here.val*/ + (hold & ((1 << op) - 1))];
76539         continue dolen;
76540       }
76541       else if (op & 32) {                     /* end-of-block */
76542         //Tracevv((stderr, "inflate:         end of block\n"));
76543         state.mode = TYPE;
76544         break top;
76545       }
76546       else {
76547         strm.msg = 'invalid literal/length code';
76548         state.mode = BAD;
76549         break top;
76550       }
76551
76552       break; // need to emulate goto via "continue"
76553     }
76554   } while (_in < last && _out < end);
76555
76556   /* return unused bytes (on entry, bits < 8, so in won't go too far back) */
76557   len = bits >> 3;
76558   _in -= len;
76559   bits -= len << 3;
76560   hold &= (1 << bits) - 1;
76561
76562   /* update state and return */
76563   strm.next_in = _in;
76564   strm.next_out = _out;
76565   strm.avail_in = (_in < last ? 5 + (last - _in) : 5 - (_in - last));
76566   strm.avail_out = (_out < end ? 257 + (end - _out) : 257 - (_out - end));
76567   state.hold = hold;
76568   state.bits = bits;
76569   return;
76570 };
76571
76572 // (C) 1995-2013 Jean-loup Gailly and Mark Adler
76573 // (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin
76574 //
76575 // This software is provided 'as-is', without any express or implied
76576 // warranty. In no event will the authors be held liable for any damages
76577 // arising from the use of this software.
76578 //
76579 // Permission is granted to anyone to use this software for any purpose,
76580 // including commercial applications, and to alter it and redistribute it
76581 // freely, subject to the following restrictions:
76582 //
76583 // 1. The origin of this software must not be misrepresented; you must not
76584 //   claim that you wrote the original software. If you use this software
76585 //   in a product, an acknowledgment in the product documentation would be
76586 //   appreciated but is not required.
76587 // 2. Altered source versions must be plainly marked as such, and must not be
76588 //   misrepresented as being the original software.
76589 // 3. This notice may not be removed or altered from any source distribution.
76590
76591 const MAXBITS = 15;
76592 const ENOUGH_LENS = 852;
76593 const ENOUGH_DISTS = 592;
76594 //const ENOUGH = (ENOUGH_LENS+ENOUGH_DISTS);
76595
76596 const CODES = 0;
76597 const LENS = 1;
76598 const DISTS = 2;
76599
76600 const lbase = new Uint16Array([ /* Length codes 257..285 base */
76601   3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
76602   35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0
76603 ]);
76604
76605 const lext = new Uint8Array([ /* Length codes 257..285 extra */
76606   16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18,
76607   19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 72, 78
76608 ]);
76609
76610 const dbase = new Uint16Array([ /* Distance codes 0..29 base */
76611   1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
76612   257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
76613   8193, 12289, 16385, 24577, 0, 0
76614 ]);
76615
76616 const dext = new Uint8Array([ /* Distance codes 0..29 extra */
76617   16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22,
76618   23, 23, 24, 24, 25, 25, 26, 26, 27, 27,
76619   28, 28, 29, 29, 64, 64
76620 ]);
76621
76622 const inflate_table = (type, lens, lens_index, codes, table, table_index, work, opts) =>
76623 {
76624   const bits = opts.bits;
76625       //here = opts.here; /* table entry for duplication */
76626
76627   let len = 0;               /* a code's length in bits */
76628   let sym = 0;               /* index of code symbols */
76629   let min = 0, max = 0;          /* minimum and maximum code lengths */
76630   let root = 0;              /* number of index bits for root table */
76631   let curr = 0;              /* number of index bits for current table */
76632   let drop = 0;              /* code bits to drop for sub-table */
76633   let left = 0;                   /* number of prefix codes available */
76634   let used = 0;              /* code entries in table used */
76635   let huff = 0;              /* Huffman code */
76636   let incr;              /* for incrementing code, index */
76637   let fill;              /* index for replicating entries */
76638   let low;               /* low bits for current root entry */
76639   let mask;              /* mask for low root bits */
76640   let next;             /* next available space in table */
76641   let base = null;     /* base value table to use */
76642   let base_index = 0;
76643 //  let shoextra;    /* extra bits table to use */
76644   let end;                    /* use base and extra for symbol > end */
76645   const count = new Uint16Array(MAXBITS + 1); //[MAXBITS+1];    /* number of codes of each length */
76646   const offs = new Uint16Array(MAXBITS + 1); //[MAXBITS+1];     /* offsets in table for each length */
76647   let extra = null;
76648   let extra_index = 0;
76649
76650   let here_bits, here_op, here_val;
76651
76652   /*
76653    Process a set of code lengths to create a canonical Huffman code.  The
76654    code lengths are lens[0..codes-1].  Each length corresponds to the
76655    symbols 0..codes-1.  The Huffman code is generated by first sorting the
76656    symbols by length from short to long, and retaining the symbol order
76657    for codes with equal lengths.  Then the code starts with all zero bits
76658    for the first code of the shortest length, and the codes are integer
76659    increments for the same length, and zeros are appended as the length
76660    increases.  For the deflate format, these bits are stored backwards
76661    from their more natural integer increment ordering, and so when the
76662    decoding tables are built in the large loop below, the integer codes
76663    are incremented backwards.
76664
76665    This routine assumes, but does not check, that all of the entries in
76666    lens[] are in the range 0..MAXBITS.  The caller must assure this.
76667    1..MAXBITS is interpreted as that code length.  zero means that that
76668    symbol does not occur in this code.
76669
76670    The codes are sorted by computing a count of codes for each length,
76671    creating from that a table of starting indices for each length in the
76672    sorted table, and then entering the symbols in order in the sorted
76673    table.  The sorted table is work[], with that space being provided by
76674    the caller.
76675
76676    The length counts are used for other purposes as well, i.e. finding
76677    the minimum and maximum length codes, determining if there are any
76678    codes at all, checking for a valid set of lengths, and looking ahead
76679    at length counts to determine sub-table sizes when building the
76680    decoding tables.
76681    */
76682
76683   /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */
76684   for (len = 0; len <= MAXBITS; len++) {
76685     count[len] = 0;
76686   }
76687   for (sym = 0; sym < codes; sym++) {
76688     count[lens[lens_index + sym]]++;
76689   }
76690
76691   /* bound code lengths, force root to be within code lengths */
76692   root = bits;
76693   for (max = MAXBITS; max >= 1; max--) {
76694     if (count[max] !== 0) { break; }
76695   }
76696   if (root > max) {
76697     root = max;
76698   }
76699   if (max === 0) {                     /* no symbols to code at all */
76700     //table.op[opts.table_index] = 64;  //here.op = (var char)64;    /* invalid code marker */
76701     //table.bits[opts.table_index] = 1;   //here.bits = (var char)1;
76702     //table.val[opts.table_index++] = 0;   //here.val = (var short)0;
76703     table[table_index++] = (1 << 24) | (64 << 16) | 0;
76704
76705
76706     //table.op[opts.table_index] = 64;
76707     //table.bits[opts.table_index] = 1;
76708     //table.val[opts.table_index++] = 0;
76709     table[table_index++] = (1 << 24) | (64 << 16) | 0;
76710
76711     opts.bits = 1;
76712     return 0;     /* no symbols, but wait for decoding to report error */
76713   }
76714   for (min = 1; min < max; min++) {
76715     if (count[min] !== 0) { break; }
76716   }
76717   if (root < min) {
76718     root = min;
76719   }
76720
76721   /* check for an over-subscribed or incomplete set of lengths */
76722   left = 1;
76723   for (len = 1; len <= MAXBITS; len++) {
76724     left <<= 1;
76725     left -= count[len];
76726     if (left < 0) {
76727       return -1;
76728     }        /* over-subscribed */
76729   }
76730   if (left > 0 && (type === CODES || max !== 1)) {
76731     return -1;                      /* incomplete set */
76732   }
76733
76734   /* generate offsets into symbol table for each length for sorting */
76735   offs[1] = 0;
76736   for (len = 1; len < MAXBITS; len++) {
76737     offs[len + 1] = offs[len] + count[len];
76738   }
76739
76740   /* sort symbols by length, by symbol order within each length */
76741   for (sym = 0; sym < codes; sym++) {
76742     if (lens[lens_index + sym] !== 0) {
76743       work[offs[lens[lens_index + sym]]++] = sym;
76744     }
76745   }
76746
76747   /*
76748    Create and fill in decoding tables.  In this loop, the table being
76749    filled is at next and has curr index bits.  The code being used is huff
76750    with length len.  That code is converted to an index by dropping drop
76751    bits off of the bottom.  For codes where len is less than drop + curr,
76752    those top drop + curr - len bits are incremented through all values to
76753    fill the table with replicated entries.
76754
76755    root is the number of index bits for the root table.  When len exceeds
76756    root, sub-tables are created pointed to by the root entry with an index
76757    of the low root bits of huff.  This is saved in low to check for when a
76758    new sub-table should be started.  drop is zero when the root table is
76759    being filled, and drop is root when sub-tables are being filled.
76760
76761    When a new sub-table is needed, it is necessary to look ahead in the
76762    code lengths to determine what size sub-table is needed.  The length
76763    counts are used for this, and so count[] is decremented as codes are
76764    entered in the tables.
76765
76766    used keeps track of how many table entries have been allocated from the
76767    provided *table space.  It is checked for LENS and DIST tables against
76768    the constants ENOUGH_LENS and ENOUGH_DISTS to guard against changes in
76769    the initial root table size constants.  See the comments in inftrees.h
76770    for more information.
76771
76772    sym increments through all symbols, and the loop terminates when
76773    all codes of length max, i.e. all codes, have been processed.  This
76774    routine permits incomplete codes, so another loop after this one fills
76775    in the rest of the decoding tables with invalid code markers.
76776    */
76777
76778   /* set up for code type */
76779   // poor man optimization - use if-else instead of switch,
76780   // to avoid deopts in old v8
76781   if (type === CODES) {
76782     base = extra = work;    /* dummy value--not used */
76783     end = 19;
76784
76785   } else if (type === LENS) {
76786     base = lbase;
76787     base_index -= 257;
76788     extra = lext;
76789     extra_index -= 257;
76790     end = 256;
76791
76792   } else {                    /* DISTS */
76793     base = dbase;
76794     extra = dext;
76795     end = -1;
76796   }
76797
76798   /* initialize opts for loop */
76799   huff = 0;                   /* starting code */
76800   sym = 0;                    /* starting code symbol */
76801   len = min;                  /* starting code length */
76802   next = table_index;              /* current table to fill in */
76803   curr = root;                /* current table index bits */
76804   drop = 0;                   /* current bits to drop from code for index */
76805   low = -1;                   /* trigger new sub-table when len > root */
76806   used = 1 << root;          /* use root table entries */
76807   mask = used - 1;            /* mask for comparing low */
76808
76809   /* check available table space */
76810   if ((type === LENS && used > ENOUGH_LENS) ||
76811     (type === DISTS && used > ENOUGH_DISTS)) {
76812     return 1;
76813   }
76814
76815   /* process all codes and make table entries */
76816   for (;;) {
76817     /* create table entry */
76818     here_bits = len - drop;
76819     if (work[sym] < end) {
76820       here_op = 0;
76821       here_val = work[sym];
76822     }
76823     else if (work[sym] > end) {
76824       here_op = extra[extra_index + work[sym]];
76825       here_val = base[base_index + work[sym]];
76826     }
76827     else {
76828       here_op = 32 + 64;         /* end of block */
76829       here_val = 0;
76830     }
76831
76832     /* replicate for those indices with low len bits equal to huff */
76833     incr = 1 << (len - drop);
76834     fill = 1 << curr;
76835     min = fill;                 /* save offset to next table */
76836     do {
76837       fill -= incr;
76838       table[next + (huff >> drop) + fill] = (here_bits << 24) | (here_op << 16) | here_val |0;
76839     } while (fill !== 0);
76840
76841     /* backwards increment the len-bit code huff */
76842     incr = 1 << (len - 1);
76843     while (huff & incr) {
76844       incr >>= 1;
76845     }
76846     if (incr !== 0) {
76847       huff &= incr - 1;
76848       huff += incr;
76849     } else {
76850       huff = 0;
76851     }
76852
76853     /* go to next symbol, update count, len */
76854     sym++;
76855     if (--count[len] === 0) {
76856       if (len === max) { break; }
76857       len = lens[lens_index + work[sym]];
76858     }
76859
76860     /* create new sub-table if needed */
76861     if (len > root && (huff & mask) !== low) {
76862       /* if first time, transition to sub-tables */
76863       if (drop === 0) {
76864         drop = root;
76865       }
76866
76867       /* increment past last table */
76868       next += min;            /* here min is 1 << curr */
76869
76870       /* determine length of next table */
76871       curr = len - drop;
76872       left = 1 << curr;
76873       while (curr + drop < max) {
76874         left -= count[curr + drop];
76875         if (left <= 0) { break; }
76876         curr++;
76877         left <<= 1;
76878       }
76879
76880       /* check for enough space */
76881       used += 1 << curr;
76882       if ((type === LENS && used > ENOUGH_LENS) ||
76883         (type === DISTS && used > ENOUGH_DISTS)) {
76884         return 1;
76885       }
76886
76887       /* point entry in root table to sub-table */
76888       low = huff & mask;
76889       /*table.op[low] = curr;
76890       table.bits[low] = root;
76891       table.val[low] = next - opts.table_index;*/
76892       table[low] = (root << 24) | (curr << 16) | (next - table_index) |0;
76893     }
76894   }
76895
76896   /* fill in remaining table entry if code is incomplete (guaranteed to have
76897    at most one remaining entry, since if the code is incomplete, the
76898    maximum code length that was allowed to get this far is one bit) */
76899   if (huff !== 0) {
76900     //table.op[next + huff] = 64;            /* invalid code marker */
76901     //table.bits[next + huff] = len - drop;
76902     //table.val[next + huff] = 0;
76903     table[next + huff] = ((len - drop) << 24) | (64 << 16) |0;
76904   }
76905
76906   /* set return parameters */
76907   //opts.table_index += used;
76908   opts.bits = root;
76909   return 0;
76910 };
76911
76912
76913 var inftrees = inflate_table;
76914
76915 // (C) 1995-2013 Jean-loup Gailly and Mark Adler
76916 // (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin
76917 //
76918 // This software is provided 'as-is', without any express or implied
76919 // warranty. In no event will the authors be held liable for any damages
76920 // arising from the use of this software.
76921 //
76922 // Permission is granted to anyone to use this software for any purpose,
76923 // including commercial applications, and to alter it and redistribute it
76924 // freely, subject to the following restrictions:
76925 //
76926 // 1. The origin of this software must not be misrepresented; you must not
76927 //   claim that you wrote the original software. If you use this software
76928 //   in a product, an acknowledgment in the product documentation would be
76929 //   appreciated but is not required.
76930 // 2. Altered source versions must be plainly marked as such, and must not be
76931 //   misrepresented as being the original software.
76932 // 3. This notice may not be removed or altered from any source distribution.
76933
76934
76935
76936
76937
76938
76939 const CODES$1 = 0;
76940 const LENS$1 = 1;
76941 const DISTS$1 = 2;
76942
76943 /* Public constants ==========================================================*/
76944 /* ===========================================================================*/
76945
76946 const {
76947   Z_FINISH: Z_FINISH$2, Z_BLOCK: Z_BLOCK$1, Z_TREES,
76948   Z_OK: Z_OK$2, Z_STREAM_END: Z_STREAM_END$2, Z_NEED_DICT, Z_STREAM_ERROR: Z_STREAM_ERROR$1, Z_DATA_ERROR: Z_DATA_ERROR$1, Z_MEM_ERROR, Z_BUF_ERROR: Z_BUF_ERROR$1,
76949   Z_DEFLATED: Z_DEFLATED$2
76950 } = constants;
76951
76952
76953 /* STATES ====================================================================*/
76954 /* ===========================================================================*/
76955
76956
76957 const    HEAD = 1;       /* i: waiting for magic header */
76958 const    FLAGS = 2;      /* i: waiting for method and flags (gzip) */
76959 const    TIME = 3;       /* i: waiting for modification time (gzip) */
76960 const    OS = 4;         /* i: waiting for extra flags and operating system (gzip) */
76961 const    EXLEN = 5;      /* i: waiting for extra length (gzip) */
76962 const    EXTRA = 6;      /* i: waiting for extra bytes (gzip) */
76963 const    NAME = 7;       /* i: waiting for end of file name (gzip) */
76964 const    COMMENT = 8;    /* i: waiting for end of comment (gzip) */
76965 const    HCRC = 9;       /* i: waiting for header crc (gzip) */
76966 const    DICTID = 10;    /* i: waiting for dictionary check value */
76967 const    DICT = 11;      /* waiting for inflateSetDictionary() call */
76968 const        TYPE$1 = 12;      /* i: waiting for type bits, including last-flag bit */
76969 const        TYPEDO = 13;    /* i: same, but skip check to exit inflate on new block */
76970 const        STORED = 14;    /* i: waiting for stored size (length and complement) */
76971 const        COPY_ = 15;     /* i/o: same as COPY below, but only first time in */
76972 const        COPY = 16;      /* i/o: waiting for input or output to copy stored block */
76973 const        TABLE = 17;     /* i: waiting for dynamic block table lengths */
76974 const        LENLENS = 18;   /* i: waiting for code length code lengths */
76975 const        CODELENS = 19;  /* i: waiting for length/lit and distance code lengths */
76976 const            LEN_ = 20;      /* i: same as LEN below, but only first time in */
76977 const            LEN = 21;       /* i: waiting for length/lit/eob code */
76978 const            LENEXT = 22;    /* i: waiting for length extra bits */
76979 const            DIST = 23;      /* i: waiting for distance code */
76980 const            DISTEXT = 24;   /* i: waiting for distance extra bits */
76981 const            MATCH = 25;     /* o: waiting for output space to copy string */
76982 const            LIT = 26;       /* o: waiting for output space to write literal */
76983 const    CHECK = 27;     /* i: waiting for 32-bit check value */
76984 const    LENGTH = 28;    /* i: waiting for 32-bit length (gzip) */
76985 const    DONE = 29;      /* finished check, done -- remain here until reset */
76986 const    BAD$1 = 30;       /* got a data error -- remain here until reset */
76987 const    MEM = 31;       /* got an inflate() memory error -- remain here until reset */
76988 const    SYNC = 32;      /* looking for synchronization bytes to restart inflate() */
76989
76990 /* ===========================================================================*/
76991
76992
76993
76994 const ENOUGH_LENS$1 = 852;
76995 const ENOUGH_DISTS$1 = 592;
76996 //const ENOUGH =  (ENOUGH_LENS+ENOUGH_DISTS);
76997
76998 const MAX_WBITS$1 = 15;
76999 /* 32K LZ77 window */
77000 const DEF_WBITS = MAX_WBITS$1;
77001
77002
77003 const zswap32 = (q) => {
77004
77005   return  (((q >>> 24) & 0xff) +
77006           ((q >>> 8) & 0xff00) +
77007           ((q & 0xff00) << 8) +
77008           ((q & 0xff) << 24));
77009 };
77010
77011
77012 function InflateState() {
77013   this.mode = 0;             /* current inflate mode */
77014   this.last = false;          /* true if processing last block */
77015   this.wrap = 0;              /* bit 0 true for zlib, bit 1 true for gzip */
77016   this.havedict = false;      /* true if dictionary provided */
77017   this.flags = 0;             /* gzip header method and flags (0 if zlib) */
77018   this.dmax = 0;              /* zlib header max distance (INFLATE_STRICT) */
77019   this.check = 0;             /* protected copy of check value */
77020   this.total = 0;             /* protected copy of output count */
77021   // TODO: may be {}
77022   this.head = null;           /* where to save gzip header information */
77023
77024   /* sliding window */
77025   this.wbits = 0;             /* log base 2 of requested window size */
77026   this.wsize = 0;             /* window size or zero if not using window */
77027   this.whave = 0;             /* valid bytes in the window */
77028   this.wnext = 0;             /* window write index */
77029   this.window = null;         /* allocated sliding window, if needed */
77030
77031   /* bit accumulator */
77032   this.hold = 0;              /* input bit accumulator */
77033   this.bits = 0;              /* number of bits in "in" */
77034
77035   /* for string and stored block copying */
77036   this.length = 0;            /* literal or length of data to copy */
77037   this.offset = 0;            /* distance back to copy string from */
77038
77039   /* for table and code decoding */
77040   this.extra = 0;             /* extra bits needed */
77041
77042   /* fixed and dynamic code tables */
77043   this.lencode = null;          /* starting table for length/literal codes */
77044   this.distcode = null;         /* starting table for distance codes */
77045   this.lenbits = 0;           /* index bits for lencode */
77046   this.distbits = 0;          /* index bits for distcode */
77047
77048   /* dynamic table building */
77049   this.ncode = 0;             /* number of code length code lengths */
77050   this.nlen = 0;              /* number of length code lengths */
77051   this.ndist = 0;             /* number of distance code lengths */
77052   this.have = 0;              /* number of code lengths in lens[] */
77053   this.next = null;              /* next available space in codes[] */
77054
77055   this.lens = new Uint16Array(320); /* temporary storage for code lengths */
77056   this.work = new Uint16Array(288); /* work area for code table building */
77057
77058   /*
77059    because we don't have pointers in js, we use lencode and distcode directly
77060    as buffers so we don't need codes
77061   */
77062   //this.codes = new Int32Array(ENOUGH);       /* space for code tables */
77063   this.lendyn = null;              /* dynamic table for length/literal codes (JS specific) */
77064   this.distdyn = null;             /* dynamic table for distance codes (JS specific) */
77065   this.sane = 0;                   /* if false, allow invalid distance too far */
77066   this.back = 0;                   /* bits back of last unprocessed length/lit */
77067   this.was = 0;                    /* initial length of match */
77068 }
77069
77070
77071 const inflateResetKeep = (strm) => {
77072
77073   if (!strm || !strm.state) { return Z_STREAM_ERROR$1; }
77074   const state = strm.state;
77075   strm.total_in = strm.total_out = state.total = 0;
77076   strm.msg = ''; /*Z_NULL*/
77077   if (state.wrap) {       /* to support ill-conceived Java test suite */
77078     strm.adler = state.wrap & 1;
77079   }
77080   state.mode = HEAD;
77081   state.last = 0;
77082   state.havedict = 0;
77083   state.dmax = 32768;
77084   state.head = null/*Z_NULL*/;
77085   state.hold = 0;
77086   state.bits = 0;
77087   //state.lencode = state.distcode = state.next = state.codes;
77088   state.lencode = state.lendyn = new Int32Array(ENOUGH_LENS$1);
77089   state.distcode = state.distdyn = new Int32Array(ENOUGH_DISTS$1);
77090
77091   state.sane = 1;
77092   state.back = -1;
77093   //Tracev((stderr, "inflate: reset\n"));
77094   return Z_OK$2;
77095 };
77096
77097
77098 const inflateReset = (strm) => {
77099
77100   if (!strm || !strm.state) { return Z_STREAM_ERROR$1; }
77101   const state = strm.state;
77102   state.wsize = 0;
77103   state.whave = 0;
77104   state.wnext = 0;
77105   return inflateResetKeep(strm);
77106
77107 };
77108
77109
77110 const inflateReset2 = (strm, windowBits) => {
77111   let wrap;
77112
77113   /* get the state */
77114   if (!strm || !strm.state) { return Z_STREAM_ERROR$1; }
77115   const state = strm.state;
77116
77117   /* extract wrap request from windowBits parameter */
77118   if (windowBits < 0) {
77119     wrap = 0;
77120     windowBits = -windowBits;
77121   }
77122   else {
77123     wrap = (windowBits >> 4) + 1;
77124     if (windowBits < 48) {
77125       windowBits &= 15;
77126     }
77127   }
77128
77129   /* set number of window bits, free window if different */
77130   if (windowBits && (windowBits < 8 || windowBits > 15)) {
77131     return Z_STREAM_ERROR$1;
77132   }
77133   if (state.window !== null && state.wbits !== windowBits) {
77134     state.window = null;
77135   }
77136
77137   /* update state and reset the rest of it */
77138   state.wrap = wrap;
77139   state.wbits = windowBits;
77140   return inflateReset(strm);
77141 };
77142
77143
77144 const inflateInit2 = (strm, windowBits) => {
77145
77146   if (!strm) { return Z_STREAM_ERROR$1; }
77147   //strm.msg = Z_NULL;                 /* in case we return an error */
77148
77149   const state = new InflateState();
77150
77151   //if (state === Z_NULL) return Z_MEM_ERROR;
77152   //Tracev((stderr, "inflate: allocated\n"));
77153   strm.state = state;
77154   state.window = null/*Z_NULL*/;
77155   const ret = inflateReset2(strm, windowBits);
77156   if (ret !== Z_OK$2) {
77157     strm.state = null/*Z_NULL*/;
77158   }
77159   return ret;
77160 };
77161
77162
77163 const inflateInit = (strm) => {
77164
77165   return inflateInit2(strm, DEF_WBITS);
77166 };
77167
77168
77169 /*
77170  Return state with length and distance decoding tables and index sizes set to
77171  fixed code decoding.  Normally this returns fixed tables from inffixed.h.
77172  If BUILDFIXED is defined, then instead this routine builds the tables the
77173  first time it's called, and returns those tables the first time and
77174  thereafter.  This reduces the size of the code by about 2K bytes, in
77175  exchange for a little execution time.  However, BUILDFIXED should not be
77176  used for threaded applications, since the rewriting of the tables and virgin
77177  may not be thread-safe.
77178  */
77179 let virgin = true;
77180
77181 let lenfix, distfix; // We have no pointers in JS, so keep tables separate
77182
77183
77184 const fixedtables = (state) => {
77185
77186   /* build fixed huffman tables if first call (may not be thread safe) */
77187   if (virgin) {
77188     lenfix = new Int32Array(512);
77189     distfix = new Int32Array(32);
77190
77191     /* literal/length table */
77192     let sym = 0;
77193     while (sym < 144) { state.lens[sym++] = 8; }
77194     while (sym < 256) { state.lens[sym++] = 9; }
77195     while (sym < 280) { state.lens[sym++] = 7; }
77196     while (sym < 288) { state.lens[sym++] = 8; }
77197
77198     inftrees(LENS$1,  state.lens, 0, 288, lenfix,   0, state.work, { bits: 9 });
77199
77200     /* distance table */
77201     sym = 0;
77202     while (sym < 32) { state.lens[sym++] = 5; }
77203
77204     inftrees(DISTS$1, state.lens, 0, 32,   distfix, 0, state.work, { bits: 5 });
77205
77206     /* do this just once */
77207     virgin = false;
77208   }
77209
77210   state.lencode = lenfix;
77211   state.lenbits = 9;
77212   state.distcode = distfix;
77213   state.distbits = 5;
77214 };
77215
77216
77217 /*
77218  Update the window with the last wsize (normally 32K) bytes written before
77219  returning.  If window does not exist yet, create it.  This is only called
77220  when a window is already in use, or when output has been written during this
77221  inflate call, but the end of the deflate stream has not been reached yet.
77222  It is also called to create a window for dictionary data when a dictionary
77223  is loaded.
77224
77225  Providing output buffers larger than 32K to inflate() should provide a speed
77226  advantage, since only the last 32K of output is copied to the sliding window
77227  upon return from inflate(), and since all distances after the first 32K of
77228  output will fall in the output data, making match copies simpler and faster.
77229  The advantage may be dependent on the size of the processor's data caches.
77230  */
77231 const updatewindow = (strm, src, end, copy) => {
77232
77233   let dist;
77234   const state = strm.state;
77235
77236   /* if it hasn't been done already, allocate space for the window */
77237   if (state.window === null) {
77238     state.wsize = 1 << state.wbits;
77239     state.wnext = 0;
77240     state.whave = 0;
77241
77242     state.window = new Uint8Array(state.wsize);
77243   }
77244
77245   /* copy state->wsize or less output bytes into the circular window */
77246   if (copy >= state.wsize) {
77247     state.window.set(src.subarray(end - state.wsize, end), 0);
77248     state.wnext = 0;
77249     state.whave = state.wsize;
77250   }
77251   else {
77252     dist = state.wsize - state.wnext;
77253     if (dist > copy) {
77254       dist = copy;
77255     }
77256     //zmemcpy(state->window + state->wnext, end - copy, dist);
77257     state.window.set(src.subarray(end - copy, end - copy + dist), state.wnext);
77258     copy -= dist;
77259     if (copy) {
77260       //zmemcpy(state->window, end - copy, copy);
77261       state.window.set(src.subarray(end - copy, end), 0);
77262       state.wnext = copy;
77263       state.whave = state.wsize;
77264     }
77265     else {
77266       state.wnext += dist;
77267       if (state.wnext === state.wsize) { state.wnext = 0; }
77268       if (state.whave < state.wsize) { state.whave += dist; }
77269     }
77270   }
77271   return 0;
77272 };
77273
77274
77275 const inflate = (strm, flush) => {
77276
77277   let state;
77278   let input, output;          // input/output buffers
77279   let next;                   /* next input INDEX */
77280   let put;                    /* next output INDEX */
77281   let have, left;             /* available input and output */
77282   let hold;                   /* bit buffer */
77283   let bits;                   /* bits in bit buffer */
77284   let _in, _out;              /* save starting available input and output */
77285   let copy;                   /* number of stored or match bytes to copy */
77286   let from;                   /* where to copy match bytes from */
77287   let from_source;
77288   let here = 0;               /* current decoding table entry */
77289   let here_bits, here_op, here_val; // paked "here" denormalized (JS specific)
77290   //let last;                   /* parent table entry */
77291   let last_bits, last_op, last_val; // paked "last" denormalized (JS specific)
77292   let len;                    /* length to copy for repeats, bits to drop */
77293   let ret;                    /* return code */
77294   const hbuf = new Uint8Array(4);    /* buffer for gzip header crc calculation */
77295   let opts;
77296
77297   let n; // temporary variable for NEED_BITS
77298
77299   const order = /* permutation of code lengths */
77300     new Uint8Array([ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 ]);
77301
77302
77303   if (!strm || !strm.state || !strm.output ||
77304       (!strm.input && strm.avail_in !== 0)) {
77305     return Z_STREAM_ERROR$1;
77306   }
77307
77308   state = strm.state;
77309   if (state.mode === TYPE$1) { state.mode = TYPEDO; }    /* skip check */
77310
77311
77312   //--- LOAD() ---
77313   put = strm.next_out;
77314   output = strm.output;
77315   left = strm.avail_out;
77316   next = strm.next_in;
77317   input = strm.input;
77318   have = strm.avail_in;
77319   hold = state.hold;
77320   bits = state.bits;
77321   //---
77322
77323   _in = have;
77324   _out = left;
77325   ret = Z_OK$2;
77326
77327   inf_leave: // goto emulation
77328   for (;;) {
77329     switch (state.mode) {
77330       case HEAD:
77331         if (state.wrap === 0) {
77332           state.mode = TYPEDO;
77333           break;
77334         }
77335         //=== NEEDBITS(16);
77336         while (bits < 16) {
77337           if (have === 0) { break inf_leave; }
77338           have--;
77339           hold += input[next++] << bits;
77340           bits += 8;
77341         }
77342         //===//
77343         if ((state.wrap & 2) && hold === 0x8b1f) {  /* gzip header */
77344           state.check = 0/*crc32(0L, Z_NULL, 0)*/;
77345           //=== CRC2(state.check, hold);
77346           hbuf[0] = hold & 0xff;
77347           hbuf[1] = (hold >>> 8) & 0xff;
77348           state.check = crc32_1(state.check, hbuf, 2, 0);
77349           //===//
77350
77351           //=== INITBITS();
77352           hold = 0;
77353           bits = 0;
77354           //===//
77355           state.mode = FLAGS;
77356           break;
77357         }
77358         state.flags = 0;           /* expect zlib header */
77359         if (state.head) {
77360           state.head.done = false;
77361         }
77362         if (!(state.wrap & 1) ||   /* check if zlib header allowed */
77363           (((hold & 0xff)/*BITS(8)*/ << 8) + (hold >> 8)) % 31) {
77364           strm.msg = 'incorrect header check';
77365           state.mode = BAD$1;
77366           break;
77367         }
77368         if ((hold & 0x0f)/*BITS(4)*/ !== Z_DEFLATED$2) {
77369           strm.msg = 'unknown compression method';
77370           state.mode = BAD$1;
77371           break;
77372         }
77373         //--- DROPBITS(4) ---//
77374         hold >>>= 4;
77375         bits -= 4;
77376         //---//
77377         len = (hold & 0x0f)/*BITS(4)*/ + 8;
77378         if (state.wbits === 0) {
77379           state.wbits = len;
77380         }
77381         else if (len > state.wbits) {
77382           strm.msg = 'invalid window size';
77383           state.mode = BAD$1;
77384           break;
77385         }
77386
77387         // !!! pako patch. Force use `options.windowBits` if passed.
77388         // Required to always use max window size by default.
77389         state.dmax = 1 << state.wbits;
77390         //state.dmax = 1 << len;
77391
77392         //Tracev((stderr, "inflate:   zlib header ok\n"));
77393         strm.adler = state.check = 1/*adler32(0L, Z_NULL, 0)*/;
77394         state.mode = hold & 0x200 ? DICTID : TYPE$1;
77395         //=== INITBITS();
77396         hold = 0;
77397         bits = 0;
77398         //===//
77399         break;
77400       case FLAGS:
77401         //=== NEEDBITS(16); */
77402         while (bits < 16) {
77403           if (have === 0) { break inf_leave; }
77404           have--;
77405           hold += input[next++] << bits;
77406           bits += 8;
77407         }
77408         //===//
77409         state.flags = hold;
77410         if ((state.flags & 0xff) !== Z_DEFLATED$2) {
77411           strm.msg = 'unknown compression method';
77412           state.mode = BAD$1;
77413           break;
77414         }
77415         if (state.flags & 0xe000) {
77416           strm.msg = 'unknown header flags set';
77417           state.mode = BAD$1;
77418           break;
77419         }
77420         if (state.head) {
77421           state.head.text = ((hold >> 8) & 1);
77422         }
77423         if (state.flags & 0x0200) {
77424           //=== CRC2(state.check, hold);
77425           hbuf[0] = hold & 0xff;
77426           hbuf[1] = (hold >>> 8) & 0xff;
77427           state.check = crc32_1(state.check, hbuf, 2, 0);
77428           //===//
77429         }
77430         //=== INITBITS();
77431         hold = 0;
77432         bits = 0;
77433         //===//
77434         state.mode = TIME;
77435         /* falls through */
77436       case TIME:
77437         //=== NEEDBITS(32); */
77438         while (bits < 32) {
77439           if (have === 0) { break inf_leave; }
77440           have--;
77441           hold += input[next++] << bits;
77442           bits += 8;
77443         }
77444         //===//
77445         if (state.head) {
77446           state.head.time = hold;
77447         }
77448         if (state.flags & 0x0200) {
77449           //=== CRC4(state.check, hold)
77450           hbuf[0] = hold & 0xff;
77451           hbuf[1] = (hold >>> 8) & 0xff;
77452           hbuf[2] = (hold >>> 16) & 0xff;
77453           hbuf[3] = (hold >>> 24) & 0xff;
77454           state.check = crc32_1(state.check, hbuf, 4, 0);
77455           //===
77456         }
77457         //=== INITBITS();
77458         hold = 0;
77459         bits = 0;
77460         //===//
77461         state.mode = OS;
77462         /* falls through */
77463       case OS:
77464         //=== NEEDBITS(16); */
77465         while (bits < 16) {
77466           if (have === 0) { break inf_leave; }
77467           have--;
77468           hold += input[next++] << bits;
77469           bits += 8;
77470         }
77471         //===//
77472         if (state.head) {
77473           state.head.xflags = (hold & 0xff);
77474           state.head.os = (hold >> 8);
77475         }
77476         if (state.flags & 0x0200) {
77477           //=== CRC2(state.check, hold);
77478           hbuf[0] = hold & 0xff;
77479           hbuf[1] = (hold >>> 8) & 0xff;
77480           state.check = crc32_1(state.check, hbuf, 2, 0);
77481           //===//
77482         }
77483         //=== INITBITS();
77484         hold = 0;
77485         bits = 0;
77486         //===//
77487         state.mode = EXLEN;
77488         /* falls through */
77489       case EXLEN:
77490         if (state.flags & 0x0400) {
77491           //=== NEEDBITS(16); */
77492           while (bits < 16) {
77493             if (have === 0) { break inf_leave; }
77494             have--;
77495             hold += input[next++] << bits;
77496             bits += 8;
77497           }
77498           //===//
77499           state.length = hold;
77500           if (state.head) {
77501             state.head.extra_len = hold;
77502           }
77503           if (state.flags & 0x0200) {
77504             //=== CRC2(state.check, hold);
77505             hbuf[0] = hold & 0xff;
77506             hbuf[1] = (hold >>> 8) & 0xff;
77507             state.check = crc32_1(state.check, hbuf, 2, 0);
77508             //===//
77509           }
77510           //=== INITBITS();
77511           hold = 0;
77512           bits = 0;
77513           //===//
77514         }
77515         else if (state.head) {
77516           state.head.extra = null/*Z_NULL*/;
77517         }
77518         state.mode = EXTRA;
77519         /* falls through */
77520       case EXTRA:
77521         if (state.flags & 0x0400) {
77522           copy = state.length;
77523           if (copy > have) { copy = have; }
77524           if (copy) {
77525             if (state.head) {
77526               len = state.head.extra_len - state.length;
77527               if (!state.head.extra) {
77528                 // Use untyped array for more convenient processing later
77529                 state.head.extra = new Uint8Array(state.head.extra_len);
77530               }
77531               state.head.extra.set(
77532                 input.subarray(
77533                   next,
77534                   // extra field is limited to 65536 bytes
77535                   // - no need for additional size check
77536                   next + copy
77537                 ),
77538                 /*len + copy > state.head.extra_max - len ? state.head.extra_max : copy,*/
77539                 len
77540               );
77541               //zmemcpy(state.head.extra + len, next,
77542               //        len + copy > state.head.extra_max ?
77543               //        state.head.extra_max - len : copy);
77544             }
77545             if (state.flags & 0x0200) {
77546               state.check = crc32_1(state.check, input, copy, next);
77547             }
77548             have -= copy;
77549             next += copy;
77550             state.length -= copy;
77551           }
77552           if (state.length) { break inf_leave; }
77553         }
77554         state.length = 0;
77555         state.mode = NAME;
77556         /* falls through */
77557       case NAME:
77558         if (state.flags & 0x0800) {
77559           if (have === 0) { break inf_leave; }
77560           copy = 0;
77561           do {
77562             // TODO: 2 or 1 bytes?
77563             len = input[next + copy++];
77564             /* use constant limit because in js we should not preallocate memory */
77565             if (state.head && len &&
77566                 (state.length < 65536 /*state.head.name_max*/)) {
77567               state.head.name += String.fromCharCode(len);
77568             }
77569           } while (len && copy < have);
77570
77571           if (state.flags & 0x0200) {
77572             state.check = crc32_1(state.check, input, copy, next);
77573           }
77574           have -= copy;
77575           next += copy;
77576           if (len) { break inf_leave; }
77577         }
77578         else if (state.head) {
77579           state.head.name = null;
77580         }
77581         state.length = 0;
77582         state.mode = COMMENT;
77583         /* falls through */
77584       case COMMENT:
77585         if (state.flags & 0x1000) {
77586           if (have === 0) { break inf_leave; }
77587           copy = 0;
77588           do {
77589             len = input[next + copy++];
77590             /* use constant limit because in js we should not preallocate memory */
77591             if (state.head && len &&
77592                 (state.length < 65536 /*state.head.comm_max*/)) {
77593               state.head.comment += String.fromCharCode(len);
77594             }
77595           } while (len && copy < have);
77596           if (state.flags & 0x0200) {
77597             state.check = crc32_1(state.check, input, copy, next);
77598           }
77599           have -= copy;
77600           next += copy;
77601           if (len) { break inf_leave; }
77602         }
77603         else if (state.head) {
77604           state.head.comment = null;
77605         }
77606         state.mode = HCRC;
77607         /* falls through */
77608       case HCRC:
77609         if (state.flags & 0x0200) {
77610           //=== NEEDBITS(16); */
77611           while (bits < 16) {
77612             if (have === 0) { break inf_leave; }
77613             have--;
77614             hold += input[next++] << bits;
77615             bits += 8;
77616           }
77617           //===//
77618           if (hold !== (state.check & 0xffff)) {
77619             strm.msg = 'header crc mismatch';
77620             state.mode = BAD$1;
77621             break;
77622           }
77623           //=== INITBITS();
77624           hold = 0;
77625           bits = 0;
77626           //===//
77627         }
77628         if (state.head) {
77629           state.head.hcrc = ((state.flags >> 9) & 1);
77630           state.head.done = true;
77631         }
77632         strm.adler = state.check = 0;
77633         state.mode = TYPE$1;
77634         break;
77635       case DICTID:
77636         //=== NEEDBITS(32); */
77637         while (bits < 32) {
77638           if (have === 0) { break inf_leave; }
77639           have--;
77640           hold += input[next++] << bits;
77641           bits += 8;
77642         }
77643         //===//
77644         strm.adler = state.check = zswap32(hold);
77645         //=== INITBITS();
77646         hold = 0;
77647         bits = 0;
77648         //===//
77649         state.mode = DICT;
77650         /* falls through */
77651       case DICT:
77652         if (state.havedict === 0) {
77653           //--- RESTORE() ---
77654           strm.next_out = put;
77655           strm.avail_out = left;
77656           strm.next_in = next;
77657           strm.avail_in = have;
77658           state.hold = hold;
77659           state.bits = bits;
77660           //---
77661           return Z_NEED_DICT;
77662         }
77663         strm.adler = state.check = 1/*adler32(0L, Z_NULL, 0)*/;
77664         state.mode = TYPE$1;
77665         /* falls through */
77666       case TYPE$1:
77667         if (flush === Z_BLOCK$1 || flush === Z_TREES) { break inf_leave; }
77668         /* falls through */
77669       case TYPEDO:
77670         if (state.last) {
77671           //--- BYTEBITS() ---//
77672           hold >>>= bits & 7;
77673           bits -= bits & 7;
77674           //---//
77675           state.mode = CHECK;
77676           break;
77677         }
77678         //=== NEEDBITS(3); */
77679         while (bits < 3) {
77680           if (have === 0) { break inf_leave; }
77681           have--;
77682           hold += input[next++] << bits;
77683           bits += 8;
77684         }
77685         //===//
77686         state.last = (hold & 0x01)/*BITS(1)*/;
77687         //--- DROPBITS(1) ---//
77688         hold >>>= 1;
77689         bits -= 1;
77690         //---//
77691
77692         switch ((hold & 0x03)/*BITS(2)*/) {
77693           case 0:                             /* stored block */
77694             //Tracev((stderr, "inflate:     stored block%s\n",
77695             //        state.last ? " (last)" : ""));
77696             state.mode = STORED;
77697             break;
77698           case 1:                             /* fixed block */
77699             fixedtables(state);
77700             //Tracev((stderr, "inflate:     fixed codes block%s\n",
77701             //        state.last ? " (last)" : ""));
77702             state.mode = LEN_;             /* decode codes */
77703             if (flush === Z_TREES) {
77704               //--- DROPBITS(2) ---//
77705               hold >>>= 2;
77706               bits -= 2;
77707               //---//
77708               break inf_leave;
77709             }
77710             break;
77711           case 2:                             /* dynamic block */
77712             //Tracev((stderr, "inflate:     dynamic codes block%s\n",
77713             //        state.last ? " (last)" : ""));
77714             state.mode = TABLE;
77715             break;
77716           case 3:
77717             strm.msg = 'invalid block type';
77718             state.mode = BAD$1;
77719         }
77720         //--- DROPBITS(2) ---//
77721         hold >>>= 2;
77722         bits -= 2;
77723         //---//
77724         break;
77725       case STORED:
77726         //--- BYTEBITS() ---// /* go to byte boundary */
77727         hold >>>= bits & 7;
77728         bits -= bits & 7;
77729         //---//
77730         //=== NEEDBITS(32); */
77731         while (bits < 32) {
77732           if (have === 0) { break inf_leave; }
77733           have--;
77734           hold += input[next++] << bits;
77735           bits += 8;
77736         }
77737         //===//
77738         if ((hold & 0xffff) !== ((hold >>> 16) ^ 0xffff)) {
77739           strm.msg = 'invalid stored block lengths';
77740           state.mode = BAD$1;
77741           break;
77742         }
77743         state.length = hold & 0xffff;
77744         //Tracev((stderr, "inflate:       stored length %u\n",
77745         //        state.length));
77746         //=== INITBITS();
77747         hold = 0;
77748         bits = 0;
77749         //===//
77750         state.mode = COPY_;
77751         if (flush === Z_TREES) { break inf_leave; }
77752         /* falls through */
77753       case COPY_:
77754         state.mode = COPY;
77755         /* falls through */
77756       case COPY:
77757         copy = state.length;
77758         if (copy) {
77759           if (copy > have) { copy = have; }
77760           if (copy > left) { copy = left; }
77761           if (copy === 0) { break inf_leave; }
77762           //--- zmemcpy(put, next, copy); ---
77763           output.set(input.subarray(next, next + copy), put);
77764           //---//
77765           have -= copy;
77766           next += copy;
77767           left -= copy;
77768           put += copy;
77769           state.length -= copy;
77770           break;
77771         }
77772         //Tracev((stderr, "inflate:       stored end\n"));
77773         state.mode = TYPE$1;
77774         break;
77775       case TABLE:
77776         //=== NEEDBITS(14); */
77777         while (bits < 14) {
77778           if (have === 0) { break inf_leave; }
77779           have--;
77780           hold += input[next++] << bits;
77781           bits += 8;
77782         }
77783         //===//
77784         state.nlen = (hold & 0x1f)/*BITS(5)*/ + 257;
77785         //--- DROPBITS(5) ---//
77786         hold >>>= 5;
77787         bits -= 5;
77788         //---//
77789         state.ndist = (hold & 0x1f)/*BITS(5)*/ + 1;
77790         //--- DROPBITS(5) ---//
77791         hold >>>= 5;
77792         bits -= 5;
77793         //---//
77794         state.ncode = (hold & 0x0f)/*BITS(4)*/ + 4;
77795         //--- DROPBITS(4) ---//
77796         hold >>>= 4;
77797         bits -= 4;
77798         //---//
77799 //#ifndef PKZIP_BUG_WORKAROUND
77800         if (state.nlen > 286 || state.ndist > 30) {
77801           strm.msg = 'too many length or distance symbols';
77802           state.mode = BAD$1;
77803           break;
77804         }
77805 //#endif
77806         //Tracev((stderr, "inflate:       table sizes ok\n"));
77807         state.have = 0;
77808         state.mode = LENLENS;
77809         /* falls through */
77810       case LENLENS:
77811         while (state.have < state.ncode) {
77812           //=== NEEDBITS(3);
77813           while (bits < 3) {
77814             if (have === 0) { break inf_leave; }
77815             have--;
77816             hold += input[next++] << bits;
77817             bits += 8;
77818           }
77819           //===//
77820           state.lens[order[state.have++]] = (hold & 0x07);//BITS(3);
77821           //--- DROPBITS(3) ---//
77822           hold >>>= 3;
77823           bits -= 3;
77824           //---//
77825         }
77826         while (state.have < 19) {
77827           state.lens[order[state.have++]] = 0;
77828         }
77829         // We have separate tables & no pointers. 2 commented lines below not needed.
77830         //state.next = state.codes;
77831         //state.lencode = state.next;
77832         // Switch to use dynamic table
77833         state.lencode = state.lendyn;
77834         state.lenbits = 7;
77835
77836         opts = { bits: state.lenbits };
77837         ret = inftrees(CODES$1, state.lens, 0, 19, state.lencode, 0, state.work, opts);
77838         state.lenbits = opts.bits;
77839
77840         if (ret) {
77841           strm.msg = 'invalid code lengths set';
77842           state.mode = BAD$1;
77843           break;
77844         }
77845         //Tracev((stderr, "inflate:       code lengths ok\n"));
77846         state.have = 0;
77847         state.mode = CODELENS;
77848         /* falls through */
77849       case CODELENS:
77850         while (state.have < state.nlen + state.ndist) {
77851           for (;;) {
77852             here = state.lencode[hold & ((1 << state.lenbits) - 1)];/*BITS(state.lenbits)*/
77853             here_bits = here >>> 24;
77854             here_op = (here >>> 16) & 0xff;
77855             here_val = here & 0xffff;
77856
77857             if ((here_bits) <= bits) { break; }
77858             //--- PULLBYTE() ---//
77859             if (have === 0) { break inf_leave; }
77860             have--;
77861             hold += input[next++] << bits;
77862             bits += 8;
77863             //---//
77864           }
77865           if (here_val < 16) {
77866             //--- DROPBITS(here.bits) ---//
77867             hold >>>= here_bits;
77868             bits -= here_bits;
77869             //---//
77870             state.lens[state.have++] = here_val;
77871           }
77872           else {
77873             if (here_val === 16) {
77874               //=== NEEDBITS(here.bits + 2);
77875               n = here_bits + 2;
77876               while (bits < n) {
77877                 if (have === 0) { break inf_leave; }
77878                 have--;
77879                 hold += input[next++] << bits;
77880                 bits += 8;
77881               }
77882               //===//
77883               //--- DROPBITS(here.bits) ---//
77884               hold >>>= here_bits;
77885               bits -= here_bits;
77886               //---//
77887               if (state.have === 0) {
77888                 strm.msg = 'invalid bit length repeat';
77889                 state.mode = BAD$1;
77890                 break;
77891               }
77892               len = state.lens[state.have - 1];
77893               copy = 3 + (hold & 0x03);//BITS(2);
77894               //--- DROPBITS(2) ---//
77895               hold >>>= 2;
77896               bits -= 2;
77897               //---//
77898             }
77899             else if (here_val === 17) {
77900               //=== NEEDBITS(here.bits + 3);
77901               n = here_bits + 3;
77902               while (bits < n) {
77903                 if (have === 0) { break inf_leave; }
77904                 have--;
77905                 hold += input[next++] << bits;
77906                 bits += 8;
77907               }
77908               //===//
77909               //--- DROPBITS(here.bits) ---//
77910               hold >>>= here_bits;
77911               bits -= here_bits;
77912               //---//
77913               len = 0;
77914               copy = 3 + (hold & 0x07);//BITS(3);
77915               //--- DROPBITS(3) ---//
77916               hold >>>= 3;
77917               bits -= 3;
77918               //---//
77919             }
77920             else {
77921               //=== NEEDBITS(here.bits + 7);
77922               n = here_bits + 7;
77923               while (bits < n) {
77924                 if (have === 0) { break inf_leave; }
77925                 have--;
77926                 hold += input[next++] << bits;
77927                 bits += 8;
77928               }
77929               //===//
77930               //--- DROPBITS(here.bits) ---//
77931               hold >>>= here_bits;
77932               bits -= here_bits;
77933               //---//
77934               len = 0;
77935               copy = 11 + (hold & 0x7f);//BITS(7);
77936               //--- DROPBITS(7) ---//
77937               hold >>>= 7;
77938               bits -= 7;
77939               //---//
77940             }
77941             if (state.have + copy > state.nlen + state.ndist) {
77942               strm.msg = 'invalid bit length repeat';
77943               state.mode = BAD$1;
77944               break;
77945             }
77946             while (copy--) {
77947               state.lens[state.have++] = len;
77948             }
77949           }
77950         }
77951
77952         /* handle error breaks in while */
77953         if (state.mode === BAD$1) { break; }
77954
77955         /* check for end-of-block code (better have one) */
77956         if (state.lens[256] === 0) {
77957           strm.msg = 'invalid code -- missing end-of-block';
77958           state.mode = BAD$1;
77959           break;
77960         }
77961
77962         /* build code tables -- note: do not change the lenbits or distbits
77963            values here (9 and 6) without reading the comments in inftrees.h
77964            concerning the ENOUGH constants, which depend on those values */
77965         state.lenbits = 9;
77966
77967         opts = { bits: state.lenbits };
77968         ret = inftrees(LENS$1, state.lens, 0, state.nlen, state.lencode, 0, state.work, opts);
77969         // We have separate tables & no pointers. 2 commented lines below not needed.
77970         // state.next_index = opts.table_index;
77971         state.lenbits = opts.bits;
77972         // state.lencode = state.next;
77973
77974         if (ret) {
77975           strm.msg = 'invalid literal/lengths set';
77976           state.mode = BAD$1;
77977           break;
77978         }
77979
77980         state.distbits = 6;
77981         //state.distcode.copy(state.codes);
77982         // Switch to use dynamic table
77983         state.distcode = state.distdyn;
77984         opts = { bits: state.distbits };
77985         ret = inftrees(DISTS$1, state.lens, state.nlen, state.ndist, state.distcode, 0, state.work, opts);
77986         // We have separate tables & no pointers. 2 commented lines below not needed.
77987         // state.next_index = opts.table_index;
77988         state.distbits = opts.bits;
77989         // state.distcode = state.next;
77990
77991         if (ret) {
77992           strm.msg = 'invalid distances set';
77993           state.mode = BAD$1;
77994           break;
77995         }
77996         //Tracev((stderr, 'inflate:       codes ok\n'));
77997         state.mode = LEN_;
77998         if (flush === Z_TREES) { break inf_leave; }
77999         /* falls through */
78000       case LEN_:
78001         state.mode = LEN;
78002         /* falls through */
78003       case LEN:
78004         if (have >= 6 && left >= 258) {
78005           //--- RESTORE() ---
78006           strm.next_out = put;
78007           strm.avail_out = left;
78008           strm.next_in = next;
78009           strm.avail_in = have;
78010           state.hold = hold;
78011           state.bits = bits;
78012           //---
78013           inffast(strm, _out);
78014           //--- LOAD() ---
78015           put = strm.next_out;
78016           output = strm.output;
78017           left = strm.avail_out;
78018           next = strm.next_in;
78019           input = strm.input;
78020           have = strm.avail_in;
78021           hold = state.hold;
78022           bits = state.bits;
78023           //---
78024
78025           if (state.mode === TYPE$1) {
78026             state.back = -1;
78027           }
78028           break;
78029         }
78030         state.back = 0;
78031         for (;;) {
78032           here = state.lencode[hold & ((1 << state.lenbits) - 1)];  /*BITS(state.lenbits)*/
78033           here_bits = here >>> 24;
78034           here_op = (here >>> 16) & 0xff;
78035           here_val = here & 0xffff;
78036
78037           if (here_bits <= bits) { break; }
78038           //--- PULLBYTE() ---//
78039           if (have === 0) { break inf_leave; }
78040           have--;
78041           hold += input[next++] << bits;
78042           bits += 8;
78043           //---//
78044         }
78045         if (here_op && (here_op & 0xf0) === 0) {
78046           last_bits = here_bits;
78047           last_op = here_op;
78048           last_val = here_val;
78049           for (;;) {
78050             here = state.lencode[last_val +
78051                     ((hold & ((1 << (last_bits + last_op)) - 1))/*BITS(last.bits + last.op)*/ >> last_bits)];
78052             here_bits = here >>> 24;
78053             here_op = (here >>> 16) & 0xff;
78054             here_val = here & 0xffff;
78055
78056             if ((last_bits + here_bits) <= bits) { break; }
78057             //--- PULLBYTE() ---//
78058             if (have === 0) { break inf_leave; }
78059             have--;
78060             hold += input[next++] << bits;
78061             bits += 8;
78062             //---//
78063           }
78064           //--- DROPBITS(last.bits) ---//
78065           hold >>>= last_bits;
78066           bits -= last_bits;
78067           //---//
78068           state.back += last_bits;
78069         }
78070         //--- DROPBITS(here.bits) ---//
78071         hold >>>= here_bits;
78072         bits -= here_bits;
78073         //---//
78074         state.back += here_bits;
78075         state.length = here_val;
78076         if (here_op === 0) {
78077           //Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ?
78078           //        "inflate:         literal '%c'\n" :
78079           //        "inflate:         literal 0x%02x\n", here.val));
78080           state.mode = LIT;
78081           break;
78082         }
78083         if (here_op & 32) {
78084           //Tracevv((stderr, "inflate:         end of block\n"));
78085           state.back = -1;
78086           state.mode = TYPE$1;
78087           break;
78088         }
78089         if (here_op & 64) {
78090           strm.msg = 'invalid literal/length code';
78091           state.mode = BAD$1;
78092           break;
78093         }
78094         state.extra = here_op & 15;
78095         state.mode = LENEXT;
78096         /* falls through */
78097       case LENEXT:
78098         if (state.extra) {
78099           //=== NEEDBITS(state.extra);
78100           n = state.extra;
78101           while (bits < n) {
78102             if (have === 0) { break inf_leave; }
78103             have--;
78104             hold += input[next++] << bits;
78105             bits += 8;
78106           }
78107           //===//
78108           state.length += hold & ((1 << state.extra) - 1)/*BITS(state.extra)*/;
78109           //--- DROPBITS(state.extra) ---//
78110           hold >>>= state.extra;
78111           bits -= state.extra;
78112           //---//
78113           state.back += state.extra;
78114         }
78115         //Tracevv((stderr, "inflate:         length %u\n", state.length));
78116         state.was = state.length;
78117         state.mode = DIST;
78118         /* falls through */
78119       case DIST:
78120         for (;;) {
78121           here = state.distcode[hold & ((1 << state.distbits) - 1)];/*BITS(state.distbits)*/
78122           here_bits = here >>> 24;
78123           here_op = (here >>> 16) & 0xff;
78124           here_val = here & 0xffff;
78125
78126           if ((here_bits) <= bits) { break; }
78127           //--- PULLBYTE() ---//
78128           if (have === 0) { break inf_leave; }
78129           have--;
78130           hold += input[next++] << bits;
78131           bits += 8;
78132           //---//
78133         }
78134         if ((here_op & 0xf0) === 0) {
78135           last_bits = here_bits;
78136           last_op = here_op;
78137           last_val = here_val;
78138           for (;;) {
78139             here = state.distcode[last_val +
78140                     ((hold & ((1 << (last_bits + last_op)) - 1))/*BITS(last.bits + last.op)*/ >> last_bits)];
78141             here_bits = here >>> 24;
78142             here_op = (here >>> 16) & 0xff;
78143             here_val = here & 0xffff;
78144
78145             if ((last_bits + here_bits) <= bits) { break; }
78146             //--- PULLBYTE() ---//
78147             if (have === 0) { break inf_leave; }
78148             have--;
78149             hold += input[next++] << bits;
78150             bits += 8;
78151             //---//
78152           }
78153           //--- DROPBITS(last.bits) ---//
78154           hold >>>= last_bits;
78155           bits -= last_bits;
78156           //---//
78157           state.back += last_bits;
78158         }
78159         //--- DROPBITS(here.bits) ---//
78160         hold >>>= here_bits;
78161         bits -= here_bits;
78162         //---//
78163         state.back += here_bits;
78164         if (here_op & 64) {
78165           strm.msg = 'invalid distance code';
78166           state.mode = BAD$1;
78167           break;
78168         }
78169         state.offset = here_val;
78170         state.extra = (here_op) & 15;
78171         state.mode = DISTEXT;
78172         /* falls through */
78173       case DISTEXT:
78174         if (state.extra) {
78175           //=== NEEDBITS(state.extra);
78176           n = state.extra;
78177           while (bits < n) {
78178             if (have === 0) { break inf_leave; }
78179             have--;
78180             hold += input[next++] << bits;
78181             bits += 8;
78182           }
78183           //===//
78184           state.offset += hold & ((1 << state.extra) - 1)/*BITS(state.extra)*/;
78185           //--- DROPBITS(state.extra) ---//
78186           hold >>>= state.extra;
78187           bits -= state.extra;
78188           //---//
78189           state.back += state.extra;
78190         }
78191 //#ifdef INFLATE_STRICT
78192         if (state.offset > state.dmax) {
78193           strm.msg = 'invalid distance too far back';
78194           state.mode = BAD$1;
78195           break;
78196         }
78197 //#endif
78198         //Tracevv((stderr, "inflate:         distance %u\n", state.offset));
78199         state.mode = MATCH;
78200         /* falls through */
78201       case MATCH:
78202         if (left === 0) { break inf_leave; }
78203         copy = _out - left;
78204         if (state.offset > copy) {         /* copy from window */
78205           copy = state.offset - copy;
78206           if (copy > state.whave) {
78207             if (state.sane) {
78208               strm.msg = 'invalid distance too far back';
78209               state.mode = BAD$1;
78210               break;
78211             }
78212 // (!) This block is disabled in zlib defaults,
78213 // don't enable it for binary compatibility
78214 //#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR
78215 //          Trace((stderr, "inflate.c too far\n"));
78216 //          copy -= state.whave;
78217 //          if (copy > state.length) { copy = state.length; }
78218 //          if (copy > left) { copy = left; }
78219 //          left -= copy;
78220 //          state.length -= copy;
78221 //          do {
78222 //            output[put++] = 0;
78223 //          } while (--copy);
78224 //          if (state.length === 0) { state.mode = LEN; }
78225 //          break;
78226 //#endif
78227           }
78228           if (copy > state.wnext) {
78229             copy -= state.wnext;
78230             from = state.wsize - copy;
78231           }
78232           else {
78233             from = state.wnext - copy;
78234           }
78235           if (copy > state.length) { copy = state.length; }
78236           from_source = state.window;
78237         }
78238         else {                              /* copy from output */
78239           from_source = output;
78240           from = put - state.offset;
78241           copy = state.length;
78242         }
78243         if (copy > left) { copy = left; }
78244         left -= copy;
78245         state.length -= copy;
78246         do {
78247           output[put++] = from_source[from++];
78248         } while (--copy);
78249         if (state.length === 0) { state.mode = LEN; }
78250         break;
78251       case LIT:
78252         if (left === 0) { break inf_leave; }
78253         output[put++] = state.length;
78254         left--;
78255         state.mode = LEN;
78256         break;
78257       case CHECK:
78258         if (state.wrap) {
78259           //=== NEEDBITS(32);
78260           while (bits < 32) {
78261             if (have === 0) { break inf_leave; }
78262             have--;
78263             // Use '|' instead of '+' to make sure that result is signed
78264             hold |= input[next++] << bits;
78265             bits += 8;
78266           }
78267           //===//
78268           _out -= left;
78269           strm.total_out += _out;
78270           state.total += _out;
78271           if (_out) {
78272             strm.adler = state.check =
78273                 /*UPDATE(state.check, put - _out, _out);*/
78274                 (state.flags ? crc32_1(state.check, output, _out, put - _out) : adler32_1(state.check, output, _out, put - _out));
78275
78276           }
78277           _out = left;
78278           // NB: crc32 stored as signed 32-bit int, zswap32 returns signed too
78279           if ((state.flags ? hold : zswap32(hold)) !== state.check) {
78280             strm.msg = 'incorrect data check';
78281             state.mode = BAD$1;
78282             break;
78283           }
78284           //=== INITBITS();
78285           hold = 0;
78286           bits = 0;
78287           //===//
78288           //Tracev((stderr, "inflate:   check matches trailer\n"));
78289         }
78290         state.mode = LENGTH;
78291         /* falls through */
78292       case LENGTH:
78293         if (state.wrap && state.flags) {
78294           //=== NEEDBITS(32);
78295           while (bits < 32) {
78296             if (have === 0) { break inf_leave; }
78297             have--;
78298             hold += input[next++] << bits;
78299             bits += 8;
78300           }
78301           //===//
78302           if (hold !== (state.total & 0xffffffff)) {
78303             strm.msg = 'incorrect length check';
78304             state.mode = BAD$1;
78305             break;
78306           }
78307           //=== INITBITS();
78308           hold = 0;
78309           bits = 0;
78310           //===//
78311           //Tracev((stderr, "inflate:   length matches trailer\n"));
78312         }
78313         state.mode = DONE;
78314         /* falls through */
78315       case DONE:
78316         ret = Z_STREAM_END$2;
78317         break inf_leave;
78318       case BAD$1:
78319         ret = Z_DATA_ERROR$1;
78320         break inf_leave;
78321       case MEM:
78322         return Z_MEM_ERROR;
78323       case SYNC:
78324         /* falls through */
78325       default:
78326         return Z_STREAM_ERROR$1;
78327     }
78328   }
78329
78330   // inf_leave <- here is real place for "goto inf_leave", emulated via "break inf_leave"
78331
78332   /*
78333      Return from inflate(), updating the total counts and the check value.
78334      If there was no progress during the inflate() call, return a buffer
78335      error.  Call updatewindow() to create and/or update the window state.
78336      Note: a memory error from inflate() is non-recoverable.
78337    */
78338
78339   //--- RESTORE() ---
78340   strm.next_out = put;
78341   strm.avail_out = left;
78342   strm.next_in = next;
78343   strm.avail_in = have;
78344   state.hold = hold;
78345   state.bits = bits;
78346   //---
78347
78348   if (state.wsize || (_out !== strm.avail_out && state.mode < BAD$1 &&
78349                       (state.mode < CHECK || flush !== Z_FINISH$2))) {
78350     if (updatewindow(strm, strm.output, strm.next_out, _out - strm.avail_out)) ;
78351   }
78352   _in -= strm.avail_in;
78353   _out -= strm.avail_out;
78354   strm.total_in += _in;
78355   strm.total_out += _out;
78356   state.total += _out;
78357   if (state.wrap && _out) {
78358     strm.adler = state.check = /*UPDATE(state.check, strm.next_out - _out, _out);*/
78359       (state.flags ? crc32_1(state.check, output, _out, strm.next_out - _out) : adler32_1(state.check, output, _out, strm.next_out - _out));
78360   }
78361   strm.data_type = state.bits + (state.last ? 64 : 0) +
78362                     (state.mode === TYPE$1 ? 128 : 0) +
78363                     (state.mode === LEN_ || state.mode === COPY_ ? 256 : 0);
78364   if (((_in === 0 && _out === 0) || flush === Z_FINISH$2) && ret === Z_OK$2) {
78365     ret = Z_BUF_ERROR$1;
78366   }
78367   return ret;
78368 };
78369
78370
78371 const inflateEnd = (strm) => {
78372
78373   if (!strm || !strm.state /*|| strm->zfree == (free_func)0*/) {
78374     return Z_STREAM_ERROR$1;
78375   }
78376
78377   let state = strm.state;
78378   if (state.window) {
78379     state.window = null;
78380   }
78381   strm.state = null;
78382   return Z_OK$2;
78383 };
78384
78385
78386 const inflateGetHeader = (strm, head) => {
78387
78388   /* check state */
78389   if (!strm || !strm.state) { return Z_STREAM_ERROR$1; }
78390   const state = strm.state;
78391   if ((state.wrap & 2) === 0) { return Z_STREAM_ERROR$1; }
78392
78393   /* save header structure */
78394   state.head = head;
78395   head.done = false;
78396   return Z_OK$2;
78397 };
78398
78399
78400 const inflateSetDictionary = (strm, dictionary) => {
78401   const dictLength = dictionary.length;
78402
78403   let state;
78404   let dictid;
78405   let ret;
78406
78407   /* check state */
78408   if (!strm /* == Z_NULL */ || !strm.state /* == Z_NULL */) { return Z_STREAM_ERROR$1; }
78409   state = strm.state;
78410
78411   if (state.wrap !== 0 && state.mode !== DICT) {
78412     return Z_STREAM_ERROR$1;
78413   }
78414
78415   /* check for correct dictionary identifier */
78416   if (state.mode === DICT) {
78417     dictid = 1; /* adler32(0, null, 0)*/
78418     /* dictid = adler32(dictid, dictionary, dictLength); */
78419     dictid = adler32_1(dictid, dictionary, dictLength, 0);
78420     if (dictid !== state.check) {
78421       return Z_DATA_ERROR$1;
78422     }
78423   }
78424   /* copy dictionary to window using updatewindow(), which will amend the
78425    existing dictionary if appropriate */
78426   ret = updatewindow(strm, dictionary, dictLength, dictLength);
78427   if (ret) {
78428     state.mode = MEM;
78429     return Z_MEM_ERROR;
78430   }
78431   state.havedict = 1;
78432   // Tracev((stderr, "inflate:   dictionary set\n"));
78433   return Z_OK$2;
78434 };
78435
78436
78437 var inflateReset_1 = inflateReset;
78438 var inflateReset2_1 = inflateReset2;
78439 var inflateResetKeep_1 = inflateResetKeep;
78440 var inflateInit_1 = inflateInit;
78441 var inflateInit2_1 = inflateInit2;
78442 var inflate_2 = inflate;
78443 var inflateEnd_1 = inflateEnd;
78444 var inflateGetHeader_1 = inflateGetHeader;
78445 var inflateSetDictionary_1 = inflateSetDictionary;
78446 var inflateInfo = 'pako inflate (from Nodeca project)';
78447
78448 /* Not implemented
78449 module.exports.inflateCopy = inflateCopy;
78450 module.exports.inflateGetDictionary = inflateGetDictionary;
78451 module.exports.inflateMark = inflateMark;
78452 module.exports.inflatePrime = inflatePrime;
78453 module.exports.inflateSync = inflateSync;
78454 module.exports.inflateSyncPoint = inflateSyncPoint;
78455 module.exports.inflateUndermine = inflateUndermine;
78456 */
78457
78458 var inflate_1 = {
78459         inflateReset: inflateReset_1,
78460         inflateReset2: inflateReset2_1,
78461         inflateResetKeep: inflateResetKeep_1,
78462         inflateInit: inflateInit_1,
78463         inflateInit2: inflateInit2_1,
78464         inflate: inflate_2,
78465         inflateEnd: inflateEnd_1,
78466         inflateGetHeader: inflateGetHeader_1,
78467         inflateSetDictionary: inflateSetDictionary_1,
78468         inflateInfo: inflateInfo
78469 };
78470
78471 // (C) 1995-2013 Jean-loup Gailly and Mark Adler
78472 // (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin
78473 //
78474 // This software is provided 'as-is', without any express or implied
78475 // warranty. In no event will the authors be held liable for any damages
78476 // arising from the use of this software.
78477 //
78478 // Permission is granted to anyone to use this software for any purpose,
78479 // including commercial applications, and to alter it and redistribute it
78480 // freely, subject to the following restrictions:
78481 //
78482 // 1. The origin of this software must not be misrepresented; you must not
78483 //   claim that you wrote the original software. If you use this software
78484 //   in a product, an acknowledgment in the product documentation would be
78485 //   appreciated but is not required.
78486 // 2. Altered source versions must be plainly marked as such, and must not be
78487 //   misrepresented as being the original software.
78488 // 3. This notice may not be removed or altered from any source distribution.
78489
78490 function GZheader() {
78491   /* true if compressed data believed to be text */
78492   this.text       = 0;
78493   /* modification time */
78494   this.time       = 0;
78495   /* extra flags (not used when writing a gzip file) */
78496   this.xflags     = 0;
78497   /* operating system */
78498   this.os         = 0;
78499   /* pointer to extra field or Z_NULL if none */
78500   this.extra      = null;
78501   /* extra field length (valid if extra != Z_NULL) */
78502   this.extra_len  = 0; // Actually, we don't need it in JS,
78503                        // but leave for few code modifications
78504
78505   //
78506   // Setup limits is not necessary because in js we should not preallocate memory
78507   // for inflate use constant limit in 65536 bytes
78508   //
78509
78510   /* space at extra (only when reading header) */
78511   // this.extra_max  = 0;
78512   /* pointer to zero-terminated file name or Z_NULL */
78513   this.name       = '';
78514   /* space at name (only when reading header) */
78515   // this.name_max   = 0;
78516   /* pointer to zero-terminated comment or Z_NULL */
78517   this.comment    = '';
78518   /* space at comment (only when reading header) */
78519   // this.comm_max   = 0;
78520   /* true if there was or will be a header crc */
78521   this.hcrc       = 0;
78522   /* true when done reading gzip header (not used when writing a gzip file) */
78523   this.done       = false;
78524 }
78525
78526 var gzheader = GZheader;
78527
78528 const toString$1 = Object.prototype.toString;
78529
78530 /* Public constants ==========================================================*/
78531 /* ===========================================================================*/
78532
78533 const {
78534   Z_NO_FLUSH: Z_NO_FLUSH$2, Z_FINISH: Z_FINISH$3,
78535   Z_OK: Z_OK$3, Z_STREAM_END: Z_STREAM_END$3, Z_NEED_DICT: Z_NEED_DICT$1, Z_STREAM_ERROR: Z_STREAM_ERROR$2, Z_DATA_ERROR: Z_DATA_ERROR$2, Z_MEM_ERROR: Z_MEM_ERROR$1
78536 } = constants;
78537
78538 /* ===========================================================================*/
78539
78540
78541 /**
78542  * class Inflate
78543  *
78544  * Generic JS-style wrapper for zlib calls. If you don't need
78545  * streaming behaviour - use more simple functions: [[inflate]]
78546  * and [[inflateRaw]].
78547  **/
78548
78549 /* internal
78550  * inflate.chunks -> Array
78551  *
78552  * Chunks of output data, if [[Inflate#onData]] not overridden.
78553  **/
78554
78555 /**
78556  * Inflate.result -> Uint8Array|String
78557  *
78558  * Uncompressed result, generated by default [[Inflate#onData]]
78559  * and [[Inflate#onEnd]] handlers. Filled after you push last chunk
78560  * (call [[Inflate#push]] with `Z_FINISH` / `true` param).
78561  **/
78562
78563 /**
78564  * Inflate.err -> Number
78565  *
78566  * Error code after inflate finished. 0 (Z_OK) on success.
78567  * Should be checked if broken data possible.
78568  **/
78569
78570 /**
78571  * Inflate.msg -> String
78572  *
78573  * Error message, if [[Inflate.err]] != 0
78574  **/
78575
78576
78577 /**
78578  * new Inflate(options)
78579  * - options (Object): zlib inflate options.
78580  *
78581  * Creates new inflator instance with specified params. Throws exception
78582  * on bad params. Supported options:
78583  *
78584  * - `windowBits`
78585  * - `dictionary`
78586  *
78587  * [http://zlib.net/manual.html#Advanced](http://zlib.net/manual.html#Advanced)
78588  * for more information on these.
78589  *
78590  * Additional options, for internal needs:
78591  *
78592  * - `chunkSize` - size of generated data chunks (16K by default)
78593  * - `raw` (Boolean) - do raw inflate
78594  * - `to` (String) - if equal to 'string', then result will be converted
78595  *   from utf8 to utf16 (javascript) string. When string output requested,
78596  *   chunk length can differ from `chunkSize`, depending on content.
78597  *
78598  * By default, when no options set, autodetect deflate/gzip data format via
78599  * wrapper header.
78600  *
78601  * ##### Example:
78602  *
78603  * ```javascript
78604  * const pako = require('pako')
78605  * const chunk1 = new Uint8Array([1,2,3,4,5,6,7,8,9])
78606  * const chunk2 = new Uint8Array([10,11,12,13,14,15,16,17,18,19]);
78607  *
78608  * const inflate = new pako.Inflate({ level: 3});
78609  *
78610  * inflate.push(chunk1, false);
78611  * inflate.push(chunk2, true);  // true -> last chunk
78612  *
78613  * if (inflate.err) { throw new Error(inflate.err); }
78614  *
78615  * console.log(inflate.result);
78616  * ```
78617  **/
78618 function Inflate(options) {
78619   this.options = common.assign({
78620     chunkSize: 1024 * 64,
78621     windowBits: 15,
78622     to: ''
78623   }, options || {});
78624
78625   const opt = this.options;
78626
78627   // Force window size for `raw` data, if not set directly,
78628   // because we have no header for autodetect.
78629   if (opt.raw && (opt.windowBits >= 0) && (opt.windowBits < 16)) {
78630     opt.windowBits = -opt.windowBits;
78631     if (opt.windowBits === 0) { opt.windowBits = -15; }
78632   }
78633
78634   // If `windowBits` not defined (and mode not raw) - set autodetect flag for gzip/deflate
78635   if ((opt.windowBits >= 0) && (opt.windowBits < 16) &&
78636       !(options && options.windowBits)) {
78637     opt.windowBits += 32;
78638   }
78639
78640   // Gzip header has no info about windows size, we can do autodetect only
78641   // for deflate. So, if window size not set, force it to max when gzip possible
78642   if ((opt.windowBits > 15) && (opt.windowBits < 48)) {
78643     // bit 3 (16) -> gzipped data
78644     // bit 4 (32) -> autodetect gzip/deflate
78645     if ((opt.windowBits & 15) === 0) {
78646       opt.windowBits |= 15;
78647     }
78648   }
78649
78650   this.err    = 0;      // error code, if happens (0 = Z_OK)
78651   this.msg    = '';     // error message
78652   this.ended  = false;  // used to avoid multiple onEnd() calls
78653   this.chunks = [];     // chunks of compressed data
78654
78655   this.strm   = new zstream();
78656   this.strm.avail_out = 0;
78657
78658   let status  = inflate_1.inflateInit2(
78659     this.strm,
78660     opt.windowBits
78661   );
78662
78663   if (status !== Z_OK$3) {
78664     throw new Error(messages[status]);
78665   }
78666
78667   this.header = new gzheader();
78668
78669   inflate_1.inflateGetHeader(this.strm, this.header);
78670
78671   // Setup dictionary
78672   if (opt.dictionary) {
78673     // Convert data if needed
78674     if (typeof opt.dictionary === 'string') {
78675       opt.dictionary = strings.string2buf(opt.dictionary);
78676     } else if (toString$1.call(opt.dictionary) === '[object ArrayBuffer]') {
78677       opt.dictionary = new Uint8Array(opt.dictionary);
78678     }
78679     if (opt.raw) { //In raw mode we need to set the dictionary early
78680       status = inflate_1.inflateSetDictionary(this.strm, opt.dictionary);
78681       if (status !== Z_OK$3) {
78682         throw new Error(messages[status]);
78683       }
78684     }
78685   }
78686 }
78687
78688 /**
78689  * Inflate#push(data[, flush_mode]) -> Boolean
78690  * - data (Uint8Array|ArrayBuffer): input data
78691  * - flush_mode (Number|Boolean): 0..6 for corresponding Z_NO_FLUSH..Z_TREE
78692  *   flush modes. See constants. Skipped or `false` means Z_NO_FLUSH,
78693  *   `true` means Z_FINISH.
78694  *
78695  * Sends input data to inflate pipe, generating [[Inflate#onData]] calls with
78696  * new output chunks. Returns `true` on success. If end of stream detected,
78697  * [[Inflate#onEnd]] will be called.
78698  *
78699  * `flush_mode` is not needed for normal operation, because end of stream
78700  * detected automatically. You may try to use it for advanced things, but
78701  * this functionality was not tested.
78702  *
78703  * On fail call [[Inflate#onEnd]] with error code and return false.
78704  *
78705  * ##### Example
78706  *
78707  * ```javascript
78708  * push(chunk, false); // push one of data chunks
78709  * ...
78710  * push(chunk, true);  // push last chunk
78711  * ```
78712  **/
78713 Inflate.prototype.push = function (data, flush_mode) {
78714   const strm = this.strm;
78715   const chunkSize = this.options.chunkSize;
78716   const dictionary = this.options.dictionary;
78717   let status, _flush_mode, last_avail_out;
78718
78719   if (this.ended) return false;
78720
78721   if (flush_mode === ~~flush_mode) _flush_mode = flush_mode;
78722   else _flush_mode = flush_mode === true ? Z_FINISH$3 : Z_NO_FLUSH$2;
78723
78724   // Convert data if needed
78725   if (toString$1.call(data) === '[object ArrayBuffer]') {
78726     strm.input = new Uint8Array(data);
78727   } else {
78728     strm.input = data;
78729   }
78730
78731   strm.next_in = 0;
78732   strm.avail_in = strm.input.length;
78733
78734   for (;;) {
78735     if (strm.avail_out === 0) {
78736       strm.output = new Uint8Array(chunkSize);
78737       strm.next_out = 0;
78738       strm.avail_out = chunkSize;
78739     }
78740
78741     status = inflate_1.inflate(strm, _flush_mode);
78742
78743     if (status === Z_NEED_DICT$1 && dictionary) {
78744       status = inflate_1.inflateSetDictionary(strm, dictionary);
78745
78746       if (status === Z_OK$3) {
78747         status = inflate_1.inflate(strm, _flush_mode);
78748       } else if (status === Z_DATA_ERROR$2) {
78749         // Replace code with more verbose
78750         status = Z_NEED_DICT$1;
78751       }
78752     }
78753
78754     // Skip snyc markers if more data follows and not raw mode
78755     while (strm.avail_in > 0 &&
78756            status === Z_STREAM_END$3 &&
78757            strm.state.wrap > 0 &&
78758            data[strm.next_in] !== 0)
78759     {
78760       inflate_1.inflateReset(strm);
78761       status = inflate_1.inflate(strm, _flush_mode);
78762     }
78763
78764     switch (status) {
78765       case Z_STREAM_ERROR$2:
78766       case Z_DATA_ERROR$2:
78767       case Z_NEED_DICT$1:
78768       case Z_MEM_ERROR$1:
78769         this.onEnd(status);
78770         this.ended = true;
78771         return false;
78772     }
78773
78774     // Remember real `avail_out` value, because we may patch out buffer content
78775     // to align utf8 strings boundaries.
78776     last_avail_out = strm.avail_out;
78777
78778     if (strm.next_out) {
78779       if (strm.avail_out === 0 || status === Z_STREAM_END$3) {
78780
78781         if (this.options.to === 'string') {
78782
78783           let next_out_utf8 = strings.utf8border(strm.output, strm.next_out);
78784
78785           let tail = strm.next_out - next_out_utf8;
78786           let utf8str = strings.buf2string(strm.output, next_out_utf8);
78787
78788           // move tail & realign counters
78789           strm.next_out = tail;
78790           strm.avail_out = chunkSize - tail;
78791           if (tail) strm.output.set(strm.output.subarray(next_out_utf8, next_out_utf8 + tail), 0);
78792
78793           this.onData(utf8str);
78794
78795         } else {
78796           this.onData(strm.output.length === strm.next_out ? strm.output : strm.output.subarray(0, strm.next_out));
78797         }
78798       }
78799     }
78800
78801     // Must repeat iteration if out buffer is full
78802     if (status === Z_OK$3 && last_avail_out === 0) continue;
78803
78804     // Finalize if end of stream reached.
78805     if (status === Z_STREAM_END$3) {
78806       status = inflate_1.inflateEnd(this.strm);
78807       this.onEnd(status);
78808       this.ended = true;
78809       return true;
78810     }
78811
78812     if (strm.avail_in === 0) break;
78813   }
78814
78815   return true;
78816 };
78817
78818
78819 /**
78820  * Inflate#onData(chunk) -> Void
78821  * - chunk (Uint8Array|String): output data. When string output requested,
78822  *   each chunk will be string.
78823  *
78824  * By default, stores data blocks in `chunks[]` property and glue
78825  * those in `onEnd`. Override this handler, if you need another behaviour.
78826  **/
78827 Inflate.prototype.onData = function (chunk) {
78828   this.chunks.push(chunk);
78829 };
78830
78831
78832 /**
78833  * Inflate#onEnd(status) -> Void
78834  * - status (Number): inflate status. 0 (Z_OK) on success,
78835  *   other if not.
78836  *
78837  * Called either after you tell inflate that the input stream is
78838  * complete (Z_FINISH). By default - join collected chunks,
78839  * free memory and fill `results` / `err` properties.
78840  **/
78841 Inflate.prototype.onEnd = function (status) {
78842   // On success - join
78843   if (status === Z_OK$3) {
78844     if (this.options.to === 'string') {
78845       this.result = this.chunks.join('');
78846     } else {
78847       this.result = common.flattenChunks(this.chunks);
78848     }
78849   }
78850   this.chunks = [];
78851   this.err = status;
78852   this.msg = this.strm.msg;
78853 };
78854
78855
78856 /**
78857  * inflate(data[, options]) -> Uint8Array|String
78858  * - data (Uint8Array): input data to decompress.
78859  * - options (Object): zlib inflate options.
78860  *
78861  * Decompress `data` with inflate/ungzip and `options`. Autodetect
78862  * format via wrapper header by default. That's why we don't provide
78863  * separate `ungzip` method.
78864  *
78865  * Supported options are:
78866  *
78867  * - windowBits
78868  *
78869  * [http://zlib.net/manual.html#Advanced](http://zlib.net/manual.html#Advanced)
78870  * for more information.
78871  *
78872  * Sugar (options):
78873  *
78874  * - `raw` (Boolean) - say that we work with raw stream, if you don't wish to specify
78875  *   negative windowBits implicitly.
78876  * - `to` (String) - if equal to 'string', then result will be converted
78877  *   from utf8 to utf16 (javascript) string. When string output requested,
78878  *   chunk length can differ from `chunkSize`, depending on content.
78879  *
78880  *
78881  * ##### Example:
78882  *
78883  * ```javascript
78884  * const pako = require('pako');
78885  * const input = pako.deflate(new Uint8Array([1,2,3,4,5,6,7,8,9]));
78886  * let output;
78887  *
78888  * try {
78889  *   output = pako.inflate(input);
78890  * } catch (err)
78891  *   console.log(err);
78892  * }
78893  * ```
78894  **/
78895 function inflate$1(input, options) {
78896   const inflator = new Inflate(options);
78897
78898   inflator.push(input);
78899
78900   // That will never happens, if you don't cheat with options :)
78901   if (inflator.err) throw inflator.msg || messages[inflator.err];
78902
78903   return inflator.result;
78904 }
78905
78906
78907 /**
78908  * inflateRaw(data[, options]) -> Uint8Array|String
78909  * - data (Uint8Array): input data to decompress.
78910  * - options (Object): zlib inflate options.
78911  *
78912  * The same as [[inflate]], but creates raw data, without wrapper
78913  * (header and adler32 crc).
78914  **/
78915 function inflateRaw(input, options) {
78916   options = options || {};
78917   options.raw = true;
78918   return inflate$1(input, options);
78919 }
78920
78921
78922 /**
78923  * ungzip(data[, options]) -> Uint8Array|String
78924  * - data (Uint8Array): input data to decompress.
78925  * - options (Object): zlib inflate options.
78926  *
78927  * Just shortcut to [[inflate]], because it autodetects format
78928  * by header.content. Done for convenience.
78929  **/
78930
78931
78932 var Inflate_1 = Inflate;
78933 var inflate_2$1 = inflate$1;
78934 var inflateRaw_1 = inflateRaw;
78935 var ungzip = inflate$1;
78936 var constants$2 = constants;
78937
78938 var inflate_1$1 = {
78939         Inflate: Inflate_1,
78940         inflate: inflate_2$1,
78941         inflateRaw: inflateRaw_1,
78942         ungzip: ungzip,
78943         constants: constants$2
78944 };
78945
78946 const { Inflate: Inflate$1, inflate: inflate$2, inflateRaw: inflateRaw$1, ungzip: ungzip$1 } = inflate_1$1;
78947 var inflate_1$2 = inflate$2;
78948
78949 /*! ieee754. BSD-3-Clause License. Feross Aboukhadijeh <https://feross.org/opensource> */
78950 var read = function (buffer, offset, isLE, mLen, nBytes) {
78951   var e, m;
78952   var eLen = (nBytes * 8) - mLen - 1;
78953   var eMax = (1 << eLen) - 1;
78954   var eBias = eMax >> 1;
78955   var nBits = -7;
78956   var i = isLE ? (nBytes - 1) : 0;
78957   var d = isLE ? -1 : 1;
78958   var s = buffer[offset + i];
78959
78960   i += d;
78961
78962   e = s & ((1 << (-nBits)) - 1);
78963   s >>= (-nBits);
78964   nBits += eLen;
78965   for (; nBits > 0; e = (e * 256) + buffer[offset + i], i += d, nBits -= 8) {}
78966
78967   m = e & ((1 << (-nBits)) - 1);
78968   e >>= (-nBits);
78969   nBits += mLen;
78970   for (; nBits > 0; m = (m * 256) + buffer[offset + i], i += d, nBits -= 8) {}
78971
78972   if (e === 0) {
78973     e = 1 - eBias;
78974   } else if (e === eMax) {
78975     return m ? NaN : ((s ? -1 : 1) * Infinity)
78976   } else {
78977     m = m + Math.pow(2, mLen);
78978     e = e - eBias;
78979   }
78980   return (s ? -1 : 1) * m * Math.pow(2, e - mLen)
78981 };
78982
78983 var write = function (buffer, value, offset, isLE, mLen, nBytes) {
78984   var e, m, c;
78985   var eLen = (nBytes * 8) - mLen - 1;
78986   var eMax = (1 << eLen) - 1;
78987   var eBias = eMax >> 1;
78988   var rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0);
78989   var i = isLE ? 0 : (nBytes - 1);
78990   var d = isLE ? 1 : -1;
78991   var s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0;
78992
78993   value = Math.abs(value);
78994
78995   if (isNaN(value) || value === Infinity) {
78996     m = isNaN(value) ? 1 : 0;
78997     e = eMax;
78998   } else {
78999     e = Math.floor(Math.log(value) / Math.LN2);
79000     if (value * (c = Math.pow(2, -e)) < 1) {
79001       e--;
79002       c *= 2;
79003     }
79004     if (e + eBias >= 1) {
79005       value += rt / c;
79006     } else {
79007       value += rt * Math.pow(2, 1 - eBias);
79008     }
79009     if (value * c >= 2) {
79010       e++;
79011       c /= 2;
79012     }
79013
79014     if (e + eBias >= eMax) {
79015       m = 0;
79016       e = eMax;
79017     } else if (e + eBias >= 1) {
79018       m = ((value * c) - 1) * Math.pow(2, mLen);
79019       e = e + eBias;
79020     } else {
79021       m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen);
79022       e = 0;
79023     }
79024   }
79025
79026   for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8) {}
79027
79028   e = (e << mLen) | m;
79029   eLen += mLen;
79030   for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8) {}
79031
79032   buffer[offset + i - d] |= s * 128;
79033 };
79034
79035 var ieee754 = {
79036         read: read,
79037         write: write
79038 };
79039
79040 var pbf = Pbf;
79041
79042
79043
79044 function Pbf(buf) {
79045     this.buf = ArrayBuffer.isView && ArrayBuffer.isView(buf) ? buf : new Uint8Array(buf || 0);
79046     this.pos = 0;
79047     this.type = 0;
79048     this.length = this.buf.length;
79049 }
79050
79051 Pbf.Varint  = 0; // varint: int32, int64, uint32, uint64, sint32, sint64, bool, enum
79052 Pbf.Fixed64 = 1; // 64-bit: double, fixed64, sfixed64
79053 Pbf.Bytes   = 2; // length-delimited: string, bytes, embedded messages, packed repeated fields
79054 Pbf.Fixed32 = 5; // 32-bit: float, fixed32, sfixed32
79055
79056 var SHIFT_LEFT_32 = (1 << 16) * (1 << 16),
79057     SHIFT_RIGHT_32 = 1 / SHIFT_LEFT_32;
79058
79059 // Threshold chosen based on both benchmarking and knowledge about browser string
79060 // data structures (which currently switch structure types at 12 bytes or more)
79061 var TEXT_DECODER_MIN_LENGTH = 12;
79062 var utf8TextDecoder = typeof TextDecoder === 'undefined' ? null : new TextDecoder('utf8');
79063
79064 Pbf.prototype = {
79065
79066     destroy: function() {
79067         this.buf = null;
79068     },
79069
79070     // === READING =================================================================
79071
79072     readFields: function(readField, result, end) {
79073         end = end || this.length;
79074
79075         while (this.pos < end) {
79076             var val = this.readVarint(),
79077                 tag = val >> 3,
79078                 startPos = this.pos;
79079
79080             this.type = val & 0x7;
79081             readField(tag, result, this);
79082
79083             if (this.pos === startPos) this.skip(val);
79084         }
79085         return result;
79086     },
79087
79088     readMessage: function(readField, result) {
79089         return this.readFields(readField, result, this.readVarint() + this.pos);
79090     },
79091
79092     readFixed32: function() {
79093         var val = readUInt32(this.buf, this.pos);
79094         this.pos += 4;
79095         return val;
79096     },
79097
79098     readSFixed32: function() {
79099         var val = readInt32(this.buf, this.pos);
79100         this.pos += 4;
79101         return val;
79102     },
79103
79104     // 64-bit int handling is based on github.com/dpw/node-buffer-more-ints (MIT-licensed)
79105
79106     readFixed64: function() {
79107         var val = readUInt32(this.buf, this.pos) + readUInt32(this.buf, this.pos + 4) * SHIFT_LEFT_32;
79108         this.pos += 8;
79109         return val;
79110     },
79111
79112     readSFixed64: function() {
79113         var val = readUInt32(this.buf, this.pos) + readInt32(this.buf, this.pos + 4) * SHIFT_LEFT_32;
79114         this.pos += 8;
79115         return val;
79116     },
79117
79118     readFloat: function() {
79119         var val = ieee754.read(this.buf, this.pos, true, 23, 4);
79120         this.pos += 4;
79121         return val;
79122     },
79123
79124     readDouble: function() {
79125         var val = ieee754.read(this.buf, this.pos, true, 52, 8);
79126         this.pos += 8;
79127         return val;
79128     },
79129
79130     readVarint: function(isSigned) {
79131         var buf = this.buf,
79132             val, b;
79133
79134         b = buf[this.pos++]; val  =  b & 0x7f;        if (b < 0x80) return val;
79135         b = buf[this.pos++]; val |= (b & 0x7f) << 7;  if (b < 0x80) return val;
79136         b = buf[this.pos++]; val |= (b & 0x7f) << 14; if (b < 0x80) return val;
79137         b = buf[this.pos++]; val |= (b & 0x7f) << 21; if (b < 0x80) return val;
79138         b = buf[this.pos];   val |= (b & 0x0f) << 28;
79139
79140         return readVarintRemainder(val, isSigned, this);
79141     },
79142
79143     readVarint64: function() { // for compatibility with v2.0.1
79144         return this.readVarint(true);
79145     },
79146
79147     readSVarint: function() {
79148         var num = this.readVarint();
79149         return num % 2 === 1 ? (num + 1) / -2 : num / 2; // zigzag encoding
79150     },
79151
79152     readBoolean: function() {
79153         return Boolean(this.readVarint());
79154     },
79155
79156     readString: function() {
79157         var end = this.readVarint() + this.pos;
79158         var pos = this.pos;
79159         this.pos = end;
79160
79161         if (end - pos >= TEXT_DECODER_MIN_LENGTH && utf8TextDecoder) {
79162             // longer strings are fast with the built-in browser TextDecoder API
79163             return readUtf8TextDecoder(this.buf, pos, end);
79164         }
79165         // short strings are fast with our custom implementation
79166         return readUtf8(this.buf, pos, end);
79167     },
79168
79169     readBytes: function() {
79170         var end = this.readVarint() + this.pos,
79171             buffer = this.buf.subarray(this.pos, end);
79172         this.pos = end;
79173         return buffer;
79174     },
79175
79176     // verbose for performance reasons; doesn't affect gzipped size
79177
79178     readPackedVarint: function(arr, isSigned) {
79179         if (this.type !== Pbf.Bytes) return arr.push(this.readVarint(isSigned));
79180         var end = readPackedEnd(this);
79181         arr = arr || [];
79182         while (this.pos < end) arr.push(this.readVarint(isSigned));
79183         return arr;
79184     },
79185     readPackedSVarint: function(arr) {
79186         if (this.type !== Pbf.Bytes) return arr.push(this.readSVarint());
79187         var end = readPackedEnd(this);
79188         arr = arr || [];
79189         while (this.pos < end) arr.push(this.readSVarint());
79190         return arr;
79191     },
79192     readPackedBoolean: function(arr) {
79193         if (this.type !== Pbf.Bytes) return arr.push(this.readBoolean());
79194         var end = readPackedEnd(this);
79195         arr = arr || [];
79196         while (this.pos < end) arr.push(this.readBoolean());
79197         return arr;
79198     },
79199     readPackedFloat: function(arr) {
79200         if (this.type !== Pbf.Bytes) return arr.push(this.readFloat());
79201         var end = readPackedEnd(this);
79202         arr = arr || [];
79203         while (this.pos < end) arr.push(this.readFloat());
79204         return arr;
79205     },
79206     readPackedDouble: function(arr) {
79207         if (this.type !== Pbf.Bytes) return arr.push(this.readDouble());
79208         var end = readPackedEnd(this);
79209         arr = arr || [];
79210         while (this.pos < end) arr.push(this.readDouble());
79211         return arr;
79212     },
79213     readPackedFixed32: function(arr) {
79214         if (this.type !== Pbf.Bytes) return arr.push(this.readFixed32());
79215         var end = readPackedEnd(this);
79216         arr = arr || [];
79217         while (this.pos < end) arr.push(this.readFixed32());
79218         return arr;
79219     },
79220     readPackedSFixed32: function(arr) {
79221         if (this.type !== Pbf.Bytes) return arr.push(this.readSFixed32());
79222         var end = readPackedEnd(this);
79223         arr = arr || [];
79224         while (this.pos < end) arr.push(this.readSFixed32());
79225         return arr;
79226     },
79227     readPackedFixed64: function(arr) {
79228         if (this.type !== Pbf.Bytes) return arr.push(this.readFixed64());
79229         var end = readPackedEnd(this);
79230         arr = arr || [];
79231         while (this.pos < end) arr.push(this.readFixed64());
79232         return arr;
79233     },
79234     readPackedSFixed64: function(arr) {
79235         if (this.type !== Pbf.Bytes) return arr.push(this.readSFixed64());
79236         var end = readPackedEnd(this);
79237         arr = arr || [];
79238         while (this.pos < end) arr.push(this.readSFixed64());
79239         return arr;
79240     },
79241
79242     skip: function(val) {
79243         var type = val & 0x7;
79244         if (type === Pbf.Varint) while (this.buf[this.pos++] > 0x7f) {}
79245         else if (type === Pbf.Bytes) this.pos = this.readVarint() + this.pos;
79246         else if (type === Pbf.Fixed32) this.pos += 4;
79247         else if (type === Pbf.Fixed64) this.pos += 8;
79248         else throw new Error('Unimplemented type: ' + type);
79249     },
79250
79251     // === WRITING =================================================================
79252
79253     writeTag: function(tag, type) {
79254         this.writeVarint((tag << 3) | type);
79255     },
79256
79257     realloc: function(min) {
79258         var length = this.length || 16;
79259
79260         while (length < this.pos + min) length *= 2;
79261
79262         if (length !== this.length) {
79263             var buf = new Uint8Array(length);
79264             buf.set(this.buf);
79265             this.buf = buf;
79266             this.length = length;
79267         }
79268     },
79269
79270     finish: function() {
79271         this.length = this.pos;
79272         this.pos = 0;
79273         return this.buf.subarray(0, this.length);
79274     },
79275
79276     writeFixed32: function(val) {
79277         this.realloc(4);
79278         writeInt32(this.buf, val, this.pos);
79279         this.pos += 4;
79280     },
79281
79282     writeSFixed32: function(val) {
79283         this.realloc(4);
79284         writeInt32(this.buf, val, this.pos);
79285         this.pos += 4;
79286     },
79287
79288     writeFixed64: function(val) {
79289         this.realloc(8);
79290         writeInt32(this.buf, val & -1, this.pos);
79291         writeInt32(this.buf, Math.floor(val * SHIFT_RIGHT_32), this.pos + 4);
79292         this.pos += 8;
79293     },
79294
79295     writeSFixed64: function(val) {
79296         this.realloc(8);
79297         writeInt32(this.buf, val & -1, this.pos);
79298         writeInt32(this.buf, Math.floor(val * SHIFT_RIGHT_32), this.pos + 4);
79299         this.pos += 8;
79300     },
79301
79302     writeVarint: function(val) {
79303         val = +val || 0;
79304
79305         if (val > 0xfffffff || val < 0) {
79306             writeBigVarint(val, this);
79307             return;
79308         }
79309
79310         this.realloc(4);
79311
79312         this.buf[this.pos++] =           val & 0x7f  | (val > 0x7f ? 0x80 : 0); if (val <= 0x7f) return;
79313         this.buf[this.pos++] = ((val >>>= 7) & 0x7f) | (val > 0x7f ? 0x80 : 0); if (val <= 0x7f) return;
79314         this.buf[this.pos++] = ((val >>>= 7) & 0x7f) | (val > 0x7f ? 0x80 : 0); if (val <= 0x7f) return;
79315         this.buf[this.pos++] =   (val >>> 7) & 0x7f;
79316     },
79317
79318     writeSVarint: function(val) {
79319         this.writeVarint(val < 0 ? -val * 2 - 1 : val * 2);
79320     },
79321
79322     writeBoolean: function(val) {
79323         this.writeVarint(Boolean(val));
79324     },
79325
79326     writeString: function(str) {
79327         str = String(str);
79328         this.realloc(str.length * 4);
79329
79330         this.pos++; // reserve 1 byte for short string length
79331
79332         var startPos = this.pos;
79333         // write the string directly to the buffer and see how much was written
79334         this.pos = writeUtf8(this.buf, str, this.pos);
79335         var len = this.pos - startPos;
79336
79337         if (len >= 0x80) makeRoomForExtraLength(startPos, len, this);
79338
79339         // finally, write the message length in the reserved place and restore the position
79340         this.pos = startPos - 1;
79341         this.writeVarint(len);
79342         this.pos += len;
79343     },
79344
79345     writeFloat: function(val) {
79346         this.realloc(4);
79347         ieee754.write(this.buf, val, this.pos, true, 23, 4);
79348         this.pos += 4;
79349     },
79350
79351     writeDouble: function(val) {
79352         this.realloc(8);
79353         ieee754.write(this.buf, val, this.pos, true, 52, 8);
79354         this.pos += 8;
79355     },
79356
79357     writeBytes: function(buffer) {
79358         var len = buffer.length;
79359         this.writeVarint(len);
79360         this.realloc(len);
79361         for (var i = 0; i < len; i++) this.buf[this.pos++] = buffer[i];
79362     },
79363
79364     writeRawMessage: function(fn, obj) {
79365         this.pos++; // reserve 1 byte for short message length
79366
79367         // write the message directly to the buffer and see how much was written
79368         var startPos = this.pos;
79369         fn(obj, this);
79370         var len = this.pos - startPos;
79371
79372         if (len >= 0x80) makeRoomForExtraLength(startPos, len, this);
79373
79374         // finally, write the message length in the reserved place and restore the position
79375         this.pos = startPos - 1;
79376         this.writeVarint(len);
79377         this.pos += len;
79378     },
79379
79380     writeMessage: function(tag, fn, obj) {
79381         this.writeTag(tag, Pbf.Bytes);
79382         this.writeRawMessage(fn, obj);
79383     },
79384
79385     writePackedVarint:   function(tag, arr) { if (arr.length) this.writeMessage(tag, writePackedVarint, arr);   },
79386     writePackedSVarint:  function(tag, arr) { if (arr.length) this.writeMessage(tag, writePackedSVarint, arr);  },
79387     writePackedBoolean:  function(tag, arr) { if (arr.length) this.writeMessage(tag, writePackedBoolean, arr);  },
79388     writePackedFloat:    function(tag, arr) { if (arr.length) this.writeMessage(tag, writePackedFloat, arr);    },
79389     writePackedDouble:   function(tag, arr) { if (arr.length) this.writeMessage(tag, writePackedDouble, arr);   },
79390     writePackedFixed32:  function(tag, arr) { if (arr.length) this.writeMessage(tag, writePackedFixed32, arr);  },
79391     writePackedSFixed32: function(tag, arr) { if (arr.length) this.writeMessage(tag, writePackedSFixed32, arr); },
79392     writePackedFixed64:  function(tag, arr) { if (arr.length) this.writeMessage(tag, writePackedFixed64, arr);  },
79393     writePackedSFixed64: function(tag, arr) { if (arr.length) this.writeMessage(tag, writePackedSFixed64, arr); },
79394
79395     writeBytesField: function(tag, buffer) {
79396         this.writeTag(tag, Pbf.Bytes);
79397         this.writeBytes(buffer);
79398     },
79399     writeFixed32Field: function(tag, val) {
79400         this.writeTag(tag, Pbf.Fixed32);
79401         this.writeFixed32(val);
79402     },
79403     writeSFixed32Field: function(tag, val) {
79404         this.writeTag(tag, Pbf.Fixed32);
79405         this.writeSFixed32(val);
79406     },
79407     writeFixed64Field: function(tag, val) {
79408         this.writeTag(tag, Pbf.Fixed64);
79409         this.writeFixed64(val);
79410     },
79411     writeSFixed64Field: function(tag, val) {
79412         this.writeTag(tag, Pbf.Fixed64);
79413         this.writeSFixed64(val);
79414     },
79415     writeVarintField: function(tag, val) {
79416         this.writeTag(tag, Pbf.Varint);
79417         this.writeVarint(val);
79418     },
79419     writeSVarintField: function(tag, val) {
79420         this.writeTag(tag, Pbf.Varint);
79421         this.writeSVarint(val);
79422     },
79423     writeStringField: function(tag, str) {
79424         this.writeTag(tag, Pbf.Bytes);
79425         this.writeString(str);
79426     },
79427     writeFloatField: function(tag, val) {
79428         this.writeTag(tag, Pbf.Fixed32);
79429         this.writeFloat(val);
79430     },
79431     writeDoubleField: function(tag, val) {
79432         this.writeTag(tag, Pbf.Fixed64);
79433         this.writeDouble(val);
79434     },
79435     writeBooleanField: function(tag, val) {
79436         this.writeVarintField(tag, Boolean(val));
79437     }
79438 };
79439
79440 function readVarintRemainder(l, s, p) {
79441     var buf = p.buf,
79442         h, b;
79443
79444     b = buf[p.pos++]; h  = (b & 0x70) >> 4;  if (b < 0x80) return toNum(l, h, s);
79445     b = buf[p.pos++]; h |= (b & 0x7f) << 3;  if (b < 0x80) return toNum(l, h, s);
79446     b = buf[p.pos++]; h |= (b & 0x7f) << 10; if (b < 0x80) return toNum(l, h, s);
79447     b = buf[p.pos++]; h |= (b & 0x7f) << 17; if (b < 0x80) return toNum(l, h, s);
79448     b = buf[p.pos++]; h |= (b & 0x7f) << 24; if (b < 0x80) return toNum(l, h, s);
79449     b = buf[p.pos++]; h |= (b & 0x01) << 31; if (b < 0x80) return toNum(l, h, s);
79450
79451     throw new Error('Expected varint not more than 10 bytes');
79452 }
79453
79454 function readPackedEnd(pbf) {
79455     return pbf.type === Pbf.Bytes ?
79456         pbf.readVarint() + pbf.pos : pbf.pos + 1;
79457 }
79458
79459 function toNum(low, high, isSigned) {
79460     if (isSigned) {
79461         return high * 0x100000000 + (low >>> 0);
79462     }
79463
79464     return ((high >>> 0) * 0x100000000) + (low >>> 0);
79465 }
79466
79467 function writeBigVarint(val, pbf) {
79468     var low, high;
79469
79470     if (val >= 0) {
79471         low  = (val % 0x100000000) | 0;
79472         high = (val / 0x100000000) | 0;
79473     } else {
79474         low  = ~(-val % 0x100000000);
79475         high = ~(-val / 0x100000000);
79476
79477         if (low ^ 0xffffffff) {
79478             low = (low + 1) | 0;
79479         } else {
79480             low = 0;
79481             high = (high + 1) | 0;
79482         }
79483     }
79484
79485     if (val >= 0x10000000000000000 || val < -0x10000000000000000) {
79486         throw new Error('Given varint doesn\'t fit into 10 bytes');
79487     }
79488
79489     pbf.realloc(10);
79490
79491     writeBigVarintLow(low, high, pbf);
79492     writeBigVarintHigh(high, pbf);
79493 }
79494
79495 function writeBigVarintLow(low, high, pbf) {
79496     pbf.buf[pbf.pos++] = low & 0x7f | 0x80; low >>>= 7;
79497     pbf.buf[pbf.pos++] = low & 0x7f | 0x80; low >>>= 7;
79498     pbf.buf[pbf.pos++] = low & 0x7f | 0x80; low >>>= 7;
79499     pbf.buf[pbf.pos++] = low & 0x7f | 0x80; low >>>= 7;
79500     pbf.buf[pbf.pos]   = low & 0x7f;
79501 }
79502
79503 function writeBigVarintHigh(high, pbf) {
79504     var lsb = (high & 0x07) << 4;
79505
79506     pbf.buf[pbf.pos++] |= lsb         | ((high >>>= 3) ? 0x80 : 0); if (!high) return;
79507     pbf.buf[pbf.pos++]  = high & 0x7f | ((high >>>= 7) ? 0x80 : 0); if (!high) return;
79508     pbf.buf[pbf.pos++]  = high & 0x7f | ((high >>>= 7) ? 0x80 : 0); if (!high) return;
79509     pbf.buf[pbf.pos++]  = high & 0x7f | ((high >>>= 7) ? 0x80 : 0); if (!high) return;
79510     pbf.buf[pbf.pos++]  = high & 0x7f | ((high >>>= 7) ? 0x80 : 0); if (!high) return;
79511     pbf.buf[pbf.pos++]  = high & 0x7f;
79512 }
79513
79514 function makeRoomForExtraLength(startPos, len, pbf) {
79515     var extraLen =
79516         len <= 0x3fff ? 1 :
79517         len <= 0x1fffff ? 2 :
79518         len <= 0xfffffff ? 3 : Math.floor(Math.log(len) / (Math.LN2 * 7));
79519
79520     // if 1 byte isn't enough for encoding message length, shift the data to the right
79521     pbf.realloc(extraLen);
79522     for (var i = pbf.pos - 1; i >= startPos; i--) pbf.buf[i + extraLen] = pbf.buf[i];
79523 }
79524
79525 function writePackedVarint(arr, pbf)   { for (var i = 0; i < arr.length; i++) pbf.writeVarint(arr[i]);   }
79526 function writePackedSVarint(arr, pbf)  { for (var i = 0; i < arr.length; i++) pbf.writeSVarint(arr[i]);  }
79527 function writePackedFloat(arr, pbf)    { for (var i = 0; i < arr.length; i++) pbf.writeFloat(arr[i]);    }
79528 function writePackedDouble(arr, pbf)   { for (var i = 0; i < arr.length; i++) pbf.writeDouble(arr[i]);   }
79529 function writePackedBoolean(arr, pbf)  { for (var i = 0; i < arr.length; i++) pbf.writeBoolean(arr[i]);  }
79530 function writePackedFixed32(arr, pbf)  { for (var i = 0; i < arr.length; i++) pbf.writeFixed32(arr[i]);  }
79531 function writePackedSFixed32(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeSFixed32(arr[i]); }
79532 function writePackedFixed64(arr, pbf)  { for (var i = 0; i < arr.length; i++) pbf.writeFixed64(arr[i]);  }
79533 function writePackedSFixed64(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeSFixed64(arr[i]); }
79534
79535 // Buffer code below from https://github.com/feross/buffer, MIT-licensed
79536
79537 function readUInt32(buf, pos) {
79538     return ((buf[pos]) |
79539         (buf[pos + 1] << 8) |
79540         (buf[pos + 2] << 16)) +
79541         (buf[pos + 3] * 0x1000000);
79542 }
79543
79544 function writeInt32(buf, val, pos) {
79545     buf[pos] = val;
79546     buf[pos + 1] = (val >>> 8);
79547     buf[pos + 2] = (val >>> 16);
79548     buf[pos + 3] = (val >>> 24);
79549 }
79550
79551 function readInt32(buf, pos) {
79552     return ((buf[pos]) |
79553         (buf[pos + 1] << 8) |
79554         (buf[pos + 2] << 16)) +
79555         (buf[pos + 3] << 24);
79556 }
79557
79558 function readUtf8(buf, pos, end) {
79559     var str = '';
79560     var i = pos;
79561
79562     while (i < end) {
79563         var b0 = buf[i];
79564         var c = null; // codepoint
79565         var bytesPerSequence =
79566             b0 > 0xEF ? 4 :
79567             b0 > 0xDF ? 3 :
79568             b0 > 0xBF ? 2 : 1;
79569
79570         if (i + bytesPerSequence > end) break;
79571
79572         var b1, b2, b3;
79573
79574         if (bytesPerSequence === 1) {
79575             if (b0 < 0x80) {
79576                 c = b0;
79577             }
79578         } else if (bytesPerSequence === 2) {
79579             b1 = buf[i + 1];
79580             if ((b1 & 0xC0) === 0x80) {
79581                 c = (b0 & 0x1F) << 0x6 | (b1 & 0x3F);
79582                 if (c <= 0x7F) {
79583                     c = null;
79584                 }
79585             }
79586         } else if (bytesPerSequence === 3) {
79587             b1 = buf[i + 1];
79588             b2 = buf[i + 2];
79589             if ((b1 & 0xC0) === 0x80 && (b2 & 0xC0) === 0x80) {
79590                 c = (b0 & 0xF) << 0xC | (b1 & 0x3F) << 0x6 | (b2 & 0x3F);
79591                 if (c <= 0x7FF || (c >= 0xD800 && c <= 0xDFFF)) {
79592                     c = null;
79593                 }
79594             }
79595         } else if (bytesPerSequence === 4) {
79596             b1 = buf[i + 1];
79597             b2 = buf[i + 2];
79598             b3 = buf[i + 3];
79599             if ((b1 & 0xC0) === 0x80 && (b2 & 0xC0) === 0x80 && (b3 & 0xC0) === 0x80) {
79600                 c = (b0 & 0xF) << 0x12 | (b1 & 0x3F) << 0xC | (b2 & 0x3F) << 0x6 | (b3 & 0x3F);
79601                 if (c <= 0xFFFF || c >= 0x110000) {
79602                     c = null;
79603                 }
79604             }
79605         }
79606
79607         if (c === null) {
79608             c = 0xFFFD;
79609             bytesPerSequence = 1;
79610
79611         } else if (c > 0xFFFF) {
79612             c -= 0x10000;
79613             str += String.fromCharCode(c >>> 10 & 0x3FF | 0xD800);
79614             c = 0xDC00 | c & 0x3FF;
79615         }
79616
79617         str += String.fromCharCode(c);
79618         i += bytesPerSequence;
79619     }
79620
79621     return str;
79622 }
79623
79624 function readUtf8TextDecoder(buf, pos, end) {
79625     return utf8TextDecoder.decode(buf.subarray(pos, end));
79626 }
79627
79628 function writeUtf8(buf, str, pos) {
79629     for (var i = 0, c, lead; i < str.length; i++) {
79630         c = str.charCodeAt(i); // code point
79631
79632         if (c > 0xD7FF && c < 0xE000) {
79633             if (lead) {
79634                 if (c < 0xDC00) {
79635                     buf[pos++] = 0xEF;
79636                     buf[pos++] = 0xBF;
79637                     buf[pos++] = 0xBD;
79638                     lead = c;
79639                     continue;
79640                 } else {
79641                     c = lead - 0xD800 << 10 | c - 0xDC00 | 0x10000;
79642                     lead = null;
79643                 }
79644             } else {
79645                 if (c > 0xDBFF || (i + 1 === str.length)) {
79646                     buf[pos++] = 0xEF;
79647                     buf[pos++] = 0xBF;
79648                     buf[pos++] = 0xBD;
79649                 } else {
79650                     lead = c;
79651                 }
79652                 continue;
79653             }
79654         } else if (lead) {
79655             buf[pos++] = 0xEF;
79656             buf[pos++] = 0xBF;
79657             buf[pos++] = 0xBD;
79658             lead = null;
79659         }
79660
79661         if (c < 0x80) {
79662             buf[pos++] = c;
79663         } else {
79664             if (c < 0x800) {
79665                 buf[pos++] = c >> 0x6 | 0xC0;
79666             } else {
79667                 if (c < 0x10000) {
79668                     buf[pos++] = c >> 0xC | 0xE0;
79669                 } else {
79670                     buf[pos++] = c >> 0x12 | 0xF0;
79671                     buf[pos++] = c >> 0xC & 0x3F | 0x80;
79672                 }
79673                 buf[pos++] = c >> 0x6 & 0x3F | 0x80;
79674             }
79675             buf[pos++] = c & 0x3F | 0x80;
79676         }
79677     }
79678     return pos;
79679 }
79680
79681 /**
79682  * Decompress and parse an array buffer containing zipped
79683  * json data and return as a json object.
79684  *
79685  * @description Handles array buffers continaing zipped json
79686  * data.
79687  *
79688  * @param {ArrayBuffer} buffer - Array buffer to decompress.
79689  * @returns {Object} Parsed object.
79690  */
79691 function decompress(buffer) {
79692     const inflated = inflate_1$2(buffer, { to: "string" });
79693     return JSON.parse(inflated);
79694 }
79695 /**
79696  * Retrieves a resource as an array buffer and returns a promise
79697  * to the buffer.
79698  *
79699  * @description Rejects the promise on request failure.
79700  *
79701  * @param {string} url - URL for resource to retrieve.
79702  * @param {Promise} [abort] - Optional promise for aborting
79703  * the request through rejection.
79704  * @returns {Promise<ArrayBuffer>} Promise to the array buffer
79705  * resource.
79706  */
79707 function fetchArrayBuffer(url, abort) {
79708     const method = "GET";
79709     const responseType = "arraybuffer";
79710     return xhrFetch(url, method, responseType, [], null, abort);
79711 }
79712 function xhrFetch(url, method, responseType, headers, body, abort) {
79713     const xhr = new XMLHttpRequest();
79714     const promise = new Promise((resolve, reject) => {
79715         xhr.open(method, url, true);
79716         for (const header of headers) {
79717             xhr.setRequestHeader(header.name, header.value);
79718         }
79719         xhr.responseType = responseType;
79720         xhr.timeout = 15000;
79721         xhr.onload = () => {
79722             var _a;
79723             if (xhr.status !== 200) {
79724                 const error = (_a = xhr.response) !== null && _a !== void 0 ? _a : new MapillaryError(`Response status error: ${url}`);
79725                 reject(error);
79726             }
79727             if (!xhr.response) {
79728                 reject(new MapillaryError(`Response empty: ${url}`));
79729             }
79730             resolve(xhr.response);
79731         };
79732         xhr.onerror = () => {
79733             reject(new MapillaryError(`Request error: ${url}`));
79734         };
79735         xhr.ontimeout = () => {
79736             reject(new MapillaryError(`Request timeout: ${url}`));
79737         };
79738         xhr.onabort = () => {
79739             reject(new MapillaryError(`Request aborted: ${url}`));
79740         };
79741         xhr.send(method === "POST" ? body : null);
79742     });
79743     if (!!abort) {
79744         abort.catch(() => { xhr.abort(); });
79745     }
79746     return promise;
79747 }
79748 /**
79749  * Read the fields of a protobuf array buffer into a mesh
79750  * object.
79751  *
79752  * @param {ArrayBuffer} buffer - Protobuf array buffer
79753  * to read from.
79754  * @returns {MeshContract} Mesh object.
79755  */
79756 function readMeshPbf(buffer) {
79757     const pbf$1 = new pbf(buffer);
79758     const mesh = { faces: [], vertices: [] };
79759     return pbf$1.readFields(readMeshPbfField, mesh);
79760 }
79761 function readMeshPbfField(tag, mesh, pbf) {
79762     if (tag === 1) {
79763         mesh.vertices.push(pbf.readFloat());
79764     }
79765     else if (tag === 2) {
79766         mesh.faces.push(pbf.readVarint());
79767     }
79768     else {
79769         console.warn(`Unsupported pbf tag (${tag})`);
79770     }
79771 }
79772
79773 /**
79774  * @class GeometryProviderBase
79775  *
79776  * @classdesc Base class to extend if implementing a geometry
79777  * provider class.
79778  *
79779  * @example
79780  * ```js
79781  * class MyGeometryProvider extends GeometryProviderBase {
79782  *      ...
79783  * }
79784  * ```
79785  */
79786 class GeometryProviderBase {
79787     /**
79788      * Create a new geometry provider base instance.
79789      */
79790     constructor() { }
79791     /**
79792      * Convert a geodetic bounding box to the the minimum set
79793      * of cell ids containing the bounding box.
79794      *
79795      * @description The bounding box needs
79796      * to be sufficiently small to be contained in an area with the size
79797      * of maximally four tiles. Up to nine adjacent tiles may be returned.
79798      *
79799      * @param {LngLat} sw - South west corner of bounding box.
79800      * @param {LngLat} ne - North east corner of bounding box.
79801      *
79802      * @returns {Array<string>} Array of cell ids.
79803      */
79804     bboxToCellIds(sw, ne) {
79805         throw new MapillaryError("Not implemented");
79806     }
79807     /**
79808      * Get the cell ids of all adjacent cells.
79809      *
79810      * @description In the case of approximately rectangular cells
79811      * this is typically the eight orthogonally and diagonally adjacent
79812      * cells.
79813      *
79814      * @param {string} cellId - Id of cell.
79815      * @returns {Array<string>} Array of cell ids. No specific
79816      * order is guaranteed.
79817      */
79818     getAdjacent(cellId) {
79819         throw new MapillaryError("Not implemented");
79820     }
79821     /**
79822      * Get the vertices of a cell.
79823      *
79824      * @description The vertices form an unclosed
79825      * clockwise polygon in the 2D longitude, latitude
79826      * space. No assumption on the position of the first
79827      * vertex relative to the others can be made.
79828      *
79829      * @param {string} cellId - Id of cell.
79830      * @returns {Array<LngLat>} Unclosed clockwise polygon.
79831      */
79832     getVertices(cellId) {
79833         throw new MapillaryError("Not implemented");
79834     }
79835     /**
79836      * Convert geodetic coordinates to a cell id.
79837      *
79838      * @param {LngLat} lngLat - Longitude, latitude to convert.
79839      * @returns {string} Cell id for the longitude, latitude.
79840      */
79841     lngLatToCellId(lngLat) {
79842         throw new MapillaryError("Not implemented");
79843     }
79844     /** @ignore */
79845     _approxBboxToCellIds(sw, ne) {
79846         if (ne.lat <= sw.lat || ne.lng <= sw.lng) {
79847             throw new MapillaryError("North east needs to be top right of south west");
79848         }
79849         const centerLat = (sw.lat + ne.lat) / 2;
79850         const centerLng = (sw.lng + ne.lng) / 2;
79851         const enu = geodeticToEnu(ne.lng, ne.lat, 0, centerLng, centerLat, 0);
79852         const threshold = Math.max(enu[0], enu[1]);
79853         return this._lngLatToCellIds({ lat: centerLat, lng: centerLng }, threshold);
79854     }
79855     /** @ignore */
79856     _enuToGeodetic(point, reference) {
79857         const [lng, lat] = enuToGeodetic(point[0], point[1], point[2], reference.lng, reference.lat, 0);
79858         return { lat, lng };
79859     }
79860     /** @ignore */
79861     _getLngLatBoundingBoxCorners(lngLat, threshold) {
79862         return [
79863             [-threshold, threshold, 0],
79864             [threshold, threshold, 0],
79865             [threshold, -threshold, 0],
79866             [-threshold, -threshold, 0],
79867         ].map((point) => {
79868             return this._enuToGeodetic(point, lngLat);
79869         });
79870     }
79871     /**
79872      * Convert a geodetic square to cell ids.
79873      *
79874      * The square is specified as a longitude, latitude
79875      * and a threshold from the position using Manhattan distance.
79876      *
79877      * @param {LngLat} lngLat - Longitude, latitude.
79878      * @param {number} threshold - Threshold of the conversion in meters.
79879      *
79880      * @returns {Array<string>} Array of cell ids reachable within
79881      * the threshold.
79882      *
79883      * @ignore
79884      */
79885     _lngLatToCellIds(lngLat, threshold) {
79886         const cellId = this.lngLatToCellId(lngLat);
79887         const bboxCorners = this._getLngLatBoundingBoxCorners(lngLat, threshold);
79888         for (const corner of bboxCorners) {
79889             const cid = this.lngLatToCellId(corner);
79890             if (cid !== cellId) {
79891                 return [cellId, ...this.getAdjacent(cellId)];
79892             }
79893         }
79894         return [cellId];
79895     }
79896 }
79897
79898 /**
79899  * @class DataProviderBase
79900  *
79901  * @classdesc Base class to extend if implementing a data provider
79902  * class.
79903  *
79904  * @fires datacreate
79905  *
79906  * @example
79907  * ```js
79908  * class MyDataProvider extends DataProviderBase {
79909  *   constructor() {
79910  *     super(new S2GeometryProvider());
79911  *   }
79912  *   ...
79913  * }
79914  * ```
79915  */
79916 class DataProviderBase extends EventEmitter {
79917     /**
79918      * Create a new data provider base instance.
79919      *
79920      * @param {GeometryProviderBase} geometry - Geometry
79921      * provider instance.
79922      */
79923     constructor(_geometry) {
79924         super();
79925         this._geometry = _geometry;
79926         if (!(this._geometry instanceof GeometryProviderBase)) {
79927             throw new MapillaryError("The data provider requires a geometry provider base instance.");
79928         }
79929     }
79930     /**
79931      * Get geometry property.
79932      *
79933      * @returns {GeometryProviderBase} Geometry provider instance.
79934      */
79935     get geometry() {
79936         return this._geometry;
79937     }
79938     fire(type, event) {
79939         super.fire(type, event);
79940     }
79941     /**
79942      * Get core images in a geometry cell.
79943      *
79944      * @param {string} cellId - The id of the geometry cell.
79945      * @returns {Promise<CoreImagesContract>} Promise to
79946      * the core images of the requested geometry cell id.
79947      * @throws Rejects the promise on errors.
79948      */
79949     getCoreImages(cellId) {
79950         return Promise.reject(new MapillaryError("Not implemented"));
79951     }
79952     /**
79953      * Get a cluster reconstruction.
79954      *
79955      * @param {string} url - URL for the cluster reconstruction
79956      * to retrieve.
79957      * @param {Promise} [abort] - Optional promise for aborting
79958      * the request through rejection.
79959      * @returns {Promise<ClusterContract>} Promise to the
79960      * cluster reconstruction.
79961      * @throws Rejects the promise on errors.
79962      */
79963     getCluster(url, abort) {
79964         return Promise.reject(new MapillaryError("Not implemented"));
79965     }
79966     /**
79967      * Get spatial images.
79968      *
79969      * @param {Array<string>} imageIds - The ids for the
79970      * images to retrieve.
79971      * @returns {Promise<SpatialImagesContract>} Promise to
79972      * the spatial images of the requested image ids.
79973      * @throws Rejects the promise on errors.
79974      */
79975     getSpatialImages(imageIds) {
79976         return Promise.reject(new MapillaryError("Not implemented"));
79977     }
79978     /**
79979      * Get complete images.
79980      *
79981      * @param {Array<string>} imageIds - The ids for the
79982      * images to retrieve.
79983      * @returns {Promise<ImagesContract>} Promise to the images of the
79984      * requested image ids.
79985      * @throws Rejects the promise on errors.
79986      */
79987     getImages(imageIds) {
79988         return Promise.reject(new MapillaryError("Not implemented"));
79989     }
79990     /**
79991      * Get an image as an array buffer.
79992      *
79993      * @param {string} url - URL for image to retrieve.
79994      * @param {Promise<void>} [abort] - Optional promise for aborting
79995      * the request through rejection.
79996      * @returns {Promise<ArrayBuffer>} Promise to the array
79997      * buffer containing the image.
79998      * @throws Rejects the promise on errors.
79999      */
80000     getImageBuffer(url, abort) {
80001         return Promise.reject(new MapillaryError("Not implemented"));
80002     }
80003     /**
80004      * Get image tiles urls for a tile level.
80005      *
80006      * @param {ImageTilesRequestContract} tiles - Tiles to request
80007      * @returns {Promise<ImageTilesContract>} Promise to the
80008      * image tiles response contract
80009      *
80010      * @throws Rejects the promise on errors.
80011      *
80012      * @example
80013      * ```js
80014      * var tileRequest = { imageId: 'image-id', z: 12 };
80015      * provider.getImageTiles(tileRequest)
80016      *   .then((response) => console.log(response));
80017      * ```
80018      */
80019     getImageTiles(tiles) {
80020         return Promise.reject(new MapillaryError("Not implemented"));
80021     }
80022     /**
80023      * Get a mesh.
80024      *
80025      * @param {string} url - URL for mesh to retrieve.
80026      * @param {Promise<void>} [abort] - Optional promise for aborting
80027      * the request through rejection.
80028      * @returns {Promise<MeshContract>} Promise to the mesh.
80029      * @throws Rejects the promise on errors.
80030      */
80031     getMesh(url, abort) {
80032         return Promise.reject(new MapillaryError("Not implemented"));
80033     }
80034     /**
80035      * Get sequence.
80036      *
80037      * @param {Array<string>} sequenceId - The id for the
80038      * sequence to retrieve.
80039      * @returns {Promise} Promise to the sequences of the
80040      * requested image ids.
80041      * @throws Rejects the promise on errors.
80042      */
80043     getSequence(sequenceId) {
80044         return Promise.reject(new MapillaryError("Not implemented"));
80045     }
80046     off(type, handler) {
80047         super.off(type, handler);
80048     }
80049     on(type, handler) {
80050         super.on(type, handler);
80051     }
80052     /**
80053      * Set an access token for authenticated API requests of
80054      * protected resources.
80055      *
80056      * @param {string} [accessToken] accessToken - User access
80057      * token or client access token.
80058      */
80059     setAccessToken(accessToken) {
80060         throw new MapillaryError("Not implemented");
80061     }
80062 }
80063
80064 /*
80065  Copyright 2013 Daniel Wirtz <dcode@dcode.io>
80066  Copyright 2009 The Closure Library Authors. All Rights Reserved.
80067
80068  Licensed under the Apache License, Version 2.0 (the "License");
80069  you may not use this file except in compliance with the License.
80070  You may obtain a copy of the License at
80071
80072  http://www.apache.org/licenses/LICENSE-2.0
80073
80074  Unless required by applicable law or agreed to in writing, software
80075  distributed under the License is distributed on an "AS-IS" BASIS,
80076  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
80077  See the License for the specific language governing permissions and
80078  limitations under the License.
80079  */
80080
80081 var long = createCommonjsModule(function (module) {
80082 /**
80083  * @license long.js (c) 2013 Daniel Wirtz <dcode@dcode.io>
80084  * Released under the Apache License, Version 2.0
80085  * see: https://github.com/dcodeIO/long.js for details
80086  */
80087 (function(global, factory) {
80088
80089     /* AMD */ if (typeof commonjsRequire === 'function' && 'object' === "object" && module && module["exports"])
80090         module["exports"] = factory();
80091     /* Global */ else
80092         (global["dcodeIO"] = global["dcodeIO"] || {})["Long"] = factory();
80093
80094 })(commonjsGlobal, function() {
80095
80096     /**
80097      * Constructs a 64 bit two's-complement integer, given its low and high 32 bit values as *signed* integers.
80098      *  See the from* functions below for more convenient ways of constructing Longs.
80099      * @exports Long
80100      * @class A Long class for representing a 64 bit two's-complement integer value.
80101      * @param {number} low The low (signed) 32 bits of the long
80102      * @param {number} high The high (signed) 32 bits of the long
80103      * @param {boolean=} unsigned Whether unsigned or not, defaults to `false` for signed
80104      * @constructor
80105      */
80106     function Long(low, high, unsigned) {
80107
80108         /**
80109          * The low 32 bits as a signed value.
80110          * @type {number}
80111          */
80112         this.low = low | 0;
80113
80114         /**
80115          * The high 32 bits as a signed value.
80116          * @type {number}
80117          */
80118         this.high = high | 0;
80119
80120         /**
80121          * Whether unsigned or not.
80122          * @type {boolean}
80123          */
80124         this.unsigned = !!unsigned;
80125     }
80126
80127     // The internal representation of a long is the two given signed, 32-bit values.
80128     // We use 32-bit pieces because these are the size of integers on which
80129     // Javascript performs bit-operations.  For operations like addition and
80130     // multiplication, we split each number into 16 bit pieces, which can easily be
80131     // multiplied within Javascript's floating-point representation without overflow
80132     // or change in sign.
80133     //
80134     // In the algorithms below, we frequently reduce the negative case to the
80135     // positive case by negating the input(s) and then post-processing the result.
80136     // Note that we must ALWAYS check specially whether those values are MIN_VALUE
80137     // (-2^63) because -MIN_VALUE == MIN_VALUE (since 2^63 cannot be represented as
80138     // a positive number, it overflows back into a negative).  Not handling this
80139     // case would often result in infinite recursion.
80140     //
80141     // Common constant values ZERO, ONE, NEG_ONE, etc. are defined below the from*
80142     // methods on which they depend.
80143
80144     /**
80145      * An indicator used to reliably determine if an object is a Long or not.
80146      * @type {boolean}
80147      * @const
80148      * @private
80149      */
80150     Long.prototype.__isLong__;
80151
80152     Object.defineProperty(Long.prototype, "__isLong__", {
80153         value: true,
80154         enumerable: false,
80155         configurable: false
80156     });
80157
80158     /**
80159      * @function
80160      * @param {*} obj Object
80161      * @returns {boolean}
80162      * @inner
80163      */
80164     function isLong(obj) {
80165         return (obj && obj["__isLong__"]) === true;
80166     }
80167
80168     /**
80169      * Tests if the specified object is a Long.
80170      * @function
80171      * @param {*} obj Object
80172      * @returns {boolean}
80173      */
80174     Long.isLong = isLong;
80175
80176     /**
80177      * A cache of the Long representations of small integer values.
80178      * @type {!Object}
80179      * @inner
80180      */
80181     var INT_CACHE = {};
80182
80183     /**
80184      * A cache of the Long representations of small unsigned integer values.
80185      * @type {!Object}
80186      * @inner
80187      */
80188     var UINT_CACHE = {};
80189
80190     /**
80191      * @param {number} value
80192      * @param {boolean=} unsigned
80193      * @returns {!Long}
80194      * @inner
80195      */
80196     function fromInt(value, unsigned) {
80197         var obj, cachedObj, cache;
80198         if (unsigned) {
80199             value >>>= 0;
80200             if (cache = (0 <= value && value < 256)) {
80201                 cachedObj = UINT_CACHE[value];
80202                 if (cachedObj)
80203                     return cachedObj;
80204             }
80205             obj = fromBits(value, (value | 0) < 0 ? -1 : 0, true);
80206             if (cache)
80207                 UINT_CACHE[value] = obj;
80208             return obj;
80209         } else {
80210             value |= 0;
80211             if (cache = (-128 <= value && value < 128)) {
80212                 cachedObj = INT_CACHE[value];
80213                 if (cachedObj)
80214                     return cachedObj;
80215             }
80216             obj = fromBits(value, value < 0 ? -1 : 0, false);
80217             if (cache)
80218                 INT_CACHE[value] = obj;
80219             return obj;
80220         }
80221     }
80222
80223     /**
80224      * Returns a Long representing the given 32 bit integer value.
80225      * @function
80226      * @param {number} value The 32 bit integer in question
80227      * @param {boolean=} unsigned Whether unsigned or not, defaults to `false` for signed
80228      * @returns {!Long} The corresponding Long value
80229      */
80230     Long.fromInt = fromInt;
80231
80232     /**
80233      * @param {number} value
80234      * @param {boolean=} unsigned
80235      * @returns {!Long}
80236      * @inner
80237      */
80238     function fromNumber(value, unsigned) {
80239         if (isNaN(value) || !isFinite(value))
80240             return unsigned ? UZERO : ZERO;
80241         if (unsigned) {
80242             if (value < 0)
80243                 return UZERO;
80244             if (value >= TWO_PWR_64_DBL)
80245                 return MAX_UNSIGNED_VALUE;
80246         } else {
80247             if (value <= -TWO_PWR_63_DBL)
80248                 return MIN_VALUE;
80249             if (value + 1 >= TWO_PWR_63_DBL)
80250                 return MAX_VALUE;
80251         }
80252         if (value < 0)
80253             return fromNumber(-value, unsigned).neg();
80254         return fromBits((value % TWO_PWR_32_DBL) | 0, (value / TWO_PWR_32_DBL) | 0, unsigned);
80255     }
80256
80257     /**
80258      * Returns a Long representing the given value, provided that it is a finite number. Otherwise, zero is returned.
80259      * @function
80260      * @param {number} value The number in question
80261      * @param {boolean=} unsigned Whether unsigned or not, defaults to `false` for signed
80262      * @returns {!Long} The corresponding Long value
80263      */
80264     Long.fromNumber = fromNumber;
80265
80266     /**
80267      * @param {number} lowBits
80268      * @param {number} highBits
80269      * @param {boolean=} unsigned
80270      * @returns {!Long}
80271      * @inner
80272      */
80273     function fromBits(lowBits, highBits, unsigned) {
80274         return new Long(lowBits, highBits, unsigned);
80275     }
80276
80277     /**
80278      * Returns a Long representing the 64 bit integer that comes by concatenating the given low and high bits. Each is
80279      *  assumed to use 32 bits.
80280      * @function
80281      * @param {number} lowBits The low 32 bits
80282      * @param {number} highBits The high 32 bits
80283      * @param {boolean=} unsigned Whether unsigned or not, defaults to `false` for signed
80284      * @returns {!Long} The corresponding Long value
80285      */
80286     Long.fromBits = fromBits;
80287
80288     /**
80289      * @function
80290      * @param {number} base
80291      * @param {number} exponent
80292      * @returns {number}
80293      * @inner
80294      */
80295     var pow_dbl = Math.pow; // Used 4 times (4*8 to 15+4)
80296
80297     /**
80298      * @param {string} str
80299      * @param {(boolean|number)=} unsigned
80300      * @param {number=} radix
80301      * @returns {!Long}
80302      * @inner
80303      */
80304     function fromString(str, unsigned, radix) {
80305         if (str.length === 0)
80306             throw Error('empty string');
80307         if (str === "NaN" || str === "Infinity" || str === "+Infinity" || str === "-Infinity")
80308             return ZERO;
80309         if (typeof unsigned === 'number') {
80310             // For goog.math.long compatibility
80311             radix = unsigned,
80312             unsigned = false;
80313         } else {
80314             unsigned = !! unsigned;
80315         }
80316         radix = radix || 10;
80317         if (radix < 2 || 36 < radix)
80318             throw RangeError('radix');
80319
80320         var p;
80321         if ((p = str.indexOf('-')) > 0)
80322             throw Error('interior hyphen');
80323         else if (p === 0) {
80324             return fromString(str.substring(1), unsigned, radix).neg();
80325         }
80326
80327         // Do several (8) digits each time through the loop, so as to
80328         // minimize the calls to the very expensive emulated div.
80329         var radixToPower = fromNumber(pow_dbl(radix, 8));
80330
80331         var result = ZERO;
80332         for (var i = 0; i < str.length; i += 8) {
80333             var size = Math.min(8, str.length - i),
80334                 value = parseInt(str.substring(i, i + size), radix);
80335             if (size < 8) {
80336                 var power = fromNumber(pow_dbl(radix, size));
80337                 result = result.mul(power).add(fromNumber(value));
80338             } else {
80339                 result = result.mul(radixToPower);
80340                 result = result.add(fromNumber(value));
80341             }
80342         }
80343         result.unsigned = unsigned;
80344         return result;
80345     }
80346
80347     /**
80348      * Returns a Long representation of the given string, written using the specified radix.
80349      * @function
80350      * @param {string} str The textual representation of the Long
80351      * @param {(boolean|number)=} unsigned Whether unsigned or not, defaults to `false` for signed
80352      * @param {number=} radix The radix in which the text is written (2-36), defaults to 10
80353      * @returns {!Long} The corresponding Long value
80354      */
80355     Long.fromString = fromString;
80356
80357     /**
80358      * @function
80359      * @param {!Long|number|string|!{low: number, high: number, unsigned: boolean}} val
80360      * @returns {!Long}
80361      * @inner
80362      */
80363     function fromValue(val) {
80364         if (val /* is compatible */ instanceof Long)
80365             return val;
80366         if (typeof val === 'number')
80367             return fromNumber(val);
80368         if (typeof val === 'string')
80369             return fromString(val);
80370         // Throws for non-objects, converts non-instanceof Long:
80371         return fromBits(val.low, val.high, val.unsigned);
80372     }
80373
80374     /**
80375      * Converts the specified value to a Long.
80376      * @function
80377      * @param {!Long|number|string|!{low: number, high: number, unsigned: boolean}} val Value
80378      * @returns {!Long}
80379      */
80380     Long.fromValue = fromValue;
80381
80382     // NOTE: the compiler should inline these constant values below and then remove these variables, so there should be
80383     // no runtime penalty for these.
80384
80385     /**
80386      * @type {number}
80387      * @const
80388      * @inner
80389      */
80390     var TWO_PWR_16_DBL = 1 << 16;
80391
80392     /**
80393      * @type {number}
80394      * @const
80395      * @inner
80396      */
80397     var TWO_PWR_24_DBL = 1 << 24;
80398
80399     /**
80400      * @type {number}
80401      * @const
80402      * @inner
80403      */
80404     var TWO_PWR_32_DBL = TWO_PWR_16_DBL * TWO_PWR_16_DBL;
80405
80406     /**
80407      * @type {number}
80408      * @const
80409      * @inner
80410      */
80411     var TWO_PWR_64_DBL = TWO_PWR_32_DBL * TWO_PWR_32_DBL;
80412
80413     /**
80414      * @type {number}
80415      * @const
80416      * @inner
80417      */
80418     var TWO_PWR_63_DBL = TWO_PWR_64_DBL / 2;
80419
80420     /**
80421      * @type {!Long}
80422      * @const
80423      * @inner
80424      */
80425     var TWO_PWR_24 = fromInt(TWO_PWR_24_DBL);
80426
80427     /**
80428      * @type {!Long}
80429      * @inner
80430      */
80431     var ZERO = fromInt(0);
80432
80433     /**
80434      * Signed zero.
80435      * @type {!Long}
80436      */
80437     Long.ZERO = ZERO;
80438
80439     /**
80440      * @type {!Long}
80441      * @inner
80442      */
80443     var UZERO = fromInt(0, true);
80444
80445     /**
80446      * Unsigned zero.
80447      * @type {!Long}
80448      */
80449     Long.UZERO = UZERO;
80450
80451     /**
80452      * @type {!Long}
80453      * @inner
80454      */
80455     var ONE = fromInt(1);
80456
80457     /**
80458      * Signed one.
80459      * @type {!Long}
80460      */
80461     Long.ONE = ONE;
80462
80463     /**
80464      * @type {!Long}
80465      * @inner
80466      */
80467     var UONE = fromInt(1, true);
80468
80469     /**
80470      * Unsigned one.
80471      * @type {!Long}
80472      */
80473     Long.UONE = UONE;
80474
80475     /**
80476      * @type {!Long}
80477      * @inner
80478      */
80479     var NEG_ONE = fromInt(-1);
80480
80481     /**
80482      * Signed negative one.
80483      * @type {!Long}
80484      */
80485     Long.NEG_ONE = NEG_ONE;
80486
80487     /**
80488      * @type {!Long}
80489      * @inner
80490      */
80491     var MAX_VALUE = fromBits(0xFFFFFFFF|0, 0x7FFFFFFF|0, false);
80492
80493     /**
80494      * Maximum signed value.
80495      * @type {!Long}
80496      */
80497     Long.MAX_VALUE = MAX_VALUE;
80498
80499     /**
80500      * @type {!Long}
80501      * @inner
80502      */
80503     var MAX_UNSIGNED_VALUE = fromBits(0xFFFFFFFF|0, 0xFFFFFFFF|0, true);
80504
80505     /**
80506      * Maximum unsigned value.
80507      * @type {!Long}
80508      */
80509     Long.MAX_UNSIGNED_VALUE = MAX_UNSIGNED_VALUE;
80510
80511     /**
80512      * @type {!Long}
80513      * @inner
80514      */
80515     var MIN_VALUE = fromBits(0, 0x80000000|0, false);
80516
80517     /**
80518      * Minimum signed value.
80519      * @type {!Long}
80520      */
80521     Long.MIN_VALUE = MIN_VALUE;
80522
80523     /**
80524      * @alias Long.prototype
80525      * @inner
80526      */
80527     var LongPrototype = Long.prototype;
80528
80529     /**
80530      * Converts the Long to a 32 bit integer, assuming it is a 32 bit integer.
80531      * @returns {number}
80532      */
80533     LongPrototype.toInt = function toInt() {
80534         return this.unsigned ? this.low >>> 0 : this.low;
80535     };
80536
80537     /**
80538      * Converts the Long to a the nearest floating-point representation of this value (double, 53 bit mantissa).
80539      * @returns {number}
80540      */
80541     LongPrototype.toNumber = function toNumber() {
80542         if (this.unsigned)
80543             return ((this.high >>> 0) * TWO_PWR_32_DBL) + (this.low >>> 0);
80544         return this.high * TWO_PWR_32_DBL + (this.low >>> 0);
80545     };
80546
80547     /**
80548      * Converts the Long to a string written in the specified radix.
80549      * @param {number=} radix Radix (2-36), defaults to 10
80550      * @returns {string}
80551      * @override
80552      * @throws {RangeError} If `radix` is out of range
80553      */
80554     LongPrototype.toString = function toString(radix) {
80555         radix = radix || 10;
80556         if (radix < 2 || 36 < radix)
80557             throw RangeError('radix');
80558         if (this.isZero())
80559             return '0';
80560         if (this.isNegative()) { // Unsigned Longs are never negative
80561             if (this.eq(MIN_VALUE)) {
80562                 // We need to change the Long value before it can be negated, so we remove
80563                 // the bottom-most digit in this base and then recurse to do the rest.
80564                 var radixLong = fromNumber(radix),
80565                     div = this.div(radixLong),
80566                     rem1 = div.mul(radixLong).sub(this);
80567                 return div.toString(radix) + rem1.toInt().toString(radix);
80568             } else
80569                 return '-' + this.neg().toString(radix);
80570         }
80571
80572         // Do several (6) digits each time through the loop, so as to
80573         // minimize the calls to the very expensive emulated div.
80574         var radixToPower = fromNumber(pow_dbl(radix, 6), this.unsigned),
80575             rem = this;
80576         var result = '';
80577         while (true) {
80578             var remDiv = rem.div(radixToPower),
80579                 intval = rem.sub(remDiv.mul(radixToPower)).toInt() >>> 0,
80580                 digits = intval.toString(radix);
80581             rem = remDiv;
80582             if (rem.isZero())
80583                 return digits + result;
80584             else {
80585                 while (digits.length < 6)
80586                     digits = '0' + digits;
80587                 result = '' + digits + result;
80588             }
80589         }
80590     };
80591
80592     /**
80593      * Gets the high 32 bits as a signed integer.
80594      * @returns {number} Signed high bits
80595      */
80596     LongPrototype.getHighBits = function getHighBits() {
80597         return this.high;
80598     };
80599
80600     /**
80601      * Gets the high 32 bits as an unsigned integer.
80602      * @returns {number} Unsigned high bits
80603      */
80604     LongPrototype.getHighBitsUnsigned = function getHighBitsUnsigned() {
80605         return this.high >>> 0;
80606     };
80607
80608     /**
80609      * Gets the low 32 bits as a signed integer.
80610      * @returns {number} Signed low bits
80611      */
80612     LongPrototype.getLowBits = function getLowBits() {
80613         return this.low;
80614     };
80615
80616     /**
80617      * Gets the low 32 bits as an unsigned integer.
80618      * @returns {number} Unsigned low bits
80619      */
80620     LongPrototype.getLowBitsUnsigned = function getLowBitsUnsigned() {
80621         return this.low >>> 0;
80622     };
80623
80624     /**
80625      * Gets the number of bits needed to represent the absolute value of this Long.
80626      * @returns {number}
80627      */
80628     LongPrototype.getNumBitsAbs = function getNumBitsAbs() {
80629         if (this.isNegative()) // Unsigned Longs are never negative
80630             return this.eq(MIN_VALUE) ? 64 : this.neg().getNumBitsAbs();
80631         var val = this.high != 0 ? this.high : this.low;
80632         for (var bit = 31; bit > 0; bit--)
80633             if ((val & (1 << bit)) != 0)
80634                 break;
80635         return this.high != 0 ? bit + 33 : bit + 1;
80636     };
80637
80638     /**
80639      * Tests if this Long's value equals zero.
80640      * @returns {boolean}
80641      */
80642     LongPrototype.isZero = function isZero() {
80643         return this.high === 0 && this.low === 0;
80644     };
80645
80646     /**
80647      * Tests if this Long's value is negative.
80648      * @returns {boolean}
80649      */
80650     LongPrototype.isNegative = function isNegative() {
80651         return !this.unsigned && this.high < 0;
80652     };
80653
80654     /**
80655      * Tests if this Long's value is positive.
80656      * @returns {boolean}
80657      */
80658     LongPrototype.isPositive = function isPositive() {
80659         return this.unsigned || this.high >= 0;
80660     };
80661
80662     /**
80663      * Tests if this Long's value is odd.
80664      * @returns {boolean}
80665      */
80666     LongPrototype.isOdd = function isOdd() {
80667         return (this.low & 1) === 1;
80668     };
80669
80670     /**
80671      * Tests if this Long's value is even.
80672      * @returns {boolean}
80673      */
80674     LongPrototype.isEven = function isEven() {
80675         return (this.low & 1) === 0;
80676     };
80677
80678     /**
80679      * Tests if this Long's value equals the specified's.
80680      * @param {!Long|number|string} other Other value
80681      * @returns {boolean}
80682      */
80683     LongPrototype.equals = function equals(other) {
80684         if (!isLong(other))
80685             other = fromValue(other);
80686         if (this.unsigned !== other.unsigned && (this.high >>> 31) === 1 && (other.high >>> 31) === 1)
80687             return false;
80688         return this.high === other.high && this.low === other.low;
80689     };
80690
80691     /**
80692      * Tests if this Long's value equals the specified's. This is an alias of {@link Long#equals}.
80693      * @function
80694      * @param {!Long|number|string} other Other value
80695      * @returns {boolean}
80696      */
80697     LongPrototype.eq = LongPrototype.equals;
80698
80699     /**
80700      * Tests if this Long's value differs from the specified's.
80701      * @param {!Long|number|string} other Other value
80702      * @returns {boolean}
80703      */
80704     LongPrototype.notEquals = function notEquals(other) {
80705         return !this.eq(/* validates */ other);
80706     };
80707
80708     /**
80709      * Tests if this Long's value differs from the specified's. This is an alias of {@link Long#notEquals}.
80710      * @function
80711      * @param {!Long|number|string} other Other value
80712      * @returns {boolean}
80713      */
80714     LongPrototype.neq = LongPrototype.notEquals;
80715
80716     /**
80717      * Tests if this Long's value is less than the specified's.
80718      * @param {!Long|number|string} other Other value
80719      * @returns {boolean}
80720      */
80721     LongPrototype.lessThan = function lessThan(other) {
80722         return this.comp(/* validates */ other) < 0;
80723     };
80724
80725     /**
80726      * Tests if this Long's value is less than the specified's. This is an alias of {@link Long#lessThan}.
80727      * @function
80728      * @param {!Long|number|string} other Other value
80729      * @returns {boolean}
80730      */
80731     LongPrototype.lt = LongPrototype.lessThan;
80732
80733     /**
80734      * Tests if this Long's value is less than or equal the specified's.
80735      * @param {!Long|number|string} other Other value
80736      * @returns {boolean}
80737      */
80738     LongPrototype.lessThanOrEqual = function lessThanOrEqual(other) {
80739         return this.comp(/* validates */ other) <= 0;
80740     };
80741
80742     /**
80743      * Tests if this Long's value is less than or equal the specified's. This is an alias of {@link Long#lessThanOrEqual}.
80744      * @function
80745      * @param {!Long|number|string} other Other value
80746      * @returns {boolean}
80747      */
80748     LongPrototype.lte = LongPrototype.lessThanOrEqual;
80749
80750     /**
80751      * Tests if this Long's value is greater than the specified's.
80752      * @param {!Long|number|string} other Other value
80753      * @returns {boolean}
80754      */
80755     LongPrototype.greaterThan = function greaterThan(other) {
80756         return this.comp(/* validates */ other) > 0;
80757     };
80758
80759     /**
80760      * Tests if this Long's value is greater than the specified's. This is an alias of {@link Long#greaterThan}.
80761      * @function
80762      * @param {!Long|number|string} other Other value
80763      * @returns {boolean}
80764      */
80765     LongPrototype.gt = LongPrototype.greaterThan;
80766
80767     /**
80768      * Tests if this Long's value is greater than or equal the specified's.
80769      * @param {!Long|number|string} other Other value
80770      * @returns {boolean}
80771      */
80772     LongPrototype.greaterThanOrEqual = function greaterThanOrEqual(other) {
80773         return this.comp(/* validates */ other) >= 0;
80774     };
80775
80776     /**
80777      * Tests if this Long's value is greater than or equal the specified's. This is an alias of {@link Long#greaterThanOrEqual}.
80778      * @function
80779      * @param {!Long|number|string} other Other value
80780      * @returns {boolean}
80781      */
80782     LongPrototype.gte = LongPrototype.greaterThanOrEqual;
80783
80784     /**
80785      * Compares this Long's value with the specified's.
80786      * @param {!Long|number|string} other Other value
80787      * @returns {number} 0 if they are the same, 1 if the this is greater and -1
80788      *  if the given one is greater
80789      */
80790     LongPrototype.compare = function compare(other) {
80791         if (!isLong(other))
80792             other = fromValue(other);
80793         if (this.eq(other))
80794             return 0;
80795         var thisNeg = this.isNegative(),
80796             otherNeg = other.isNegative();
80797         if (thisNeg && !otherNeg)
80798             return -1;
80799         if (!thisNeg && otherNeg)
80800             return 1;
80801         // At this point the sign bits are the same
80802         if (!this.unsigned)
80803             return this.sub(other).isNegative() ? -1 : 1;
80804         // Both are positive if at least one is unsigned
80805         return (other.high >>> 0) > (this.high >>> 0) || (other.high === this.high && (other.low >>> 0) > (this.low >>> 0)) ? -1 : 1;
80806     };
80807
80808     /**
80809      * Compares this Long's value with the specified's. This is an alias of {@link Long#compare}.
80810      * @function
80811      * @param {!Long|number|string} other Other value
80812      * @returns {number} 0 if they are the same, 1 if the this is greater and -1
80813      *  if the given one is greater
80814      */
80815     LongPrototype.comp = LongPrototype.compare;
80816
80817     /**
80818      * Negates this Long's value.
80819      * @returns {!Long} Negated Long
80820      */
80821     LongPrototype.negate = function negate() {
80822         if (!this.unsigned && this.eq(MIN_VALUE))
80823             return MIN_VALUE;
80824         return this.not().add(ONE);
80825     };
80826
80827     /**
80828      * Negates this Long's value. This is an alias of {@link Long#negate}.
80829      * @function
80830      * @returns {!Long} Negated Long
80831      */
80832     LongPrototype.neg = LongPrototype.negate;
80833
80834     /**
80835      * Returns the sum of this and the specified Long.
80836      * @param {!Long|number|string} addend Addend
80837      * @returns {!Long} Sum
80838      */
80839     LongPrototype.add = function add(addend) {
80840         if (!isLong(addend))
80841             addend = fromValue(addend);
80842
80843         // Divide each number into 4 chunks of 16 bits, and then sum the chunks.
80844
80845         var a48 = this.high >>> 16;
80846         var a32 = this.high & 0xFFFF;
80847         var a16 = this.low >>> 16;
80848         var a00 = this.low & 0xFFFF;
80849
80850         var b48 = addend.high >>> 16;
80851         var b32 = addend.high & 0xFFFF;
80852         var b16 = addend.low >>> 16;
80853         var b00 = addend.low & 0xFFFF;
80854
80855         var c48 = 0, c32 = 0, c16 = 0, c00 = 0;
80856         c00 += a00 + b00;
80857         c16 += c00 >>> 16;
80858         c00 &= 0xFFFF;
80859         c16 += a16 + b16;
80860         c32 += c16 >>> 16;
80861         c16 &= 0xFFFF;
80862         c32 += a32 + b32;
80863         c48 += c32 >>> 16;
80864         c32 &= 0xFFFF;
80865         c48 += a48 + b48;
80866         c48 &= 0xFFFF;
80867         return fromBits((c16 << 16) | c00, (c48 << 16) | c32, this.unsigned);
80868     };
80869
80870     /**
80871      * Returns the difference of this and the specified Long.
80872      * @param {!Long|number|string} subtrahend Subtrahend
80873      * @returns {!Long} Difference
80874      */
80875     LongPrototype.subtract = function subtract(subtrahend) {
80876         if (!isLong(subtrahend))
80877             subtrahend = fromValue(subtrahend);
80878         return this.add(subtrahend.neg());
80879     };
80880
80881     /**
80882      * Returns the difference of this and the specified Long. This is an alias of {@link Long#subtract}.
80883      * @function
80884      * @param {!Long|number|string} subtrahend Subtrahend
80885      * @returns {!Long} Difference
80886      */
80887     LongPrototype.sub = LongPrototype.subtract;
80888
80889     /**
80890      * Returns the product of this and the specified Long.
80891      * @param {!Long|number|string} multiplier Multiplier
80892      * @returns {!Long} Product
80893      */
80894     LongPrototype.multiply = function multiply(multiplier) {
80895         if (this.isZero())
80896             return ZERO;
80897         if (!isLong(multiplier))
80898             multiplier = fromValue(multiplier);
80899         if (multiplier.isZero())
80900             return ZERO;
80901         if (this.eq(MIN_VALUE))
80902             return multiplier.isOdd() ? MIN_VALUE : ZERO;
80903         if (multiplier.eq(MIN_VALUE))
80904             return this.isOdd() ? MIN_VALUE : ZERO;
80905
80906         if (this.isNegative()) {
80907             if (multiplier.isNegative())
80908                 return this.neg().mul(multiplier.neg());
80909             else
80910                 return this.neg().mul(multiplier).neg();
80911         } else if (multiplier.isNegative())
80912             return this.mul(multiplier.neg()).neg();
80913
80914         // If both longs are small, use float multiplication
80915         if (this.lt(TWO_PWR_24) && multiplier.lt(TWO_PWR_24))
80916             return fromNumber(this.toNumber() * multiplier.toNumber(), this.unsigned);
80917
80918         // Divide each long into 4 chunks of 16 bits, and then add up 4x4 products.
80919         // We can skip products that would overflow.
80920
80921         var a48 = this.high >>> 16;
80922         var a32 = this.high & 0xFFFF;
80923         var a16 = this.low >>> 16;
80924         var a00 = this.low & 0xFFFF;
80925
80926         var b48 = multiplier.high >>> 16;
80927         var b32 = multiplier.high & 0xFFFF;
80928         var b16 = multiplier.low >>> 16;
80929         var b00 = multiplier.low & 0xFFFF;
80930
80931         var c48 = 0, c32 = 0, c16 = 0, c00 = 0;
80932         c00 += a00 * b00;
80933         c16 += c00 >>> 16;
80934         c00 &= 0xFFFF;
80935         c16 += a16 * b00;
80936         c32 += c16 >>> 16;
80937         c16 &= 0xFFFF;
80938         c16 += a00 * b16;
80939         c32 += c16 >>> 16;
80940         c16 &= 0xFFFF;
80941         c32 += a32 * b00;
80942         c48 += c32 >>> 16;
80943         c32 &= 0xFFFF;
80944         c32 += a16 * b16;
80945         c48 += c32 >>> 16;
80946         c32 &= 0xFFFF;
80947         c32 += a00 * b32;
80948         c48 += c32 >>> 16;
80949         c32 &= 0xFFFF;
80950         c48 += a48 * b00 + a32 * b16 + a16 * b32 + a00 * b48;
80951         c48 &= 0xFFFF;
80952         return fromBits((c16 << 16) | c00, (c48 << 16) | c32, this.unsigned);
80953     };
80954
80955     /**
80956      * Returns the product of this and the specified Long. This is an alias of {@link Long#multiply}.
80957      * @function
80958      * @param {!Long|number|string} multiplier Multiplier
80959      * @returns {!Long} Product
80960      */
80961     LongPrototype.mul = LongPrototype.multiply;
80962
80963     /**
80964      * Returns this Long divided by the specified. The result is signed if this Long is signed or
80965      *  unsigned if this Long is unsigned.
80966      * @param {!Long|number|string} divisor Divisor
80967      * @returns {!Long} Quotient
80968      */
80969     LongPrototype.divide = function divide(divisor) {
80970         if (!isLong(divisor))
80971             divisor = fromValue(divisor);
80972         if (divisor.isZero())
80973             throw Error('division by zero');
80974         if (this.isZero())
80975             return this.unsigned ? UZERO : ZERO;
80976         var approx, rem, res;
80977         if (!this.unsigned) {
80978             // This section is only relevant for signed longs and is derived from the
80979             // closure library as a whole.
80980             if (this.eq(MIN_VALUE)) {
80981                 if (divisor.eq(ONE) || divisor.eq(NEG_ONE))
80982                     return MIN_VALUE;  // recall that -MIN_VALUE == MIN_VALUE
80983                 else if (divisor.eq(MIN_VALUE))
80984                     return ONE;
80985                 else {
80986                     // At this point, we have |other| >= 2, so |this/other| < |MIN_VALUE|.
80987                     var halfThis = this.shr(1);
80988                     approx = halfThis.div(divisor).shl(1);
80989                     if (approx.eq(ZERO)) {
80990                         return divisor.isNegative() ? ONE : NEG_ONE;
80991                     } else {
80992                         rem = this.sub(divisor.mul(approx));
80993                         res = approx.add(rem.div(divisor));
80994                         return res;
80995                     }
80996                 }
80997             } else if (divisor.eq(MIN_VALUE))
80998                 return this.unsigned ? UZERO : ZERO;
80999             if (this.isNegative()) {
81000                 if (divisor.isNegative())
81001                     return this.neg().div(divisor.neg());
81002                 return this.neg().div(divisor).neg();
81003             } else if (divisor.isNegative())
81004                 return this.div(divisor.neg()).neg();
81005             res = ZERO;
81006         } else {
81007             // The algorithm below has not been made for unsigned longs. It's therefore
81008             // required to take special care of the MSB prior to running it.
81009             if (!divisor.unsigned)
81010                 divisor = divisor.toUnsigned();
81011             if (divisor.gt(this))
81012                 return UZERO;
81013             if (divisor.gt(this.shru(1))) // 15 >>> 1 = 7 ; with divisor = 8 ; true
81014                 return UONE;
81015             res = UZERO;
81016         }
81017
81018         // Repeat the following until the remainder is less than other:  find a
81019         // floating-point that approximates remainder / other *from below*, add this
81020         // into the result, and subtract it from the remainder.  It is critical that
81021         // the approximate value is less than or equal to the real value so that the
81022         // remainder never becomes negative.
81023         rem = this;
81024         while (rem.gte(divisor)) {
81025             // Approximate the result of division. This may be a little greater or
81026             // smaller than the actual value.
81027             approx = Math.max(1, Math.floor(rem.toNumber() / divisor.toNumber()));
81028
81029             // We will tweak the approximate result by changing it in the 48-th digit or
81030             // the smallest non-fractional digit, whichever is larger.
81031             var log2 = Math.ceil(Math.log(approx) / Math.LN2),
81032                 delta = (log2 <= 48) ? 1 : pow_dbl(2, log2 - 48),
81033
81034             // Decrease the approximation until it is smaller than the remainder.  Note
81035             // that if it is too large, the product overflows and is negative.
81036                 approxRes = fromNumber(approx),
81037                 approxRem = approxRes.mul(divisor);
81038             while (approxRem.isNegative() || approxRem.gt(rem)) {
81039                 approx -= delta;
81040                 approxRes = fromNumber(approx, this.unsigned);
81041                 approxRem = approxRes.mul(divisor);
81042             }
81043
81044             // We know the answer can't be zero... and actually, zero would cause
81045             // infinite recursion since we would make no progress.
81046             if (approxRes.isZero())
81047                 approxRes = ONE;
81048
81049             res = res.add(approxRes);
81050             rem = rem.sub(approxRem);
81051         }
81052         return res;
81053     };
81054
81055     /**
81056      * Returns this Long divided by the specified. This is an alias of {@link Long#divide}.
81057      * @function
81058      * @param {!Long|number|string} divisor Divisor
81059      * @returns {!Long} Quotient
81060      */
81061     LongPrototype.div = LongPrototype.divide;
81062
81063     /**
81064      * Returns this Long modulo the specified.
81065      * @param {!Long|number|string} divisor Divisor
81066      * @returns {!Long} Remainder
81067      */
81068     LongPrototype.modulo = function modulo(divisor) {
81069         if (!isLong(divisor))
81070             divisor = fromValue(divisor);
81071         return this.sub(this.div(divisor).mul(divisor));
81072     };
81073
81074     /**
81075      * Returns this Long modulo the specified. This is an alias of {@link Long#modulo}.
81076      * @function
81077      * @param {!Long|number|string} divisor Divisor
81078      * @returns {!Long} Remainder
81079      */
81080     LongPrototype.mod = LongPrototype.modulo;
81081
81082     /**
81083      * Returns the bitwise NOT of this Long.
81084      * @returns {!Long}
81085      */
81086     LongPrototype.not = function not() {
81087         return fromBits(~this.low, ~this.high, this.unsigned);
81088     };
81089
81090     /**
81091      * Returns the bitwise AND of this Long and the specified.
81092      * @param {!Long|number|string} other Other Long
81093      * @returns {!Long}
81094      */
81095     LongPrototype.and = function and(other) {
81096         if (!isLong(other))
81097             other = fromValue(other);
81098         return fromBits(this.low & other.low, this.high & other.high, this.unsigned);
81099     };
81100
81101     /**
81102      * Returns the bitwise OR of this Long and the specified.
81103      * @param {!Long|number|string} other Other Long
81104      * @returns {!Long}
81105      */
81106     LongPrototype.or = function or(other) {
81107         if (!isLong(other))
81108             other = fromValue(other);
81109         return fromBits(this.low | other.low, this.high | other.high, this.unsigned);
81110     };
81111
81112     /**
81113      * Returns the bitwise XOR of this Long and the given one.
81114      * @param {!Long|number|string} other Other Long
81115      * @returns {!Long}
81116      */
81117     LongPrototype.xor = function xor(other) {
81118         if (!isLong(other))
81119             other = fromValue(other);
81120         return fromBits(this.low ^ other.low, this.high ^ other.high, this.unsigned);
81121     };
81122
81123     /**
81124      * Returns this Long with bits shifted to the left by the given amount.
81125      * @param {number|!Long} numBits Number of bits
81126      * @returns {!Long} Shifted Long
81127      */
81128     LongPrototype.shiftLeft = function shiftLeft(numBits) {
81129         if (isLong(numBits))
81130             numBits = numBits.toInt();
81131         if ((numBits &= 63) === 0)
81132             return this;
81133         else if (numBits < 32)
81134             return fromBits(this.low << numBits, (this.high << numBits) | (this.low >>> (32 - numBits)), this.unsigned);
81135         else
81136             return fromBits(0, this.low << (numBits - 32), this.unsigned);
81137     };
81138
81139     /**
81140      * Returns this Long with bits shifted to the left by the given amount. This is an alias of {@link Long#shiftLeft}.
81141      * @function
81142      * @param {number|!Long} numBits Number of bits
81143      * @returns {!Long} Shifted Long
81144      */
81145     LongPrototype.shl = LongPrototype.shiftLeft;
81146
81147     /**
81148      * Returns this Long with bits arithmetically shifted to the right by the given amount.
81149      * @param {number|!Long} numBits Number of bits
81150      * @returns {!Long} Shifted Long
81151      */
81152     LongPrototype.shiftRight = function shiftRight(numBits) {
81153         if (isLong(numBits))
81154             numBits = numBits.toInt();
81155         if ((numBits &= 63) === 0)
81156             return this;
81157         else if (numBits < 32)
81158             return fromBits((this.low >>> numBits) | (this.high << (32 - numBits)), this.high >> numBits, this.unsigned);
81159         else
81160             return fromBits(this.high >> (numBits - 32), this.high >= 0 ? 0 : -1, this.unsigned);
81161     };
81162
81163     /**
81164      * Returns this Long with bits arithmetically shifted to the right by the given amount. This is an alias of {@link Long#shiftRight}.
81165      * @function
81166      * @param {number|!Long} numBits Number of bits
81167      * @returns {!Long} Shifted Long
81168      */
81169     LongPrototype.shr = LongPrototype.shiftRight;
81170
81171     /**
81172      * Returns this Long with bits logically shifted to the right by the given amount.
81173      * @param {number|!Long} numBits Number of bits
81174      * @returns {!Long} Shifted Long
81175      */
81176     LongPrototype.shiftRightUnsigned = function shiftRightUnsigned(numBits) {
81177         if (isLong(numBits))
81178             numBits = numBits.toInt();
81179         numBits &= 63;
81180         if (numBits === 0)
81181             return this;
81182         else {
81183             var high = this.high;
81184             if (numBits < 32) {
81185                 var low = this.low;
81186                 return fromBits((low >>> numBits) | (high << (32 - numBits)), high >>> numBits, this.unsigned);
81187             } else if (numBits === 32)
81188                 return fromBits(high, 0, this.unsigned);
81189             else
81190                 return fromBits(high >>> (numBits - 32), 0, this.unsigned);
81191         }
81192     };
81193
81194     /**
81195      * Returns this Long with bits logically shifted to the right by the given amount. This is an alias of {@link Long#shiftRightUnsigned}.
81196      * @function
81197      * @param {number|!Long} numBits Number of bits
81198      * @returns {!Long} Shifted Long
81199      */
81200     LongPrototype.shru = LongPrototype.shiftRightUnsigned;
81201
81202     /**
81203      * Converts this Long to signed.
81204      * @returns {!Long} Signed long
81205      */
81206     LongPrototype.toSigned = function toSigned() {
81207         if (!this.unsigned)
81208             return this;
81209         return fromBits(this.low, this.high, false);
81210     };
81211
81212     /**
81213      * Converts this Long to unsigned.
81214      * @returns {!Long} Unsigned long
81215      */
81216     LongPrototype.toUnsigned = function toUnsigned() {
81217         if (this.unsigned)
81218             return this;
81219         return fromBits(this.low, this.high, true);
81220     };
81221
81222     /**
81223      * Converts this Long to its byte representation.
81224      * @param {boolean=} le Whether little or big endian, defaults to big endian
81225      * @returns {!Array.<number>} Byte representation
81226      */
81227     LongPrototype.toBytes = function(le) {
81228         return le ? this.toBytesLE() : this.toBytesBE();
81229     };
81230
81231     /**
81232      * Converts this Long to its little endian byte representation.
81233      * @returns {!Array.<number>} Little endian byte representation
81234      */
81235     LongPrototype.toBytesLE = function() {
81236         var hi = this.high,
81237             lo = this.low;
81238         return [
81239              lo         & 0xff,
81240             (lo >>>  8) & 0xff,
81241             (lo >>> 16) & 0xff,
81242             (lo >>> 24) & 0xff,
81243              hi         & 0xff,
81244             (hi >>>  8) & 0xff,
81245             (hi >>> 16) & 0xff,
81246             (hi >>> 24) & 0xff
81247         ];
81248     };
81249
81250     /**
81251      * Converts this Long to its big endian byte representation.
81252      * @returns {!Array.<number>} Big endian byte representation
81253      */
81254     LongPrototype.toBytesBE = function() {
81255         var hi = this.high,
81256             lo = this.low;
81257         return [
81258             (hi >>> 24) & 0xff,
81259             (hi >>> 16) & 0xff,
81260             (hi >>>  8) & 0xff,
81261              hi         & 0xff,
81262             (lo >>> 24) & 0xff,
81263             (lo >>> 16) & 0xff,
81264             (lo >>>  8) & 0xff,
81265              lo         & 0xff
81266         ];
81267     };
81268
81269     return Long;
81270 });
81271 });
81272
81273 var s2geometry = createCommonjsModule(function (module) {
81274 /// S2 Geometry functions
81275 // the regional scoreboard is based on a level 6 S2 Cell
81276 // - https://docs.google.com/presentation/d/1Hl4KapfAENAOf4gv-pSngKwvS_jwNVHRPZTTDzXXn6Q/view?pli=1#slide=id.i22
81277 // at the time of writing there's no actual API for the intel map to retrieve scoreboard data,
81278 // but it's still useful to plot the score cells on the intel map
81279
81280
81281 // the S2 geometry is based on projecting the earth sphere onto a cube, with some scaling of face coordinates to
81282 // keep things close to approximate equal area for adjacent cells
81283 // to convert a lat,lng into a cell id:
81284 // - convert lat,lng to x,y,z
81285 // - convert x,y,z into face,u,v
81286 // - u,v scaled to s,t with quadratic formula
81287 // - s,t converted to integer i,j offsets
81288 // - i,j converted to a position along a Hubbert space-filling curve
81289 // - combine face,position to get the cell id
81290
81291 //NOTE: compared to the google S2 geometry library, we vary from their code in the following ways
81292 // - cell IDs: they combine face and the hilbert curve position into a single 64 bit number. this gives efficient space
81293 //             and speed. javascript doesn't have appropriate data types, and speed is not cricical, so we use
81294 //             as [face,[bitpair,bitpair,...]] instead
81295 // - i,j: they always use 30 bits, adjusting as needed. we use 0 to (1<<level)-1 instead
81296 //        (so GetSizeIJ for a cell is always 1)
81297
81298 (function (exports) {
81299
81300 var S2 = exports.S2 = { L: {} };
81301
81302 S2.L.LatLng = function (/*Number*/ rawLat, /*Number*/ rawLng, /*Boolean*/ noWrap) {
81303   var lat = parseFloat(rawLat, 10);
81304   var lng = parseFloat(rawLng, 10);
81305
81306   if (isNaN(lat) || isNaN(lng)) {
81307     throw new Error('Invalid LatLng object: (' + rawLat + ', ' + rawLng + ')');
81308   }
81309
81310   if (noWrap !== true) {
81311     lat = Math.max(Math.min(lat, 90), -90);                 // clamp latitude into -90..90
81312     lng = (lng + 180) % 360 + ((lng < -180 || lng === 180) ? 180 : -180);   // wrap longtitude into -180..180
81313   }
81314
81315   return { lat: lat, lng: lng };
81316 };
81317
81318 S2.L.LatLng.DEG_TO_RAD = Math.PI / 180;
81319 S2.L.LatLng.RAD_TO_DEG = 180 / Math.PI;
81320
81321 /*
81322 S2.LatLngToXYZ = function(latLng) {
81323   // http://stackoverflow.com/questions/8981943/lat-long-to-x-y-z-position-in-js-not-working
81324   var lat = latLng.lat;
81325   var lon = latLng.lng;
81326   var DEG_TO_RAD = Math.PI / 180.0;
81327
81328   var phi = lat * DEG_TO_RAD;
81329   var theta = lon * DEG_TO_RAD;
81330
81331   var cosLat = Math.cos(phi);
81332   var sinLat = Math.sin(phi);
81333   var cosLon = Math.cos(theta);
81334   var sinLon = Math.sin(theta);
81335   var rad = 500.0;
81336
81337   return [
81338     rad * cosLat * cosLon
81339   , rad * cosLat * sinLon
81340   , rad * sinLat
81341   ];
81342 };
81343 */
81344 S2.LatLngToXYZ = function(latLng) {
81345   var d2r = S2.L.LatLng.DEG_TO_RAD;
81346
81347   var phi = latLng.lat*d2r;
81348   var theta = latLng.lng*d2r;
81349
81350   var cosphi = Math.cos(phi);
81351
81352   return [Math.cos(theta)*cosphi, Math.sin(theta)*cosphi, Math.sin(phi)];
81353 };
81354
81355 S2.XYZToLatLng = function(xyz) {
81356   var r2d = S2.L.LatLng.RAD_TO_DEG;
81357
81358   var lat = Math.atan2(xyz[2], Math.sqrt(xyz[0]*xyz[0]+xyz[1]*xyz[1]));
81359   var lng = Math.atan2(xyz[1], xyz[0]);
81360
81361   return S2.L.LatLng(lat*r2d, lng*r2d);
81362 };
81363
81364 var largestAbsComponent = function(xyz) {
81365   var temp = [Math.abs(xyz[0]), Math.abs(xyz[1]), Math.abs(xyz[2])];
81366
81367   if (temp[0] > temp[1]) {
81368     if (temp[0] > temp[2]) {
81369       return 0;
81370     } else {
81371       return 2;
81372     }
81373   } else {
81374     if (temp[1] > temp[2]) {
81375       return 1;
81376     } else {
81377       return 2;
81378     }
81379   }
81380
81381 };
81382
81383 var faceXYZToUV = function(face,xyz) {
81384   var u,v;
81385
81386   switch (face) {
81387     case 0: u =  xyz[1]/xyz[0]; v =  xyz[2]/xyz[0]; break;
81388     case 1: u = -xyz[0]/xyz[1]; v =  xyz[2]/xyz[1]; break;
81389     case 2: u = -xyz[0]/xyz[2]; v = -xyz[1]/xyz[2]; break;
81390     case 3: u =  xyz[2]/xyz[0]; v =  xyz[1]/xyz[0]; break;
81391     case 4: u =  xyz[2]/xyz[1]; v = -xyz[0]/xyz[1]; break;
81392     case 5: u = -xyz[1]/xyz[2]; v = -xyz[0]/xyz[2]; break;
81393     default: throw {error: 'Invalid face'};
81394   }
81395
81396   return [u,v];
81397 };
81398
81399
81400
81401
81402 S2.XYZToFaceUV = function(xyz) {
81403   var face = largestAbsComponent(xyz);
81404
81405   if (xyz[face] < 0) {
81406     face += 3;
81407   }
81408
81409   var uv = faceXYZToUV (face,xyz);
81410
81411   return [face, uv];
81412 };
81413
81414 S2.FaceUVToXYZ = function(face,uv) {
81415   var u = uv[0];
81416   var v = uv[1];
81417
81418   switch (face) {
81419     case 0: return [ 1, u, v];
81420     case 1: return [-u, 1, v];
81421     case 2: return [-u,-v, 1];
81422     case 3: return [-1,-v,-u];
81423     case 4: return [ v,-1,-u];
81424     case 5: return [ v, u,-1];
81425     default: throw {error: 'Invalid face'};
81426   }
81427 };
81428
81429 var singleSTtoUV = function(st) {
81430   if (st >= 0.5) {
81431     return (1/3.0) * (4*st*st - 1);
81432   } else {
81433     return (1/3.0) * (1 - (4*(1-st)*(1-st)));
81434   }
81435 };
81436
81437 S2.STToUV = function(st) {
81438   return [singleSTtoUV(st[0]), singleSTtoUV(st[1])];
81439 };
81440
81441
81442 var singleUVtoST = function(uv) {
81443   if (uv >= 0) {
81444     return 0.5 * Math.sqrt (1 + 3*uv);
81445   } else {
81446     return 1 - 0.5 * Math.sqrt (1 - 3*uv);
81447   }
81448 };
81449 S2.UVToST = function(uv) {
81450   return [singleUVtoST(uv[0]), singleUVtoST(uv[1])];
81451 };
81452
81453
81454 S2.STToIJ = function(st,order) {
81455   var maxSize = (1<<order);
81456
81457   var singleSTtoIJ = function(st) {
81458     var ij = Math.floor(st * maxSize);
81459     return Math.max(0, Math.min(maxSize-1, ij));
81460   };
81461
81462   return [singleSTtoIJ(st[0]), singleSTtoIJ(st[1])];
81463 };
81464
81465
81466 S2.IJToST = function(ij,order,offsets) {
81467   var maxSize = (1<<order);
81468
81469   return [
81470     (ij[0]+offsets[0])/maxSize,
81471     (ij[1]+offsets[1])/maxSize
81472   ];
81473 };
81474
81475
81476
81477 var rotateAndFlipQuadrant = function(n, point, rx, ry)
81478 {
81479         if(ry == 0)
81480         {
81481                 if(rx == 1){
81482                         point.x = n - 1 - point.x;
81483                         point.y = n - 1 - point.y;
81484
81485                 }
81486
81487     var x = point.x;
81488                 point.x = point.y;
81489                 point.y = x;
81490         }
81491
81492 };
81493
81494
81495
81496
81497
81498 // hilbert space-filling curve
81499 // based on http://blog.notdot.net/2009/11/Damn-Cool-Algorithms-Spatial-indexing-with-Quadtrees-and-Hilbert-Curves
81500 // note: rather then calculating the final integer hilbert position, we just return the list of quads
81501 // this ensures no precision issues whth large orders (S3 cell IDs use up to 30), and is more
81502 // convenient for pulling out the individual bits as needed later
81503 var pointToHilbertQuadList = function(x,y,order,face) {
81504   var hilbertMap = {
81505     'a': [ [0,'d'], [1,'a'], [3,'b'], [2,'a'] ],
81506     'b': [ [2,'b'], [1,'b'], [3,'a'], [0,'c'] ],
81507     'c': [ [2,'c'], [3,'d'], [1,'c'], [0,'b'] ],
81508     'd': [ [0,'a'], [3,'c'], [1,'d'], [2,'d'] ]
81509   };
81510
81511   if ('number' !== typeof face) {
81512     console.warn(new Error("called pointToHilbertQuadList without face value, defaulting to '0'").stack);
81513   }
81514   var currentSquare = (face % 2) ? 'd' : 'a';
81515   var positions = [];
81516
81517   for (var i=order-1; i>=0; i--) {
81518
81519     var mask = 1<<i;
81520
81521     var quad_x = x&mask ? 1 : 0;
81522     var quad_y = y&mask ? 1 : 0;
81523
81524     var t = hilbertMap[currentSquare][quad_x*2+quad_y];
81525
81526     positions.push(t[0]);
81527
81528     currentSquare = t[1];
81529   }
81530
81531   return positions;
81532 };
81533
81534 // S2Cell class
81535
81536 S2.S2Cell = function(){};
81537
81538 S2.S2Cell.FromHilbertQuadKey = function(hilbertQuadkey) {
81539   var parts = hilbertQuadkey.split('/');
81540   var face = parseInt(parts[0]);
81541   var position = parts[1];
81542   var maxLevel = position.length;
81543   var point = {
81544     x : 0,
81545     y: 0
81546   };
81547   var i;
81548   var level;
81549   var bit;
81550   var rx, ry;
81551   var val;
81552
81553         for(i = maxLevel - 1; i >= 0; i--) {
81554
81555                 level = maxLevel - i;
81556                 bit = position[i];
81557                 rx = 0;
81558     ry = 0;
81559                 if (bit === '1') {
81560                         ry = 1;
81561                 }
81562                 else if (bit === '2') {
81563                         rx = 1;
81564                         ry = 1;
81565                 }
81566                 else if (bit === '3') {
81567                         rx = 1;
81568                 }
81569
81570                 val = Math.pow(2, level - 1);
81571                 rotateAndFlipQuadrant(val, point, rx, ry);
81572
81573                 point.x += val * rx;
81574                 point.y += val * ry;
81575
81576         }
81577
81578   if (face % 2 === 1) {
81579     var t = point.x;
81580     point.x = point.y;
81581     point.y = t;
81582   }
81583
81584
81585   return S2.S2Cell.FromFaceIJ(parseInt(face), [point.x, point.y], level);
81586 };
81587
81588 //static method to construct
81589 S2.S2Cell.FromLatLng = function(latLng, level) {
81590   if ((!latLng.lat && latLng.lat !== 0) || (!latLng.lng && latLng.lng !== 0)) {
81591     throw new Error("Pass { lat: lat, lng: lng } to S2.S2Cell.FromLatLng");
81592   }
81593   var xyz = S2.LatLngToXYZ(latLng);
81594
81595   var faceuv = S2.XYZToFaceUV(xyz);
81596   var st = S2.UVToST(faceuv[1]);
81597
81598   var ij = S2.STToIJ(st,level);
81599
81600   return S2.S2Cell.FromFaceIJ (faceuv[0], ij, level);
81601 };
81602
81603 /*
81604 S2.faceIjLevelToXyz = function (face, ij, level) {
81605   var st = S2.IJToST(ij, level, [0.5, 0.5]);
81606   var uv = S2.STToUV(st);
81607   var xyz = S2.FaceUVToXYZ(face, uv);
81608
81609   return S2.XYZToLatLng(xyz);
81610   return xyz;
81611 };
81612 */
81613
81614 S2.S2Cell.FromFaceIJ = function(face,ij,level) {
81615   var cell = new S2.S2Cell();
81616   cell.face = face;
81617   cell.ij = ij;
81618   cell.level = level;
81619
81620   return cell;
81621 };
81622
81623
81624 S2.S2Cell.prototype.toString = function() {
81625   return 'F'+this.face+'ij['+this.ij[0]+','+this.ij[1]+']@'+this.level;
81626 };
81627
81628 S2.S2Cell.prototype.getLatLng = function() {
81629   var st = S2.IJToST(this.ij,this.level, [0.5,0.5]);
81630   var uv = S2.STToUV(st);
81631   var xyz = S2.FaceUVToXYZ(this.face, uv);
81632
81633   return S2.XYZToLatLng(xyz);
81634 };
81635
81636 S2.S2Cell.prototype.getCornerLatLngs = function() {
81637   var result = [];
81638   var offsets = [
81639     [ 0.0, 0.0 ],
81640     [ 0.0, 1.0 ],
81641     [ 1.0, 1.0 ],
81642     [ 1.0, 0.0 ]
81643   ];
81644
81645   for (var i=0; i<4; i++) {
81646     var st = S2.IJToST(this.ij, this.level, offsets[i]);
81647     var uv = S2.STToUV(st);
81648     var xyz = S2.FaceUVToXYZ(this.face, uv);
81649
81650     result.push ( S2.XYZToLatLng(xyz) );
81651   }
81652   return result;
81653 };
81654
81655
81656 S2.S2Cell.prototype.getFaceAndQuads = function () {
81657   var quads = pointToHilbertQuadList(this.ij[0], this.ij[1], this.level, this.face);
81658
81659   return [this.face,quads];
81660 };
81661 S2.S2Cell.prototype.toHilbertQuadkey = function () {
81662   var quads = pointToHilbertQuadList(this.ij[0], this.ij[1], this.level, this.face);
81663
81664   return this.face.toString(10) + '/' + quads.join('');
81665 };
81666
81667 S2.latLngToNeighborKeys = S2.S2Cell.latLngToNeighborKeys = function (lat, lng, level) {
81668   return S2.S2Cell.FromLatLng({ lat: lat, lng: lng }, level).getNeighbors().map(function (cell) {
81669     return cell.toHilbertQuadkey();
81670   });
81671 };
81672 S2.S2Cell.prototype.getNeighbors = function() {
81673
81674   var fromFaceIJWrap = function(face,ij,level) {
81675     var maxSize = (1<<level);
81676     if (ij[0]>=0 && ij[1]>=0 && ij[0]<maxSize && ij[1]<maxSize) {
81677       // no wrapping out of bounds
81678       return S2.S2Cell.FromFaceIJ(face,ij,level);
81679     } else {
81680       // the new i,j are out of range.
81681       // with the assumption that they're only a little past the borders we can just take the points as
81682       // just beyond the cube face, project to XYZ, then re-create FaceUV from the XYZ vector
81683
81684       var st = S2.IJToST(ij,level,[0.5,0.5]);
81685       var uv = S2.STToUV(st);
81686       var xyz = S2.FaceUVToXYZ(face,uv);
81687       var faceuv = S2.XYZToFaceUV(xyz);
81688       face = faceuv[0];
81689       uv = faceuv[1];
81690       st = S2.UVToST(uv);
81691       ij = S2.STToIJ(st,level);
81692       return S2.S2Cell.FromFaceIJ (face, ij, level);
81693     }
81694   };
81695
81696   var face = this.face;
81697   var i = this.ij[0];
81698   var j = this.ij[1];
81699   var level = this.level;
81700
81701
81702   return [
81703     fromFaceIJWrap(face, [i-1,j], level),
81704     fromFaceIJWrap(face, [i,j-1], level),
81705     fromFaceIJWrap(face, [i+1,j], level),
81706     fromFaceIJWrap(face, [i,j+1], level)
81707   ];
81708
81709 };
81710
81711 //
81712 // Functional Style
81713 //
81714 S2.FACE_BITS = 3;
81715 S2.MAX_LEVEL = 30;
81716 S2.POS_BITS = (2 * S2.MAX_LEVEL) + 1; // 61 (60 bits of data, 1 bit lsb marker)
81717
81718 S2.facePosLevelToId = S2.S2Cell.facePosLevelToId = S2.fromFacePosLevel = function (faceN, posS, levelN) {
81719   var Long = exports.dcodeIO && exports.dcodeIO.Long || long;
81720   var faceB;
81721   var posB;
81722   var bin;
81723
81724   if (!levelN) {
81725     levelN = posS.length;
81726   }
81727   if (posS.length > levelN) {
81728     posS = posS.substr(0, levelN);
81729   }
81730
81731   // 3-bit face value
81732   faceB = Long.fromString(faceN.toString(10), true, 10).toString(2);
81733   while (faceB.length < S2.FACE_BITS) {
81734     faceB = '0' + faceB;
81735   }
81736
81737   // 60-bit position value
81738   posB = Long.fromString(posS, true, 4).toString(2);
81739   while (posB.length < (2 * levelN)) {
81740     posB = '0' + posB;
81741   }
81742
81743   bin = faceB + posB;
81744   // 1-bit lsb marker
81745   bin += '1';
81746   // n-bit padding to 64-bits
81747   while (bin.length < (S2.FACE_BITS + S2.POS_BITS)) {
81748     bin += '0';
81749   }
81750
81751   return Long.fromString(bin, true, 2).toString(10);
81752 };
81753
81754 S2.keyToId = S2.S2Cell.keyToId
81755 = S2.toId = S2.toCellId = S2.fromKey
81756 = function (key) {
81757   var parts = key.split('/');
81758
81759   return S2.fromFacePosLevel(parts[0], parts[1], parts[1].length);
81760 };
81761
81762 S2.idToKey = S2.S2Cell.idToKey
81763 = S2.S2Cell.toKey = S2.toKey
81764 = S2.fromId = S2.fromCellId
81765 = S2.S2Cell.toHilbertQuadkey  = S2.toHilbertQuadkey
81766 = function (idS) {
81767   var Long = exports.dcodeIO && exports.dcodeIO.Long || long;
81768   var bin = Long.fromString(idS, true, 10).toString(2);
81769
81770   while (bin.length < (S2.FACE_BITS + S2.POS_BITS)) {
81771     bin = '0' + bin;
81772   }
81773
81774   // MUST come AFTER binstr has been left-padded with '0's
81775   var lsbIndex = bin.lastIndexOf('1');
81776   // substr(start, len)
81777   // substring(start, end) // includes start, does not include end
81778   var faceB = bin.substring(0, 3);
81779   // posB will always be a multiple of 2 (or it's invalid)
81780   var posB = bin.substring(3, lsbIndex);
81781   var levelN = posB.length / 2;
81782
81783   var faceS = Long.fromString(faceB, true, 2).toString(10);
81784   var posS = Long.fromString(posB, true, 2).toString(4);
81785
81786   while (posS.length < levelN) {
81787     posS = '0' + posS;
81788   }
81789
81790   return faceS + '/' + posS;
81791 };
81792
81793 S2.keyToLatLng = S2.S2Cell.keyToLatLng = function (key) {
81794   var cell2 = S2.S2Cell.FromHilbertQuadKey(key);
81795   return cell2.getLatLng();
81796 };
81797
81798 S2.idToLatLng = S2.S2Cell.idToLatLng = function (id) {
81799   var key = S2.idToKey(id);
81800   return S2.keyToLatLng(key);
81801 };
81802
81803 S2.S2Cell.latLngToKey = S2.latLngToKey
81804 = S2.latLngToQuadkey = function (lat, lng, level) {
81805   if (isNaN(level) || level < 1 || level > 30) {
81806     throw new Error("'level' is not a number between 1 and 30 (but it should be)");
81807   }
81808   // TODO
81809   //
81810   // S2.idToLatLng(id)
81811   // S2.keyToLatLng(key)
81812   // S2.nextFace(key)     // prevent wrapping on nextKey
81813   // S2.prevFace(key)     // prevent wrapping on prevKey
81814   //
81815   // .toKeyArray(id)  // face,quadtree
81816   // .toKey(id)       // hilbert
81817   // .toPoint(id)     // ij
81818   // .toId(key)       // uint64 (as string)
81819   // .toLong(key)     // long.js
81820   // .toLatLng(id)    // object? or array?, or string (with comma)?
81821   //
81822   // maybe S2.HQ.x, S2.GPS.x, S2.CI.x?
81823   return S2.S2Cell.FromLatLng({ lat: lat, lng: lng }, level).toHilbertQuadkey();
81824 };
81825
81826 S2.stepKey = function (key, num) {
81827   var Long = exports.dcodeIO && exports.dcodeIO.Long || long;
81828   var parts = key.split('/');
81829
81830   var faceS = parts[0];
81831   var posS = parts[1];
81832   var level = parts[1].length;
81833
81834   var posL = Long.fromString(posS, true, 4);
81835   // TODO handle wrapping (0 === pos + 1)
81836   // (only on the 12 edges of the globe)
81837   var otherL;
81838   if (num > 0) {
81839     otherL = posL.add(Math.abs(num));
81840   }
81841   else if (num < 0) {
81842     otherL = posL.subtract(Math.abs(num));
81843   }
81844   var otherS = otherL.toString(4);
81845
81846   if ('0' === otherS) {
81847     console.warning(new Error("face/position wrapping is not yet supported"));
81848   }
81849
81850   while (otherS.length < level) {
81851     otherS = '0' + otherS;
81852   }
81853
81854   return faceS + '/' + otherS;
81855 };
81856
81857 S2.S2Cell.prevKey = S2.prevKey = function (key) {
81858   return S2.stepKey(key, -1);
81859 };
81860
81861 S2.S2Cell.nextKey = S2.nextKey = function (key) {
81862   return S2.stepKey(key, 1);
81863 };
81864
81865 })(module.exports );
81866 });
81867
81868 /**
81869  * @class S2GeometryProvider
81870  *
81871  * @classdesc Geometry provider based on S2 cells.
81872  *
81873  * @example
81874  * ```js
81875  * class MyDataProvider extends DataProviderBase {
81876  *      ...
81877  * }
81878  *
81879  * const geometryProvider = new S2GeometryProvider();
81880  * const dataProvider = new MyDataProvider(geometryProvider);
81881  * ```
81882  */
81883 class S2GeometryProvider extends GeometryProviderBase {
81884     /**
81885      * Create a new S2 geometry provider instance.
81886      */
81887     constructor(_level = 17) {
81888         super();
81889         this._level = _level;
81890     }
81891     /** @inheritdoc */
81892     bboxToCellIds(sw, ne) {
81893         return this._approxBboxToCellIds(sw, ne);
81894     }
81895     /** @inheritdoc */
81896     getAdjacent(cellId) {
81897         const k = s2geometry.S2.idToKey(cellId);
81898         const position = k.split('/')[1];
81899         const level = position.length;
81900         const [a0, a1, a2, a3] = this._getNeighbors(k, level);
81901         const existing = [k, a0, a1, a2, a3];
81902         const others = Array
81903             .from(new Set([
81904             ...this._getNeighbors(a0, level),
81905             ...this._getNeighbors(a1, level),
81906             ...this._getNeighbors(a2, level),
81907             ...this._getNeighbors(a3, level),
81908         ].filter((o) => {
81909             return !existing.includes(o);
81910         })));
81911         const adjacent = [a0, a1, a2, a3];
81912         for (const other of others) {
81913             let count = 0;
81914             for (const n of this._getNeighbors(other, level)) {
81915                 if (existing.includes(n)) {
81916                     count++;
81917                 }
81918             }
81919             if (count === 2) {
81920                 adjacent.push(other);
81921             }
81922         }
81923         return adjacent.map((a) => s2geometry.S2.keyToId(a));
81924     }
81925     /** @inheritdoc */
81926     getVertices(cellId) {
81927         const key = s2geometry.S2.idToKey(cellId);
81928         const cell = s2geometry.S2.S2Cell.FromHilbertQuadKey(key);
81929         return cell
81930             .getCornerLatLngs()
81931             .map((c) => {
81932             return { lat: c.lat, lng: c.lng };
81933         });
81934     }
81935     /** @inheritdoc */
81936     lngLatToCellId(lngLat) {
81937         return this._lngLatToId(lngLat, this._level);
81938     }
81939     _getNeighbors(s2key, level) {
81940         const latlng = s2geometry.S2.keyToLatLng(s2key);
81941         const neighbors = s2geometry.S2.latLngToNeighborKeys(latlng.lat, latlng.lng, level);
81942         return neighbors;
81943     }
81944     _lngLatToId(lngLat, level) {
81945         const s2key = s2geometry.S2.latLngToKey(lngLat.lat, lngLat.lng, level);
81946         return s2geometry.S2.keyToId(s2key);
81947     }
81948 }
81949
81950 function convertCameraType(graphCameraType) {
81951     switch (graphCameraType) {
81952         case "equirectangular":
81953         case "spherical":
81954             return "spherical";
81955         case "fisheye":
81956             return "fisheye";
81957         default:
81958             return "perspective";
81959     }
81960 }
81961 class GraphConverter {
81962     clusterReconstruction(source) {
81963         const id = null;
81964         const points = source.points;
81965         const normalize = 1 / 255;
81966         for (const pointId in points) {
81967             if (!points.hasOwnProperty(pointId)) {
81968                 continue;
81969             }
81970             const color = points[pointId].color;
81971             color[0] *= normalize;
81972             color[1] *= normalize;
81973             color[2] *= normalize;
81974         }
81975         const lla = source.reference_lla;
81976         const reference = {
81977             alt: lla.altitude,
81978             lat: lla.latitude,
81979             lng: lla.longitude,
81980         };
81981         return {
81982             id,
81983             points,
81984             reference,
81985         };
81986     }
81987     coreImage(source) {
81988         const geometry = this._geometry(source.geometry);
81989         const computedGeometry = this._geometry(source.computed_geometry);
81990         const sequence = { id: source.sequence };
81991         const id = source.id;
81992         return {
81993             computed_geometry: computedGeometry,
81994             geometry,
81995             id,
81996             sequence,
81997         };
81998     }
81999     spatialImage(source) {
82000         var _a, _b, _c, _d;
82001         source.camera_type = convertCameraType(source.camera_type);
82002         source.merge_id = source.merge_cc ? source.merge_cc.toString() : null;
82003         source.private = null;
82004         const thumbUrl = source.camera_type === 'spherical' ?
82005             source.thumb_2048_url : source.thumb_1024_url;
82006         source.thumb = (_a = source.thumb) !== null && _a !== void 0 ? _a : { id: null, url: thumbUrl };
82007         source.cluster = (_b = source.sfm_cluster) !== null && _b !== void 0 ? _b : { id: null, url: null };
82008         source.creator = { id: null, username: null };
82009         source.owner = (_c = source.owner) !== null && _c !== void 0 ? _c : { id: null };
82010         source.mesh = (_d = source.mesh) !== null && _d !== void 0 ? _d : { id: null, url: null };
82011         return source;
82012     }
82013     _geometry(geometry) {
82014         const coords = geometry === null || geometry === void 0 ? void 0 : geometry.coordinates;
82015         const lngLat = coords ?
82016             {
82017                 lat: coords[1],
82018                 lng: coords[0],
82019             } : null;
82020         return lngLat;
82021     }
82022 }
82023
82024 class GraphQueryCreator {
82025     constructor() {
82026         this.imagesPath = 'images';
82027         this.sequencePath = 'image_ids';
82028         this._imageTilesPath = 'tiles';
82029         this.coreFields = ['computed_geometry', 'geometry', 'sequence'];
82030         this.idFields = ['id'];
82031         this.spatialFields = [
82032             'altitude',
82033             'atomic_scale',
82034             'camera_parameters',
82035             'camera_type',
82036             'captured_at',
82037             'compass_angle',
82038             'computed_altitude',
82039             'computed_compass_angle',
82040             'computed_rotation',
82041             'exif_orientation',
82042             'height',
82043             'merge_cc',
82044             'mesh',
82045             'quality_score',
82046             'sfm_cluster',
82047             'thumb_1024_url',
82048             'thumb_2048_url',
82049             'width',
82050         ];
82051         this.imageTileFields = ['url', 'z', 'x', 'y'];
82052     }
82053     images(imageIds, fields) {
82054         return `image_ids=${imageIds.join(',')}&fields=${fields.join(',')}`;
82055     }
82056     imagesS2(cellId, fields) {
82057         return `s2=${cellId}&fields=${fields.join(',')}`;
82058     }
82059     imageTiles(z, fields) {
82060         return `z=${z}&fields=${fields.join(',')}`;
82061     }
82062     imageTilesPath(imageId) {
82063         return `${imageId}/${this._imageTilesPath}`;
82064     }
82065     sequence(sequenceId) {
82066         return `sequence_id=${sequenceId}`;
82067     }
82068 }
82069
82070 class GraphDataProvider extends DataProviderBase {
82071     constructor(options, geometry, converter, queryCreator) {
82072         var _a;
82073         super(geometry !== null && geometry !== void 0 ? geometry : new S2GeometryProvider());
82074         this._convert = converter !== null && converter !== void 0 ? converter : new GraphConverter();
82075         this._query = queryCreator !== null && queryCreator !== void 0 ? queryCreator : new GraphQueryCreator();
82076         this._method = 'GET';
82077         const opts = options !== null && options !== void 0 ? options : {};
82078         this._endpoint = (_a = opts.endpoint) !== null && _a !== void 0 ? _a : "https://graph.mapillary.com";
82079         this._accessToken = opts.accessToken;
82080     }
82081     getCluster(url, abort) {
82082         return fetchArrayBuffer(url, abort)
82083             .then((buffer) => {
82084             const reconstructions = decompress(buffer);
82085             if (reconstructions.length < 1) {
82086                 throw new Error('Cluster reconstruction empty');
82087             }
82088             return this._convert
82089                 .clusterReconstruction(reconstructions[0]);
82090         });
82091     }
82092     getCoreImages(cellId) {
82093         const fields = [
82094             ...this._query.idFields,
82095             ...this._query.coreFields,
82096         ];
82097         const query = this._query.imagesS2(cellId, fields);
82098         const url = new URL(this._query.imagesPath, this._endpoint).href;
82099         return this
82100             ._fetchGraphContract(query, url)
82101             .then(r => {
82102             const result = {
82103                 cell_id: cellId,
82104                 images: [],
82105             };
82106             const items = r.data;
82107             for (const item of items) {
82108                 const coreImage = this._convert.coreImage(item);
82109                 result.images.push(coreImage);
82110             }
82111             return result;
82112         });
82113     }
82114     getImageBuffer(url, abort) {
82115         return fetchArrayBuffer(url, abort);
82116     }
82117     getImages(imageIds) {
82118         const fields = [
82119             ...this._query.idFields,
82120             ...this._query.coreFields,
82121             ...this._query.spatialFields,
82122         ];
82123         const query = this._query.images(imageIds, fields);
82124         const url = new URL(this._query.imagesPath, this._endpoint).href;
82125         return this
82126             ._fetchGraphContract(query, url)
82127             .then(r => {
82128             const result = [];
82129             const items = r.data;
82130             for (const item of items) {
82131                 const coreImage = this._convert.coreImage(item);
82132                 const spatialImage = this._convert.spatialImage(item);
82133                 const image = Object.assign({}, spatialImage, coreImage);
82134                 const contract = {
82135                     node: image,
82136                     node_id: item.id,
82137                 };
82138                 result.push(contract);
82139             }
82140             return result;
82141         });
82142     }
82143     getImageTiles(request) {
82144         const fields = [
82145             ...this._query.imageTileFields,
82146         ];
82147         const query = this._query.imageTiles(request.z, fields);
82148         const url = new URL(this._query.imageTilesPath(request.imageId), this._endpoint).href;
82149         return this
82150             ._fetchGraphContract(query, url)
82151             .then(r => {
82152             const result = {
82153                 node: r.data,
82154                 node_id: request.imageId,
82155             };
82156             return result;
82157         });
82158     }
82159     getMesh(url, abort) {
82160         return fetchArrayBuffer(url, abort)
82161             .then((buffer) => {
82162             return readMeshPbf(buffer);
82163         });
82164     }
82165     getSequence(sequenceId) {
82166         const query = this._query.sequence(sequenceId);
82167         const url = new URL(this._query.sequencePath, this._endpoint).href;
82168         return this
82169             ._fetchGraphContract(query, url)
82170             .then(r => {
82171             const result = {
82172                 id: sequenceId,
82173                 image_ids: r.data.map(item => item.id),
82174             };
82175             return result;
82176         });
82177     }
82178     getSpatialImages(imageIds) {
82179         const fields = [
82180             ...this._query.idFields,
82181             ...this._query.coreFields,
82182             ...this._query.spatialFields,
82183         ];
82184         const query = this._query.images(imageIds, fields);
82185         const url = new URL(this._query.imagesPath, this._endpoint).href;
82186         return this
82187             ._fetchGraphContract(query, url)
82188             .then(r => {
82189             const result = [];
82190             const items = r.data;
82191             for (const item of items) {
82192                 const spatialImage = this._convert.spatialImage(item);
82193                 const contract = {
82194                     node: spatialImage,
82195                     node_id: item.id,
82196                 };
82197                 result.push(contract);
82198             }
82199             return result;
82200         });
82201     }
82202     setAccessToken(accessToken) {
82203         this._accessToken = accessToken;
82204     }
82205     _createHeaders() {
82206         const headers = [
82207             { name: 'Accept', value: 'application/json' },
82208             {
82209                 name: 'Content-Type',
82210                 value: 'application/x-www-form-urlencoded',
82211             },
82212         ];
82213         if (this._accessToken) {
82214             headers.push({
82215                 name: 'Authorization',
82216                 value: `OAuth ${this._accessToken}`,
82217             });
82218         }
82219         return headers;
82220     }
82221     _fetchGraphContract(body, url) {
82222         const method = this._method;
82223         const headers = this._createHeaders();
82224         const query = `${url}?${body}`;
82225         return xhrFetch(query, method, "json", headers, null, null)
82226             .catch((error) => {
82227             const message = this._makeErrorMessage(error);
82228             throw new MapillaryError(message);
82229         });
82230     }
82231     _makeErrorMessage(graphError) {
82232         const error = graphError.error;
82233         const message = error ?
82234             `${error.code} (${error.type}, ${error.fbtrace_id}): ${error.message}` :
82235             "Failed to fetch data";
82236         return message;
82237     }
82238 }
82239
82240 /**
82241  * @class Marker
82242  *
82243  * @classdesc Represents an abstract marker class that should be extended
82244  * by marker implementations used in the marker component.
82245  */
82246 class Marker {
82247     constructor(id, lngLat) {
82248         this._id = id;
82249         this._lngLat = lngLat;
82250     }
82251     /**
82252      * Get id.
82253      * @returns {string} The id of the marker.
82254      */
82255     get id() {
82256         return this._id;
82257     }
82258     /**
82259      * Get geometry.
82260      *
82261      * @ignore
82262      */
82263     get geometry() {
82264         return this._geometry;
82265     }
82266     /**
82267      * Get lngLat.
82268      * @returns {LngLat} The geographic coordinates of the marker.
82269      */
82270     get lngLat() {
82271         return this._lngLat;
82272     }
82273     /** @ignore */
82274     createGeometry(position) {
82275         if (!!this._geometry) {
82276             return;
82277         }
82278         this._createGeometry(position);
82279         // update matrix world if raycasting occurs before first render
82280         this._geometry.updateMatrixWorld(true);
82281     }
82282     /** @ignore */
82283     disposeGeometry() {
82284         if (!this._geometry) {
82285             return;
82286         }
82287         this._disposeGeometry();
82288         this._geometry = undefined;
82289     }
82290     /** @ignore */
82291     getInteractiveObjects() {
82292         if (!this._geometry) {
82293             return [];
82294         }
82295         return this._getInteractiveObjects();
82296     }
82297     /** @ignore */
82298     lerpAltitude(alt, alpha) {
82299         if (!this._geometry) {
82300             return;
82301         }
82302         this._geometry.position.z =
82303             (1 - alpha) * this._geometry.position.z + alpha * alt;
82304     }
82305     /** @ignore */
82306     updatePosition(position, lngLat) {
82307         if (!!lngLat) {
82308             this._lngLat.lat = lngLat.lat;
82309             this._lngLat.lng = lngLat.lng;
82310         }
82311         if (!this._geometry) {
82312             return;
82313         }
82314         this._geometry.position.fromArray(position);
82315         this._geometry.updateMatrixWorld(true);
82316     }
82317 }
82318
82319 /**
82320  * @class CircleMarker
82321  *
82322  * @classdesc Non-interactive marker with a flat circle shape. The circle
82323  * marker can not be configured to be interactive.
82324  *
82325  * Circle marker properties can not be updated after creation.
82326  *
82327  * To create and add one `CircleMarker` with default configuration
82328  * and one with configuration use
82329  *
82330  * @example
82331  * ```js
82332  * var defaultMarker = new CircleMarker(
82333  *     "id-1",
82334  *     { lat: 0, lng: 0, });
82335  *
82336  * var configuredMarker = new CircleMarker(
82337  *     "id-2",
82338  *     { lat: 0, lng: 0, },
82339  *     {
82340  *         color: "#0ff",
82341  *         opacity: 0.3,
82342  *         radius: 0.7,
82343  *     });
82344  *
82345  * markerComponent.add([defaultMarker, configuredMarker]);
82346  * ```
82347  */
82348 class CircleMarker extends Marker {
82349     constructor(id, lngLat, options) {
82350         super(id, lngLat);
82351         options = !!options ? options : {};
82352         this._color = options.color != null ? options.color : 0xffffff;
82353         this._opacity = options.opacity != null ? options.opacity : 0.4;
82354         this._radius = options.radius != null ? options.radius : 1;
82355     }
82356     _createGeometry(position) {
82357         const circle = new Mesh(new CircleGeometry(this._radius, 16), new MeshBasicMaterial({
82358             color: this._color,
82359             opacity: this._opacity,
82360             transparent: true,
82361         }));
82362         circle.up.fromArray([0, 0, 1]);
82363         circle.renderOrder = -1;
82364         const group = new Object3D();
82365         group.add(circle);
82366         group.position.fromArray(position);
82367         this._geometry = group;
82368     }
82369     _disposeGeometry() {
82370         for (let mesh of this._geometry.children) {
82371             mesh.geometry.dispose();
82372             mesh.material.dispose();
82373         }
82374     }
82375     _getInteractiveObjects() {
82376         return [];
82377     }
82378 }
82379
82380 /**
82381  * @class SimpleMarker
82382  *
82383  * @classdesc Interactive marker with ice cream shape. The sphere
82384  * inside the ice cream can be configured to be interactive.
82385  *
82386  * Simple marker properties can not be updated after creation.
82387  *
82388  * To create and add one `SimpleMarker` with default configuration
82389  * (non-interactive) and one interactive with configuration use
82390  *
82391  * @example
82392  * ```js
82393  * var defaultMarker = new SimpleMarker(
82394  *     "id-1",
82395  *     { lat: 0, lng: 0, });
82396  *
82397  * var interactiveMarker = new SimpleMarker(
82398  *     "id-2",
82399  *     { lat: 0, lng: 0, },
82400  *     {
82401  *         ballColor: "#00f",
82402  *         ballOpacity: 0.5,
82403  *         color: "#00f",
82404  *         interactive: true,
82405  *         opacity: 0.3,
82406  *         radius: 0.7,
82407  *     });
82408  *
82409  * markerComponent.add([defaultMarker, interactiveMarker]);
82410  * ```
82411  */
82412 class SimpleMarker extends Marker {
82413     constructor(id, lngLat, options) {
82414         super(id, lngLat);
82415         options = !!options ? options : {};
82416         this._ballColor = options.ballColor != null ? options.ballColor : 0xff0000;
82417         this._ballOpacity = options.ballOpacity != null ? options.ballOpacity : 0.8;
82418         this._circleToRayAngle = 2;
82419         this._color = options.color != null ? options.color : 0xff0000;
82420         this._interactive = !!options.interactive;
82421         this._opacity = options.opacity != null ? options.opacity : 0.4;
82422         this._radius = options.radius != null ? options.radius : 1;
82423     }
82424     _createGeometry(position) {
82425         const radius = this._radius;
82426         const height = this._markerHeight(radius);
82427         const markerMaterial = new MeshBasicMaterial({
82428             color: this._color,
82429             opacity: this._opacity,
82430             transparent: true,
82431             depthWrite: false,
82432         });
82433         const marker = new Mesh(this._createMarkerGeometry(radius, 8, 8), markerMaterial);
82434         const interactive = new Mesh(new SphereGeometry(radius / 2, 8, 8), new MeshBasicMaterial({
82435             color: this._ballColor,
82436             opacity: this._ballOpacity,
82437             transparent: true,
82438         }));
82439         interactive.position.z = height;
82440         interactive.renderOrder = 1;
82441         const group = new Object3D();
82442         group.add(interactive);
82443         group.add(marker);
82444         group.position.fromArray(position);
82445         this._geometry = group;
82446     }
82447     _disposeGeometry() {
82448         for (const mesh of this._geometry.children) {
82449             mesh.geometry.dispose();
82450             mesh.material.dispose();
82451         }
82452     }
82453     _getInteractiveObjects() {
82454         return this._interactive ? [this._geometry.children[0]] : [];
82455     }
82456     _markerHeight(radius) {
82457         const t = Math.tan(Math.PI - this._circleToRayAngle);
82458         return radius * Math.sqrt(1 + t * t);
82459     }
82460     _createMarkerGeometry(radius, widthSegments, heightSegments) {
82461         const height = this._markerHeight(radius);
82462         const circleToRayAngle = this._circleToRayAngle;
82463         const indexRows = [];
82464         const positions = new Float32Array(3 * (widthSegments + 1) * (heightSegments + 1));
82465         let positionIndex = 0;
82466         for (let y = 0; y <= heightSegments; ++y) {
82467             const indexRow = [];
82468             for (let x = 0; x <= widthSegments; ++x) {
82469                 const u = x / widthSegments * Math.PI * 2;
82470                 const v = y / heightSegments * Math.PI;
82471                 let r = radius;
82472                 if (v > circleToRayAngle) {
82473                     const t = Math.tan(v - circleToRayAngle);
82474                     r = radius * Math.sqrt(1 + t * t);
82475                 }
82476                 const arrayIndex = 3 * positionIndex;
82477                 const sinv = Math.sin(v);
82478                 positions[arrayIndex + 0] = r * Math.cos(u) * sinv;
82479                 positions[arrayIndex + 1] = r * Math.sin(u) * sinv;
82480                 positions[arrayIndex + 2] = r * Math.cos(v) + height;
82481                 indexRow.push(positionIndex++);
82482             }
82483             indexRows.push(indexRow);
82484         }
82485         const indices = new Uint16Array(6 * widthSegments * heightSegments);
82486         let index = 0;
82487         for (let y = 0; y < heightSegments; ++y) {
82488             for (let x = 0; x < widthSegments; ++x) {
82489                 const pi1 = indexRows[y][x + 1];
82490                 const pi2 = indexRows[y][x];
82491                 const pi3 = indexRows[y + 1][x];
82492                 const pi4 = indexRows[y + 1][x + 1];
82493                 indices[index++] = pi1;
82494                 indices[index++] = pi2;
82495                 indices[index++] = pi4;
82496                 indices[index++] = pi2;
82497                 indices[index++] = pi3;
82498                 indices[index++] = pi4;
82499             }
82500         }
82501         const geometry = new BufferGeometry();
82502         const positionAttribute = new BufferAttribute(positions, 3);
82503         geometry.setAttribute("position", positionAttribute);
82504         geometry.setIndex(new BufferAttribute(indices, 1));
82505         return geometry;
82506     }
82507 }
82508
82509 /**
82510  * @class Popup
82511  *
82512  * @classdesc Popup instance for rendering custom HTML content
82513  * on top of images. Popups are based on 2D basic image coordinates
82514  * (see the {@link Viewer} class documentation for more information about coordinate
82515  * systems) and a certain popup is therefore only relevant to a single image.
82516  * Popups related to a certain image should be removed when moving
82517  * to another image.
82518  *
82519  * A popup must have both its content and its point or rect set to be
82520  * rendered. Popup options can not be updated after creation but the
82521  * basic point or rect as well as its content can be changed by calling
82522  * the appropriate methods.
82523  *
82524  * To create and add one `Popup` with default configuration
82525  * (tooltip visuals and automatic float) and one with specific options
82526  * use
82527  *
82528  * @example
82529  * ```js
82530  * var defaultSpan = document.createElement('span');
82531  * defaultSpan.innerHTML = 'hello default';
82532  *
82533  * var defaultPopup = new Popup();
82534  * defaultPopup.setDOMContent(defaultSpan);
82535  * defaultPopup.setBasicPoint([0.3, 0.3]);
82536  *
82537  * var cleanSpan = document.createElement('span');
82538  * cleanSpan.innerHTML = 'hello clean';
82539  *
82540  * var cleanPopup = new Popup({
82541  *     clean: true,
82542  *     float: Alignment.Top,
82543  *     offset: 10,
82544  *     opacity: 0.7,
82545  * });
82546  *
82547  * cleanPopup.setDOMContent(cleanSpan);
82548  * cleanPopup.setBasicPoint([0.6, 0.6]);
82549  *
82550  * popupComponent.add([defaultPopup, cleanPopup]);
82551  * ```
82552  *
82553  * @description Implementation of API methods and API documentation inspired
82554  * by/used from https://github.com/mapbox/mapbox-gl-js/blob/v0.38.0/src/ui/popup.js
82555  */
82556 class Popup {
82557     constructor(options, viewportCoords, dom) {
82558         this._options = {};
82559         options = !!options ? options : {};
82560         this._options.capturePointer = options.capturePointer === false ?
82561             options.capturePointer : true;
82562         this._options.clean = options.clean;
82563         this._options.float = options.float;
82564         this._options.offset = options.offset;
82565         this._options.opacity = options.opacity;
82566         this._options.position = options.position;
82567         this._dom = !!dom ? dom : new DOM();
82568         this._viewportCoords = !!viewportCoords ? viewportCoords : new ViewportCoords();
82569         this._notifyChanged$ = new Subject();
82570     }
82571     /**
82572      * @description Internal observable used by the component to
82573      * render the popup when its position or content has changed.
82574      * @ignore
82575      */
82576     get changed$() {
82577         return this._notifyChanged$;
82578     }
82579     /**
82580      * @description Internal method used by the component to
82581      * remove all references to the popup.
82582      * @ignore
82583      */
82584     remove() {
82585         if (this._content && this._content.parentNode) {
82586             this._content.parentNode.removeChild(this._content);
82587         }
82588         if (this._container) {
82589             this._container.parentNode.removeChild(this._container);
82590             delete this._container;
82591         }
82592         if (this._parentContainer) {
82593             delete this._parentContainer;
82594         }
82595     }
82596     /**
82597      * Sets a 2D basic image coordinates point to the popup's anchor, and
82598      * moves the popup to it.
82599      *
82600      * @description Overwrites any previously set point or rect.
82601      *
82602      * @param {Array<number>} basicPoint - Point in 2D basic image coordinates.
82603      *
82604      * @example
82605      * ```js
82606      * var popup = new Popup();
82607      * popup.setText('hello image');
82608      * popup.setBasicPoint([0.3, 0.3]);
82609      *
82610      * popupComponent.add([popup]);
82611      * ```
82612      */
82613     setBasicPoint(basicPoint) {
82614         this._point = basicPoint.slice();
82615         this._rect = null;
82616         this._notifyChanged$.next(this);
82617     }
82618     /**
82619      * Sets a 2D basic image coordinates rect to the popup's anchor, and
82620      * moves the popup to it.
82621      *
82622      * @description Overwrites any previously set point or rect.
82623      *
82624      * @param {Array<number>} basicRect - Rect in 2D basic image
82625      * coordinates ([topLeftX, topLeftY, bottomRightX, bottomRightY]) .
82626      *
82627      * @example
82628      * ```js
82629      * var popup = new Popup();
82630      * popup.setText('hello image');
82631      * popup.setBasicRect([0.3, 0.3, 0.5, 0.6]);
82632      *
82633      * popupComponent.add([popup]);
82634      * ```
82635      */
82636     setBasicRect(basicRect) {
82637         this._rect = basicRect.slice();
82638         this._point = null;
82639         this._notifyChanged$.next(this);
82640     }
82641     /**
82642      * Sets the popup's content to the element provided as a DOM node.
82643      *
82644      * @param {Node} htmlNode - A DOM node to be used as content for the popup.
82645      *
82646      * @example
82647      * ```js
82648      * var div = document.createElement('div');
82649      * div.innerHTML = 'hello image';
82650      *
82651      * var popup = new Popup();
82652      * popup.setDOMContent(div);
82653      * popup.setBasicPoint([0.3, 0.3]);
82654      *
82655      * popupComponent.add([popup]);
82656      * ```
82657      */
82658     setDOMContent(htmlNode) {
82659         if (this._content && this._content.parentNode) {
82660             this._content.parentNode.removeChild(this._content);
82661         }
82662         const className = "mapillary-popup-content" +
82663             (this._options.clean === true ? "-clean" : "") +
82664             (this._options.capturePointer === true ? " mapillary-popup-capture-pointer" : "");
82665         this._content = this._dom.createElement("div", className, this._container);
82666         this._content.appendChild(htmlNode);
82667         this._notifyChanged$.next(this);
82668     }
82669     /**
82670      * Sets the popup's content to the HTML provided as a string.
82671      *
82672      * @description This method does not perform HTML filtering or sanitization,
82673      * and must be used only with trusted content. Consider
82674      * {@link Popup.setText} if the
82675      * content is an untrusted text string.
82676      *
82677      * @param {string} html - A string representing HTML content for the popup.
82678      *
82679      * @example
82680      * ```js
82681      * var popup = new Popup();
82682      * popup.setHTML('<div>hello image</div>');
82683      * popup.setBasicPoint([0.3, 0.3]);
82684      *
82685      * popupComponent.add([popup]);
82686      * ```
82687      */
82688     setHTML(html) {
82689         const frag = this._dom.document.createDocumentFragment();
82690         const temp = this._dom.createElement("body");
82691         let child;
82692         temp.innerHTML = html;
82693         while (true) {
82694             child = temp.firstChild;
82695             if (!child) {
82696                 break;
82697             }
82698             frag.appendChild(child);
82699         }
82700         this.setDOMContent(frag);
82701     }
82702     /**
82703      * Sets the popup's content to a string of text.
82704      *
82705      * @description This function creates a Text node in the DOM, so it cannot insert raw HTML.
82706      * Use this method for security against XSS if the popup content is user-provided.
82707      *
82708      * @param {string} text - Textual content for the popup.
82709      *
82710      * @example
82711      * ```js
82712      * var popup = new Popup();
82713      * popup.setText('hello image');
82714      * popup.setBasicPoint([0.3, 0.3]);
82715      *
82716      * popupComponent.add([popup]);
82717      * ```
82718      */
82719     setText(text) {
82720         this.setDOMContent(this._dom.document.createTextNode(text));
82721     }
82722     /**
82723      * @description Internal method for attaching the popup to
82724      * its parent container so that it is rendered in the DOM tree.
82725      * @ignore
82726      */
82727     setParentContainer(parentContainer) {
82728         this._parentContainer = parentContainer;
82729     }
82730     /**
82731      * @description Internal method for updating the rendered
82732      * position of the popup called by the popup component.
82733      * @ignore
82734      */
82735     update(renderCamera, size, transform) {
82736         if (!this._parentContainer || !this._content) {
82737             return;
82738         }
82739         if (!this._point && !this._rect) {
82740             return;
82741         }
82742         if (!this._container) {
82743             this._container = this._dom.createElement("div", "mapillary-popup", this._parentContainer);
82744             const showTip = this._options.clean !== true &&
82745                 this._options.float !== Alignment.Center;
82746             if (showTip) {
82747                 const tipClassName = "mapillary-popup-tip" +
82748                     (this._options.capturePointer === true ? " mapillary-popup-capture-pointer" : "");
82749                 this._tip = this._dom.createElement("div", tipClassName, this._container);
82750                 this._dom.createElement("div", "mapillary-popup-tip-inner", this._tip);
82751             }
82752             this._container.appendChild(this._content);
82753             this._parentContainer.appendChild(this._container);
82754             if (this._options.opacity != null) {
82755                 this._container.style.opacity = this._options.opacity.toString();
82756             }
82757         }
82758         let pointPixel = null;
82759         let position = this._alignmentToPopupAligment(this._options.position);
82760         let float = this._alignmentToPopupAligment(this._options.float);
82761         const classList = this._container.classList;
82762         if (this._point != null) {
82763             pointPixel =
82764                 this._viewportCoords.basicToCanvasSafe(this._point[0], this._point[1], { offsetHeight: size.height, offsetWidth: size.width }, transform, renderCamera.perspective);
82765         }
82766         else {
82767             const alignments = ["center", "top", "bottom", "left", "right", "top-left", "top-right", "bottom-left", "bottom-right"];
82768             let appliedPosition = null;
82769             for (const alignment of alignments) {
82770                 if (classList.contains(`mapillary-popup-float-${alignment}`)) {
82771                     appliedPosition = alignment;
82772                     break;
82773                 }
82774             }
82775             [pointPixel, position] = this._rectToPixel(this._rect, position, appliedPosition, renderCamera, size, transform);
82776             if (!float) {
82777                 float = position;
82778             }
82779         }
82780         if (pointPixel == null) {
82781             this._container.style.display = "none";
82782             return;
82783         }
82784         this._container.style.display = "";
82785         if (!float) {
82786             const width = this._container.offsetWidth;
82787             const height = this._container.offsetHeight;
82788             const floats = this._pixelToFloats(pointPixel, size, width, height);
82789             float = floats.length === 0 ? "top" : floats.join("-");
82790         }
82791         const offset = this._normalizeOffset(this._options.offset);
82792         pointPixel = [pointPixel[0] + offset[float][0], pointPixel[1] + offset[float][1]];
82793         pointPixel = [Math.round(pointPixel[0]), Math.round(pointPixel[1])];
82794         const floatTranslate = {
82795             "bottom": "translate(-50%,0)",
82796             "bottom-left": "translate(-100%,0)",
82797             "bottom-right": "translate(0,0)",
82798             "center": "translate(-50%,-50%)",
82799             "left": "translate(-100%,-50%)",
82800             "right": "translate(0,-50%)",
82801             "top": "translate(-50%,-100%)",
82802             "top-left": "translate(-100%,-100%)",
82803             "top-right": "translate(0,-100%)",
82804         };
82805         for (const key in floatTranslate) {
82806             if (!floatTranslate.hasOwnProperty(key)) {
82807                 continue;
82808             }
82809             classList.remove(`mapillary-popup-float-${key}`);
82810         }
82811         classList.add(`mapillary-popup-float-${float}`);
82812         this._container.style.transform = `${floatTranslate[float]} translate(${pointPixel[0]}px,${pointPixel[1]}px)`;
82813     }
82814     _rectToPixel(rect, position, appliedPosition, renderCamera, size, transform) {
82815         if (!position) {
82816             const width = this._container.offsetWidth;
82817             const height = this._container.offsetHeight;
82818             const floatOffsets = {
82819                 "bottom": [0, height / 2],
82820                 "bottom-left": [-width / 2, height / 2],
82821                 "bottom-right": [width / 2, height / 2],
82822                 "left": [-width / 2, 0],
82823                 "right": [width / 2, 0],
82824                 "top": [0, -height / 2],
82825                 "top-left": [-width / 2, -height / 2],
82826                 "top-right": [width / 2, -height / 2],
82827             };
82828             const automaticPositions = ["top", "bottom", "left", "right"];
82829             let largestVisibleArea = [0, null, null];
82830             for (const automaticPosition of automaticPositions) {
82831                 const autoPointBasic = this._pointFromRectPosition(rect, automaticPosition);
82832                 const autoPointPixel = this._viewportCoords.basicToCanvasSafe(autoPointBasic[0], autoPointBasic[1], { offsetHeight: size.height, offsetWidth: size.width }, transform, renderCamera.perspective);
82833                 if (autoPointPixel == null) {
82834                     continue;
82835                 }
82836                 const floatOffset = floatOffsets[automaticPosition];
82837                 const offsetedPosition = [autoPointPixel[0] + floatOffset[0], autoPointPixel[1] + floatOffset[1]];
82838                 const staticCoeff = appliedPosition != null && appliedPosition === automaticPosition ? 1 : 0.7;
82839                 const floats = this._pixelToFloats(offsetedPosition, size, width / staticCoeff, height / (2 * staticCoeff));
82840                 if (floats.length === 0 &&
82841                     autoPointPixel[0] > 0 &&
82842                     autoPointPixel[0] < size.width &&
82843                     autoPointPixel[1] > 0 &&
82844                     autoPointPixel[1] < size.height) {
82845                     return [autoPointPixel, automaticPosition];
82846                 }
82847                 const minX = Math.max(offsetedPosition[0] - width / 2, 0);
82848                 const maxX = Math.min(offsetedPosition[0] + width / 2, size.width);
82849                 const minY = Math.max(offsetedPosition[1] - height / 2, 0);
82850                 const maxY = Math.min(offsetedPosition[1] + height / 2, size.height);
82851                 const visibleX = Math.max(0, maxX - minX);
82852                 const visibleY = Math.max(0, maxY - minY);
82853                 const visibleArea = staticCoeff * visibleX * visibleY;
82854                 if (visibleArea > largestVisibleArea[0]) {
82855                     largestVisibleArea[0] = visibleArea;
82856                     largestVisibleArea[1] = autoPointPixel;
82857                     largestVisibleArea[2] = automaticPosition;
82858                 }
82859             }
82860             if (largestVisibleArea[0] > 0) {
82861                 return [largestVisibleArea[1], largestVisibleArea[2]];
82862             }
82863         }
82864         const pointBasic = this._pointFromRectPosition(rect, position);
82865         const pointPixel = this._viewportCoords.basicToCanvasSafe(pointBasic[0], pointBasic[1], { offsetHeight: size.height, offsetWidth: size.width }, transform, renderCamera.perspective);
82866         return [pointPixel, position != null ? position : "top"];
82867     }
82868     _alignmentToPopupAligment(float) {
82869         switch (float) {
82870             case Alignment.Bottom:
82871                 return "bottom";
82872             case Alignment.BottomLeft:
82873                 return "bottom-left";
82874             case Alignment.BottomRight:
82875                 return "bottom-right";
82876             case Alignment.Center:
82877                 return "center";
82878             case Alignment.Left:
82879                 return "left";
82880             case Alignment.Right:
82881                 return "right";
82882             case Alignment.Top:
82883                 return "top";
82884             case Alignment.TopLeft:
82885                 return "top-left";
82886             case Alignment.TopRight:
82887                 return "top-right";
82888             default:
82889                 return null;
82890         }
82891     }
82892     _normalizeOffset(offset) {
82893         if (offset == null) {
82894             return this._normalizeOffset(0);
82895         }
82896         if (typeof offset === "number") {
82897             // input specifies a radius
82898             const sideOffset = offset;
82899             const sign = sideOffset >= 0 ? 1 : -1;
82900             const cornerOffset = sign * Math.round(Math.sqrt(0.5 * Math.pow(sideOffset, 2)));
82901             return {
82902                 "bottom": [0, sideOffset],
82903                 "bottom-left": [-cornerOffset, cornerOffset],
82904                 "bottom-right": [cornerOffset, cornerOffset],
82905                 "center": [0, 0],
82906                 "left": [-sideOffset, 0],
82907                 "right": [sideOffset, 0],
82908                 "top": [0, -sideOffset],
82909                 "top-left": [-cornerOffset, -cornerOffset],
82910                 "top-right": [cornerOffset, -cornerOffset],
82911             };
82912         }
82913         else {
82914             // input specifes a value for each position
82915             return {
82916                 "bottom": offset.bottom || [0, 0],
82917                 "bottom-left": offset.bottomLeft || [0, 0],
82918                 "bottom-right": offset.bottomRight || [0, 0],
82919                 "center": offset.center || [0, 0],
82920                 "left": offset.left || [0, 0],
82921                 "right": offset.right || [0, 0],
82922                 "top": offset.top || [0, 0],
82923                 "top-left": offset.topLeft || [0, 0],
82924                 "top-right": offset.topRight || [0, 0],
82925             };
82926         }
82927     }
82928     _pixelToFloats(pointPixel, size, width, height) {
82929         const floats = [];
82930         if (pointPixel[1] < height) {
82931             floats.push("bottom");
82932         }
82933         else if (pointPixel[1] > size.height - height) {
82934             floats.push("top");
82935         }
82936         if (pointPixel[0] < width / 2) {
82937             floats.push("right");
82938         }
82939         else if (pointPixel[0] > size.width - width / 2) {
82940             floats.push("left");
82941         }
82942         return floats;
82943     }
82944     _pointFromRectPosition(rect, position) {
82945         const x0 = rect[0];
82946         const x1 = rect[0] < rect[2] ? rect[2] : rect[2] + 1;
82947         const y0 = rect[1];
82948         const y1 = rect[3];
82949         switch (position) {
82950             case "bottom":
82951                 return [(x0 + x1) / 2, y1];
82952             case "bottom-left":
82953                 return [x0, y1];
82954             case "bottom-right":
82955                 return [x1, y1];
82956             case "center":
82957                 return [(x0 + x1) / 2, (y0 + y1) / 2];
82958             case "left":
82959                 return [x0, (y0 + y1) / 2];
82960             case "right":
82961                 return [x1, (y0 + y1) / 2];
82962             case "top":
82963                 return [(x0 + x1) / 2, y0];
82964             case "top-left":
82965                 return [x0, y0];
82966             case "top-right":
82967                 return [x1, y0];
82968             default:
82969                 return [(x0 + x1) / 2, y1];
82970         }
82971     }
82972 }
82973
82974 function isBrowser() {
82975     return (typeof window !== "undefined" &&
82976         typeof document !== "undefined");
82977 }
82978 function isArraySupported() {
82979     return !!(Array.prototype &&
82980         Array.prototype.concat &&
82981         Array.prototype.filter &&
82982         Array.prototype.includes &&
82983         Array.prototype.indexOf &&
82984         Array.prototype.join &&
82985         Array.prototype.map &&
82986         Array.prototype.push &&
82987         Array.prototype.pop &&
82988         Array.prototype.reverse &&
82989         Array.prototype.shift &&
82990         Array.prototype.slice &&
82991         Array.prototype.splice &&
82992         Array.prototype.sort &&
82993         Array.prototype.unshift);
82994 }
82995 function isBlobSupported() {
82996     return ("Blob" in window &&
82997         "URL" in window);
82998 }
82999 function isFunctionSupported() {
83000     return !!(Function.prototype &&
83001         Function.prototype.apply &&
83002         Function.prototype.bind);
83003 }
83004 function isJSONSupported() {
83005     return ("JSON" in window &&
83006         "parse" in JSON &&
83007         "stringify" in JSON);
83008 }
83009 function isMapSupported() {
83010     return "Map" in window;
83011 }
83012 function isObjectSupported() {
83013     return !!(Object.assign &&
83014         Object.keys &&
83015         Object.values);
83016 }
83017 function isPromiseSupported() {
83018     return !!("Promise" in window &&
83019         Promise.resolve &&
83020         Promise.reject &&
83021         Promise.prototype &&
83022         Promise.prototype.catch &&
83023         Promise.prototype.then);
83024 }
83025 function isSetSupported() {
83026     return "Set" in window;
83027 }
83028 let isWebGLSupportedCache = undefined;
83029 function isWebGLSupportedCached() {
83030     if (isWebGLSupportedCache === undefined) {
83031         isWebGLSupportedCache = isWebGLSupported();
83032     }
83033     return isWebGLSupportedCache;
83034 }
83035 function isWebGLSupported() {
83036     const attributes = {
83037         alpha: false,
83038         antialias: false,
83039         depth: true,
83040         failIfMajorPerformanceCaveat: false,
83041         premultipliedAlpha: true,
83042         preserveDrawingBuffer: false,
83043         stencil: true,
83044     };
83045     const canvas = document.createElement("canvas");
83046     const webGL2Context = canvas.getContext("webgl2", attributes);
83047     if (!!webGL2Context) {
83048         return true;
83049     }
83050     const context = canvas.getContext("webgl", attributes) ||
83051         canvas
83052             .getContext("experimental-webgl", attributes);
83053     if (!context) {
83054         return false;
83055     }
83056     const requiredExtensions = ["OES_standard_derivatives"];
83057     const supportedExtensions = context.getSupportedExtensions();
83058     for (const requiredExtension of requiredExtensions) {
83059         if (supportedExtensions.indexOf(requiredExtension) === -1) {
83060             return false;
83061         }
83062     }
83063     return true;
83064 }
83065 /**
83066  * Test whether the current browser supports the full
83067  * functionality of MapillaryJS.
83068  *
83069  * @description The full functionality includes WebGL rendering.
83070  *
83071  * @return {boolean}
83072  *
83073  * @example `var supported = isSupported();`
83074  */
83075 function isSupported() {
83076     return isFallbackSupported() &&
83077         isWebGLSupportedCached();
83078 }
83079 /**
83080  * Test whether the current browser supports the fallback
83081  * functionality of MapillaryJS.
83082  *
83083  * @description The fallback functionality does not include WebGL
83084  * rendering, only 2D canvas rendering.
83085  *
83086  * @return {boolean}
83087  *
83088  * @example `var fallbackSupported = isFallbackSupported();`
83089  */
83090 function isFallbackSupported() {
83091     return isBrowser() &&
83092         isArraySupported() &&
83093         isBlobSupported() &&
83094         isFunctionSupported() &&
83095         isJSONSupported() &&
83096         isMapSupported() &&
83097         isObjectSupported() &&
83098         isPromiseSupported() &&
83099         isSetSupported();
83100 }
83101
83102 /**
83103  * Enumeration for camera controls.
83104  *
83105  * @description Specifies different modes for how the
83106  * camera is controlled through pointer, keyboard or
83107  * other modes of input.
83108  *
83109  * @enum {number}
83110  * @readonly
83111  */
83112 var CameraControls;
83113 (function (CameraControls) {
83114     /**
83115      * Control the camera with custom logic by
83116      * attaching a custom camera controls
83117      * instance to the {@link Viewer}.
83118      */
83119     CameraControls[CameraControls["Custom"] = 0] = "Custom";
83120     /**
83121      * Control the camera from a birds perspective
83122      * to get an overview.
83123      */
83124     CameraControls[CameraControls["Earth"] = 1] = "Earth";
83125     /**
83126      * Control the camera in a first person view
83127      * from the street level perspective.
83128      */
83129     CameraControls[CameraControls["Street"] = 2] = "Street";
83130 })(CameraControls || (CameraControls = {}));
83131
83132 /**
83133  * Enumeration for render mode
83134  * @enum {number}
83135  * @readonly
83136  * @description Modes for specifying how rendering is done
83137  * in the viewer. All modes preserves the original aspect
83138  * ratio of the images.
83139  */
83140 var RenderMode;
83141 (function (RenderMode) {
83142     /**
83143      * Displays all content within the viewer.
83144      *
83145      * @description Black bars shown on both
83146      * sides of the content. Bars are shown
83147      * either below and above or to the left
83148      * and right of the content depending on
83149      * the aspect ratio relation between the
83150      * image and the viewer.
83151      */
83152     RenderMode[RenderMode["Letterbox"] = 0] = "Letterbox";
83153     /**
83154      * Fills the viewer by cropping content.
83155      *
83156      * @description Cropping is done either
83157      * in horizontal or vertical direction
83158      * depending on the aspect ratio relation
83159      * between the image and the viewer.
83160      */
83161     RenderMode[RenderMode["Fill"] = 1] = "Fill";
83162 })(RenderMode || (RenderMode = {}));
83163
83164 var RenderPass;
83165 (function (RenderPass) {
83166     /**
83167      * Occurs after the background render pass.
83168      */
83169     RenderPass[RenderPass["Opaque"] = 0] = "Opaque";
83170 })(RenderPass || (RenderPass = {}));
83171
83172 class ComponentController {
83173     constructor(container, navigator, observer, key, options, componentService) {
83174         this._container = container;
83175         this._observer = observer;
83176         this._navigator = navigator;
83177         this._options = options != null ? options : {};
83178         this._key = key;
83179         this._navigable = key == null;
83180         this._componentService = !!componentService ?
83181             componentService :
83182             new ComponentService(this._container, this._navigator);
83183         this._coverComponent = this._componentService.getCover();
83184         this._initializeComponents();
83185         if (key) {
83186             this._initilizeCoverComponent();
83187             this._subscribeCoverComponent();
83188         }
83189         else {
83190             this._navigator.movedToId$.pipe(first((k) => {
83191                 return k != null;
83192             }))
83193                 .subscribe((k) => {
83194                 this._key = k;
83195                 this._componentService.deactivateCover();
83196                 this._coverComponent.configure({
83197                     id: this._key,
83198                     state: CoverState.Hidden,
83199                 });
83200                 this._subscribeCoverComponent();
83201                 this._navigator.stateService.start();
83202                 this._navigator.cacheService.start();
83203                 this._navigator.panService.start();
83204                 this._observer.startEmit();
83205             });
83206         }
83207     }
83208     get navigable() {
83209         return this._navigable;
83210     }
83211     get(name) {
83212         return this._componentService.get(name);
83213     }
83214     activate(name) {
83215         this._componentService.activate(name);
83216     }
83217     activateCover() {
83218         this._coverComponent.configure({ state: CoverState.Visible });
83219     }
83220     deactivate(name) {
83221         this._componentService.deactivate(name);
83222     }
83223     deactivateCover() {
83224         this._coverComponent.configure({ state: CoverState.Loading });
83225     }
83226     remove() {
83227         this._componentService.remove();
83228         if (this._configurationSubscription != null) {
83229             this._configurationSubscription.unsubscribe();
83230         }
83231     }
83232     _initializeComponents() {
83233         var _a, _b;
83234         const options = this._options;
83235         this._uFalse((_a = options.fallback) === null || _a === void 0 ? void 0 : _a.image, "imagefallback");
83236         this._uFalse((_b = options.fallback) === null || _b === void 0 ? void 0 : _b.navigation, "navigationfallback");
83237         this._uFalse(options.marker, "marker");
83238         this._uFalse(options.popup, "popup");
83239         this._uFalse(options.slider, "slider");
83240         this._uFalse(options.spatial, "spatial");
83241         this._uFalse(options.tag, "tag");
83242         this._uTrue(options.attribution, "attribution");
83243         this._uTrue(options.bearing, "bearing");
83244         this._uTrue(options.cache, "cache");
83245         this._uTrue(options.direction, "direction");
83246         this._uTrue(options.image, "image");
83247         this._uTrue(options.keyboard, "keyboard");
83248         this._uTrue(options.pointer, "pointer");
83249         this._uTrue(options.sequence, "sequence");
83250         this._uTrue(options.zoom, "zoom");
83251     }
83252     _initilizeCoverComponent() {
83253         let options = this._options;
83254         this._coverComponent.configure({ id: this._key });
83255         if (options.cover === undefined || options.cover) {
83256             this.activateCover();
83257         }
83258         else {
83259             this.deactivateCover();
83260         }
83261     }
83262     _setNavigable(navigable) {
83263         if (this._navigable === navigable) {
83264             return;
83265         }
83266         this._navigable = navigable;
83267         this._observer.navigable$.next(navigable);
83268     }
83269     _subscribeCoverComponent() {
83270         this._configurationSubscription =
83271             this._coverComponent.configuration$.pipe(distinctUntilChanged(undefined, (c) => {
83272                 return c.state;
83273             }))
83274                 .subscribe((conf) => {
83275                 if (conf.state === CoverState.Loading) {
83276                     this._navigator.stateService.currentId$.pipe(first(), switchMap((key) => {
83277                         const keyChanged = key == null || key !== conf.id;
83278                         if (keyChanged) {
83279                             this._setNavigable(false);
83280                         }
83281                         return keyChanged ?
83282                             this._navigator.moveTo$(conf.id) :
83283                             this._navigator.stateService.currentImage$.pipe(first());
83284                     }))
83285                         .subscribe(() => {
83286                         this._navigator.stateService.start();
83287                         this._navigator.cacheService.start();
83288                         this._navigator.panService.start();
83289                         this._observer.startEmit();
83290                         this._coverComponent.configure({ state: CoverState.Hidden });
83291                         this._componentService.deactivateCover();
83292                         this._setNavigable(true);
83293                     }, (error) => {
83294                         console.error("Failed to deactivate cover.", error);
83295                         this._coverComponent.configure({ state: CoverState.Visible });
83296                     });
83297                 }
83298                 else if (conf.state === CoverState.Visible) {
83299                     this._observer.stopEmit();
83300                     this._navigator.stateService.stop();
83301                     this._navigator.cacheService.stop();
83302                     this._navigator.playService.stop();
83303                     this._navigator.panService.stop();
83304                     this._componentService.activateCover();
83305                     this._setNavigable(conf.id == null);
83306                 }
83307             });
83308     }
83309     _uFalse(option, name) {
83310         if (option === undefined) {
83311             this._componentService.deactivate(name);
83312             return;
83313         }
83314         if (typeof option === "boolean") {
83315             if (option) {
83316                 this._componentService.activate(name);
83317             }
83318             else {
83319                 this._componentService.deactivate(name);
83320             }
83321             return;
83322         }
83323         this._componentService.configure(name, option);
83324         this._componentService.activate(name);
83325     }
83326     _uTrue(option, name) {
83327         if (option === undefined) {
83328             this._componentService.activate(name);
83329             return;
83330         }
83331         if (typeof option === "boolean") {
83332             if (option) {
83333                 this._componentService.activate(name);
83334             }
83335             else {
83336                 this._componentService.deactivate(name);
83337             }
83338             return;
83339         }
83340         this._componentService.configure(name, option);
83341         this._componentService.activate(name);
83342     }
83343 }
83344
83345 class DOMRenderer {
83346     constructor(element, renderService, currentFrame$) {
83347         this._adaptiveOperation$ = new Subject();
83348         this._render$ = new Subject();
83349         this._renderAdaptive$ = new Subject();
83350         this._subscriptions = new SubscriptionHolder();
83351         this._renderService = renderService;
83352         this._currentFrame$ = currentFrame$;
83353         const subs = this._subscriptions;
83354         const rootNode = virtualDom.create(virtualDom.h("div.mapillary-dom-renderer", []));
83355         element.appendChild(rootNode);
83356         this._offset$ = this._adaptiveOperation$.pipe(scan((adaptive, operation) => {
83357             return operation(adaptive);
83358         }, {
83359             elementHeight: element.offsetHeight,
83360             elementWidth: element.offsetWidth,
83361             imageAspect: 0,
83362             renderMode: RenderMode.Fill,
83363         }), filter((adaptive) => {
83364             return adaptive.imageAspect > 0 && adaptive.elementWidth > 0 && adaptive.elementHeight > 0;
83365         }), map((adaptive) => {
83366             const elementAspect = adaptive.elementWidth / adaptive.elementHeight;
83367             const ratio = adaptive.imageAspect / elementAspect;
83368             let verticalOffset = 0;
83369             let horizontalOffset = 0;
83370             if (adaptive.renderMode === RenderMode.Letterbox) {
83371                 if (adaptive.imageAspect > elementAspect) {
83372                     verticalOffset = adaptive.elementHeight * (1 - 1 / ratio) / 2;
83373                 }
83374                 else {
83375                     horizontalOffset = adaptive.elementWidth * (1 - ratio) / 2;
83376                 }
83377             }
83378             else {
83379                 if (adaptive.imageAspect > elementAspect) {
83380                     horizontalOffset = -adaptive.elementWidth * (ratio - 1) / 2;
83381                 }
83382                 else {
83383                     verticalOffset = -adaptive.elementHeight * (1 / ratio - 1) / 2;
83384                 }
83385             }
83386             return {
83387                 bottom: verticalOffset,
83388                 left: horizontalOffset,
83389                 right: horizontalOffset,
83390                 top: verticalOffset,
83391             };
83392         }));
83393         const imageAspectSubscription = this._currentFrame$.pipe(filter((frame) => {
83394             return frame.state.currentImage != null;
83395         }), distinctUntilChanged((k1, k2) => {
83396             return k1 === k2;
83397         }, (frame) => {
83398             return frame.state.currentImage.id;
83399         }), map((frame) => {
83400             return frame.state.currentTransform.basicAspect;
83401         }), map((aspect) => {
83402             return (adaptive) => {
83403                 adaptive.imageAspect = aspect;
83404                 return adaptive;
83405             };
83406         }))
83407             .subscribe(this._adaptiveOperation$);
83408         const renderAdaptiveSubscription = combineLatest(this._renderAdaptive$.pipe(scan((vNodeHashes, vNodeHash) => {
83409             if (vNodeHash.vNode == null) {
83410                 delete vNodeHashes[vNodeHash.name];
83411             }
83412             else {
83413                 vNodeHashes[vNodeHash.name] = vNodeHash.vNode;
83414             }
83415             return vNodeHashes;
83416         }, {})), this._offset$).pipe(map((vo) => {
83417             const vNodes = [];
83418             const hashes = vo[0];
83419             for (const name in hashes) {
83420                 if (!hashes.hasOwnProperty(name)) {
83421                     continue;
83422                 }
83423                 vNodes.push(hashes[name]);
83424             }
83425             const offset = vo[1];
83426             const properties = {
83427                 style: {
83428                     bottom: offset.bottom + "px",
83429                     left: offset.left + "px",
83430                     "pointer-events": "none",
83431                     position: "absolute",
83432                     right: offset.right + "px",
83433                     top: offset.top + "px",
83434                 },
83435             };
83436             return {
83437                 name: "mapillary-dom-adaptive-renderer",
83438                 vNode: virtualDom.h("div.mapillary-dom-adaptive-renderer", properties, vNodes),
83439             };
83440         }))
83441             .subscribe(this._render$);
83442         this._vNode$ = this._render$.pipe(scan((vNodeHashes, vNodeHash) => {
83443             if (vNodeHash.vNode == null) {
83444                 delete vNodeHashes[vNodeHash.name];
83445             }
83446             else {
83447                 vNodeHashes[vNodeHash.name] = vNodeHash.vNode;
83448             }
83449             return vNodeHashes;
83450         }, {}), map((hashes) => {
83451             const vNodes = [];
83452             for (const name in hashes) {
83453                 if (!hashes.hasOwnProperty(name)) {
83454                     continue;
83455                 }
83456                 vNodes.push(hashes[name]);
83457             }
83458             return virtualDom.h("div.mapillary-dom-renderer", vNodes);
83459         }));
83460         this._vPatch$ = this._vNode$.pipe(scan((nodePatch, vNode) => {
83461             nodePatch.vpatch = virtualDom.diff(nodePatch.vNode, vNode);
83462             nodePatch.vNode = vNode;
83463             return nodePatch;
83464         }, { vNode: virtualDom.h("div.mapillary-dom-renderer", []), vpatch: null }), pluck("vpatch"));
83465         this._element$ = this._vPatch$.pipe(scan((oldElement, vPatch) => {
83466             return virtualDom.patch(oldElement, vPatch);
83467         }, rootNode), publishReplay(1), refCount());
83468         subs.push(imageAspectSubscription);
83469         subs.push(renderAdaptiveSubscription);
83470         subs.push(this._element$.subscribe(() => { }));
83471         subs.push(this._renderService.size$.pipe(map((size) => {
83472             return (adaptive) => {
83473                 adaptive.elementWidth = size.width;
83474                 adaptive.elementHeight = size.height;
83475                 return adaptive;
83476             };
83477         }))
83478             .subscribe(this._adaptiveOperation$));
83479         subs.push(this._renderService.renderMode$.pipe(map((renderMode) => {
83480             return (adaptive) => {
83481                 adaptive.renderMode = renderMode;
83482                 return adaptive;
83483             };
83484         }))
83485             .subscribe(this._adaptiveOperation$));
83486     }
83487     get element$() {
83488         return this._element$;
83489     }
83490     get render$() {
83491         return this._render$;
83492     }
83493     get renderAdaptive$() {
83494         return this._renderAdaptive$;
83495     }
83496     clear(name) {
83497         this._renderAdaptive$.next({ name: name, vNode: null });
83498         this._render$.next({ name: name, vNode: null });
83499     }
83500     remove() {
83501         this._subscriptions.unsubscribe();
83502     }
83503 }
83504
83505 class GLRenderer {
83506     constructor(canvas, canvasContainer, renderService) {
83507         this._renderFrame$ = new Subject();
83508         this._renderCameraOperation$ = new Subject();
83509         this._render$ = new Subject();
83510         this._clear$ = new Subject();
83511         this._renderOperation$ = new Subject();
83512         this._rendererOperation$ = new Subject();
83513         this._eraserOperation$ = new Subject();
83514         this._triggerOperation$ = new Subject();
83515         this._subscriptions = new SubscriptionHolder();
83516         this._opaqueRender$ = new Subject();
83517         this._renderService = renderService;
83518         const subs = this._subscriptions;
83519         this._renderer$ = this._rendererOperation$.pipe(scan((renderer, operation) => {
83520             return operation(renderer);
83521         }, { needsRender: false, renderer: null }), filter((renderer) => {
83522             return !!renderer.renderer;
83523         }));
83524         this._renderCollection$ = this._renderOperation$.pipe(scan((hashes, operation) => {
83525             return operation(hashes);
83526         }, {}), share());
83527         this._renderCamera$ = this._renderCameraOperation$.pipe(scan((rc, operation) => {
83528             return operation(rc);
83529         }, { frameId: -1, needsRender: false, perspective: null }));
83530         this._eraser$ = this._eraserOperation$.pipe(startWith((eraser) => {
83531             return eraser;
83532         }), scan((eraser, operation) => {
83533             return operation(eraser);
83534         }, { needsRender: false }));
83535         const trigger$ = this._triggerOperation$.pipe(startWith((trigger) => {
83536             return trigger;
83537         }), scan((trigger, operation) => {
83538             return operation(trigger);
83539         }, { needsRender: false }));
83540         const clearColor = new Color(0x0F0F0F);
83541         const renderSubscription = combineLatest(this._renderer$, this._renderCollection$, this._renderCamera$, this._eraser$, trigger$).pipe(map(([renderer, hashes, rc, eraser, trigger]) => {
83542             const renders = Object.keys(hashes)
83543                 .map((key) => {
83544                 return hashes[key];
83545             });
83546             return { camera: rc, eraser: eraser, trigger: trigger, renderer: renderer, renders: renders };
83547         }), filter((co) => {
83548             let needsRender = co.renderer.needsRender ||
83549                 co.camera.needsRender ||
83550                 co.eraser.needsRender ||
83551                 co.trigger.needsRender;
83552             const frameId = co.camera.frameId;
83553             for (const render of co.renders) {
83554                 if (render.frameId !== frameId) {
83555                     return false;
83556                 }
83557                 needsRender = needsRender || render.needsRender;
83558             }
83559             return needsRender;
83560         }), distinctUntilChanged((n1, n2) => {
83561             return n1 === n2;
83562         }, (co) => {
83563             return co.eraser.needsRender ||
83564                 co.trigger.needsRender ? -co.camera.frameId : co.camera.frameId;
83565         }))
83566             .subscribe((co) => {
83567             co.renderer.needsRender = false;
83568             co.camera.needsRender = false;
83569             co.eraser.needsRender = false;
83570             co.trigger.needsRender = false;
83571             const perspectiveCamera = co.camera.perspective;
83572             const backgroundRenders = [];
83573             const opaqueRenders = [];
83574             for (const render of co.renders) {
83575                 if (render.pass === RenderPass$1.Background) {
83576                     backgroundRenders.push(render.render);
83577                 }
83578                 else if (render.pass === RenderPass$1.Opaque) {
83579                     opaqueRenders.push(render.render);
83580                 }
83581             }
83582             const renderer = co.renderer.renderer;
83583             renderer.resetState();
83584             renderer.setClearColor(clearColor, 1.0);
83585             renderer.clear();
83586             for (const renderBackground of backgroundRenders) {
83587                 renderBackground(perspectiveCamera, renderer);
83588             }
83589             renderer.clearDepth();
83590             for (const renderOpaque of opaqueRenders) {
83591                 renderOpaque(perspectiveCamera, renderer);
83592             }
83593             renderer.resetState();
83594             this._opaqueRender$.next();
83595         });
83596         subs.push(renderSubscription);
83597         subs.push(this._renderFrame$.pipe(map((rc) => {
83598             return (irc) => {
83599                 irc.frameId = rc.frameId;
83600                 irc.perspective = rc.perspective;
83601                 if (rc.changed === true) {
83602                     irc.needsRender = true;
83603                 }
83604                 return irc;
83605             };
83606         }))
83607             .subscribe(this._renderCameraOperation$));
83608         this._renderFrameSubscribe();
83609         const renderHash$ = this._render$.pipe(map((hash) => {
83610             return (hashes) => {
83611                 hashes[hash.name] = hash.renderer;
83612                 return hashes;
83613             };
83614         }));
83615         const clearHash$ = this._clear$.pipe(map((name) => {
83616             return (hashes) => {
83617                 delete hashes[name];
83618                 return hashes;
83619             };
83620         }));
83621         subs.push(merge(renderHash$, clearHash$)
83622             .subscribe(this._renderOperation$));
83623         this._webGLRenderer$ = this._render$.pipe(first(), map(() => {
83624             canvasContainer.appendChild(canvas);
83625             const element = renderService.element;
83626             const webGLRenderer = new WebGLRenderer({ canvas: canvas });
83627             webGLRenderer.setPixelRatio(window.devicePixelRatio);
83628             webGLRenderer.setSize(element.offsetWidth, element.offsetHeight);
83629             webGLRenderer.autoClear = false;
83630             return webGLRenderer;
83631         }), publishReplay(1), refCount());
83632         subs.push(this._webGLRenderer$
83633             .subscribe(() => { }));
83634         const createRenderer$ = this._webGLRenderer$.pipe(first(), map((webGLRenderer) => {
83635             return (renderer) => {
83636                 renderer.needsRender = true;
83637                 renderer.renderer = webGLRenderer;
83638                 return renderer;
83639             };
83640         }));
83641         const resizeRenderer$ = this._renderService.size$.pipe(map((size) => {
83642             return (renderer) => {
83643                 if (renderer.renderer == null) {
83644                     return renderer;
83645                 }
83646                 renderer.renderer.setSize(size.width, size.height);
83647                 renderer.needsRender = true;
83648                 return renderer;
83649             };
83650         }));
83651         const clearRenderer$ = this._clear$.pipe(map(() => {
83652             return (renderer) => {
83653                 if (renderer.renderer == null) {
83654                     return renderer;
83655                 }
83656                 renderer.needsRender = true;
83657                 return renderer;
83658             };
83659         }));
83660         subs.push(merge(createRenderer$, resizeRenderer$, clearRenderer$)
83661             .subscribe(this._rendererOperation$));
83662         const renderCollectionEmpty$ = this._renderCollection$.pipe(filter((hashes) => {
83663             return Object.keys(hashes).length === 0;
83664         }), share());
83665         subs.push(renderCollectionEmpty$
83666             .subscribe(() => {
83667             if (this._renderFrameSubscription == null) {
83668                 return;
83669             }
83670             this._renderFrameSubscription.unsubscribe();
83671             this._renderFrameSubscription = null;
83672             this._renderFrameSubscribe();
83673         }));
83674         subs.push(renderCollectionEmpty$.pipe(map(() => {
83675             return (eraser) => {
83676                 eraser.needsRender = true;
83677                 return eraser;
83678             };
83679         }))
83680             .subscribe(this._eraserOperation$));
83681     }
83682     get render$() {
83683         return this._render$;
83684     }
83685     get opaqueRender$() {
83686         return this._opaqueRender$;
83687     }
83688     get webGLRenderer$() {
83689         return this._webGLRenderer$;
83690     }
83691     clear(name) {
83692         this._clear$.next(name);
83693     }
83694     remove() {
83695         this._rendererOperation$.next((renderer) => {
83696             if (renderer.renderer != null) {
83697                 const extension = renderer.renderer
83698                     .getContext()
83699                     .getExtension('WEBGL_lose_context');
83700                 if (!!extension) {
83701                     extension.loseContext();
83702                 }
83703                 renderer.renderer = null;
83704             }
83705             return renderer;
83706         });
83707         if (this._renderFrameSubscription != null) {
83708             this._renderFrameSubscription.unsubscribe();
83709         }
83710         this._subscriptions.unsubscribe();
83711     }
83712     triggerRerender() {
83713         this._renderService.renderCameraFrame$
83714             .pipe(skip(1), first())
83715             .subscribe(() => {
83716             this._triggerOperation$.next((trigger) => {
83717                 trigger.needsRender = true;
83718                 return trigger;
83719             });
83720         });
83721     }
83722     _renderFrameSubscribe() {
83723         this._render$.pipe(first(), map(() => {
83724             return (irc) => {
83725                 irc.needsRender = true;
83726                 return irc;
83727             };
83728         }))
83729             .subscribe((operation) => {
83730             this._renderCameraOperation$.next(operation);
83731         });
83732         this._renderFrameSubscription = this._render$.pipe(first(), mergeMap(() => {
83733             return this._renderService.renderCameraFrame$;
83734         }))
83735             .subscribe(this._renderFrame$);
83736     }
83737 }
83738
83739 class RenderCamera {
83740     constructor(elementWidth, elementHeight, renderMode) {
83741         this._spatial = new Spatial();
83742         this._viewportCoords = new ViewportCoords();
83743         this._size = { width: elementWidth, height: elementHeight };
83744         this._initialFov = 60;
83745         this._alpha = -1;
83746         this._renderMode = renderMode;
83747         this._zoom = 0;
83748         this._frameId = -1;
83749         this._changed = false;
83750         this._changedForFrame = -1;
83751         this._currentImageId = null;
83752         this._previousImageId = null;
83753         this._currentSpherical = false;
83754         this._previousSpherical = false;
83755         this._state = null;
83756         this._currentProjectedPoints = [];
83757         this._previousProjectedPoints = [];
83758         this._currentFov = this._initialFov;
83759         this._previousFov = this._initialFov;
83760         this._camera = new Camera();
83761         this._perspective = new PerspectiveCamera(this._initialFov, this._computeAspect(elementWidth, elementHeight), 0.16, 10000);
83762         this._perspective.position.copy(this._camera.position);
83763         this._perspective.up.copy(this._camera.up);
83764         this._perspective.lookAt(this._camera.lookat);
83765         this._perspective.updateMatrixWorld(true);
83766         this._perspective.matrixAutoUpdate = false;
83767         this._rotation = { phi: 0, theta: 0 };
83768     }
83769     get alpha() {
83770         return this._alpha;
83771     }
83772     get camera() {
83773         return this._camera;
83774     }
83775     get changed() {
83776         return this._frameId === this._changedForFrame;
83777     }
83778     get frameId() {
83779         return this._frameId;
83780     }
83781     get perspective() {
83782         return this._perspective;
83783     }
83784     get renderMode() {
83785         return this._renderMode;
83786     }
83787     get rotation() {
83788         return this._rotation;
83789     }
83790     get zoom() {
83791         return this._zoom;
83792     }
83793     get size() {
83794         return this._size;
83795     }
83796     getTilt() {
83797         return 90 - this._spatial.radToDeg(this._rotation.theta);
83798     }
83799     fovToZoom(fov) {
83800         fov = Math.min(90, Math.max(0, fov));
83801         const currentFov = this._computeCurrentFov(0);
83802         const actualFov = this._alpha === 1 ?
83803             currentFov :
83804             this._interpolateFov(currentFov, this._computePreviousFov(0), this._alpha);
83805         const y0 = Math.tan(actualFov / 2 * Math.PI / 180);
83806         const y1 = Math.tan(fov / 2 * Math.PI / 180);
83807         const zoom = Math.log(y0 / y1) / Math.log(2);
83808         return zoom;
83809     }
83810     setFrame(frame) {
83811         const state = frame.state;
83812         if (state.state !== this._state) {
83813             this._state = state.state;
83814             if (this._state !== State.Custom) {
83815                 this.setRenderMode(this._renderMode);
83816                 this.setSize(this._size);
83817             }
83818             this._changed = true;
83819         }
83820         const currentImageId = state.currentImage.id;
83821         const previousImageId = !!state.previousImage ? state.previousImage.id : null;
83822         if (currentImageId !== this._currentImageId) {
83823             this._currentImageId = currentImageId;
83824             this._currentSpherical = isSpherical(state.currentTransform.cameraType);
83825             this._currentProjectedPoints = this._computeProjectedPoints(state.currentTransform);
83826             this._changed = true;
83827         }
83828         if (previousImageId !== this._previousImageId) {
83829             this._previousImageId = previousImageId;
83830             this._previousSpherical =
83831                 isSpherical(state.previousTransform.cameraType);
83832             this._previousProjectedPoints = this._computeProjectedPoints(state.previousTransform);
83833             this._changed = true;
83834         }
83835         const zoom = state.zoom;
83836         if (zoom !== this._zoom) {
83837             this._zoom = zoom;
83838             this._changed = true;
83839         }
83840         if (this._changed) {
83841             this._currentFov = this._computeCurrentFov(this.zoom);
83842             this._previousFov = this._computePreviousFov(this._zoom);
83843         }
83844         const alpha = state.alpha;
83845         if (this._changed || alpha !== this._alpha) {
83846             this._alpha = alpha;
83847             switch (this._state) {
83848                 case State.Earth:
83849                     this._perspective.fov = 60;
83850                     this._changed = true;
83851                     break;
83852                 case State.Custom:
83853                     break;
83854                 default:
83855                     this._perspective.fov =
83856                         this._interpolateFov(this._currentFov, this._previousFov, this._alpha);
83857                     this._changed = true;
83858                     break;
83859             }
83860             if (this._state !== State.Custom) {
83861                 this._perspective.updateProjectionMatrix();
83862             }
83863         }
83864         const camera = state.camera;
83865         if (this._camera.diff(camera) > 1e-9) {
83866             this._camera.copy(camera);
83867             this._rotation = this._computeRotation(camera);
83868             this._perspective.up.copy(camera.up);
83869             this._perspective.position.copy(camera.position);
83870             // Workaround for shaking camera
83871             this._perspective.matrixAutoUpdate = true;
83872             this._perspective.lookAt(camera.lookat);
83873             this._perspective.matrixAutoUpdate = false;
83874             this._perspective.updateMatrix();
83875             this._perspective.updateMatrixWorld(false);
83876             this._changed = true;
83877         }
83878         this._setFrameId(frame.id);
83879     }
83880     setProjectionMatrix(matrix) {
83881         this._perspective.projectionMatrix.fromArray(matrix);
83882         this._perspective.projectionMatrixInverse
83883             .copy(this._perspective.projectionMatrix)
83884             .invert();
83885         this._changed = true;
83886     }
83887     setRenderMode(renderMode) {
83888         this._renderMode = renderMode;
83889         if (this._state === State.Custom) {
83890             return;
83891         }
83892         this._perspective.fov = this._computeFov();
83893         this._perspective.updateProjectionMatrix();
83894         this._changed = true;
83895     }
83896     setSize(size) {
83897         this._size = size;
83898         if (this._state === State.Custom) {
83899             return;
83900         }
83901         this._perspective.aspect = this._computeAspect(size.width, size.height);
83902         this._perspective.fov = this._computeFov();
83903         this._perspective.updateProjectionMatrix();
83904         this._changed = true;
83905     }
83906     _computeAspect(elementWidth, elementHeight) {
83907         return elementWidth === 0 ? 0 : elementWidth / elementHeight;
83908     }
83909     _computeCurrentFov(zoom) {
83910         if (this._perspective.aspect === 0) {
83911             return 0;
83912         }
83913         if (!this._currentImageId) {
83914             return this._initialFov;
83915         }
83916         return this._currentSpherical ?
83917             this._yToFov(1, zoom) :
83918             this._computeVerticalFov(this._currentProjectedPoints, this._renderMode, zoom, this.perspective.aspect);
83919     }
83920     _computeFov() {
83921         this._currentFov = this._computeCurrentFov(this._zoom);
83922         this._previousFov = this._computePreviousFov(this._zoom);
83923         return this._interpolateFov(this._currentFov, this._previousFov, this._alpha);
83924     }
83925     _computePreviousFov(zoom) {
83926         if (this._perspective.aspect === 0) {
83927             return 0;
83928         }
83929         if (!this._currentImageId) {
83930             return this._initialFov;
83931         }
83932         return !this._previousImageId ?
83933             this._currentFov :
83934             this._previousSpherical ?
83935                 this._yToFov(1, zoom) :
83936                 this._computeVerticalFov(this._previousProjectedPoints, this._renderMode, zoom, this.perspective.aspect);
83937     }
83938     _computeProjectedPoints(transform) {
83939         const vertices = [[0.5, 0], [1, 0]];
83940         const directions = [[0.5, 0], [0, 0.5]];
83941         const pointsPerLine = 100;
83942         return computeProjectedPoints(transform, vertices, directions, pointsPerLine, this._viewportCoords);
83943     }
83944     _computeRequiredVerticalFov(projectedPoint, zoom, aspect) {
83945         const maxY = Math.max(projectedPoint[0] / aspect, projectedPoint[1]);
83946         return this._yToFov(maxY, zoom);
83947     }
83948     _computeRotation(camera) {
83949         let direction = camera.lookat.clone().sub(camera.position);
83950         let up = camera.up.clone();
83951         let phi = this._spatial.azimuthal(direction.toArray(), up.toArray());
83952         let theta = Math.PI / 2 - this._spatial.angleToPlane(direction.toArray(), [0, 0, 1]);
83953         return { phi: phi, theta: theta };
83954     }
83955     _computeVerticalFov(projectedPoints, renderMode, zoom, aspect) {
83956         const fovs = projectedPoints
83957             .map((projectedPoint) => {
83958             return this._computeRequiredVerticalFov(projectedPoint, zoom, aspect);
83959         });
83960         const fov = renderMode === RenderMode.Fill ?
83961             Math.min(...fovs) * 0.995 :
83962             Math.max(...fovs);
83963         return fov;
83964     }
83965     _yToFov(y, zoom) {
83966         return 2 * Math.atan(y / Math.pow(2, zoom)) * 180 / Math.PI;
83967     }
83968     _interpolateFov(v1, v2, alpha) {
83969         return alpha * v1 + (1 - alpha) * v2;
83970     }
83971     _setFrameId(frameId) {
83972         this._frameId = frameId;
83973         if (this._changed) {
83974             this._changed = false;
83975             this._changedForFrame = frameId;
83976         }
83977     }
83978 }
83979
83980 class RenderService {
83981     constructor(element, currentFrame$, renderMode, renderCamera) {
83982         this._subscriptions = new SubscriptionHolder();
83983         this._element = element;
83984         this._currentFrame$ = currentFrame$;
83985         this._spatial = new Spatial();
83986         renderMode = renderMode != null ? renderMode : RenderMode.Fill;
83987         this._resize$ = new Subject();
83988         this._projectionMatrix$ = new Subject();
83989         this._renderCameraOperation$ =
83990             new Subject();
83991         this._size$ =
83992             new BehaviorSubject({
83993                 height: this._element.offsetHeight,
83994                 width: this._element.offsetWidth,
83995             });
83996         const subs = this._subscriptions;
83997         subs.push(this._resize$.pipe(map(() => {
83998             return {
83999                 height: this._element.offsetHeight,
84000                 width: this._element.offsetWidth,
84001             };
84002         }))
84003             .subscribe(this._size$));
84004         this._renderMode$ = new BehaviorSubject(renderMode);
84005         this._renderCameraHolder$ = this._renderCameraOperation$.pipe(startWith((rc) => {
84006             return rc;
84007         }), scan((rc, operation) => {
84008             return operation(rc);
84009         }, renderCamera !== null && renderCamera !== void 0 ? renderCamera : new RenderCamera(this._element.offsetWidth, this._element.offsetHeight, renderMode)), publishReplay(1), refCount());
84010         this._renderCameraFrame$ = this._currentFrame$.pipe(withLatestFrom(this._renderCameraHolder$), tap(([frame, rc]) => {
84011             rc.setFrame(frame);
84012         }), map((args) => {
84013             return args[1];
84014         }), publishReplay(1), refCount());
84015         this._renderCamera$ = this._renderCameraFrame$.pipe(filter((rc) => {
84016             return rc.changed;
84017         }), publishReplay(1), refCount());
84018         this._bearing$ = this._renderCamera$.pipe(map((rc) => {
84019             let bearing = this._spatial.radToDeg(this._spatial.azimuthalToBearing(rc.rotation.phi));
84020             return this._spatial.wrap(bearing, 0, 360);
84021         }), publishReplay(1), refCount());
84022         subs.push(this._size$.pipe(skip(1), map((size) => {
84023             return (rc) => {
84024                 rc.setSize(size);
84025                 return rc;
84026             };
84027         }))
84028             .subscribe(this._renderCameraOperation$));
84029         subs.push(this._renderMode$.pipe(skip(1), map((rm) => {
84030             return (rc) => {
84031                 rc.setRenderMode(rm);
84032                 return rc;
84033             };
84034         }))
84035             .subscribe(this._renderCameraOperation$));
84036         subs.push(this._projectionMatrix$.pipe(map((projectionMatrix) => {
84037             return (rc) => {
84038                 rc.setProjectionMatrix(projectionMatrix);
84039                 return rc;
84040             };
84041         }))
84042             .subscribe(this._renderCameraOperation$));
84043         subs.push(this._bearing$.subscribe(() => { }));
84044         subs.push(this._renderCameraHolder$.subscribe(() => { }));
84045         subs.push(this._size$.subscribe(() => { }));
84046         subs.push(this._renderMode$.subscribe(() => { }));
84047         subs.push(this._renderCamera$.subscribe(() => { }));
84048         subs.push(this._renderCameraFrame$.subscribe(() => { }));
84049     }
84050     get bearing$() {
84051         return this._bearing$;
84052     }
84053     get element() {
84054         return this._element;
84055     }
84056     get projectionMatrix$() {
84057         return this._projectionMatrix$;
84058     }
84059     get renderCamera$() {
84060         return this._renderCamera$;
84061     }
84062     get renderCameraFrame$() {
84063         return this._renderCameraFrame$;
84064     }
84065     get renderMode$() {
84066         return this._renderMode$;
84067     }
84068     get resize$() {
84069         return this._resize$;
84070     }
84071     get size$() {
84072         return this._size$;
84073     }
84074     dispose() {
84075         this._subscriptions.unsubscribe();
84076     }
84077 }
84078
84079 class KeyboardService {
84080     constructor(canvasContainer) {
84081         this._keyDown$ = fromEvent(canvasContainer, "keydown");
84082         this._keyUp$ = fromEvent(canvasContainer, "keyup");
84083     }
84084     get keyDown$() {
84085         return this._keyDown$;
84086     }
84087     get keyUp$() {
84088         return this._keyUp$;
84089     }
84090 }
84091
84092 // MouseEvent.button
84093 const LEFT_BUTTON = 0;
84094 const RIGHT_BUTTON = 2;
84095 // MouseEvent.buttons
84096 const BUTTONS_MAP = {
84097     [LEFT_BUTTON]: 1,
84098     [RIGHT_BUTTON]: 2
84099 };
84100 class MouseService {
84101     constructor(container, canvasContainer, domContainer, doc) {
84102         this._subscriptions = new SubscriptionHolder();
84103         const subs = this._subscriptions;
84104         this._activeSubject$ = new BehaviorSubject(false);
84105         this._active$ = this._activeSubject$
84106             .pipe(distinctUntilChanged(), publishReplay(1), refCount());
84107         this._claimMouse$ = new Subject();
84108         this._claimWheel$ = new Subject();
84109         this._deferPixelClaims$ = new Subject();
84110         this._deferPixels$ = this._deferPixelClaims$
84111             .pipe(scan((claims, claim) => {
84112             if (claim.deferPixels == null) {
84113                 delete claims[claim.name];
84114             }
84115             else {
84116                 claims[claim.name] = claim.deferPixels;
84117             }
84118             return claims;
84119         }, {}), map((claims) => {
84120             let deferPixelMax = -1;
84121             for (const key in claims) {
84122                 if (!claims.hasOwnProperty(key)) {
84123                     continue;
84124                 }
84125                 const deferPixels = claims[key];
84126                 if (deferPixels > deferPixelMax) {
84127                     deferPixelMax = deferPixels;
84128                 }
84129             }
84130             return deferPixelMax;
84131         }), startWith(-1), publishReplay(1), refCount());
84132         subs.push(this._deferPixels$.subscribe(() => { }));
84133         this._documentMouseMove$ =
84134             fromEvent(doc, "pointermove")
84135                 .pipe(filter(this._isMousePen));
84136         this._documentMouseUp$ =
84137             fromEvent(doc, "pointerup")
84138                 .pipe(filter(this._isMousePen));
84139         this._mouseDown$ =
84140             fromEvent(canvasContainer, "pointerdown")
84141                 .pipe(filter(this._isMousePen));
84142         this._mouseEnter$ =
84143             fromEvent(canvasContainer, "pointerenter")
84144                 .pipe(filter(this._isMousePen));
84145         this._mouseLeave$ =
84146             fromEvent(canvasContainer, "pointerleave")
84147                 .pipe(filter(this._isMousePen));
84148         this._mouseMove$ =
84149             fromEvent(canvasContainer, "pointermove")
84150                 .pipe(filter(this._isMousePen));
84151         this._mouseUp$ =
84152             fromEvent(canvasContainer, "pointerup")
84153                 .pipe(filter(this._isMousePen));
84154         this._mouseOut$ =
84155             fromEvent(canvasContainer, "pointerout")
84156                 .pipe(filter(this._isMousePen));
84157         this._mouseOver$ =
84158             fromEvent(canvasContainer, "pointerover")
84159                 .pipe(filter(this._isMousePen));
84160         this._domMouseDown$ =
84161             fromEvent(domContainer, "pointerdown")
84162                 .pipe(filter(this._isMousePen));
84163         this._domMouseMove$ =
84164             fromEvent(domContainer, "pointermove")
84165                 .pipe(filter(this._isMousePen));
84166         this._click$ =
84167             fromEvent(canvasContainer, "click");
84168         this._contextMenu$ =
84169             fromEvent(canvasContainer, "contextmenu");
84170         this._windowBlur$ =
84171             fromEvent(window, "blur");
84172         this._dblClick$ = merge(fromEvent(container, "click"), fromEvent(canvasContainer, "dblclick"))
84173             .pipe(bufferCount(3, 1), filter((events) => {
84174             const event1 = events[0];
84175             const event2 = events[1];
84176             const event3 = events[2];
84177             return event1.type === "click" &&
84178                 event2.type === "click" &&
84179                 event3.type === "dblclick" &&
84180                 event1.target.parentNode === canvasContainer &&
84181                 event2.target.parentNode === canvasContainer;
84182         }), map((events) => {
84183             return events[2];
84184         }), share());
84185         subs.push(merge(this._domMouseDown$, this._domMouseMove$, this._dblClick$, this._contextMenu$)
84186             .subscribe((event) => {
84187             event.preventDefault();
84188         }));
84189         this._mouseWheel$ = merge(fromEvent(canvasContainer, "wheel"), fromEvent(domContainer, "wheel"))
84190             .pipe(share());
84191         this._consistentContextMenu$ =
84192             merge(this._mouseDown$, this._mouseMove$, this._mouseOut$, this._mouseUp$, this._contextMenu$)
84193                 .pipe(bufferCount(3, 1), filter((events) => {
84194                 // fire context menu on mouse up both on mac and windows
84195                 return events[0].type === "pointerdown" &&
84196                     events[1].type === "contextmenu" &&
84197                     events[2].type === "pointerup";
84198             }), map((events) => {
84199                 return events[1];
84200             }), share());
84201         const dragStop$ = merge(this._windowBlur$, this._documentMouseMove$
84202             .pipe(filter((e) => {
84203             return this._buttonReleased(e, LEFT_BUTTON);
84204         })), this._documentMouseUp$
84205             .pipe(filter((e) => {
84206             return this._mouseButton(e) === LEFT_BUTTON;
84207         })))
84208             .pipe(share());
84209         const mouseDragInitiate$ = this._createMouseDragInitiate$(LEFT_BUTTON, this._mouseDown$, dragStop$, true)
84210             .pipe(share());
84211         this._mouseDragStart$ =
84212             this._createMouseDragStart$(mouseDragInitiate$)
84213                 .pipe(share());
84214         this._mouseDrag$ =
84215             this._createMouseDrag$(mouseDragInitiate$, dragStop$)
84216                 .pipe(share());
84217         this._mouseDragEnd$ =
84218             this._createMouseDragEnd$(this._mouseDragStart$, dragStop$)
84219                 .pipe(share());
84220         const domMouseDragInitiate$ = this._createMouseDragInitiate$(LEFT_BUTTON, this._domMouseDown$, dragStop$, false)
84221             .pipe(share());
84222         this._domMouseDragStart$ =
84223             this._createMouseDragStart$(domMouseDragInitiate$)
84224                 .pipe(share());
84225         this._domMouseDrag$ =
84226             this._createMouseDrag$(domMouseDragInitiate$, dragStop$)
84227                 .pipe(share());
84228         this._domMouseDragEnd$ =
84229             this._createMouseDragEnd$(this._domMouseDragStart$, dragStop$)
84230                 .pipe(share());
84231         const rightDragStop$ = merge(this._windowBlur$, this._documentMouseMove$.pipe(filter((e) => {
84232             return this._buttonReleased(e, RIGHT_BUTTON);
84233         })), this._documentMouseUp$.pipe(filter((e) => {
84234             return this._mouseButton(e) === RIGHT_BUTTON;
84235         })))
84236             .pipe(share());
84237         const mouseRightDragInitiate$ = this._createMouseDragInitiate$(RIGHT_BUTTON, this._mouseDown$, rightDragStop$, true)
84238             .pipe(share());
84239         this._mouseRightDragStart$ =
84240             this._createMouseDragStart$(mouseRightDragInitiate$)
84241                 .pipe(share());
84242         this._mouseRightDrag$ =
84243             this._createMouseDrag$(mouseRightDragInitiate$, rightDragStop$)
84244                 .pipe(share());
84245         this._mouseRightDragEnd$ =
84246             this._createMouseDragEnd$(this._mouseRightDragStart$, rightDragStop$)
84247                 .pipe(share());
84248         this._proximateClick$ = this._mouseDown$
84249             .pipe(switchMap((mouseDown) => {
84250             return this._click$.pipe(takeUntil(this._createDeferredMouseMove$(mouseDown, this._documentMouseMove$)), take(1));
84251         }), share());
84252         this._staticClick$ = this._mouseDown$
84253             .pipe(switchMap(() => {
84254             return this._click$.pipe(takeUntil(this._documentMouseMove$), take(1));
84255         }), share());
84256         subs.push(this._mouseDragStart$.subscribe());
84257         subs.push(this._mouseDrag$.subscribe());
84258         subs.push(this._mouseDragEnd$.subscribe());
84259         subs.push(this._domMouseDragStart$.subscribe());
84260         subs.push(this._domMouseDrag$.subscribe());
84261         subs.push(this._domMouseDragEnd$.subscribe());
84262         subs.push(this._mouseRightDragStart$.subscribe());
84263         subs.push(this._mouseRightDrag$.subscribe());
84264         subs.push(this._mouseRightDragEnd$.subscribe());
84265         subs.push(this._staticClick$.subscribe());
84266         this._mouseOwner$ = this._createOwner$(this._claimMouse$)
84267             .pipe(publishReplay(1), refCount());
84268         this._wheelOwner$ = this._createOwner$(this._claimWheel$)
84269             .pipe(publishReplay(1), refCount());
84270         subs.push(this._mouseOwner$.subscribe(() => { }));
84271         subs.push(this._wheelOwner$.subscribe(() => { }));
84272     }
84273     get active$() {
84274         return this._active$;
84275     }
84276     get activate$() {
84277         return this._activeSubject$;
84278     }
84279     get documentMouseMove$() {
84280         return this._documentMouseMove$;
84281     }
84282     get documentMouseUp$() {
84283         return this._documentMouseUp$;
84284     }
84285     get domMouseDragStart$() {
84286         return this._domMouseDragStart$;
84287     }
84288     get domMouseDrag$() {
84289         return this._domMouseDrag$;
84290     }
84291     get domMouseDragEnd$() {
84292         return this._domMouseDragEnd$;
84293     }
84294     get domMouseDown$() {
84295         return this._domMouseDown$;
84296     }
84297     get domMouseMove$() {
84298         return this._domMouseMove$;
84299     }
84300     get mouseOwner$() {
84301         return this._mouseOwner$;
84302     }
84303     get mouseDown$() {
84304         return this._mouseDown$;
84305     }
84306     get mouseEnter$() {
84307         return this._mouseEnter$;
84308     }
84309     get mouseMove$() {
84310         return this._mouseMove$;
84311     }
84312     get mouseLeave$() {
84313         return this._mouseLeave$;
84314     }
84315     get mouseOut$() {
84316         return this._mouseOut$;
84317     }
84318     get mouseOver$() {
84319         return this._mouseOver$;
84320     }
84321     get mouseUp$() {
84322         return this._mouseUp$;
84323     }
84324     get click$() {
84325         return this._click$;
84326     }
84327     get dblClick$() {
84328         return this._dblClick$;
84329     }
84330     get contextMenu$() {
84331         return this._consistentContextMenu$;
84332     }
84333     get mouseWheel$() {
84334         return this._mouseWheel$;
84335     }
84336     get mouseDragStart$() {
84337         return this._mouseDragStart$;
84338     }
84339     get mouseDrag$() {
84340         return this._mouseDrag$;
84341     }
84342     get mouseDragEnd$() {
84343         return this._mouseDragEnd$;
84344     }
84345     get mouseRightDragStart$() {
84346         return this._mouseRightDragStart$;
84347     }
84348     get mouseRightDrag$() {
84349         return this._mouseRightDrag$;
84350     }
84351     get mouseRightDragEnd$() {
84352         return this._mouseRightDragEnd$;
84353     }
84354     get proximateClick$() {
84355         return this._proximateClick$;
84356     }
84357     get staticClick$() {
84358         return this._staticClick$;
84359     }
84360     get windowBlur$() {
84361         return this._windowBlur$;
84362     }
84363     dispose() {
84364         this._subscriptions.unsubscribe();
84365     }
84366     claimMouse(name, zindex) {
84367         this._claimMouse$.next({ name: name, zindex: zindex });
84368     }
84369     unclaimMouse(name) {
84370         this._claimMouse$.next({ name: name, zindex: null });
84371     }
84372     deferPixels(name, deferPixels) {
84373         this._deferPixelClaims$.next({ name: name, deferPixels: deferPixels });
84374     }
84375     undeferPixels(name) {
84376         this._deferPixelClaims$.next({ name: name, deferPixels: null });
84377     }
84378     claimWheel(name, zindex) {
84379         this._claimWheel$.next({ name: name, zindex: zindex });
84380     }
84381     unclaimWheel(name) {
84382         this._claimWheel$.next({ name: name, zindex: null });
84383     }
84384     filtered$(name, observable$) {
84385         return this._filtered(name, observable$, this._mouseOwner$);
84386     }
84387     filteredWheel$(name, observable$) {
84388         return this._filtered(name, observable$, this._wheelOwner$);
84389     }
84390     _createDeferredMouseMove$(origin, mouseMove$) {
84391         return mouseMove$.pipe(map((mouseMove) => {
84392             const deltaX = mouseMove.clientX - origin.clientX;
84393             const deltaY = mouseMove.clientY - origin.clientY;
84394             return [mouseMove, Math.sqrt(deltaX * deltaX + deltaY * deltaY)];
84395         }), withLatestFrom(this._deferPixels$), filter(([[, delta], deferPixels]) => {
84396             return delta > deferPixels;
84397         }), map(([[mouseMove]]) => {
84398             return mouseMove;
84399         }));
84400     }
84401     _createMouseDrag$(mouseDragStartInitiate$, stop$) {
84402         return mouseDragStartInitiate$.pipe(map(([, mouseMove]) => {
84403             return mouseMove;
84404         }), switchMap((mouseMove) => {
84405             return concat(of(mouseMove), this._documentMouseMove$).pipe(takeUntil(stop$));
84406         }));
84407     }
84408     _createMouseDragEnd$(mouseDragStart$, stop$) {
84409         return mouseDragStart$.pipe(switchMap(() => {
84410             return stop$.pipe(first());
84411         }));
84412     }
84413     _createMouseDragStart$(mouseDragStartInitiate$) {
84414         return mouseDragStartInitiate$.pipe(map(([mouseDown]) => {
84415             return mouseDown;
84416         }));
84417     }
84418     _createMouseDragInitiate$(button, mouseDown$, stop$, defer) {
84419         return mouseDown$.pipe(filter((mouseDown) => {
84420             return this._mouseButton(mouseDown) === button;
84421         }), switchMap((mouseDown) => {
84422             return combineLatest(of(mouseDown), defer ?
84423                 this._createDeferredMouseMove$(mouseDown, this._documentMouseMove$) :
84424                 this._documentMouseMove$).pipe(takeUntil(stop$), take(1));
84425         }));
84426     }
84427     _createOwner$(claim$) {
84428         return claim$.pipe(scan((claims, claim) => {
84429             if (claim.zindex == null) {
84430                 delete claims[claim.name];
84431             }
84432             else {
84433                 claims[claim.name] = claim.zindex;
84434             }
84435             return claims;
84436         }, {}), map((claims) => {
84437             let owner = null;
84438             let zIndexMax = -1;
84439             for (const name in claims) {
84440                 if (!claims.hasOwnProperty(name)) {
84441                     continue;
84442                 }
84443                 if (claims[name] > zIndexMax) {
84444                     zIndexMax = claims[name];
84445                     owner = name;
84446                 }
84447             }
84448             return owner;
84449         }), startWith(null));
84450     }
84451     _filtered(name, observable$, owner$) {
84452         return observable$.pipe(withLatestFrom(owner$), filter(([, owner]) => {
84453             return owner === name;
84454         }), map(([item]) => {
84455             return item;
84456         }));
84457     }
84458     _mouseButton(event) {
84459         const upOrDown = event.type === "pointerdown" || event.type === "pointerup";
84460         const InstallTrigger = window.InstallTrigger;
84461         if (upOrDown &&
84462             typeof InstallTrigger !== 'undefined' &&
84463             event.button === RIGHT_BUTTON && event.ctrlKey &&
84464             window.navigator.platform.toUpperCase().indexOf('MAC') >= 0) {
84465             // Fix for the fact that Firefox (detected by InstallTrigger)
84466             // on Mac determines e.button = 2 when using Control + left click.
84467             return LEFT_BUTTON;
84468         }
84469         return event.button;
84470     }
84471     _buttonReleased(event, button) {
84472         // Right button `mouseup` is not fired in
84473         // Chrome on Mac outside the window or iframe. If
84474         // the button is no longer pressed during move
84475         // it may have been released and drag stop
84476         // should be emitted.
84477         const flag = BUTTONS_MAP[button];
84478         return event.buttons === undefined || (event.buttons & flag) !== flag;
84479     }
84480     _isMousePen(event) {
84481         const type = event.pointerType;
84482         return type === "mouse" || type === "pen";
84483     }
84484 }
84485
84486 class SpriteAtlas {
84487     set json(value) {
84488         this._json = value;
84489     }
84490     set image(value) {
84491         this._image = value;
84492         this._texture = new Texture(this._image);
84493         this._texture.minFilter = NearestFilter;
84494     }
84495     get loaded() {
84496         return !!(this._image && this._json);
84497     }
84498     getGLSprite(name) {
84499         if (!this.loaded) {
84500             throw new Error("Sprites cannot be retrieved before the atlas is loaded.");
84501         }
84502         let definition = this._json[name];
84503         if (!definition) {
84504             console.warn("Sprite with key" + name + "does not exist in sprite definition.");
84505             return new Object3D();
84506         }
84507         let texture = this._texture.clone();
84508         texture.needsUpdate = true;
84509         let width = this._image.width;
84510         let height = this._image.height;
84511         texture.offset.x = definition.x / width;
84512         texture.offset.y = (height - definition.y - definition.height) / height;
84513         texture.repeat.x = definition.width / width;
84514         texture.repeat.y = definition.height / height;
84515         let material = new SpriteMaterial({ map: texture });
84516         return new Sprite(material);
84517     }
84518     getDOMSprite(name, float) {
84519         if (!this.loaded) {
84520             throw new Error("Sprites cannot be retrieved before the atlas is loaded.");
84521         }
84522         if (float == null) {
84523             float = Alignment.Center;
84524         }
84525         let definition = this._json[name];
84526         if (!definition) {
84527             console.warn("Sprite with key" + name + "does not exist in sprite definition.");
84528             return virtualDom.h("div", {}, []);
84529         }
84530         let clipTop = definition.y;
84531         let clipRigth = definition.x + definition.width;
84532         let clipBottom = definition.y + definition.height;
84533         let clipLeft = definition.x;
84534         let left = -definition.x;
84535         let top = -definition.y;
84536         let height = this._image.height;
84537         let width = this._image.width;
84538         switch (float) {
84539             case Alignment.Bottom:
84540             case Alignment.Center:
84541             case Alignment.Top:
84542                 left -= definition.width / 2;
84543                 break;
84544             case Alignment.BottomLeft:
84545             case Alignment.Left:
84546             case Alignment.TopLeft:
84547                 left -= definition.width;
84548                 break;
84549             case Alignment.BottomRight:
84550             case Alignment.Right:
84551             case Alignment.TopRight:
84552         }
84553         switch (float) {
84554             case Alignment.Center:
84555             case Alignment.Left:
84556             case Alignment.Right:
84557                 top -= definition.height / 2;
84558                 break;
84559             case Alignment.Top:
84560             case Alignment.TopLeft:
84561             case Alignment.TopRight:
84562                 top -= definition.height;
84563                 break;
84564             case Alignment.Bottom:
84565             case Alignment.BottomLeft:
84566             case Alignment.BottomRight:
84567         }
84568         let pixelRatioInverse = 1 / definition.pixelRatio;
84569         clipTop *= pixelRatioInverse;
84570         clipRigth *= pixelRatioInverse;
84571         clipBottom *= pixelRatioInverse;
84572         clipLeft *= pixelRatioInverse;
84573         left *= pixelRatioInverse;
84574         top *= pixelRatioInverse;
84575         height *= pixelRatioInverse;
84576         width *= pixelRatioInverse;
84577         let properties = {
84578             src: this._image.src,
84579             style: {
84580                 clip: `rect(${clipTop}px, ${clipRigth}px, ${clipBottom}px, ${clipLeft}px)`,
84581                 height: `${height}px`,
84582                 left: `${left}px`,
84583                 position: "absolute",
84584                 top: `${top}px`,
84585                 width: `${width}px`,
84586             },
84587         };
84588         return virtualDom.h("img", properties, []);
84589     }
84590 }
84591 class SpriteService {
84592     constructor(sprite) {
84593         this._retina = window.devicePixelRatio > 1;
84594         this._spriteAtlasOperation$ = new Subject();
84595         this._spriteAtlas$ = this._spriteAtlasOperation$.pipe(startWith((atlas) => {
84596             return atlas;
84597         }), scan((atlas, operation) => {
84598             return operation(atlas);
84599         }, new SpriteAtlas()), publishReplay(1), refCount());
84600         this._atlasSubscription = this._spriteAtlas$
84601             .subscribe(() => { });
84602         if (sprite == null) {
84603             return;
84604         }
84605         let format = this._retina ? "@2x" : "";
84606         let imageXmlHTTP = new XMLHttpRequest();
84607         imageXmlHTTP.open("GET", sprite + format + ".png", true);
84608         imageXmlHTTP.responseType = "arraybuffer";
84609         imageXmlHTTP.onload = () => {
84610             let image = new Image();
84611             image.onload = () => {
84612                 this._spriteAtlasOperation$.next((atlas) => {
84613                     atlas.image = image;
84614                     return atlas;
84615                 });
84616             };
84617             let blob = new Blob([imageXmlHTTP.response]);
84618             image.src = window.URL.createObjectURL(blob);
84619         };
84620         imageXmlHTTP.onerror = (error) => {
84621             console.error(new Error(`Failed to fetch sprite sheet (${sprite}${format}.png)`));
84622         };
84623         imageXmlHTTP.send();
84624         let jsonXmlHTTP = new XMLHttpRequest();
84625         jsonXmlHTTP.open("GET", sprite + format + ".json", true);
84626         jsonXmlHTTP.responseType = "text";
84627         jsonXmlHTTP.onload = () => {
84628             let json = JSON.parse(jsonXmlHTTP.response);
84629             this._spriteAtlasOperation$.next((atlas) => {
84630                 atlas.json = json;
84631                 return atlas;
84632             });
84633         };
84634         jsonXmlHTTP.onerror = (error) => {
84635             console.error(new Error(`Failed to fetch sheet (${sprite}${format}.json)`));
84636         };
84637         jsonXmlHTTP.send();
84638     }
84639     get spriteAtlas$() {
84640         return this._spriteAtlas$;
84641     }
84642     dispose() {
84643         this._atlasSubscription.unsubscribe();
84644     }
84645 }
84646
84647 class TouchService {
84648     constructor(canvasContainer, domContainer) {
84649         this._subscriptions = new SubscriptionHolder();
84650         const subs = this._subscriptions;
84651         this._activeSubject$ = new BehaviorSubject(false);
84652         this._active$ = this._activeSubject$.pipe(distinctUntilChanged(), publishReplay(1), refCount());
84653         subs.push(fromEvent(domContainer, "touchmove")
84654             .subscribe((event) => {
84655             event.preventDefault();
84656         }));
84657         this._touchStart$ = fromEvent(canvasContainer, "touchstart");
84658         this._touchMove$ = fromEvent(canvasContainer, "touchmove");
84659         this._touchEnd$ = fromEvent(canvasContainer, "touchend");
84660         this._touchCancel$ = fromEvent(canvasContainer, "touchcancel");
84661         const tapStart$ = this._touchStart$.pipe(filter((te) => {
84662             return te.touches.length === 1 && te.targetTouches.length === 1;
84663         }), share());
84664         this._doubleTap$ = tapStart$.pipe(bufferWhen(() => {
84665             return tapStart$.pipe(first(), switchMap(() => {
84666                 return merge(timer(300), tapStart$).pipe(take(1));
84667             }));
84668         }), filter((events) => {
84669             return events.length === 2;
84670         }), map((events) => {
84671             return events[events.length - 1];
84672         }), share());
84673         subs.push(this._doubleTap$
84674             .subscribe((event) => {
84675             event.preventDefault();
84676         }));
84677         this._singleTouchMove$ = this._touchMove$.pipe(filter((te) => {
84678             return te.touches.length === 1 && te.targetTouches.length === 1;
84679         }), share());
84680         let singleTouchStart$ = merge(this._touchStart$, this._touchEnd$, this._touchCancel$).pipe(filter((te) => {
84681             return te.touches.length === 1 && te.targetTouches.length === 1;
84682         }));
84683         let multipleTouchStart$ = merge(this._touchStart$, this._touchEnd$, this._touchCancel$).pipe(filter((te) => {
84684             return te.touches.length >= 1;
84685         }));
84686         let touchStop$ = merge(this._touchEnd$, this._touchCancel$).pipe(filter((te) => {
84687             return te.touches.length === 0;
84688         }));
84689         this._singleTouchDragStart$ = singleTouchStart$.pipe(mergeMap(() => {
84690             return this._singleTouchMove$.pipe(takeUntil(merge(touchStop$, multipleTouchStart$)), take(1));
84691         }));
84692         this._singleTouchDragEnd$ = singleTouchStart$.pipe(mergeMap(() => {
84693             return merge(touchStop$, multipleTouchStart$).pipe(first());
84694         }));
84695         this._singleTouchDrag$ = singleTouchStart$.pipe(switchMap(() => {
84696             return this._singleTouchMove$.pipe(skip(1), takeUntil(merge(multipleTouchStart$, touchStop$)));
84697         }));
84698         let touchesChanged$ = merge(this._touchStart$, this._touchEnd$, this._touchCancel$);
84699         this._pinchStart$ = touchesChanged$.pipe(filter((te) => {
84700             return te.touches.length === 2 && te.targetTouches.length === 2;
84701         }));
84702         this._pinchEnd$ = touchesChanged$.pipe(filter((te) => {
84703             return te.touches.length !== 2 || te.targetTouches.length !== 2;
84704         }));
84705         this._pinchOperation$ = new Subject();
84706         this._pinch$ = this._pinchOperation$.pipe(scan((pinch, operation) => {
84707             return operation(pinch);
84708         }, {
84709             changeX: 0,
84710             changeY: 0,
84711             clientX: 0,
84712             clientY: 0,
84713             distance: 0,
84714             distanceChange: 0,
84715             distanceX: 0,
84716             distanceY: 0,
84717             originalEvent: null,
84718             pageX: 0,
84719             pageY: 0,
84720             screenX: 0,
84721             screenY: 0,
84722             touch1: null,
84723             touch2: null,
84724         }));
84725         const pinchSubscription = this._touchMove$.pipe(filter((te) => {
84726             return te.touches.length === 2 && te.targetTouches.length === 2;
84727         }), map((te) => {
84728             return (previous) => {
84729                 let touch1 = te.touches[0];
84730                 let touch2 = te.touches[1];
84731                 let minX = Math.min(touch1.clientX, touch2.clientX);
84732                 let maxX = Math.max(touch1.clientX, touch2.clientX);
84733                 let minY = Math.min(touch1.clientY, touch2.clientY);
84734                 let maxY = Math.max(touch1.clientY, touch2.clientY);
84735                 let centerClientX = minX + (maxX - minX) / 2;
84736                 let centerClientY = minY + (maxY - minY) / 2;
84737                 let centerPageX = centerClientX + touch1.pageX - touch1.clientX;
84738                 let centerPageY = centerClientY + touch1.pageY - touch1.clientY;
84739                 let centerScreenX = centerClientX + touch1.screenX - touch1.clientX;
84740                 let centerScreenY = centerClientY + touch1.screenY - touch1.clientY;
84741                 let distanceX = Math.abs(touch1.clientX - touch2.clientX);
84742                 let distanceY = Math.abs(touch1.clientY - touch2.clientY);
84743                 let distance = Math.sqrt(distanceX * distanceX + distanceY * distanceY);
84744                 let distanceChange = distance - previous.distance;
84745                 let changeX = distanceX - previous.distanceX;
84746                 let changeY = distanceY - previous.distanceY;
84747                 let current = {
84748                     changeX: changeX,
84749                     changeY: changeY,
84750                     clientX: centerClientX,
84751                     clientY: centerClientY,
84752                     distance: distance,
84753                     distanceChange: distanceChange,
84754                     distanceX: distanceX,
84755                     distanceY: distanceY,
84756                     originalEvent: te,
84757                     pageX: centerPageX,
84758                     pageY: centerPageY,
84759                     screenX: centerScreenX,
84760                     screenY: centerScreenY,
84761                     touch1: touch1,
84762                     touch2: touch2,
84763                 };
84764                 return current;
84765             };
84766         }))
84767             .subscribe(this._pinchOperation$);
84768         subs.push(pinchSubscription);
84769         this._pinchChange$ = this._pinchStart$.pipe(switchMap(() => {
84770             return this._pinch$.pipe(skip(1), takeUntil(this._pinchEnd$));
84771         }));
84772     }
84773     get active$() {
84774         return this._active$;
84775     }
84776     get activate$() {
84777         return this._activeSubject$;
84778     }
84779     get doubleTap$() {
84780         return this._doubleTap$;
84781     }
84782     get touchStart$() {
84783         return this._touchStart$;
84784     }
84785     get touchMove$() {
84786         return this._touchMove$;
84787     }
84788     get touchEnd$() {
84789         return this._touchEnd$;
84790     }
84791     get touchCancel$() {
84792         return this._touchCancel$;
84793     }
84794     get singleTouchDragStart$() {
84795         return this._singleTouchDragStart$;
84796     }
84797     get singleTouchDrag$() {
84798         return this._singleTouchDrag$;
84799     }
84800     get singleTouchDragEnd$() {
84801         return this._singleTouchDragEnd$;
84802     }
84803     get pinch$() {
84804         return this._pinchChange$;
84805     }
84806     get pinchStart$() {
84807         return this._pinchStart$;
84808     }
84809     get pinchEnd$() {
84810         return this._pinchEnd$;
84811     }
84812     dispose() {
84813         this._subscriptions.unsubscribe();
84814     }
84815 }
84816
84817 class ConfigurationService {
84818     constructor(options) {
84819         var _a, _b, _c, _d;
84820         const host = (_b = (_a = options === null || options === void 0 ? void 0 : options.url) === null || _a === void 0 ? void 0 : _a.exploreHost) !== null && _b !== void 0 ? _b : "www.mapillary.com";
84821         const scheme = (_d = (_c = options === null || options === void 0 ? void 0 : options.url) === null || _c === void 0 ? void 0 : _c.scheme) !== null && _d !== void 0 ? _d : "https";
84822         const exploreUrl = `${scheme}://${host}`;
84823         this._exploreUrl$ = of(exploreUrl);
84824         const imageTiling = (options === null || options === void 0 ? void 0 : options.imageTiling) === false ? false : true;
84825         this._imageTiling$ = of(imageTiling);
84826     }
84827     get exploreUrl$() {
84828         return this._exploreUrl$;
84829     }
84830     get imageTiling$() {
84831         return this._imageTiling$;
84832     }
84833 }
84834
84835 class Container {
84836     constructor(options, stateService, dom) {
84837         var _a;
84838         this._onWindowResize = () => {
84839             if (this._trackResize) {
84840                 this.renderService.resize$.next();
84841             }
84842         };
84843         this._dom = dom !== null && dom !== void 0 ? dom : new DOM();
84844         if (typeof options.container === "string") {
84845             this._container = this._dom.document
84846                 .getElementById(options.container);
84847             if (!this._container) {
84848                 throw new Error(`Container "${options.container}" not found.`);
84849             }
84850         }
84851         else if (options.container instanceof HTMLElement) {
84852             this._container = options.container;
84853         }
84854         else {
84855             throw new Error(`Invalid type: "container" must be ` +
84856                 `a String or HTMLElement.`);
84857         }
84858         this._trackResize =
84859             options.trackResize === false ?
84860                 false : true;
84861         this.id = (_a = this._container.id) !== null && _a !== void 0 ? _a : "mapillary-fallback-container-id";
84862         this._container.classList
84863             .add("mapillary-viewer");
84864         this._canvasContainer = this._dom
84865             .createElement("div", "mapillary-interactive", this._container);
84866         this._canvas = this._dom
84867             .createElement("canvas", "mapillary-canvas");
84868         this._canvas.style.position = "absolute";
84869         this._canvas.setAttribute("tabindex", "0");
84870         // Add DOM container after canvas container to
84871         // render DOM elements on top of the interactive
84872         // canvas.
84873         this._domContainer = this._dom
84874             .createElement("div", "mapillary-dom", this._container);
84875         this.configurationService = new ConfigurationService(options);
84876         this.renderService =
84877             new RenderService(this._container, stateService.currentState$, options.renderMode);
84878         this.glRenderer =
84879             new GLRenderer(this._canvas, this._canvasContainer, this.renderService);
84880         this.domRenderer =
84881             new DOMRenderer(this._domContainer, this.renderService, stateService.currentState$);
84882         this.keyboardService =
84883             new KeyboardService(this._canvasContainer);
84884         this.mouseService =
84885             new MouseService(this._container, this._canvasContainer, this._domContainer, document);
84886         this.touchService =
84887             new TouchService(this._canvasContainer, this._domContainer);
84888         this.spriteService =
84889             new SpriteService(options.sprite);
84890         window.addEventListener('resize', this._onWindowResize, false);
84891     }
84892     get canvas() {
84893         return !!this._canvas.parentNode ?
84894             this._canvas : null;
84895     }
84896     get canvasContainer() {
84897         return this._canvasContainer;
84898     }
84899     get container() {
84900         return this._container;
84901     }
84902     get domContainer() {
84903         return this._domContainer;
84904     }
84905     remove() {
84906         window.removeEventListener('resize', this._onWindowResize, false);
84907         this.spriteService.dispose();
84908         this.touchService.dispose();
84909         this.mouseService.dispose();
84910         this.glRenderer.remove();
84911         this.domRenderer.remove();
84912         this.renderService.dispose();
84913         this._removeNode(this._canvasContainer);
84914         this._removeNode(this._domContainer);
84915         this._container.classList
84916             .remove("mapillary-viewer");
84917     }
84918     _removeNode(node) {
84919         if (node.parentNode) {
84920             node.parentNode.removeChild(node);
84921         }
84922     }
84923 }
84924
84925 class CacheService {
84926     constructor(_graphService, _stateService, _api) {
84927         this._graphService = _graphService;
84928         this._stateService = _stateService;
84929         this._api = _api;
84930         this._subscriptions = new SubscriptionHolder();
84931         this._started = false;
84932         this._cellDepth = 1;
84933     }
84934     get started() {
84935         return this._started;
84936     }
84937     configure(configuration) {
84938         if (!configuration) {
84939             this._cellDepth = 1;
84940             return;
84941         }
84942         this._cellDepth = Math.max(1, Math.min(3, configuration.cellDepth));
84943     }
84944     start() {
84945         if (this._started) {
84946             return;
84947         }
84948         const subs = this._subscriptions;
84949         subs.push(this._stateService.currentState$
84950             .pipe(distinctUntilChanged(undefined, (frame) => {
84951             return frame.state.currentImage.id;
84952         }), map((frame) => {
84953             const state = frame.state;
84954             const trajectory = state.trajectory;
84955             const trajectoryKeys = trajectory
84956                 .map((n) => {
84957                 return n.id;
84958             });
84959             const sequenceKey = trajectory[trajectory.length - 1].sequenceId;
84960             return [
84961                 trajectoryKeys,
84962                 state.currentImage.originalLngLat,
84963                 sequenceKey,
84964             ];
84965         }), bufferCount(1, 5), withLatestFrom(this._graphService.graphMode$), switchMap(([keepBuffer, graphMode]) => {
84966             const keepKeys = keepBuffer[0][0];
84967             const lngLat = keepBuffer[0][1];
84968             const geometry = this._api.data.geometry;
84969             const cellId = geometry.lngLatToCellId(lngLat);
84970             const keepCellIds = connectedComponent(cellId, this._cellDepth, geometry);
84971             const keepSequenceKey = graphMode === GraphMode.Sequence ?
84972                 keepBuffer[0][2] :
84973                 undefined;
84974             return this._graphService
84975                 .uncache$(keepKeys, keepCellIds, keepSequenceKey);
84976         }))
84977             .subscribe(() => { }));
84978         subs.push(this._graphService.graphMode$
84979             .pipe(skip(1), withLatestFrom(this._stateService.currentState$), switchMap(([mode, frame]) => {
84980             return mode === GraphMode.Sequence ?
84981                 this._keyToEdges(frame.state.currentImage.id, (image) => {
84982                     return image.sequenceEdges$;
84983                 }) :
84984                 from(frame.state.trajectory
84985                     .map((image) => {
84986                     return image.id;
84987                 })
84988                     .slice(frame.state.currentIndex)).pipe(mergeMap((key) => {
84989                     return this._keyToEdges(key, (image) => {
84990                         return image.spatialEdges$;
84991                     });
84992                 }, 6));
84993         }))
84994             .subscribe(() => { }));
84995         subs.push(this._graphService.dataAdded$
84996             .pipe(withLatestFrom(this._stateService.currentId$), switchMap(([_, imageId]) => {
84997             return this._graphService.cacheImage$(imageId);
84998         }))
84999             .subscribe(() => { }));
85000         this._started = true;
85001     }
85002     stop() {
85003         if (!this._started) {
85004             return;
85005         }
85006         this._subscriptions.unsubscribe();
85007         this._started = false;
85008     }
85009     _keyToEdges(key, imageToEdgeMap) {
85010         return this._graphService.cacheImage$(key).pipe(switchMap(imageToEdgeMap), first((status) => {
85011             return status.cached;
85012         }), timeout(15000), catchError((error) => {
85013             console.error(`Failed to cache edges (${key}).`, error);
85014             return empty();
85015         }));
85016     }
85017 }
85018
85019 class LoadingService {
85020     constructor() {
85021         this._loadersSubject$ = new Subject();
85022         this._loaders$ = this._loadersSubject$.pipe(scan((loaders, loader) => {
85023             if (loader.task !== undefined) {
85024                 loaders[loader.task] = loader.loading;
85025             }
85026             return loaders;
85027         }, {}), startWith({}), publishReplay(1), refCount());
85028     }
85029     get loading$() {
85030         return this._loaders$.pipe(map((loaders) => {
85031             for (const key in loaders) {
85032                 if (!loaders.hasOwnProperty(key)) {
85033                     continue;
85034                 }
85035                 if (loaders[key]) {
85036                     return true;
85037                 }
85038             }
85039             return false;
85040         }), debounceTime(100), distinctUntilChanged());
85041     }
85042     taskLoading$(task) {
85043         return this._loaders$.pipe(map((loaders) => {
85044             return !!loaders[task];
85045         }), debounceTime(100), distinctUntilChanged());
85046     }
85047     startLoading(task) {
85048         this._loadersSubject$.next({ loading: true, task: task });
85049     }
85050     stopLoading(task) {
85051         this._loadersSubject$.next({ loading: false, task: task });
85052     }
85053 }
85054
85055 var PanMode;
85056 (function (PanMode) {
85057     PanMode[PanMode["Disabled"] = 0] = "Disabled";
85058     PanMode[PanMode["Enabled"] = 1] = "Enabled";
85059     PanMode[PanMode["Started"] = 2] = "Started";
85060 })(PanMode || (PanMode = {}));
85061 class PanService {
85062     constructor(graphService, stateService, enabled, graphCalculator, spatial, viewportCoords) {
85063         this._subscriptions = new SubscriptionHolder();
85064         this._graphService = graphService;
85065         this._stateService = stateService;
85066         this._graphCalculator = graphCalculator !== null && graphCalculator !== void 0 ? graphCalculator : new GraphCalculator();
85067         this._spatial = spatial !== null && spatial !== void 0 ? spatial : new Spatial();
85068         this._viewportCoords = viewportCoords !== null && viewportCoords !== void 0 ? viewportCoords : new ViewportCoords();
85069         this._mode = enabled !== false ?
85070             PanMode.Enabled : PanMode.Disabled;
85071         this._panImagesSubject$ = new Subject();
85072         this._panImages$ = this._panImagesSubject$.pipe(startWith([]), publishReplay(1), refCount());
85073         this._subscriptions.push(this._panImages$.subscribe());
85074     }
85075     get panImages$() {
85076         return this._panImages$;
85077     }
85078     dispose() {
85079         this.stop();
85080         if (this._panImagesSubscription != null) {
85081             this._panImagesSubscription.unsubscribe();
85082         }
85083         this._subscriptions.unsubscribe();
85084     }
85085     enable() {
85086         if (this._mode !== PanMode.Disabled) {
85087             return;
85088         }
85089         this._mode = PanMode.Enabled;
85090         this.start();
85091     }
85092     disable() {
85093         if (this._mode === PanMode.Disabled) {
85094             return;
85095         }
85096         this.stop();
85097         this._mode = PanMode.Disabled;
85098     }
85099     start() {
85100         if (this._mode !== PanMode.Enabled) {
85101             return;
85102         }
85103         const panImages$ = this._stateService.currentImage$.pipe(switchMap((current) => {
85104             if (!current.merged || isSpherical(current.cameraType)) {
85105                 return of([]);
85106             }
85107             const current$ = of(current);
85108             const bounds = this._graphCalculator.boundingBoxCorners(current.lngLat, 20);
85109             const adjacent$ = this._graphService
85110                 .cacheBoundingBox$(bounds[0], bounds[1]).pipe(catchError((error) => {
85111                 console.error(`Failed to cache periphery bounding box (${current.id})`, error);
85112                 return empty();
85113             }), map((images) => {
85114                 if (isSpherical(current.cameraType)) {
85115                     return [];
85116                 }
85117                 const potential = [];
85118                 for (const image of images) {
85119                     if (image.id === current.id) {
85120                         continue;
85121                     }
85122                     if (image.mergeId !== current.mergeId) {
85123                         continue;
85124                     }
85125                     if (isSpherical(image.cameraType)) {
85126                         continue;
85127                     }
85128                     if (this._distance(image, current) > 4) {
85129                         continue;
85130                     }
85131                     potential.push(image);
85132                 }
85133                 return potential;
85134             }));
85135             return combineLatest(current$, adjacent$).pipe(withLatestFrom(this._stateService.reference$), map(([[cn, adjacent], reference]) => {
85136                 const currentDirection = this._spatial.viewingDirection(cn.rotation);
85137                 const currentTranslation = computeTranslation({ lat: cn.lngLat.lat, lng: cn.lngLat.lng, alt: cn.computedAltitude }, cn.rotation, reference);
85138                 const currentTransform = this._createTransform(cn, currentTranslation);
85139                 const currentAzimuthal = this._spatial.wrap(this._spatial.azimuthal(currentDirection.toArray(), currentTransform.upVector().toArray()), 0, 2 * Math.PI);
85140                 const currentProjectedPoints = this._computeProjectedPoints(currentTransform);
85141                 const currentHFov = this._computeHorizontalFov(currentProjectedPoints) / 180 * Math.PI;
85142                 const preferredOverlap = Math.PI / 8;
85143                 let left = undefined;
85144                 let right = undefined;
85145                 for (const a of adjacent) {
85146                     const translation = computeTranslation({ lat: a.lngLat.lat, lng: a.lngLat.lng, alt: a.computedAltitude }, a.rotation, reference);
85147                     const transform = this._createTransform(a, translation);
85148                     const projectedPoints = this._computeProjectedPoints(transform);
85149                     const hFov = this._computeHorizontalFov(projectedPoints) / 180 * Math.PI;
85150                     const direction = this._spatial.viewingDirection(a.rotation);
85151                     const azimuthal = this._spatial.wrap(this._spatial.azimuthal(direction.toArray(), transform.upVector().toArray()), 0, 2 * Math.PI);
85152                     const directionChange = this._spatial.angleBetweenVector2(currentDirection.x, currentDirection.y, direction.x, direction.y);
85153                     let overlap = Number.NEGATIVE_INFINITY;
85154                     if (directionChange > 0) {
85155                         if (currentAzimuthal > azimuthal) {
85156                             overlap = currentAzimuthal - 2 * Math.PI + currentHFov / 2 - (azimuthal - hFov / 2);
85157                         }
85158                         else {
85159                             overlap = currentAzimuthal + currentHFov / 2 - (azimuthal - hFov / 2);
85160                         }
85161                     }
85162                     else {
85163                         if (currentAzimuthal < azimuthal) {
85164                             overlap = azimuthal + hFov / 2 - (currentAzimuthal + 2 * Math.PI - currentHFov / 2);
85165                         }
85166                         else {
85167                             overlap = azimuthal + hFov / 2 - (currentAzimuthal - currentHFov / 2);
85168                         }
85169                     }
85170                     const nonOverlap = Math.abs(hFov - overlap);
85171                     const distanceCost = this._distance(a, cn);
85172                     const timeCost = Math.min(this._timeDifference(a, cn), 4);
85173                     const overlapCost = 20 * Math.abs(overlap - preferredOverlap);
85174                     const fovCost = Math.min(5, 1 / Math.min(hFov / currentHFov, 1));
85175                     const nonOverlapCost = overlap > 0 ? -2 * nonOverlap : 0;
85176                     const cost = distanceCost + timeCost + overlapCost + fovCost + nonOverlapCost;
85177                     if (overlap > 0 &&
85178                         overlap < 0.5 * currentHFov &&
85179                         overlap < 0.5 * hFov &&
85180                         nonOverlap > 0.5 * currentHFov) {
85181                         if (directionChange > 0) {
85182                             if (!left) {
85183                                 left = [cost, a, transform, hFov];
85184                             }
85185                             else {
85186                                 if (cost < left[0]) {
85187                                     left = [cost, a, transform, hFov];
85188                                 }
85189                             }
85190                         }
85191                         else {
85192                             if (!right) {
85193                                 right = [cost, a, transform, hFov];
85194                             }
85195                             else {
85196                                 if (cost < right[0]) {
85197                                     right = [cost, a, transform, hFov];
85198                                 }
85199                             }
85200                         }
85201                     }
85202                 }
85203                 const panImagess = [];
85204                 if (!!left) {
85205                     panImagess.push([left[1], left[2], left[3]]);
85206                 }
85207                 if (!!right) {
85208                     panImagess.push([right[1], right[2], right[3]]);
85209                 }
85210                 return panImagess;
85211             }), startWith([]));
85212         }));
85213         this._panImagesSubscription = this._stateService.currentState$.pipe(map((frame) => {
85214             return frame.state.imagesAhead > 0;
85215         }), distinctUntilChanged(), switchMap((traversing) => {
85216             return traversing ? of([]) : panImages$;
85217         }))
85218             .subscribe((panImages) => {
85219             this._panImagesSubject$.next(panImages);
85220         });
85221         this._mode = PanMode.Started;
85222     }
85223     stop() {
85224         if (this._mode !== PanMode.Started) {
85225             return;
85226         }
85227         this._panImagesSubscription.unsubscribe();
85228         this._panImagesSubject$.next([]);
85229         this._mode = PanMode.Enabled;
85230     }
85231     _distance(image, reference) {
85232         const [x, y, z] = geodeticToEnu(image.lngLat.lng, image.lngLat.lat, image.computedAltitude, reference.lngLat.lng, reference.lngLat.lat, reference.computedAltitude);
85233         return Math.sqrt(x * x + y * y + z * z);
85234     }
85235     _timeDifference(image, reference) {
85236         const milliSecond = (1000 * 60 * 60 * 24 * 30);
85237         return Math.abs(image.capturedAt - reference.capturedAt) / milliSecond;
85238     }
85239     _createTransform(image, translation) {
85240         return new Transform(image.exifOrientation, image.width, image.height, image.scale, image.rotation, translation, image.assetsCached ? image.image : undefined, undefined, image.cameraParameters, image.cameraType);
85241     }
85242     _computeProjectedPoints(transform) {
85243         const vertices = [[1, 0]];
85244         const directions = [[0, 0.5]];
85245         const pointsPerLine = 20;
85246         return computeProjectedPoints(transform, vertices, directions, pointsPerLine, this._viewportCoords);
85247     }
85248     _computeHorizontalFov(projectedPoints) {
85249         const fovs = projectedPoints
85250             .map((projectedPoint) => {
85251             return this._coordToFov(projectedPoint[0]);
85252         });
85253         const fov = Math.min(...fovs);
85254         return fov;
85255     }
85256     _coordToFov(x) {
85257         return 2 * Math.atan(x) * 180 / Math.PI;
85258     }
85259 }
85260
85261 /**
85262  * @class API
85263  *
85264  * @classdesc Provides methods for access to the API.
85265  */
85266 class APIWrapper {
85267     constructor(_data) {
85268         this._data = _data;
85269     }
85270     get data() {
85271         return this._data;
85272     }
85273     getCoreImages$(cellId) {
85274         return this._wrap$(this._data.getCoreImages(cellId));
85275     }
85276     getImages$(imageIds) {
85277         return this._wrap$(this._data.getImages(imageIds));
85278     }
85279     getImageTiles$(tiles) {
85280         return this._wrap$(this._data.getImageTiles(tiles));
85281     }
85282     getSequence$(sequenceId) {
85283         return this._wrap$(this._data.getSequence(sequenceId));
85284     }
85285     getSpatialImages$(imageIds) {
85286         return this._wrap$(this._data.getSpatialImages(imageIds));
85287     }
85288     setAccessToken(accessToken) {
85289         this._data.setAccessToken(accessToken);
85290     }
85291     _wrap$(promise) {
85292         return Observable.create((subscriber) => {
85293             promise.then((value) => {
85294                 subscriber.next(value);
85295                 subscriber.complete();
85296             }, (error) => {
85297                 subscriber.error(error);
85298             });
85299         });
85300     }
85301 }
85302
85303 /**
85304  * @class GraphService
85305  *
85306  * @classdesc Represents a service for graph operations.
85307  */
85308 class GraphService {
85309     /**
85310      * Create a new graph service instance.
85311      *
85312      * @param {Graph} graph - Graph instance to be operated on.
85313      */
85314     constructor(graph) {
85315         this._dataAdded$ = new Subject();
85316         this._subscriptions = new SubscriptionHolder();
85317         this._onDataAdded = (event) => {
85318             this._graph$
85319                 .pipe(first(), mergeMap(graph => {
85320                 return graph.updateCells$(event.cellIds).pipe(tap(() => { graph.resetSpatialEdges(); }));
85321             }))
85322                 .subscribe(cellId => { this._dataAdded$.next(cellId); });
85323         };
85324         const subs = this._subscriptions;
85325         this._graph$ = concat(of(graph), graph.changed$).pipe(publishReplay(1), refCount());
85326         subs.push(this._graph$.subscribe(() => { }));
85327         this._graphMode = GraphMode.Spatial;
85328         this._graphModeSubject$ = new Subject();
85329         this._graphMode$ = this._graphModeSubject$.pipe(startWith(this._graphMode), publishReplay(1), refCount());
85330         subs.push(this._graphMode$.subscribe(() => { }));
85331         this._firstGraphSubjects$ = [];
85332         this._initializeCacheSubscriptions = [];
85333         this._sequenceSubscriptions = [];
85334         this._spatialSubscriptions = [];
85335         graph.api.data.on("datacreate", this._onDataAdded);
85336     }
85337     /**
85338      * Get dataAdded$.
85339      *
85340      * @returns {Observable<string>} Observable emitting
85341      * a cell id every time data has been added to a cell.
85342      */
85343     get dataAdded$() {
85344         return this._dataAdded$;
85345     }
85346     /**
85347      * Get filter observable.
85348      *
85349      * @desciption Emits the filter every time it has changed.
85350      *
85351      * @returns {Observable<FilterFunction>} Observable
85352      * emitting the filter function every time it is set.
85353      */
85354     get filter$() {
85355         return this._graph$.pipe(first(), mergeMap((graph) => {
85356             return graph.filter$;
85357         }));
85358     }
85359     /**
85360      * Get graph mode observable.
85361      *
85362      * @description Emits the current graph mode.
85363      *
85364      * @returns {Observable<GraphMode>} Observable
85365      * emitting the current graph mode when it changes.
85366      */
85367     get graphMode$() {
85368         return this._graphMode$;
85369     }
85370     /**
85371      * Cache full images in a bounding box.
85372      *
85373      * @description When called, the full properties of
85374      * the image are retrieved. The image cache is not initialized
85375      * for any new images retrieved and the image assets are not
85376      * retrieved, {@link cacheImage$} needs to be called for caching
85377      * assets.
85378      *
85379      * @param {LngLat} sw - South west corner of bounding box.
85380      * @param {LngLat} ne - North east corner of bounding box.
85381      * @return {Observable<Array<Image>>} Observable emitting a single item,
85382      * the images of the bounding box, when they have all been retrieved.
85383      * @throws {Error} Propagates any IO image caching errors to the caller.
85384      */
85385     cacheBoundingBox$(sw, ne) {
85386         return this._graph$.pipe(first(), mergeMap((graph) => {
85387             return graph.cacheBoundingBox$(sw, ne);
85388         }));
85389     }
85390     /**
85391      * Cache full images in a cell.
85392      *
85393      * @description When called, the full properties of
85394      * the image are retrieved. The image cache is not initialized
85395      * for any new images retrieved and the image assets are not
85396      * retrieved, {@link cacheImage$} needs to be called for caching
85397      * assets.
85398      *
85399      * @param {string} cellId - Id of the cell.
85400      * @return {Observable<Array<Image>>} Observable emitting a single item,
85401      * the images of the cell, when they have all been retrieved.
85402      * @throws {Error} Propagates any IO image caching errors to the caller.
85403      */
85404     cacheCell$(cellId) {
85405         return this._graph$.pipe(first(), mergeMap((graph) => {
85406             return graph.cacheCell$(cellId);
85407         }));
85408     }
85409     /**
85410      * Cache a image in the graph and retrieve it.
85411      *
85412      * @description When called, the full properties of
85413      * the image are retrieved and the image cache is initialized.
85414      * After that the image assets are cached and the image
85415      * is emitted to the observable when.
85416      * In parallel to caching the image assets, the sequence and
85417      * spatial edges of the image are cached. For this, the sequence
85418      * of the image and the required tiles and spatial images are
85419      * retrieved. The sequence and spatial edges may be set before
85420      * or after the image is returned.
85421      *
85422      * @param {string} id - Id of the image to cache.
85423      * @return {Observable<Image>} Observable emitting a single item,
85424      * the image, when it has been retrieved and its assets are cached.
85425      * @throws {Error} Propagates any IO image caching errors to the caller.
85426      */
85427     cacheImage$(id) {
85428         const firstGraphSubject$ = new Subject();
85429         this._firstGraphSubjects$.push(firstGraphSubject$);
85430         const firstGraph$ = firstGraphSubject$.pipe(publishReplay(1), refCount());
85431         const image$ = firstGraph$.pipe(map((graph) => {
85432             return graph.getNode(id);
85433         }), mergeMap((image) => {
85434             return image.assetsCached ?
85435                 of(image) :
85436                 image.cacheAssets$();
85437         }), publishReplay(1), refCount());
85438         image$.subscribe(undefined, (error) => {
85439             console.error(`Failed to cache image (${id}).`, error);
85440         });
85441         let initializeCacheSubscription;
85442         initializeCacheSubscription = this._graph$.pipe(first(), mergeMap((graph) => {
85443             if (graph.isCachingFull(id) || !graph.hasNode(id)) {
85444                 return graph.cacheFull$(id);
85445             }
85446             if (graph.isCachingFill(id) || !graph.getNode(id).complete) {
85447                 return graph.cacheFill$(id);
85448             }
85449             return of(graph);
85450         }), tap((graph) => {
85451             if (!graph.hasNode(id)) {
85452                 throw new GraphMapillaryError(`Failed to cache image (${id})`);
85453             }
85454             if (!graph.hasInitializedCache(id)) {
85455                 graph.initializeCache(id);
85456             }
85457         }), finalize(() => {
85458             if (initializeCacheSubscription == null) {
85459                 return;
85460             }
85461             this._removeFromArray(initializeCacheSubscription, this._initializeCacheSubscriptions);
85462             this._removeFromArray(firstGraphSubject$, this._firstGraphSubjects$);
85463         }))
85464             .subscribe((graph) => {
85465             firstGraphSubject$.next(graph);
85466             firstGraphSubject$.complete();
85467         }, (error) => {
85468             firstGraphSubject$.error(error);
85469         });
85470         if (!initializeCacheSubscription.closed) {
85471             this._initializeCacheSubscriptions.push(initializeCacheSubscription);
85472         }
85473         const graphSequence$ = firstGraph$.pipe(catchError(() => {
85474             return empty();
85475         }), mergeMap((graph) => {
85476             if (graph.isCachingNodeSequence(id) || !graph.hasNodeSequence(id)) {
85477                 return graph.cacheNodeSequence$(id);
85478             }
85479             return of(graph);
85480         }), publishReplay(1), refCount());
85481         let sequenceSubscription;
85482         sequenceSubscription = graphSequence$.pipe(tap((graph) => {
85483             if (!graph.getNode(id).sequenceEdges.cached) {
85484                 graph.cacheSequenceEdges(id);
85485             }
85486         }), finalize(() => {
85487             if (sequenceSubscription == null) {
85488                 return;
85489             }
85490             this._removeFromArray(sequenceSubscription, this._sequenceSubscriptions);
85491         }))
85492             .subscribe(() => { return; }, (error) => {
85493             console.error(`Failed to cache sequence edges (${id}).`, error);
85494         });
85495         if (!sequenceSubscription.closed) {
85496             this._sequenceSubscriptions.push(sequenceSubscription);
85497         }
85498         if (this._graphMode === GraphMode.Spatial) {
85499             let spatialSubscription;
85500             spatialSubscription = firstGraph$.pipe(catchError(() => {
85501                 return empty();
85502             }), expand((graph) => {
85503                 if (graph.hasTiles(id)) {
85504                     return empty();
85505                 }
85506                 return from(graph.cacheTiles$(id)).pipe(mergeMap((graph$) => {
85507                     return graph$.pipe(mergeMap((g) => {
85508                         if (g.isCachingTiles(id)) {
85509                             return empty();
85510                         }
85511                         return of(g);
85512                     }), catchError((error) => {
85513                         console.error(`Failed to cache tile data (${id}).`, error);
85514                         return empty();
85515                     }));
85516                 }));
85517             }), takeLast(1), mergeMap((graph) => {
85518                 if (graph.hasSpatialArea(id)) {
85519                     return of(graph);
85520                 }
85521                 return from(graph.cacheSpatialArea$(id)).pipe(mergeMap((graph$) => {
85522                     return graph$.pipe(catchError((error) => {
85523                         console.error(`Failed to cache spatial images (${id}).`, error);
85524                         return empty();
85525                     }));
85526                 }));
85527             }), takeLast(1), mergeMap((graph) => {
85528                 return graph.hasNodeSequence(id) ?
85529                     of(graph) :
85530                     graph.cacheNodeSequence$(id);
85531             }), tap((graph) => {
85532                 if (!graph.getNode(id).spatialEdges.cached) {
85533                     graph.cacheSpatialEdges(id);
85534                 }
85535             }), finalize(() => {
85536                 if (spatialSubscription == null) {
85537                     return;
85538                 }
85539                 this._removeFromArray(spatialSubscription, this._spatialSubscriptions);
85540             }))
85541                 .subscribe(() => { return; }, (error) => {
85542                 const message = `Failed to cache spatial edges (${id}).`;
85543                 console.error(message, error);
85544             });
85545             if (!spatialSubscription.closed) {
85546                 this._spatialSubscriptions.push(spatialSubscription);
85547             }
85548         }
85549         return image$.pipe(first((image) => {
85550             return image.assetsCached;
85551         }));
85552     }
85553     /**
85554      * Cache a sequence in the graph and retrieve it.
85555      *
85556      * @param {string} sequenceId - Sequence id.
85557      * @returns {Observable<Sequence>} Observable emitting a single item,
85558      * the sequence, when it has been retrieved and its assets are cached.
85559      * @throws {Error} Propagates any IO image caching errors to the caller.
85560      */
85561     cacheSequence$(sequenceId) {
85562         return this._graph$.pipe(first(), mergeMap((graph) => {
85563             if (graph.isCachingSequence(sequenceId) || !graph.hasSequence(sequenceId)) {
85564                 return graph.cacheSequence$(sequenceId);
85565             }
85566             return of(graph);
85567         }), map((graph) => {
85568             return graph.getSequence(sequenceId);
85569         }));
85570     }
85571     /**
85572      * Cache a sequence and its images in the graph and retrieve the sequence.
85573      *
85574      * @description Caches a sequence and its assets are cached and
85575      * retrieves all images belonging to the sequence. The image assets
85576      * or edges will not be cached.
85577      *
85578      * @param {string} sequenceId - Sequence id.
85579      * @param {string} referenceImageId - Id of image to use as reference
85580      * for optimized caching.
85581      * @returns {Observable<Sequence>} Observable emitting a single item,
85582      * the sequence, when it has been retrieved, its assets are cached and
85583      * all images belonging to the sequence has been retrieved.
85584      * @throws {Error} Propagates any IO image caching errors to the caller.
85585      */
85586     cacheSequenceImages$(sequenceId, referenceImageId) {
85587         return this._graph$.pipe(first(), mergeMap((graph) => {
85588             if (graph.isCachingSequence(sequenceId) || !graph.hasSequence(sequenceId)) {
85589                 return graph.cacheSequence$(sequenceId);
85590             }
85591             return of(graph);
85592         }), mergeMap((graph) => {
85593             if (graph.isCachingSequenceNodes(sequenceId) || !graph.hasSequenceNodes(sequenceId)) {
85594                 return graph.cacheSequenceNodes$(sequenceId, referenceImageId);
85595             }
85596             return of(graph);
85597         }), map((graph) => {
85598             return graph.getSequence(sequenceId);
85599         }));
85600     }
85601     /**
85602      * Dispose the graph service and its children.
85603      */
85604     dispose() {
85605         this._graph$
85606             .pipe(first())
85607             .subscribe((graph) => { graph.unsubscribe(); });
85608         this._subscriptions.unsubscribe();
85609     }
85610     /**
85611      * Set a spatial edge filter on the graph.
85612      *
85613      * @description Resets the spatial edges of all cached images.
85614      *
85615      * @param {FilterExpression} filter - Filter expression to be applied.
85616      * @return {Observable<Graph>} Observable emitting a single item,
85617      * the graph, when the spatial edges have been reset.
85618      */
85619     setFilter$(filter) {
85620         this._resetSubscriptions(this._spatialSubscriptions);
85621         return this._graph$.pipe(first(), tap((graph) => {
85622             graph.resetSpatialEdges();
85623             graph.setFilter(filter);
85624         }), map(() => {
85625             return undefined;
85626         }));
85627     }
85628     /**
85629      * Set the graph mode.
85630      *
85631      * @description If graph mode is set to spatial, caching
85632      * is performed with emphasis on spatial edges. If graph
85633      * mode is set to sequence no tile data is requested and
85634      * no spatial edges are computed.
85635      *
85636      * When setting graph mode to sequence all spatial
85637      * subscriptions are aborted.
85638      *
85639      * @param {GraphMode} mode - Graph mode to set.
85640      */
85641     setGraphMode(mode) {
85642         if (this._graphMode === mode) {
85643             return;
85644         }
85645         if (mode === GraphMode.Sequence) {
85646             this._resetSubscriptions(this._spatialSubscriptions);
85647         }
85648         this._graphMode = mode;
85649         this._graphModeSubject$.next(this._graphMode);
85650     }
85651     /**
85652      * Reset the graph.
85653      *
85654      * @description Resets the graph but keeps the images of the
85655      * supplied ids.
85656      *
85657      * @param {Array<string>} keepIds - Ids of images to keep in graph.
85658      * @return {Observable<Image>} Observable emitting a single item,
85659      * the graph, when it has been reset.
85660      */
85661     reset$(keepIds) {
85662         this._abortSubjects(this._firstGraphSubjects$);
85663         this._resetSubscriptions(this._initializeCacheSubscriptions);
85664         this._resetSubscriptions(this._sequenceSubscriptions);
85665         this._resetSubscriptions(this._spatialSubscriptions);
85666         return this._graph$.pipe(first(), tap((graph) => {
85667             graph.reset(keepIds);
85668         }), map(() => {
85669             return undefined;
85670         }));
85671     }
85672     /**
85673      * Uncache the graph.
85674      *
85675      * @description Uncaches the graph by removing tiles, images and
85676      * sequences. Keeps the images of the supplied ids and the tiles
85677      * related to those images.
85678      *
85679      * @param {Array<string>} keepIds - Ids of images to keep in graph.
85680      * @param {Array<string>} keepCellIds - Ids of cells to keep in graph.
85681      * @param {string} keepSequenceId - Optional id of sequence
85682      * for which the belonging images should not be disposed or
85683      * removed from the graph. These images may still be uncached if
85684      * not specified in keep ids param.
85685      * @return {Observable<Graph>} Observable emitting a single item,
85686      * the graph, when the graph has been uncached.
85687      */
85688     uncache$(keepIds, keepCellIds, keepSequenceId) {
85689         return this._graph$.pipe(first(), tap((graph) => {
85690             graph.uncache(keepIds, keepCellIds, keepSequenceId);
85691         }), map(() => {
85692             return undefined;
85693         }));
85694     }
85695     _abortSubjects(subjects) {
85696         for (const subject of subjects.slice()) {
85697             this._removeFromArray(subject, subjects);
85698             subject.error(new Error("Cache image request was aborted."));
85699         }
85700     }
85701     _removeFromArray(object, objects) {
85702         const index = objects.indexOf(object);
85703         if (index !== -1) {
85704             objects.splice(index, 1);
85705         }
85706     }
85707     _resetSubscriptions(subscriptions) {
85708         for (const subscription of subscriptions.slice()) {
85709             this._removeFromArray(subscription, subscriptions);
85710             if (!subscription.closed) {
85711                 subscription.unsubscribe();
85712             }
85713         }
85714     }
85715 }
85716
85717 class FrameGenerator {
85718     constructor(root) {
85719         if (root.requestAnimationFrame) {
85720             this._cancelAnimationFrame = root.cancelAnimationFrame.bind(root);
85721             this._requestAnimationFrame = root.requestAnimationFrame.bind(root);
85722         }
85723         else if (root.mozRequestAnimationFrame) {
85724             this._cancelAnimationFrame = root.mozCancelAnimationFrame.bind(root);
85725             this._requestAnimationFrame = root.mozRequestAnimationFrame.bind(root);
85726         }
85727         else if (root.webkitRequestAnimationFrame) {
85728             this._cancelAnimationFrame = root.webkitCancelAnimationFrame.bind(root);
85729             this._requestAnimationFrame = root.webkitRequestAnimationFrame.bind(root);
85730         }
85731         else if (root.msRequestAnimationFrame) {
85732             this._cancelAnimationFrame = root.msCancelAnimationFrame.bind(root);
85733             this._requestAnimationFrame = root.msRequestAnimationFrame.bind(root);
85734         }
85735         else if (root.oRequestAnimationFrame) {
85736             this._cancelAnimationFrame = root.oCancelAnimationFrame.bind(root);
85737             this._requestAnimationFrame = root.oRequestAnimationFrame.bind(root);
85738         }
85739         else {
85740             this._cancelAnimationFrame = root.clearTimeout.bind(root);
85741             this._requestAnimationFrame = (cb) => { return root.setTimeout(cb, 1000 / 60); };
85742         }
85743     }
85744     get cancelAnimationFrame() {
85745         return this._cancelAnimationFrame;
85746     }
85747     get requestAnimationFrame() {
85748         return this._requestAnimationFrame;
85749     }
85750 }
85751
85752 class CustomState extends StateBase {
85753     constructor(state) {
85754         super(state);
85755     }
85756     setViewMatrix(viewMatrix) {
85757         const viewMatrixInverse = new Matrix4()
85758             .fromArray(viewMatrix)
85759             .invert();
85760         const me = viewMatrixInverse.elements;
85761         const eye = new Vector3(me[12], me[13], me[14]);
85762         const forward = new Vector3(-me[8], -me[9], -me[10]);
85763         const up = new Vector3(me[4], me[5], me[6]);
85764         const camera = this._camera;
85765         camera.position.copy(eye);
85766         camera.lookat.copy(eye
85767             .clone()
85768             .add(forward));
85769         camera.up.copy(up);
85770         const focal = 0.5 / Math.tan(Math.PI / 3);
85771         camera.focal = focal;
85772     }
85773 }
85774
85775 class EarthState extends StateBase {
85776     constructor(state) {
85777         super(state);
85778         const eye = this._camera.position.clone();
85779         const forward = this._camera.lookat
85780             .clone()
85781             .sub(eye)
85782             .normalize();
85783         const xy = Math.sqrt(forward.x * forward.x + forward.y * forward.y);
85784         const angle = Math.atan2(forward.z, xy);
85785         const lookat = new Vector3();
85786         if (angle > -Math.PI / 45) {
85787             lookat.copy(eye);
85788             eye.add(new Vector3(forward.x, forward.y, 0)
85789                 .multiplyScalar(-50));
85790             eye.z = 30;
85791         }
85792         else {
85793             // Target a point on invented ground and keep forward direction
85794             const l0 = eye.clone();
85795             const n = new Vector3(0, 0, 1);
85796             const p0 = new Vector3(0, 0, -2);
85797             const d = new Vector3().subVectors(p0, l0).dot(n) / forward.dot(n);
85798             const maxDistance = 10000;
85799             const intersection = l0
85800                 .clone()
85801                 .add(forward.
85802                 clone()
85803                 .multiplyScalar(Math.min(maxDistance, d)));
85804             lookat.copy(intersection);
85805             const t = eye
85806                 .clone()
85807                 .sub(intersection)
85808                 .normalize();
85809             eye.copy(intersection.add(t.multiplyScalar(Math.max(50, t.length()))));
85810         }
85811         this._camera.position.copy(eye);
85812         this._camera.lookat.copy(lookat);
85813         this._camera.up.set(0, 0, 1);
85814     }
85815     dolly(delta) {
85816         const camera = this._camera;
85817         const offset = camera.position
85818             .clone()
85819             .sub(camera.lookat);
85820         const length = offset.length();
85821         const scaled = length * Math.pow(2, -delta);
85822         const clipped = Math.max(1, Math.min(scaled, 4000));
85823         offset.normalize();
85824         offset.multiplyScalar(clipped);
85825         camera.position
85826             .copy(camera.lookat)
85827             .add(offset);
85828     }
85829     orbit(rotation) {
85830         const camera = this._camera;
85831         const q = new Quaternion()
85832             .setFromUnitVectors(camera.up, new Vector3(0, 0, 1));
85833         const qInverse = q
85834             .clone()
85835             .invert();
85836         const offset = camera.position
85837             .clone()
85838             .sub(camera.lookat);
85839         offset.applyQuaternion(q);
85840         const length = offset.length();
85841         let phi = Math.atan2(offset.y, offset.x);
85842         phi += rotation.phi;
85843         let theta = Math.atan2(Math.sqrt(offset.x * offset.x + offset.y * offset.y), offset.z);
85844         theta += rotation.theta;
85845         const threshold = Math.PI / 36;
85846         theta = Math.max(threshold, Math.min(Math.PI / 2 - threshold, theta));
85847         offset.x = Math.sin(theta) * Math.cos(phi);
85848         offset.y = Math.sin(theta) * Math.sin(phi);
85849         offset.z = Math.cos(theta);
85850         offset.applyQuaternion(qInverse);
85851         camera.position
85852             .copy(camera.lookat)
85853             .add(offset.multiplyScalar(length));
85854     }
85855     truck(direction) {
85856         const camera = this._camera;
85857         camera.position
85858             .add(new Vector3().fromArray(direction));
85859         camera.lookat
85860             .add(new Vector3().fromArray(direction));
85861     }
85862     update() { }
85863 }
85864
85865 class InteractiveWaitingState extends InteractiveStateBase {
85866     constructor(state) {
85867         super(state);
85868         this._adjustCameras();
85869         this._motionless = this._motionlessTransition();
85870     }
85871     prepend(images) {
85872         super.prepend(images);
85873         this._motionless = this._motionlessTransition();
85874     }
85875     set(images) {
85876         super.set(images);
85877         this._motionless = this._motionlessTransition();
85878     }
85879     move(delta) {
85880         this._alpha = Math.max(0, Math.min(1, this._alpha + delta));
85881     }
85882     moveTo(position) {
85883         this._alpha = Math.max(0, Math.min(1, position));
85884     }
85885     update(fps) {
85886         this._updateRotation();
85887         if (!this._rotationDelta.isZero) {
85888             this._applyRotation(this._rotationDelta, this._previousCamera);
85889             this._applyRotation(this._rotationDelta, this._currentCamera);
85890         }
85891         this._updateRotationBasic();
85892         if (this._basicRotation[0] !== 0 || this._basicRotation[1] !== 0) {
85893             this._applyRotationBasic(this._basicRotation);
85894         }
85895         let animationSpeed = this._animationSpeed * (60 / fps);
85896         this._updateZoom(animationSpeed);
85897         this._updateLookat(animationSpeed);
85898         this._camera.lerpCameras(this._previousCamera, this._currentCamera, this.alpha);
85899     }
85900     _getAlpha() {
85901         return this._motionless ? Math.round(this._alpha) : this._alpha;
85902     }
85903     _setCurrentCamera() {
85904         super._setCurrentCamera();
85905         this._adjustCameras();
85906     }
85907     _adjustCameras() {
85908         if (this._previousImage == null) {
85909             return;
85910         }
85911         if (isSpherical(this._currentImage.cameraType)) {
85912             let lookat = this._camera.lookat.clone().sub(this._camera.position);
85913             this._currentCamera.lookat.copy(lookat.clone().add(this._currentCamera.position));
85914         }
85915         if (isSpherical(this._previousImage.cameraType)) {
85916             let lookat = this._currentCamera.lookat.clone().sub(this._currentCamera.position);
85917             this._previousCamera.lookat.copy(lookat.clone().add(this._previousCamera.position));
85918         }
85919     }
85920 }
85921
85922 class WaitingState extends StateBase {
85923     constructor(state) {
85924         super(state);
85925         this._zoom = 0;
85926         this._adjustCameras();
85927         this._motionless = this._motionlessTransition();
85928     }
85929     prepend(images) {
85930         super.prepend(images);
85931         this._motionless = this._motionlessTransition();
85932     }
85933     set(images) {
85934         super.set(images);
85935         this._motionless = this._motionlessTransition();
85936     }
85937     move(delta) {
85938         this._alpha = Math.max(0, Math.min(1, this._alpha + delta));
85939     }
85940     moveTo(position) {
85941         this._alpha = Math.max(0, Math.min(1, position));
85942     }
85943     update(fps) {
85944         this._camera.lerpCameras(this._previousCamera, this._currentCamera, this.alpha);
85945     }
85946     _getAlpha() {
85947         return this._motionless ? Math.round(this._alpha) : this._alpha;
85948     }
85949     _setCurrentCamera() {
85950         super._setCurrentCamera();
85951         this._adjustCameras();
85952     }
85953     _adjustCameras() {
85954         if (this._previousImage == null) {
85955             return;
85956         }
85957         if (isSpherical(this._currentImage.cameraType)) {
85958             let lookat = this._camera.lookat.clone().sub(this._camera.position);
85959             this._currentCamera.lookat.copy(lookat.clone().add(this._currentCamera.position));
85960         }
85961         if (isSpherical(this._previousImage.cameraType)) {
85962             let lookat = this._currentCamera.lookat.clone().sub(this._currentCamera.position);
85963             this._previousCamera.lookat.copy(lookat.clone().add(this._previousCamera.position));
85964         }
85965     }
85966 }
85967
85968 class StateTransitionMatrix {
85969     constructor() {
85970         const custom = State[State.Custom];
85971         const earth = State[State.Earth];
85972         const traverse = State[State.Traversing];
85973         const wait = State[State.Waiting];
85974         const waitInteractively = State[State.WaitingInteractively];
85975         this._creators = new Map();
85976         const creator = this._creators;
85977         creator.set(custom, CustomState);
85978         creator.set(earth, EarthState);
85979         creator.set(traverse, TraversingState);
85980         creator.set(wait, WaitingState);
85981         creator.set(waitInteractively, InteractiveWaitingState);
85982         this._transitions = new Map();
85983         const transitions = this._transitions;
85984         transitions.set(custom, [earth, traverse]);
85985         transitions.set(earth, [custom, traverse]);
85986         transitions.set(traverse, [custom, earth, wait, waitInteractively]);
85987         transitions.set(wait, [traverse, waitInteractively]);
85988         transitions.set(waitInteractively, [traverse, wait]);
85989     }
85990     getState(state) {
85991         if (state instanceof CustomState) {
85992             return State.Custom;
85993         }
85994         else if (state instanceof EarthState) {
85995             return State.Earth;
85996         }
85997         else if (state instanceof TraversingState) {
85998             return State.Traversing;
85999         }
86000         else if (state instanceof WaitingState) {
86001             return State.Waiting;
86002         }
86003         else if (state instanceof InteractiveWaitingState) {
86004             return State.WaitingInteractively;
86005         }
86006         throw new Error("Invalid state instance");
86007     }
86008     generate(state, options) {
86009         const concreteState = this._creators.get(State[state]);
86010         return new concreteState(options);
86011     }
86012     transition(state, to) {
86013         if (!this.validate(state, to)) {
86014             throw new Error("Invalid transition");
86015         }
86016         return this.generate(to, state);
86017     }
86018     validate(state, to) {
86019         const source = State[this.getState(state)];
86020         const target = State[to];
86021         const transitions = this._transitions;
86022         return transitions.has(source) &&
86023             transitions.get(source).includes(target);
86024     }
86025 }
86026
86027 class StateContext {
86028     constructor(state, transitionMode) {
86029         this._transitions = new StateTransitionMatrix();
86030         this._state = this._transitions.generate(state, {
86031             alpha: 1,
86032             camera: new Camera(),
86033             currentIndex: -1,
86034             reference: { alt: 0, lat: 0, lng: 0 },
86035             trajectory: [],
86036             transitionMode: transitionMode == null ? TransitionMode.Default : transitionMode,
86037             zoom: 0,
86038         });
86039     }
86040     get state() {
86041         return this._transitions.getState(this._state);
86042     }
86043     get reference() {
86044         return this._state.reference;
86045     }
86046     get alpha() {
86047         return this._state.alpha;
86048     }
86049     get camera() {
86050         return this._state.camera;
86051     }
86052     get zoom() {
86053         return this._state.zoom;
86054     }
86055     get currentImage() {
86056         return this._state.currentImage;
86057     }
86058     get previousImage() {
86059         return this._state.previousImage;
86060     }
86061     get currentCamera() {
86062         return this._state.currentCamera;
86063     }
86064     get currentTransform() {
86065         return this._state.currentTransform;
86066     }
86067     get previousTransform() {
86068         return this._state.previousTransform;
86069     }
86070     get trajectory() {
86071         return this._state.trajectory;
86072     }
86073     get currentIndex() {
86074         return this._state.currentIndex;
86075     }
86076     get lastImage() {
86077         return this._state.trajectory[this._state.trajectory.length - 1];
86078     }
86079     get imagesAhead() {
86080         return this._state.trajectory.length - 1 - this._state.currentIndex;
86081     }
86082     get motionless() {
86083         return this._state.motionless;
86084     }
86085     custom() {
86086         this._transition(State.Custom);
86087     }
86088     earth() {
86089         this._transition(State.Earth);
86090     }
86091     traverse() {
86092         this._transition(State.Traversing);
86093     }
86094     wait() {
86095         this._transition(State.Waiting);
86096     }
86097     waitInteractively() {
86098         this._transition(State.WaitingInteractively);
86099     }
86100     getCenter() {
86101         return this._state.getCenter();
86102     }
86103     setCenter(center) {
86104         this._state.setCenter(center);
86105     }
86106     setZoom(zoom) {
86107         this._state.setZoom(zoom);
86108     }
86109     update(fps) {
86110         this._state.update(fps);
86111     }
86112     append(images) {
86113         this._state.append(images);
86114     }
86115     prepend(images) {
86116         this._state.prepend(images);
86117     }
86118     remove(n) {
86119         this._state.remove(n);
86120     }
86121     clear() {
86122         this._state.clear();
86123     }
86124     clearPrior() {
86125         this._state.clearPrior();
86126     }
86127     cut() {
86128         this._state.cut();
86129     }
86130     set(images) {
86131         this._state.set(images);
86132     }
86133     setViewMatrix(matrix) {
86134         this._state.setViewMatrix(matrix);
86135     }
86136     rotate(delta) {
86137         this._state.rotate(delta);
86138     }
86139     rotateUnbounded(delta) {
86140         this._state.rotateUnbounded(delta);
86141     }
86142     rotateWithoutInertia(delta) {
86143         this._state.rotateWithoutInertia(delta);
86144     }
86145     rotateBasic(basicRotation) {
86146         this._state.rotateBasic(basicRotation);
86147     }
86148     rotateBasicUnbounded(basicRotation) {
86149         this._state.rotateBasicUnbounded(basicRotation);
86150     }
86151     rotateBasicWithoutInertia(basicRotation) {
86152         this._state.rotateBasicWithoutInertia(basicRotation);
86153     }
86154     rotateToBasic(basic) {
86155         this._state.rotateToBasic(basic);
86156     }
86157     move(delta) {
86158         this._state.move(delta);
86159     }
86160     moveTo(delta) {
86161         this._state.moveTo(delta);
86162     }
86163     zoomIn(delta, reference) {
86164         this._state.zoomIn(delta, reference);
86165     }
86166     setSpeed(speed) {
86167         this._state.setSpeed(speed);
86168     }
86169     setTransitionMode(mode) {
86170         this._state.setTransitionMode(mode);
86171     }
86172     dolly(delta) {
86173         this._state.dolly(delta);
86174     }
86175     orbit(rotation) {
86176         this._state.orbit(rotation);
86177     }
86178     truck(direction) {
86179         this._state.truck(direction);
86180     }
86181     _transition(to) {
86182         if (!this._transitions.validate(this._state, to)) {
86183             const from = this._transitions.getState(this._state);
86184             console.warn(`Transition not valid (${State[from]} - ${State[to]})`);
86185             return;
86186         }
86187         const state = this._transitions.transition(this._state, to);
86188         this._state = state;
86189     }
86190 }
86191
86192 class StateService {
86193     constructor(initialState, transitionMode) {
86194         this._appendImage$ = new Subject();
86195         this._subscriptions = new SubscriptionHolder();
86196         const subs = this._subscriptions;
86197         this._start$ = new Subject();
86198         this._frame$ = new Subject();
86199         this._fpsSampleRate = 30;
86200         this._contextOperation$ = new BehaviorSubject((context) => {
86201             return context;
86202         });
86203         this._context$ = this._contextOperation$.pipe(scan((context, operation) => {
86204             return operation(context);
86205         }, new StateContext(initialState, transitionMode)), publishReplay(1), refCount());
86206         this._state$ = this._context$.pipe(map((context) => {
86207             return context.state;
86208         }), distinctUntilChanged(), publishReplay(1), refCount());
86209         this._fps$ = this._start$.pipe(switchMap(() => {
86210             return this._frame$.pipe(bufferCount(1, this._fpsSampleRate), map(() => {
86211                 return new Date().getTime();
86212             }), pairwise(), map((times) => {
86213                 return Math.max(20, 1000 * this._fpsSampleRate / (times[1] - times[0]));
86214             }), startWith(60));
86215         }), share());
86216         this._currentState$ = this._frame$.pipe(withLatestFrom(this._fps$, this._context$, (frameId, fps, context) => {
86217             return [frameId, fps, context];
86218         }), filter((fc) => {
86219             return fc[2].currentImage != null;
86220         }), tap((fc) => {
86221             fc[2].update(fc[1]);
86222         }), map((fc) => {
86223             return { fps: fc[1], id: fc[0], state: fc[2] };
86224         }), share());
86225         this._lastState$ = this._currentState$.pipe(publishReplay(1), refCount());
86226         let imageChanged$ = this._currentState$.pipe(distinctUntilChanged(undefined, (f) => {
86227             return f.state.currentImage.id;
86228         }), publishReplay(1), refCount());
86229         let imageChangedSubject$ = new Subject();
86230         subs.push(imageChanged$
86231             .subscribe(imageChangedSubject$));
86232         this._currentId$ = new BehaviorSubject(null);
86233         subs.push(imageChangedSubject$.pipe(map((f) => {
86234             return f.state.currentImage.id;
86235         }))
86236             .subscribe(this._currentId$));
86237         this._currentImage$ = imageChangedSubject$.pipe(map((f) => {
86238             return f.state.currentImage;
86239         }), publishReplay(1), refCount());
86240         this._currentCamera$ = imageChangedSubject$.pipe(map((f) => {
86241             return f.state.currentCamera;
86242         }), publishReplay(1), refCount());
86243         this._currentTransform$ = imageChangedSubject$.pipe(map((f) => {
86244             return f.state.currentTransform;
86245         }), publishReplay(1), refCount());
86246         this._reference$ = imageChangedSubject$.pipe(map((f) => {
86247             return f.state.reference;
86248         }), distinctUntilChanged((r1, r2) => {
86249             return r1.lat === r2.lat && r1.lng === r2.lng;
86250         }, (reference) => {
86251             return { lat: reference.lat, lng: reference.lng };
86252         }), publishReplay(1), refCount());
86253         this._currentImageExternal$ = imageChanged$.pipe(map((f) => {
86254             return f.state.currentImage;
86255         }), publishReplay(1), refCount());
86256         subs.push(this._appendImage$.pipe(map((image) => {
86257             return (context) => {
86258                 context.append([image]);
86259                 return context;
86260             };
86261         }))
86262             .subscribe(this._contextOperation$));
86263         this._inMotionOperation$ = new Subject();
86264         subs.push(imageChanged$.pipe(map(() => {
86265             return true;
86266         }))
86267             .subscribe(this._inMotionOperation$));
86268         subs.push(this._inMotionOperation$.pipe(distinctUntilChanged(), filter((moving) => {
86269             return moving;
86270         }), switchMap(() => {
86271             return this._currentState$.pipe(filter((frame) => {
86272                 return frame.state.imagesAhead === 0;
86273             }), map((frame) => {
86274                 return [frame.state.camera.clone(), frame.state.zoom];
86275             }), pairwise(), map((pair) => {
86276                 let c1 = pair[0][0];
86277                 let c2 = pair[1][0];
86278                 let z1 = pair[0][1];
86279                 let z2 = pair[1][1];
86280                 return c1.diff(c2) > 1e-5 || Math.abs(z1 - z2) > 1e-5;
86281             }), first((changed) => {
86282                 return !changed;
86283             }));
86284         }))
86285             .subscribe(this._inMotionOperation$));
86286         this._inMotion$ = this._inMotionOperation$.pipe(distinctUntilChanged(), publishReplay(1), refCount());
86287         this._inTranslationOperation$ = new Subject();
86288         subs.push(imageChanged$.pipe(map(() => {
86289             return true;
86290         }))
86291             .subscribe(this._inTranslationOperation$));
86292         subs.push(this._inTranslationOperation$.pipe(distinctUntilChanged(), filter((inTranslation) => {
86293             return inTranslation;
86294         }), switchMap(() => {
86295             return this._currentState$.pipe(filter((frame) => {
86296                 return frame.state.imagesAhead === 0;
86297             }), map((frame) => {
86298                 return frame.state.camera.position.clone();
86299             }), pairwise(), map((pair) => {
86300                 return pair[0].distanceToSquared(pair[1]) !== 0;
86301             }), first((changed) => {
86302                 return !changed;
86303             }));
86304         }))
86305             .subscribe(this._inTranslationOperation$));
86306         this._inTranslation$ = this._inTranslationOperation$.pipe(distinctUntilChanged(), publishReplay(1), refCount());
86307         subs.push(this._state$.subscribe(() => { }));
86308         subs.push(this._currentImage$.subscribe(() => { }));
86309         subs.push(this._currentCamera$.subscribe(() => { }));
86310         subs.push(this._currentTransform$.subscribe(() => { }));
86311         subs.push(this._reference$.subscribe(() => { }));
86312         subs.push(this._currentImageExternal$.subscribe(() => { }));
86313         subs.push(this._lastState$.subscribe(() => { }));
86314         subs.push(this._inMotion$.subscribe(() => { }));
86315         subs.push(this._inTranslation$.subscribe(() => { }));
86316         this._frameId = null;
86317         this._frameGenerator = new FrameGenerator(window);
86318     }
86319     get currentState$() {
86320         return this._currentState$;
86321     }
86322     get currentImage$() {
86323         return this._currentImage$;
86324     }
86325     get currentId$() {
86326         return this._currentId$;
86327     }
86328     get currentImageExternal$() {
86329         return this._currentImageExternal$;
86330     }
86331     get currentCamera$() {
86332         return this._currentCamera$;
86333     }
86334     get currentTransform$() {
86335         return this._currentTransform$;
86336     }
86337     get state$() {
86338         return this._state$;
86339     }
86340     get reference$() {
86341         return this._reference$;
86342     }
86343     get inMotion$() {
86344         return this._inMotion$;
86345     }
86346     get inTranslation$() {
86347         return this._inTranslation$;
86348     }
86349     get appendImage$() {
86350         return this._appendImage$;
86351     }
86352     dispose() {
86353         this.stop();
86354         this._subscriptions.unsubscribe();
86355     }
86356     custom() {
86357         this._inMotionOperation$.next(true);
86358         this._invokeContextOperation((context) => {
86359             context.custom();
86360         });
86361     }
86362     earth() {
86363         this._inMotionOperation$.next(true);
86364         this._invokeContextOperation((context) => { context.earth(); });
86365     }
86366     traverse() {
86367         this._inMotionOperation$.next(true);
86368         this._invokeContextOperation((context) => { context.traverse(); });
86369     }
86370     wait() {
86371         this._invokeContextOperation((context) => { context.wait(); });
86372     }
86373     waitInteractively() {
86374         this._invokeContextOperation((context) => { context.waitInteractively(); });
86375     }
86376     appendImagess(images) {
86377         this._invokeContextOperation((context) => { context.append(images); });
86378     }
86379     prependImages(images) {
86380         this._invokeContextOperation((context) => { context.prepend(images); });
86381     }
86382     removeImages(n) {
86383         this._invokeContextOperation((context) => { context.remove(n); });
86384     }
86385     clearImages() {
86386         this._invokeContextOperation((context) => { context.clear(); });
86387     }
86388     clearPriorImages() {
86389         this._invokeContextOperation((context) => { context.clearPrior(); });
86390     }
86391     cutImages() {
86392         this._invokeContextOperation((context) => { context.cut(); });
86393     }
86394     setImages(images) {
86395         this._invokeContextOperation((context) => { context.set(images); });
86396     }
86397     setViewMatrix(matrix) {
86398         this._inMotionOperation$.next(true);
86399         this._invokeContextOperation((context) => { context.setViewMatrix(matrix); });
86400     }
86401     rotate(delta) {
86402         this._inMotionOperation$.next(true);
86403         this._invokeContextOperation((context) => { context.rotate(delta); });
86404     }
86405     rotateUnbounded(delta) {
86406         this._inMotionOperation$.next(true);
86407         this._invokeContextOperation((context) => { context.rotateUnbounded(delta); });
86408     }
86409     rotateWithoutInertia(delta) {
86410         this._inMotionOperation$.next(true);
86411         this._invokeContextOperation((context) => { context.rotateWithoutInertia(delta); });
86412     }
86413     rotateBasic(basicRotation) {
86414         this._inMotionOperation$.next(true);
86415         this._invokeContextOperation((context) => { context.rotateBasic(basicRotation); });
86416     }
86417     rotateBasicUnbounded(basicRotation) {
86418         this._inMotionOperation$.next(true);
86419         this._invokeContextOperation((context) => { context.rotateBasicUnbounded(basicRotation); });
86420     }
86421     rotateBasicWithoutInertia(basicRotation) {
86422         this._inMotionOperation$.next(true);
86423         this._invokeContextOperation((context) => { context.rotateBasicWithoutInertia(basicRotation); });
86424     }
86425     rotateToBasic(basic) {
86426         this._inMotionOperation$.next(true);
86427         this._invokeContextOperation((context) => { context.rotateToBasic(basic); });
86428     }
86429     move(delta) {
86430         this._inMotionOperation$.next(true);
86431         this._invokeContextOperation((context) => { context.move(delta); });
86432     }
86433     moveTo(position) {
86434         this._inMotionOperation$.next(true);
86435         this._invokeContextOperation((context) => { context.moveTo(position); });
86436     }
86437     dolly(delta) {
86438         this._inMotionOperation$.next(true);
86439         this._invokeContextOperation((context) => { context.dolly(delta); });
86440     }
86441     orbit(rotation) {
86442         this._inMotionOperation$.next(true);
86443         this._invokeContextOperation((context) => { context.orbit(rotation); });
86444     }
86445     truck(direction) {
86446         this._inMotionOperation$.next(true);
86447         this._invokeContextOperation((context) => { context.truck(direction); });
86448     }
86449     /**
86450      * Change zoom level while keeping the reference point position approximately static.
86451      *
86452      * @parameter {number} delta - Change in zoom level.
86453      * @parameter {Array<number>} reference - Reference point in basic coordinates.
86454      */
86455     zoomIn(delta, reference) {
86456         this._inMotionOperation$.next(true);
86457         this._invokeContextOperation((context) => { context.zoomIn(delta, reference); });
86458     }
86459     getCenter() {
86460         return this._lastState$.pipe(first(), map((frame) => {
86461             return frame.state.getCenter();
86462         }));
86463     }
86464     getZoom() {
86465         return this._lastState$.pipe(first(), map((frame) => {
86466             return frame.state.zoom;
86467         }));
86468     }
86469     setCenter(center) {
86470         this._inMotionOperation$.next(true);
86471         this._invokeContextOperation((context) => { context.setCenter(center); });
86472     }
86473     setSpeed(speed) {
86474         this._invokeContextOperation((context) => { context.setSpeed(speed); });
86475     }
86476     setTransitionMode(mode) {
86477         this._invokeContextOperation((context) => { context.setTransitionMode(mode); });
86478     }
86479     setZoom(zoom) {
86480         this._inMotionOperation$.next(true);
86481         this._invokeContextOperation((context) => { context.setZoom(zoom); });
86482     }
86483     start() {
86484         if (this._frameId == null) {
86485             this._start$.next(null);
86486             this._frameId = this._frameGenerator.requestAnimationFrame(this._frame.bind(this));
86487             this._frame$.next(this._frameId);
86488         }
86489     }
86490     stop() {
86491         if (this._frameId != null) {
86492             this._frameGenerator.cancelAnimationFrame(this._frameId);
86493             this._frameId = null;
86494         }
86495     }
86496     _invokeContextOperation(action) {
86497         this._contextOperation$
86498             .next((context) => {
86499             action(context);
86500             return context;
86501         });
86502     }
86503     _frame() {
86504         this._frameId = this._frameGenerator.requestAnimationFrame(this._frame.bind(this));
86505         this._frame$.next(this._frameId);
86506     }
86507 }
86508
86509 function cameraControlsToState(cameraControls) {
86510     switch (cameraControls) {
86511         case CameraControls.Custom:
86512             return State.Custom;
86513         case CameraControls.Earth:
86514             return State.Earth;
86515         case CameraControls.Street:
86516             return State.Traversing;
86517         default:
86518             return null;
86519     }
86520 }
86521
86522 class Navigator {
86523     constructor(options, api, graphService, loadingService, stateService, cacheService, playService, panService) {
86524         var _a;
86525         if (api) {
86526             this._api = api;
86527         }
86528         else if (options.dataProvider) {
86529             if (options.dataProvider instanceof DataProviderBase) {
86530                 this._api = new APIWrapper(options.dataProvider);
86531             }
86532             else {
86533                 throw new Error("Incorrect type: 'dataProvider' must extend the DataProviderBase class.");
86534             }
86535         }
86536         else {
86537             this._api = new APIWrapper(new GraphDataProvider({
86538                 accessToken: options.accessToken,
86539             }));
86540         }
86541         this._graphService = graphService !== null && graphService !== void 0 ? graphService : new GraphService(new Graph(this.api));
86542         this._loadingName = "navigator";
86543         this._loadingService = loadingService !== null && loadingService !== void 0 ? loadingService : new LoadingService();
86544         const cameraControls = (_a = options.cameraControls) !== null && _a !== void 0 ? _a : CameraControls.Street;
86545         this._stateService = stateService !== null && stateService !== void 0 ? stateService : new StateService(cameraControlsToState(cameraControls), options.transitionMode);
86546         this._cacheService = cacheService !== null && cacheService !== void 0 ? cacheService : new CacheService(this._graphService, this._stateService, this._api);
86547         this._playService = playService !== null && playService !== void 0 ? playService : new PlayService(this._graphService, this._stateService);
86548         this._panService = panService !== null && panService !== void 0 ? panService : new PanService(this._graphService, this._stateService, options.combinedPanning);
86549         this._idRequested$ = new BehaviorSubject(null);
86550         this._movedToId$ = new BehaviorSubject(null);
86551         this._request$ = null;
86552         this._requestSubscription = null;
86553         this._imageRequestSubscription = null;
86554     }
86555     get api() {
86556         return this._api;
86557     }
86558     get cacheService() {
86559         return this._cacheService;
86560     }
86561     get graphService() {
86562         return this._graphService;
86563     }
86564     get loadingService() {
86565         return this._loadingService;
86566     }
86567     get movedToId$() {
86568         return this._movedToId$;
86569     }
86570     get panService() {
86571         return this._panService;
86572     }
86573     get playService() {
86574         return this._playService;
86575     }
86576     get stateService() {
86577         return this._stateService;
86578     }
86579     dispose() {
86580         this._abortRequest("viewer removed");
86581         this._cacheService.stop();
86582         this._graphService.dispose();
86583         this._panService.dispose();
86584         this._playService.dispose();
86585         this._stateService.dispose();
86586     }
86587     moveTo$(id) {
86588         this._abortRequest(`to id ${id}`);
86589         this._loadingService.startLoading(this._loadingName);
86590         const image$ = this._moveTo$(id);
86591         return this._makeRequest$(image$);
86592     }
86593     moveDir$(direction) {
86594         this._abortRequest(`in dir ${NavigationDirection[direction]}`);
86595         this._loadingService.startLoading(this._loadingName);
86596         const image$ = this.stateService.currentImage$.pipe(first(), mergeMap((image) => {
86597             return ([NavigationDirection.Next, NavigationDirection.Prev].indexOf(direction) > -1 ?
86598                 image.sequenceEdges$ :
86599                 image.spatialEdges$).pipe(first(), map((status) => {
86600                 for (let edge of status.edges) {
86601                     if (edge.data.direction === direction) {
86602                         return edge.target;
86603                     }
86604                 }
86605                 return null;
86606             }));
86607         }), mergeMap((directionId) => {
86608             if (directionId == null) {
86609                 this._loadingService.stopLoading(this._loadingName);
86610                 return throwError(new Error(`Direction (${direction}) does not exist for current image.`));
86611             }
86612             return this._moveTo$(directionId);
86613         }));
86614         return this._makeRequest$(image$);
86615     }
86616     setFilter$(filter) {
86617         this._stateService.clearImages();
86618         return this._movedToId$.pipe(first(), mergeMap((id) => {
86619             if (id != null) {
86620                 return this._trajectoryIds$().pipe(mergeMap((ids) => {
86621                     return this._graphService.setFilter$(filter).pipe(mergeMap(() => {
86622                         return this._cacheIds$(ids);
86623                     }));
86624                 }), last());
86625             }
86626             return this._idRequested$.pipe(first(), mergeMap((requestedId) => {
86627                 if (requestedId != null) {
86628                     return this._graphService.setFilter$(filter).pipe(mergeMap(() => {
86629                         return this._graphService.cacheImage$(requestedId);
86630                     }));
86631                 }
86632                 return this._graphService.setFilter$(filter).pipe(map(() => {
86633                     return undefined;
86634                 }));
86635             }));
86636         }), map(() => {
86637             return undefined;
86638         }));
86639     }
86640     setAccessToken$(accessToken) {
86641         this._abortRequest("to set user token");
86642         this._stateService.clearImages();
86643         return this._movedToId$.pipe(first(), tap(() => {
86644             this._api.setAccessToken(accessToken);
86645         }), mergeMap((id) => {
86646             return id == null ?
86647                 this._graphService.reset$([]) :
86648                 this._trajectoryIds$().pipe(mergeMap((ids) => {
86649                     return this._graphService.reset$(ids).pipe(mergeMap(() => {
86650                         return this._cacheIds$(ids);
86651                     }));
86652                 }), last(), map(() => {
86653                     return undefined;
86654                 }));
86655         }));
86656     }
86657     _cacheIds$(ids) {
86658         const cacheImages$ = ids
86659             .map((id) => {
86660             return this._graphService.cacheImage$(id);
86661         });
86662         return from(cacheImages$).pipe(mergeAll());
86663     }
86664     _abortRequest(reason) {
86665         if (this._requestSubscription != null) {
86666             this._requestSubscription.unsubscribe();
86667             this._requestSubscription = null;
86668         }
86669         if (this._imageRequestSubscription != null) {
86670             this._imageRequestSubscription.unsubscribe();
86671             this._imageRequestSubscription = null;
86672         }
86673         if (this._request$ != null) {
86674             if (!(this._request$.isStopped || this._request$.hasError)) {
86675                 this._request$.error(new CancelMapillaryError(`Request aborted by a subsequent request ${reason}.`));
86676             }
86677             this._request$ = null;
86678         }
86679     }
86680     _makeRequest$(image$) {
86681         const request$ = new ReplaySubject(1);
86682         this._requestSubscription = request$
86683             .subscribe(undefined, () => { });
86684         this._request$ = request$;
86685         this._imageRequestSubscription = image$
86686             .subscribe((image) => {
86687             this._request$ = null;
86688             request$.next(image);
86689             request$.complete();
86690         }, (error) => {
86691             this._request$ = null;
86692             request$.error(error);
86693         });
86694         return request$;
86695     }
86696     _moveTo$(id) {
86697         this._idRequested$.next(id);
86698         return this._graphService.cacheImage$(id).pipe(tap((image) => {
86699             this._stateService.setImages([image]);
86700             this._movedToId$.next(image.id);
86701         }), finalize(() => {
86702             this._loadingService.stopLoading(this._loadingName);
86703         }));
86704     }
86705     _trajectoryIds$() {
86706         return this._stateService.currentState$.pipe(first(), map((frame) => {
86707             return frame.state.trajectory
86708                 .map((image) => {
86709                 return image.id;
86710             });
86711         }));
86712     }
86713 }
86714
86715 class Projection {
86716     constructor(viewportCoords, spatial) {
86717         this._spatial = spatial !== null && spatial !== void 0 ? spatial : new Spatial();
86718         this._viewportCoords = viewportCoords !== null && viewportCoords !== void 0 ? viewportCoords : new ViewportCoords();
86719     }
86720     basicToCanvas(basicPoint, container, render, transform) {
86721         return this._viewportCoords
86722             .basicToCanvasSafe(basicPoint[0], basicPoint[1], container, transform, render.perspective);
86723     }
86724     canvasToBasic(canvasPoint, container, render, transform) {
86725         let basicPoint = this._viewportCoords
86726             .canvasToBasic(canvasPoint[0], canvasPoint[1], container, transform, render.perspective);
86727         if (basicPoint[0] < 0 ||
86728             basicPoint[0] > 1 ||
86729             basicPoint[1] < 0 ||
86730             basicPoint[1] > 1) {
86731             basicPoint = null;
86732         }
86733         return basicPoint;
86734     }
86735     eventToUnprojection(event, container, render, reference, transform) {
86736         const pixelPoint = this._viewportCoords
86737             .canvasPosition(event, container);
86738         return this.canvasToUnprojection(pixelPoint, container, render, reference, transform);
86739     }
86740     canvasToUnprojection(canvasPoint, container, render, reference, transform) {
86741         const canvasX = canvasPoint[0];
86742         const canvasY = canvasPoint[1];
86743         const [viewportX, viewportY] = this._viewportCoords
86744             .canvasToViewport(canvasX, canvasY, container);
86745         const point3d = new Vector3(viewportX, viewportY, 1)
86746             .unproject(render.perspective);
86747         let basicPoint = transform
86748             .projectBasic(point3d.toArray());
86749         if (basicPoint[0] < 0 ||
86750             basicPoint[0] > 1 ||
86751             basicPoint[1] < 0 ||
86752             basicPoint[1] > 1) {
86753             basicPoint = null;
86754         }
86755         const direction3d = point3d
86756             .clone()
86757             .sub(render.camera.position)
86758             .normalize();
86759         const dist = -2 / direction3d.z;
86760         let lngLat = null;
86761         if (dist > 0 && dist < 100 && !!basicPoint) {
86762             const point = direction3d
86763                 .clone()
86764                 .multiplyScalar(dist)
86765                 .add(render.camera.position);
86766             const [lng, lat] = enuToGeodetic(point.x, point.y, point.z, reference.lng, reference.lat, reference.alt);
86767             lngLat = { lat, lng };
86768         }
86769         const unprojection = {
86770             basicPoint: basicPoint,
86771             lngLat: lngLat,
86772             pixelPoint: [canvasX, canvasY],
86773         };
86774         return unprojection;
86775     }
86776     cameraToLngLat(render, reference) {
86777         const position = render.camera.position;
86778         const [lng, lat] = enuToGeodetic(position.x, position.y, position.z, reference.lng, reference.lat, reference.alt);
86779         return { lat, lng };
86780     }
86781     lngLatToCanvas(lngLat, container, render, reference) {
86782         const point3d = geodeticToEnu(lngLat.lng, lngLat.lat, 0, reference.lng, reference.lat, reference.alt);
86783         const canvas = this._viewportCoords
86784             .projectToCanvasSafe(point3d, container, render.perspective);
86785         return canvas;
86786     }
86787     distanceBetweenLngLats(lngLat1, lngLat2) {
86788         return this._spatial
86789             .distanceFromLngLat(lngLat1.lng, lngLat1.lat, lngLat2.lng, lngLat2.lat);
86790     }
86791 }
86792
86793 class Observer {
86794     constructor(viewer, navigator, container) {
86795         this._subscriptions = new SubscriptionHolder();
86796         this._emitSubscriptions = new SubscriptionHolder();
86797         this._container = container;
86798         this._viewer = viewer;
86799         this._navigator = navigator;
86800         this._projection = new Projection();
86801         this._started = false;
86802         this._navigable$ = new Subject();
86803         const subs = this._subscriptions;
86804         // load, navigable, dataloading should always emit,
86805         // also when cover is activated.
86806         subs.push(this._navigable$
86807             .subscribe((navigable) => {
86808             const type = "navigable";
86809             const event = {
86810                 navigable,
86811                 target: this._viewer,
86812                 type,
86813             };
86814             this._viewer.fire(type, event);
86815         }));
86816         subs.push(this._navigator.loadingService.loading$
86817             .subscribe((loading) => {
86818             const type = "dataloading";
86819             const event = {
86820                 loading,
86821                 target: this._viewer,
86822                 type,
86823             };
86824             this._viewer.fire(type, event);
86825         }));
86826         subs.push(this._container.glRenderer.opaqueRender$
86827             .pipe(first())
86828             .subscribe(() => {
86829             const type = "load";
86830             const event = {
86831                 target: this._viewer,
86832                 type,
86833             };
86834             this._viewer.fire(type, event);
86835         }));
86836     }
86837     get started() {
86838         return this._started;
86839     }
86840     get navigable$() {
86841         return this._navigable$;
86842     }
86843     get projection() {
86844         return this._projection;
86845     }
86846     dispose() {
86847         this.stopEmit();
86848         this._subscriptions.unsubscribe();
86849     }
86850     project$(lngLat) {
86851         return combineLatest(this._container.renderService.renderCamera$, this._navigator.stateService.currentImage$, this._navigator.stateService.reference$).pipe(first(), map(([render, image, reference]) => {
86852             if (this._projection
86853                 .distanceBetweenLngLats(lngLat, image.lngLat) > 1000) {
86854                 return null;
86855             }
86856             const canvasPoint = this._projection.lngLatToCanvas(lngLat, this._container.container, render, reference);
86857             return !!canvasPoint ?
86858                 [Math.round(canvasPoint[0]), Math.round(canvasPoint[1])] :
86859                 null;
86860         }));
86861     }
86862     projectBasic$(basicPoint) {
86863         return combineLatest(this._container.renderService.renderCamera$, this._navigator.stateService.currentTransform$).pipe(first(), map(([render, transform]) => {
86864             const canvasPoint = this._projection.basicToCanvas(basicPoint, this._container.container, render, transform);
86865             return !!canvasPoint ?
86866                 [Math.round(canvasPoint[0]), Math.round(canvasPoint[1])] :
86867                 null;
86868         }));
86869     }
86870     startEmit() {
86871         if (this._started) {
86872             return;
86873         }
86874         this._started = true;
86875         const subs = this._emitSubscriptions;
86876         subs.push(this._navigator.stateService.currentImageExternal$
86877             .subscribe((image) => {
86878             const type = "image";
86879             const event = {
86880                 image: image,
86881                 target: this._viewer,
86882                 type,
86883             };
86884             this._viewer.fire(type, event);
86885         }));
86886         subs.push(this._navigator.stateService.currentImageExternal$.pipe(switchMap((image) => {
86887             return image.sequenceEdges$;
86888         }))
86889             .subscribe((status) => {
86890             const type = "sequenceedges";
86891             const event = {
86892                 status,
86893                 target: this._viewer,
86894                 type,
86895             };
86896             this._viewer.fire(type, event);
86897         }));
86898         subs.push(this._navigator.stateService.currentImageExternal$.pipe(switchMap((image) => {
86899             return image.spatialEdges$;
86900         }))
86901             .subscribe((status) => {
86902             const type = "spatialedges";
86903             const event = {
86904                 status,
86905                 target: this._viewer,
86906                 type,
86907             };
86908             this._viewer.fire(type, event);
86909         }));
86910         subs.push(combineLatest(this._navigator.stateService.inMotion$, this._container.mouseService.active$, this._container.touchService.active$).pipe(map((values) => {
86911             return values[0] || values[1] || values[2];
86912         }), distinctUntilChanged())
86913             .subscribe((started) => {
86914             const type = started ? "movestart" : "moveend";
86915             const event = {
86916                 target: this._viewer,
86917                 type,
86918             };
86919             this._viewer.fire(type, event);
86920         }));
86921         subs.push(this._container.renderService.bearing$.pipe(auditTime(100), distinctUntilChanged((b1, b2) => {
86922             return Math.abs(b2 - b1) < 1;
86923         }))
86924             .subscribe((bearing) => {
86925             const type = "bearing";
86926             const event = {
86927                 bearing,
86928                 target: this._viewer,
86929                 type,
86930             };
86931             this._viewer.fire(type, event);
86932         }));
86933         const mouseMove$ = this._container.mouseService.active$.pipe(switchMap((active) => {
86934             return active ?
86935                 empty() :
86936                 this._container.mouseService.mouseMove$;
86937         }));
86938         subs.push(merge(this._mapMouseEvent$("click", this._container.mouseService.staticClick$), this._mapMouseEvent$("contextmenu", this._container.mouseService.contextMenu$), this._mapMouseEvent$("dblclick", this._container.mouseService.dblClick$), this._mapMouseEvent$("mousedown", this._container.mouseService.mouseDown$), this._mapMouseEvent$("mousemove", mouseMove$), this._mapMouseEvent$("mouseout", this._container.mouseService.mouseOut$), this._mapMouseEvent$("mouseover", this._container.mouseService.mouseOver$), this._mapMouseEvent$("mouseup", this._container.mouseService.mouseUp$))
86939             .pipe(withLatestFrom(this._container.renderService.renderCamera$, this._navigator.stateService.reference$, this._navigator.stateService.currentTransform$, this._navigator.stateService.state$), map(([[type, event], render, reference, transform, state]) => {
86940             const unprojection = this._projection.eventToUnprojection(event, this._container.container, render, reference, transform);
86941             const basicPoint = state === State.Traversing ?
86942                 unprojection.basicPoint : null;
86943             return {
86944                 basicPoint,
86945                 lngLat: unprojection.lngLat,
86946                 originalEvent: event,
86947                 pixelPoint: unprojection.pixelPoint,
86948                 target: this._viewer,
86949                 type: type,
86950             };
86951         }))
86952             .subscribe((event) => {
86953             this._viewer.fire(event.type, event);
86954         }));
86955         subs.push(this._container.renderService.renderCamera$.pipe(distinctUntilChanged(([x1, y1], [x2, y2]) => {
86956             return this._closeTo(x1, x2, 1e-2) &&
86957                 this._closeTo(y1, y2, 1e-2);
86958         }, (rc) => {
86959             return rc.camera.position.toArray();
86960         }))
86961             .subscribe(() => {
86962             const type = "position";
86963             const event = {
86964                 target: this._viewer,
86965                 type,
86966             };
86967             this._viewer.fire(type, event);
86968         }));
86969         subs.push(this._container.renderService.renderCamera$.pipe(distinctUntilChanged(([phi1, theta1], [phi2, theta2]) => {
86970             return this._closeTo(phi1, phi2, 1e-3) &&
86971                 this._closeTo(theta1, theta2, 1e-3);
86972         }, (rc) => {
86973             return [rc.rotation.phi, rc.rotation.theta];
86974         }))
86975             .subscribe(() => {
86976             const type = "pov";
86977             const event = {
86978                 target: this._viewer,
86979                 type,
86980             };
86981             this._viewer.fire(type, event);
86982         }));
86983         subs.push(this._container.renderService.renderCamera$.pipe(distinctUntilChanged((fov1, fov2) => {
86984             return this._closeTo(fov1, fov2, 1e-2);
86985         }, (rc) => {
86986             return rc.perspective.fov;
86987         }))
86988             .subscribe(() => {
86989             const type = "fov";
86990             const event = {
86991                 target: this._viewer,
86992                 type,
86993             };
86994             this._viewer.fire(type, event);
86995         }));
86996     }
86997     stopEmit() {
86998         if (!this.started) {
86999             return;
87000         }
87001         this._emitSubscriptions.unsubscribe();
87002         this._started = false;
87003     }
87004     unproject$(canvasPoint) {
87005         return combineLatest(this._container.renderService.renderCamera$, this._navigator.stateService.reference$, this._navigator.stateService.currentTransform$).pipe(first(), map(([render, reference, transform]) => {
87006             const unprojection = this._projection.canvasToUnprojection(canvasPoint, this._container.container, render, reference, transform);
87007             return unprojection.lngLat;
87008         }));
87009     }
87010     unprojectBasic$(canvasPoint) {
87011         return combineLatest(this._container.renderService.renderCamera$, this._navigator.stateService.currentTransform$).pipe(first(), map(([render, transform]) => {
87012             return this._projection.canvasToBasic(canvasPoint, this._container.container, render, transform);
87013         }));
87014     }
87015     _closeTo(v1, v2, absoluteTolerance) {
87016         return Math.abs(v1 - v2) <= absoluteTolerance;
87017     }
87018     _mapMouseEvent$(type, mouseEvent$) {
87019         return mouseEvent$.pipe(map((event) => {
87020             return [type, event];
87021         }));
87022     }
87023 }
87024
87025 class CustomRenderer {
87026     constructor(_container, _navigator) {
87027         this._container = _container;
87028         this._navigator = _navigator;
87029         this._renderers = {};
87030     }
87031     add(renderer, viewer) {
87032         const subs = new SubscriptionHolder();
87033         this._renderers[renderer.id] = { subs, renderer };
87034         subs.push(combineLatest([
87035             this._container.glRenderer.webGLRenderer$,
87036             this._navigator.stateService.reference$,
87037         ])
87038             .pipe(take(1))
87039             .subscribe(([gl, reference]) => {
87040             renderer.onAdd(viewer, reference, gl.getContext());
87041         }));
87042         subs.push(this._container.glRenderer.opaqueRender$
87043             .pipe(withLatestFrom(this._container.renderService.renderCamera$, this._container.glRenderer.webGLRenderer$))
87044             .subscribe(([, renderCamera, glRenderer]) => {
87045             const context = glRenderer.getContext();
87046             const viewMatrix = renderCamera.perspective.matrixWorldInverse;
87047             const projectionMatrix = renderCamera.perspective.projectionMatrix;
87048             renderer.render(context, viewMatrix.toArray(), projectionMatrix.toArray());
87049         }));
87050         subs.push(this._navigator.stateService.reference$
87051             .pipe(skip(1))
87052             .subscribe((reference) => {
87053             renderer.onReference(viewer, reference);
87054         }));
87055     }
87056     dispose(viewer) {
87057         for (const id of Object.keys(this._renderers)) {
87058             this.remove(id, viewer);
87059         }
87060     }
87061     has(id) {
87062         return id in this._renderers;
87063     }
87064     remove(id, viewer) {
87065         this._renderers[id].subs.unsubscribe();
87066         const renderer = this._renderers[id].renderer;
87067         delete this._renderers[id];
87068         this._container.glRenderer.webGLRenderer$
87069             .subscribe((gl) => {
87070             renderer.onRemove(viewer, gl.getContext());
87071         });
87072     }
87073 }
87074
87075 class CustomCameraControls {
87076     constructor(_container, _navigator) {
87077         this._container = _container;
87078         this._navigator = _navigator;
87079         this._controls = null;
87080         this._subscriptions = new SubscriptionHolder();
87081     }
87082     attach(controls, viewer) {
87083         if (this._controls) {
87084             throw new MapillaryError('Custom camera controls already attached');
87085         }
87086         const attach$ = new Subject();
87087         const active$ = attach$
87088             .pipe(switchMap(() => {
87089             return this._navigator.stateService.state$;
87090         }), map((state) => {
87091             return state === State.Custom;
87092         }), distinctUntilChanged());
87093         const subs = this._subscriptions;
87094         subs.push(active$
87095             .pipe(startWith(false), pairwise(), withLatestFrom(this._navigator.stateService.reference$, this._container.renderService.renderCamera$))
87096             .subscribe(([[deactivate, activate], ref, cam]) => {
87097             if (activate) {
87098                 controls.onActivate(viewer, cam.perspective.matrixWorldInverse.toArray(), cam.perspective.projectionMatrix.toArray(), ref);
87099             }
87100             else if (deactivate) {
87101                 controls.onDeactivate(viewer);
87102             }
87103         }));
87104         subs.push(active$
87105             .pipe(switchMap(active => {
87106             return active ?
87107                 this._navigator.stateService.currentState$
87108                     .pipe(skip(1)) :
87109                 empty();
87110         }))
87111             .subscribe(frame => {
87112             controls.onAnimationFrame(viewer, frame.id);
87113         }));
87114         subs.push(active$
87115             .pipe(switchMap(active => {
87116             return active ?
87117                 this._navigator.stateService.reference$
87118                     .pipe(skip(1)) :
87119                 empty();
87120         }))
87121             .subscribe(ref => controls.onReference(viewer, ref)));
87122         subs.push(active$
87123             .pipe(switchMap(active => {
87124             return active ?
87125                 this._container.renderService.size$
87126                     .pipe(skip(1)) :
87127                 empty();
87128         }))
87129             .subscribe(() => controls.onResize(viewer)));
87130         subs.push(combineLatest([
87131             // Include to ensure GL renderer has been initialized
87132             this._container.glRenderer.webGLRenderer$,
87133             this._container.renderService.renderCamera$,
87134             this._navigator.stateService.reference$,
87135             this._navigator.stateService.state$,
87136         ])
87137             .pipe(first())
87138             .subscribe(() => {
87139             const projectionMatrixCallback = (projectionMatrix) => {
87140                 if (!this._controls ||
87141                     controls !== this._controls) {
87142                     return;
87143                 }
87144                 this._updateProjectionMatrix(projectionMatrix);
87145             };
87146             const viewMatrixCallback = (viewMatrix) => {
87147                 if (!this._controls ||
87148                     controls !== this._controls) {
87149                     return;
87150                 }
87151                 this._updateViewMatrix(viewMatrix);
87152             };
87153             controls.onAttach(viewer, viewMatrixCallback, projectionMatrixCallback);
87154             attach$.next();
87155             attach$.complete();
87156         }));
87157         this._controls = controls;
87158     }
87159     dispose(viewer) {
87160         this.detach(viewer);
87161     }
87162     detach(viewer) {
87163         if (!this._controls) {
87164             return;
87165         }
87166         this._subscriptions.unsubscribe();
87167         this._navigator.stateService.state$
87168             .subscribe(state => {
87169             if (state === State.Custom) {
87170                 this._controls.onDeactivate(viewer);
87171             }
87172             this._controls.onDetach(viewer);
87173             this._controls = null;
87174         });
87175     }
87176     _updateProjectionMatrix(projectionMatrix) {
87177         this._navigator.stateService.state$
87178             .pipe(first())
87179             .subscribe(state => {
87180             if (state !== State.Custom) {
87181                 const message = "Incorrect camera control mode for " +
87182                     "projection matrix update";
87183                 console.warn(message);
87184                 return;
87185             }
87186             this._container.renderService.projectionMatrix$
87187                 .next(projectionMatrix);
87188         });
87189     }
87190     _updateViewMatrix(viewMatrix) {
87191         this._navigator.stateService.state$
87192             .pipe(first())
87193             .subscribe(state => {
87194             if (state !== State.Custom) {
87195                 const message = "Incorrect camera control mode for " +
87196                     "view matrix update";
87197                 console.warn(message);
87198                 return;
87199             }
87200             this._navigator.stateService.setViewMatrix(viewMatrix);
87201         });
87202     }
87203 }
87204
87205 /**
87206  * @class Viewer
87207  *
87208  * @classdesc The Viewer object represents the navigable image viewer.
87209  * Create a Viewer by specifying a container, client ID, image id and
87210  * other options. The viewer exposes methods and events for programmatic
87211  * interaction.
87212  *
87213  * In the case of asynchronous methods, MapillaryJS returns promises to
87214  * the results. Notifications are always emitted through JavaScript events.
87215  */
87216 class Viewer extends EventEmitter {
87217     /**
87218      * Create a new viewer instance.
87219      *
87220      * @description It is possible to initialize the viewer with or
87221      * without a id.
87222      *
87223      * When you want to show a specific image in the viewer from
87224      * the start you should initialize it with a id.
87225      *
87226      * When you do not know the first image id at implementation
87227      * time, e.g. in a map-viewer application you should initialize
87228      * the viewer without a id and call `moveTo` instead.
87229      *
87230      * When initializing with a id the viewer is bound to that id
87231      * until the image for that id has been successfully loaded.
87232      * Also, a cover with the image of the id will be shown.
87233      * If the data for that id can not be loaded because the id is
87234      * faulty or other errors occur it is not possible to navigate
87235      * to another id because the viewer is not navigable. The viewer
87236      * becomes navigable when the data for the id has been loaded and
87237      * the image is shown in the viewer. This way of initializing
87238      * the viewer is mostly for embedding in blog posts and similar
87239      * where one wants to show a specific image initially.
87240      *
87241      * If the viewer is initialized without a id (with null or
87242      * undefined) it is not bound to any particular id and it is
87243      * possible to move to any id with `viewer.moveTo("<my-image-id>")`.
87244      * If the first move to a id fails it is possible to move to another
87245      * id. The viewer will show a black background until a move
87246      * succeeds. This way of intitializing is suited for a map-viewer
87247      * application when the initial id is not known at implementation
87248      * time.
87249      *
87250      * @param {ViewerOptions} options - Optional configuration object
87251      * specifing Viewer's and the components' initial setup.
87252      *
87253      * @example
87254      * ```js
87255      * var viewer = new Viewer({
87256      *     accessToken: "<my-access-token>",
87257      *     container: "<my-container-id>",
87258      * });
87259      * ```
87260      */
87261     constructor(options) {
87262         super();
87263         this._navigator =
87264             new Navigator(options);
87265         this._container =
87266             new Container(options, this._navigator.stateService);
87267         this._observer =
87268             new Observer(this, this._navigator, this._container);
87269         this._componentController =
87270             new ComponentController(this._container, this._navigator, this._observer, options.imageId, options.component);
87271         this._customRenderer =
87272             new CustomRenderer(this._container, this._navigator);
87273         this._customCameraControls =
87274             new CustomCameraControls(this._container, this._navigator);
87275     }
87276     /**
87277      * Return a boolean indicating if the viewer is in a navigable state.
87278      *
87279      * @description The navigable state indicates if the viewer supports
87280      * moving, i.e. calling the {@link moveTo} and {@link moveDir}
87281      * methods or changing the authentication state,
87282      * i.e. calling {@link setAccessToken}. The viewer will not be in a navigable
87283      * state if the cover is activated and the viewer has been supplied a id.
87284      * When the cover is deactivated or the viewer is activated without being
87285      * supplied a id it will be navigable.
87286      *
87287      * @returns {boolean} Boolean indicating whether the viewer is navigable.
87288      */
87289     get isNavigable() {
87290         return this._componentController.navigable;
87291     }
87292     /**
87293      * Activate the combined panning functionality.
87294      *
87295      * @description The combined panning functionality is active by default.
87296      */
87297     activateCombinedPanning() {
87298         this._navigator.panService.enable();
87299     }
87300     /**
87301      * Activate a component.
87302      *
87303      * @param {ComponentName | FallbackComponentName} name - Name of
87304      * the component which will become active.
87305      *
87306      * @example
87307      * ```js
87308      * viewer.activateComponent("marker");
87309      * ```
87310      */
87311     activateComponent(name) {
87312         this._componentController.activate(name);
87313     }
87314     /**
87315      * Activate the cover (deactivates all other components).
87316      */
87317     activateCover() {
87318         this._componentController.activateCover();
87319     }
87320     /**
87321      * Add a custom renderer to the viewer's rendering pipeline.
87322      *
87323      * @description During a render pass, custom renderers
87324      * are called in the order they were added.
87325      *
87326      * @param renderer - The custom renderer implementation.
87327      */
87328     addCustomRenderer(renderer) {
87329         this._customRenderer.add(renderer, this);
87330     }
87331     /**
87332      * Attach custom camera controls to control the viewer's
87333      * camera pose and projection.
87334      *
87335      * @description Custom camera controls allow the API user
87336      * to move the viewer's camera freely and define the camera
87337      * projection. These camera properties are used
87338      * to render the viewer 3D scene directly into the
87339      * viewer's GL context.
87340      *
87341      * Only a single custom camera control instance can be
87342      * attached to the viewer. A new custom camera control
87343      * instance can be attached after detaching a previous
87344      * one.
87345      *
87346      * Set the viewer's camera controls to
87347      * {@link CameraControls.Custom} to activate attached
87348      * camera controls. If {@link CameraControls.Custom}
87349      * has already been set when a custom camera control
87350      * instance is attached, it will be activated immediately.
87351      *
87352      * Set the viewer's camera controls to any other
87353      * {@link CameraControls} mode to deactivate the
87354      * custom camera controls.
87355      *
87356      * @param controls - The custom camera controls implementation.
87357      *
87358      * @throws {MapillaryError} When camera controls attached
87359      * are already attached to the viewer.
87360      */
87361     attachCustomCameraControls(controls) {
87362         this._customCameraControls.attach(controls, this);
87363     }
87364     /**
87365      * Deactivate the combined panning functionality.
87366      *
87367      * @description Deactivating the combined panning functionality
87368      * could be needed in scenarios involving sequence only navigation.
87369      */
87370     deactivateCombinedPanning() {
87371         this._navigator.panService.disable();
87372     }
87373     /**
87374      * Deactivate a component.
87375      *
87376      * @param {ComponentName | FallbackComponentName} name - Name
87377      * of component which become inactive.
87378      *
87379      * @example
87380      * ```js
87381      * viewer.deactivateComponent("pointer");
87382      * ```
87383      */
87384     deactivateComponent(name) {
87385         this._componentController.deactivate(name);
87386     }
87387     /**
87388      * Deactivate the cover (activates all components marked as active).
87389      */
87390     deactivateCover() {
87391         this._componentController.deactivateCover();
87392     }
87393     /**
87394      * Detach a previously attached custom camera control
87395      * instance from the viewer.
87396      *
87397      * @description If no custom camera control instance
87398      * has previously been attached, calling this method
87399      * has no effect.
87400      *
87401      * Already attached custom camera controls need to
87402      * be detached before attaching another custom camera
87403      * control instance.
87404      */
87405     detachCustomCameraControls() {
87406         this._customCameraControls.detach(this);
87407     }
87408     fire(type, event) {
87409         super.fire(type, event);
87410     }
87411     /**
87412      * Get the bearing of the current viewer camera.
87413      *
87414      * @description The bearing depends on how the camera
87415      * is currently rotated and does not correspond
87416      * to the compass angle of the current image if the view
87417      * has been panned.
87418      *
87419      * Bearing is measured in degrees clockwise with respect to
87420      * north.
87421      *
87422      * @returns {Promise<number>} Promise to the bearing
87423      * of the current viewer camera.
87424      *
87425      * @example
87426      * ```js
87427      * viewer.getBearing().then(b => { console.log(b); });
87428      * ```
87429      */
87430     getBearing() {
87431         return new Promise((resolve, reject) => {
87432             this._container.renderService.bearing$.pipe(first())
87433                 .subscribe((bearing) => {
87434                 resolve(bearing);
87435             }, (error) => {
87436                 reject(error);
87437             });
87438         });
87439     }
87440     /**
87441      * Get the viewer's camera control mode.
87442      *
87443      * @description The camera control mode determines
87444      * how the camera is controlled when the viewer
87445      * recieves pointer and keyboard input.
87446      *
87447      * @returns {CameraControls} controls - Camera control mode.
87448      *
87449      * @example
87450      * ```js
87451      * viewer.getCameraControls().then(c => { console.log(c); });
87452      * ```
87453      */
87454     getCameraControls() {
87455         return new Promise((resolve, reject) => {
87456             this._navigator.stateService.state$.pipe(first())
87457                 .subscribe((state) => {
87458                 switch (state) {
87459                     case State.Custom:
87460                         resolve(CameraControls.Custom);
87461                         break;
87462                     case State.Earth:
87463                         resolve(CameraControls.Earth);
87464                         break;
87465                     default:
87466                         resolve(CameraControls.Street);
87467                         break;
87468                 }
87469             }, (error) => {
87470                 reject(error);
87471             });
87472         });
87473     }
87474     /**
87475      * Returns the viewer's canvas element.
87476      *
87477      * @description This is the element onto which the viewer renders
87478      * the WebGL content.
87479      *
87480      * @returns {HTMLCanvasElement} The viewer's canvas element, or
87481      * null or not initialized.
87482      */
87483     getCanvas() {
87484         return this._container.canvas;
87485     }
87486     /**
87487      * Returns the HTML element containing the viewer's canvas element.
87488      *
87489      * @description This is the element to which event bindings for viewer
87490      * interactivity (such as panning and zooming) are attached.
87491      *
87492      * @returns {HTMLDivElement} The container for the viewer's
87493      * canvas element.
87494      */
87495     getCanvasContainer() {
87496         return this._container.canvasContainer;
87497     }
87498     /**
87499      * Get the basic coordinates of the current image that is
87500      * at the center of the viewport.
87501      *
87502      * @description Basic coordinates are 2D coordinates on the [0, 1] interval
87503      * and have the origin point, (0, 0), at the top left corner and the
87504      * maximum value, (1, 1), at the bottom right corner of the original
87505      * image.
87506      *
87507      * @returns {Promise<number[]>} Promise to the basic coordinates
87508      * of the current image at the center for the viewport.
87509      *
87510      * @example
87511      * ```js
87512      * viewer.getCenter().then(c => { console.log(c); });
87513      * ```
87514      */
87515     getCenter() {
87516         return new Promise((resolve, reject) => {
87517             this._navigator.stateService.getCenter()
87518                 .subscribe((center) => {
87519                 resolve(center);
87520             }, (error) => {
87521                 reject(error);
87522             });
87523         });
87524     }
87525     /**
87526      * Get a component.
87527      *
87528      * @param {string} name - Name of component.
87529      * @returns {Component} The requested component.
87530      *
87531      * @example
87532      * ```js
87533      * var pointerComponent = viewer.getComponent("pointer");
87534      * ```
87535      */
87536     getComponent(name) {
87537         return this._componentController.get(name);
87538     }
87539     /**
87540      * Returns the viewer's containing HTML element.
87541      *
87542      * @returns {HTMLElement} The viewer's container.
87543      */
87544     getContainer() {
87545         return this._container.container;
87546     }
87547     /**
87548      * Get the viewer's current vertical field of view.
87549      *
87550      * @description The vertical field of view rendered on the viewer canvas
87551      * measured in degrees.
87552      *
87553      * @returns {Promise<number>} Promise to the current field of view
87554      * of the viewer camera.
87555      *
87556      * @example
87557      * ```js
87558      * viewer.getFieldOfView().then(fov => { console.log(fov); });
87559      * ```
87560      */
87561     getFieldOfView() {
87562         return new Promise((resolve, reject) => {
87563             this._container.renderService.renderCamera$.pipe(first())
87564                 .subscribe((rc) => {
87565                 resolve(rc.perspective.fov);
87566             }, (error) => {
87567                 reject(error);
87568             });
87569         });
87570     }
87571     /**
87572      * Get the viewer's current image.
87573      *
87574      * @returns {Promise<Image>} Promise to the current image.
87575      *
87576      * @example
87577      * ```js
87578      * viewer.getImage().then(image => { console.log(image.id); });
87579      * ```
87580      */
87581     getImage() {
87582         return new Promise((resolve, reject) => {
87583             this._navigator.stateService.currentImage$.pipe(first())
87584                 .subscribe((image) => { resolve(image); }, (error) => { reject(error); });
87585         });
87586     }
87587     /**
87588      * Get the viewer's current point of view.
87589      *
87590      * @returns {Promise<PointOfView>} Promise to the current point of view
87591      * of the viewer camera.
87592      *
87593      * @example
87594      * ```js
87595      * viewer.getPointOfView().then(pov => { console.log(pov); });
87596      * ```
87597      */
87598     getPointOfView() {
87599         return new Promise((resolve, reject) => {
87600             combineLatest(this._container.renderService.renderCamera$, this._container.renderService.bearing$).pipe(first())
87601                 .subscribe(([rc, bearing]) => {
87602                 resolve({
87603                     bearing: bearing,
87604                     tilt: rc.getTilt(),
87605                 });
87606             }, (error) => {
87607                 reject(error);
87608             });
87609         });
87610     }
87611     /**
87612      * Get the viewer's current position
87613      *
87614      * @returns {Promise<LngLat>} Promise to the viewers's current
87615      * position.
87616      *
87617      * @example
87618      * ```js
87619      * viewer.getPosition().then(pos => { console.log(pos); });
87620      * ```
87621      */
87622     getPosition() {
87623         return new Promise((resolve, reject) => {
87624             combineLatest(this._container.renderService.renderCamera$, this._navigator.stateService.reference$).pipe(first())
87625                 .subscribe(([render, reference]) => {
87626                 resolve(this._observer.projection.cameraToLngLat(render, reference));
87627             }, (error) => {
87628                 reject(error);
87629             });
87630         });
87631     }
87632     /**
87633      * Get the image's current zoom level.
87634      *
87635      * @returns {Promise<number>} Promise to the viewers's current
87636      * zoom level.
87637      *
87638      * @example
87639      * ```js
87640      * viewer.getZoom().then(z => { console.log(z); });
87641      * ```
87642      */
87643     getZoom() {
87644         return new Promise((resolve, reject) => {
87645             this._navigator.stateService.getZoom()
87646                 .subscribe((zoom) => {
87647                 resolve(zoom);
87648             }, (error) => {
87649                 reject(error);
87650             });
87651         });
87652     }
87653     /**
87654      * Check if a custom renderer has been added to the viewer's
87655      * rendering pipeline.
87656      *
87657      * @param {string} id - Unique id of the custom renderer.
87658      * @returns {boolean} Value indicating whether the customer
87659      * renderer has been added.
87660      */
87661     hasCustomRenderer(rendererId) {
87662         return this._customRenderer.has(rendererId);
87663     }
87664     /**
87665      * Navigate in a given direction.
87666      *
87667      * @param {NavigationDirection} direction - Direction in which which to move.
87668      * @returns {Promise<Image>} Promise to the image that was navigated to.
87669      * @throws If the current image does not have the edge direction
87670      * or the edges has not yet been cached.
87671      * @throws Propagates any IO errors to the caller.
87672      * @throws When viewer is not navigable.
87673      * @throws {@link CancelMapillaryError} When a subsequent move request
87674      * is made before the move dir call has completed.
87675      *
87676      * @example
87677      * ```js
87678      * viewer.moveDir(NavigationDirection.Next).then(
87679      *     image => { console.log(image); },
87680      *     error => { console.error(error); });
87681      * ```
87682      */
87683     moveDir(direction) {
87684         const moveDir$ = this.isNavigable ?
87685             this._navigator.moveDir$(direction) :
87686             throwError(new Error("Calling moveDir is not supported when viewer is not navigable."));
87687         return new Promise((resolve, reject) => {
87688             moveDir$.subscribe((image) => {
87689                 resolve(image);
87690             }, (error) => {
87691                 reject(error);
87692             });
87693         });
87694     }
87695     /**
87696      * Navigate to a given image id.
87697      *
87698      * @param {string} imageId - Id of the image to move to.
87699      * @returns {Promise<Image>} Promise to the image that was navigated to.
87700      * @throws Propagates any IO errors to the caller.
87701      * @throws When viewer is not navigable.
87702      * @throws {@link CancelMapillaryError} When a subsequent
87703      * move request is made before the move to id call has completed.
87704      *
87705      * @example
87706      * ```js
87707      * viewer.moveTo("<my-image-id>").then(
87708      *     image => { console.log(image); },
87709      *     error => { console.error(error); });
87710      * ```
87711      */
87712     moveTo(imageId) {
87713         const moveTo$ = this.isNavigable ?
87714             this._navigator.moveTo$(imageId) :
87715             throwError(new Error("Calling moveTo is not supported when viewer is not navigable."));
87716         return new Promise((resolve, reject) => {
87717             moveTo$.subscribe((image) => {
87718                 resolve(image);
87719             }, (error) => {
87720                 reject(error);
87721             });
87722         });
87723     }
87724     off(type, handler) {
87725         super.off(type, handler);
87726     }
87727     on(type, handler) {
87728         super.on(type, handler);
87729     }
87730     /**
87731      * Project geodetic coordinates to canvas pixel coordinates.
87732      *
87733      * @description The geodetic coordinates may not always correspond to pixel
87734      * coordinates, e.g. if the geodetic coordinates have a position behind the
87735      * viewer camera. In the case of no correspondence the returned value will
87736      * be `null`.
87737      *
87738      * If the distance from the viewer camera position to the provided
87739      * longitude-latitude is more than 1000 meters `null` will be returned.
87740      *
87741      * The projection is performed from the ground plane, i.e.
87742      * the altitude with respect to the ground plane for the geodetic
87743      * point is zero.
87744      *
87745      * Note that whenever the camera moves, the result of the method will be
87746      * different.
87747      *
87748      * @param {LngLat} lngLat - Geographical coordinates to project.
87749      * @returns {Promise<Array<number>>} Promise to the pixel coordinates corresponding
87750      * to the lngLat.
87751      *
87752      * @example
87753      * ```js
87754      * viewer.project({ lat: 0, lng: 0 })
87755      *     .then(pixelPoint => {
87756      *          if (!pixelPoint) {
87757      *              console.log("no correspondence");
87758      *          }
87759      *
87760      *          console.log(pixelPoint);
87761      *     });
87762      * ```
87763      */
87764     project(lngLat) {
87765         return new Promise((resolve, reject) => {
87766             this._observer.project$(lngLat)
87767                 .subscribe((pixelPoint) => {
87768                 resolve(pixelPoint);
87769             }, (error) => {
87770                 reject(error);
87771             });
87772         });
87773     }
87774     /**
87775      * Project basic image coordinates for the current image to canvas pixel
87776      * coordinates.
87777      *
87778      * @description The basic image coordinates may not always correspond to a
87779      * pixel point that lies in the visible area of the viewer container. In the
87780      * case of no correspondence the returned value can be `null`.
87781      *
87782      *
87783      * @param {Array<number>} basicPoint - Basic images coordinates to project.
87784      * @returns {Promise<Array<number>>} Promise to the pixel coordinates corresponding
87785      * to the basic image point.
87786      *
87787      * @example
87788      * ```js
87789      * viewer.projectFromBasic([0.3, 0.7])
87790      *     .then(pixelPoint => { console.log(pixelPoint); });
87791      * ```
87792      */
87793     projectFromBasic(basicPoint) {
87794         return new Promise((resolve, reject) => {
87795             this._observer.projectBasic$(basicPoint)
87796                 .subscribe((pixelPoint) => {
87797                 resolve(pixelPoint);
87798             }, (error) => {
87799                 reject(error);
87800             });
87801         });
87802     }
87803     /**
87804      * Clean up and release all internal resources associated with
87805      * this viewer.
87806      *
87807      * @description This includes DOM elements, event bindings, and
87808      * WebGL resources.
87809      *
87810      * Use this method when you are done using the viewer and wish to
87811      * ensure that it no longer consumes browser resources. Afterwards,
87812      * you must not call any other methods on the viewer.
87813      *
87814      * @fires remove
87815      *
87816      * @example
87817      * ```js
87818      * viewer.remove();
87819      * ```
87820      */
87821     remove() {
87822         this._customRenderer.dispose(this);
87823         this._customCameraControls.dispose(this);
87824         this._observer.dispose();
87825         this._componentController.remove();
87826         this._navigator.dispose();
87827         this._container.remove();
87828         const type = "remove";
87829         const event = {
87830             target: this,
87831             type,
87832         };
87833         this.fire(type, event);
87834     }
87835     /**
87836      * Remove a custom renderer from the viewer's rendering pipeline.
87837      *
87838      * @param id - Unique id of the custom renderer.
87839      */
87840     removeCustomRenderer(rendererId) {
87841         this._customRenderer.remove(rendererId, this);
87842     }
87843     /**
87844      * Detect the viewer's new width and height and resize it
87845      * manually.
87846      *
87847      * @description The components will also detect the viewer's
87848      * new size and resize their rendered elements if needed.
87849      *
87850      * When the {@link ViewerOptions.trackResize} option is
87851      * set to true, the viewer will automatically resize
87852      * when the browser window is resized. If any other
87853      * custom behavior is preferred, the option should be set
87854      * to false and the {@link Viewer.resize} method should
87855      * be called on demand.
87856      *
87857      * @example
87858      * ```js
87859      * viewer.resize();
87860      * ```
87861      */
87862     resize() {
87863         this._container.renderService.resize$.next();
87864     }
87865     /**
87866      * Set the viewer's camera control mode.
87867      *
87868      * @description The camera control mode determines
87869      * how the camera is controlled when the viewer
87870      * recieves pointer and keyboard input.
87871      *
87872      * Changing the camera control mode is not possible
87873      * when the slider component is active and attempts
87874      * to do so will be ignored.
87875      *
87876      * @param {CameraControls} controls - Camera control mode.
87877      *
87878      * @example
87879      * ```js
87880      * viewer.setCameraControls(CameraControls.Street);
87881      * ```
87882      */
87883     setCameraControls(controls) {
87884         const state = cameraControlsToState(controls);
87885         if (state === State.Traversing) {
87886             this._navigator.stateService.traverse();
87887         }
87888         else if (state === State.Earth) {
87889             this._navigator.stateService.earth();
87890         }
87891         else if (state === State.Custom) {
87892             this._navigator.stateService.custom();
87893         }
87894         else {
87895             console.warn(`Unsupported camera control transition (${controls})`);
87896         }
87897     }
87898     /**
87899      * Set the basic coordinates of the current image to be in the
87900      * center of the viewport.
87901      *
87902      * @description Basic coordinates are 2D coordinates on the [0, 1] interval
87903      * and has the origin point, (0, 0), at the top left corner and the
87904      * maximum value, (1, 1), at the bottom right corner of the original
87905      * image.
87906      *
87907      * @param {number[]} The basic coordinates of the current
87908      * image to be at the center for the viewport.
87909      *
87910      * @example
87911      * ```js
87912      * viewer.setCenter([0.5, 0.5]);
87913      * ```
87914      */
87915     setCenter(center) {
87916         this._navigator.stateService.setCenter(center);
87917     }
87918     /**
87919      * Set the viewer's current vertical field of view.
87920      *
87921      * @description Sets the vertical field of view rendered
87922      * on the viewer canvas measured in degrees. The value
87923      * will be clamped to be able to set a valid zoom level
87924      * based on the projection model of the current image and
87925      * the viewer's current render mode.
87926      *
87927      * @param {number} fov - Vertical field of view in degrees.
87928      *
87929      * @example
87930      * ```js
87931      * viewer.setFieldOfView(45);
87932      * ```
87933      */
87934     setFieldOfView(fov) {
87935         this._container.renderService.renderCamera$.pipe(first())
87936             .subscribe((rc) => {
87937             const zoom = rc.fovToZoom(fov);
87938             this._navigator.stateService.setZoom(zoom);
87939         });
87940     }
87941     /**
87942      * Set the filter selecting images to use when calculating
87943      * the spatial edges.
87944      *
87945      * @description The following filter types are supported:
87946      *
87947      * Comparison
87948      *
87949      * `["==", key, value]` equality: `image[key] = value`
87950      *
87951      * `["!=", key, value]` inequality: `image[key] ≠ value`
87952      *
87953      * `["<", key, value]` less than: `image[key] < value`
87954      *
87955      * `["<=", key, value]` less than or equal: `image[key] ≤ value`
87956      *
87957      * `[">", key, value]` greater than: `image[key] > value`
87958      *
87959      * `[">=", key, value]` greater than or equal: `image[key] ≥ value`
87960      *
87961      * Set membership
87962      *
87963      * `["in", key, v0, ..., vn]` set inclusion: `image[key] ∈ {v0, ..., vn}`
87964      *
87965      * `["!in", key, v0, ..., vn]` set exclusion: `image[key] ∉ {v0, ..., vn}`
87966      *
87967      * Combining
87968      *
87969      * `["all", f0, ..., fn]` logical `AND`: `f0 ∧ ... ∧ fn`
87970      *
87971      * A key must be a string that identifies a property name of a
87972      * simple {@link Image} property, i.e. a key of the {@link FilterKey}
87973      * type. A value must be a string, number, or
87974      * boolean. Strictly-typed comparisons are used. The values
87975      * `f0, ..., fn` of the combining filter must be filter expressions.
87976      *
87977      * Clear the filter by setting it to null or empty array.
87978      *
87979      * Commonly used filter properties (see the {@link Image} class
87980      * documentation for a full list of properties that can be used
87981      * in a filter) are shown the the example code.
87982      *
87983      * @param {FilterExpression} filter - The filter expression.
87984      * @returns {Promise<void>} Promise that resolves after filter is applied.
87985      *
87986      * @example
87987      * ```js
87988      * // Examples
87989      * viewer.setFilter(["==", "cameraType", "spherical"]);
87990      * viewer.setFilter([">=", "capturedAt", <my-time-stamp>]);
87991      * viewer.setFilter(["in", "sequenceId", "<sequence-id-1>", "<sequence-id-2>"]);
87992      * ```
87993      */
87994     setFilter(filter) {
87995         return new Promise((resolve, reject) => {
87996             this._navigator.setFilter$(filter)
87997                 .subscribe(() => {
87998                 resolve(undefined);
87999             }, (error) => {
88000                 reject(error);
88001             });
88002         });
88003     }
88004     /**
88005      * Set the viewer's render mode.
88006      *
88007      * @param {RenderMode} renderMode - Render mode.
88008      *
88009      * @example
88010      * ```js
88011      * viewer.setRenderMode(RenderMode.Letterbox);
88012      * ```
88013      */
88014     setRenderMode(renderMode) {
88015         this._container.renderService.renderMode$.next(renderMode);
88016     }
88017     /**
88018      * Set the viewer's transition mode.
88019      *
88020      * @param {TransitionMode} transitionMode - Transition mode.
88021      *
88022      * @example
88023      * ```js
88024      * viewer.setTransitionMode(TransitionMode.Instantaneous);
88025      * ```
88026      */
88027     setTransitionMode(transitionMode) {
88028         this._navigator.stateService.setTransitionMode(transitionMode);
88029     }
88030     /**
88031      * Set an access token for authenticated API requests of protected
88032      * resources.
88033      *
88034      * The token may be a user access token or a client access token.
88035      *
88036      * @description When the supplied user token is null or undefined,
88037      * any previously set user bearer token will be cleared and the
88038      * viewer will make unauthenticated requests.
88039      *
88040      * Calling setAccessToken aborts all outstanding move requests.
88041      * The promises of those move requests will be rejected with a
88042      * {@link CancelMapillaryError} the rejections need to be caught.
88043      *
88044      * Calling setAccessToken also resets the complete viewer cache
88045      * so it should not be called repeatedly.
88046      *
88047      * @param {string} [accessToken] accessToken - Optional user
88048      * access token or client access token.
88049      * @returns {Promise<void>} Promise that resolves after token
88050      * is set.
88051      *
88052      * @throws When viewer is not navigable.
88053      *
88054      * @example
88055      * ```js
88056      * viewer.setAccessToken("<my access token>")
88057      *     .then(() => { console.log("user token set"); });
88058      * ```
88059      */
88060     setAccessToken(accessToken) {
88061         const setAccessToken$ = this.isNavigable ?
88062             this._navigator.setAccessToken$(accessToken) :
88063             throwError(new Error("Calling setAccessToken is not supported when viewer is not navigable."));
88064         return new Promise((resolve, reject) => {
88065             setAccessToken$
88066                 .subscribe(() => {
88067                 resolve(undefined);
88068             }, (error) => {
88069                 reject(error);
88070             });
88071         });
88072     }
88073     /**
88074      * Set the image's current zoom level.
88075      *
88076      * @description Possible zoom level values are on the [0, 3] interval.
88077      * Zero means zooming out to fit the image to the view whereas three
88078      * shows the highest level of detail.
88079      *
88080      * @param {number} The image's current zoom level.
88081      *
88082      * @example
88083      * ```js
88084      * viewer.setZoom(2);
88085      * ```
88086      */
88087     setZoom(zoom) {
88088         this._navigator.stateService.setZoom(zoom);
88089     }
88090     /**
88091      * Trigger the rendering of a single frame.
88092      *
88093      * @description Use this method with custom renderers to
88094      * force the viewer to rerender when the custom content
88095      * changes. Calling this multiple times before the next
88096      * frame is rendered will still result in only a single
88097      * frame being rendered.
88098      */
88099     triggerRerender() {
88100         this._container.glRenderer.triggerRerender();
88101     }
88102     /**
88103      * Unproject canvas pixel coordinates to geodetic
88104      * coordinates.
88105      *
88106      * @description The pixel point may not always correspond to geodetic
88107      * coordinates. In the case of no correspondence the returned value will
88108      * be `null`.
88109      *
88110      * The unprojection to a lngLat will be performed towards the ground plane, i.e.
88111      * the altitude with respect to the ground plane for the returned lngLat is zero.
88112      *
88113      * @param {Array<number>} pixelPoint - Pixel coordinates to unproject.
88114      * @returns {Promise<LngLat>} Promise to the lngLat corresponding to the pixel point.
88115      *
88116      * @example
88117      * ```js
88118      * viewer.unproject([100, 100])
88119      *     .then(lngLat => { console.log(lngLat); });
88120      * ```
88121      */
88122     unproject(pixelPoint) {
88123         return new Promise((resolve, reject) => {
88124             this._observer.unproject$(pixelPoint)
88125                 .subscribe((lngLat) => {
88126                 resolve(lngLat);
88127             }, (error) => {
88128                 reject(error);
88129             });
88130         });
88131     }
88132     /**
88133      * Unproject canvas pixel coordinates to basic image coordinates for the
88134      * current image.
88135      *
88136      * @description The pixel point may not always correspond to basic image
88137      * coordinates. In the case of no correspondence the returned value will
88138      * be `null`.
88139      *
88140      * @param {Array<number>} pixelPoint - Pixel coordinates to unproject.
88141      * @returns {Promise<LngLat>} Promise to the basic coordinates corresponding
88142      * to the pixel point.
88143      *
88144      * @example
88145      * ```js
88146      * viewer.unprojectToBasic([100, 100])
88147      *     .then(basicPoint => { console.log(basicPoint); });
88148      * ```
88149      */
88150     unprojectToBasic(pixelPoint) {
88151         return new Promise((resolve, reject) => {
88152             this._observer.unprojectBasic$(pixelPoint)
88153                 .subscribe((basicPoint) => {
88154                 resolve(basicPoint);
88155             }, (error) => {
88156                 reject(error);
88157             });
88158         });
88159     }
88160 }
88161
88162 /**
88163  * Internal bootstrap
88164  *
88165  * This is a workaround to make the CommonJS unit testing
88166  * work with Jest. Once Jest/Node supports ES6 modules
88167  * fully this should be removed. GeoRBush and UnitBezier
88168  * are registered here only to avoid loading them during
88169  * unit tests.
88170  */
88171 Graph.register(GeoRBush);
88172 MarkerSet.register(GeoRBush);
88173 TraversingState.register(unitbezier);
88174 ComponentService.registerCover(CoverComponent);
88175 ComponentService.register(AttributionComponent);
88176 ComponentService.register(BearingComponent);
88177 ComponentService.register(CacheComponent);
88178 ComponentService.register(DirectionComponent);
88179 ComponentService.register(ImageComponent);
88180 ComponentService.register(KeyboardComponent);
88181 ComponentService.register(MarkerComponent);
88182 ComponentService.register(PointerComponent);
88183 ComponentService.register(PopupComponent);
88184 ComponentService.register(SequenceComponent);
88185 ComponentService.register(SliderComponent);
88186 ComponentService.register(SpatialComponent);
88187 ComponentService.register(TagComponent);
88188 ComponentService.register(ZoomComponent);
88189 ComponentService.register(ImageFallbackComponent);
88190 ComponentService.register(NavigationFallbackComponent);
88191
88192 export { Alignment, ArgumentMapillaryError, BearingComponent, CacheComponent, CameraControls, CameraVisualizationMode, CancelMapillaryError, CircleMarker, Component, ComponentSize, DataProviderBase, DirectionComponent, DragPanHandler, ExtremePointTag, Geometry, GeometryProviderBase, GeometryTagError, GraphDataProvider, GraphMapillaryError, Image$1 as Image, KeyPlayHandler, KeySequenceNavigationHandler, KeySpatialNavigationHandler, KeyZoomHandler, KeyboardComponent, MapillaryError, Marker, MarkerComponent, NavigationDirection, OriginalPositionMode, OutlineTag, PointGeometry, PointerComponent, PointsGeometry, PolygonGeometry, Popup, PopupComponent, RectGeometry, RenderMode, RenderPass, S2GeometryProvider, ScrollZoomHandler, SequenceComponent, SimpleMarker, SliderComponent, SliderConfigurationMode, SpatialComponent, SpotTag, Tag, TagComponent, TagDomain, TagMode, TouchZoomHandler, TransitionMode, VertexGeometry, Viewer, ZoomComponent, decompress, enuToGeodetic, fetchArrayBuffer, geodeticToEnu, isFallbackSupported, isSupported, readMeshPbf };
88193 //# sourceMappingURL=mapillary.module.js.map